2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 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/>.
22 #include "claws-features.h"
28 #include <glib/gi18n.h>
38 #include <sys/types.h>
45 #include <X11/SM/SMlib.h>
52 #include "file_checker.h"
54 #ifdef HAVE_STARTUP_NOTIFICATION
55 # define SN_API_NOT_YET_FROZEN
56 # include <libsn/sn-launchee.h>
57 # include <gdk/gdkx.h>
61 #include <dbus/dbus-glib.h>
63 #ifdef HAVE_NETWORKMANAGER_SUPPORT
64 #include <NetworkManager.h>
72 #include "mainwindow.h"
73 #include "folderview.h"
74 #include "image_viewer.h"
75 #include "summaryview.h"
76 #include "prefs_common.h"
77 #include "prefs_account.h"
78 #include "prefs_actions.h"
79 #include "prefs_ext_prog.h"
80 #include "prefs_fonts.h"
81 #include "prefs_image_viewer.h"
82 #include "prefs_message.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_NEW_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"
132 #include "imap-thread.h"
133 #include "nntp-thread.h"
135 #include "stock_pixmap.h"
146 #ifdef HAVE_NETWORKMANAGER_SUPPORT
147 /* Went offline due to NetworkManager */
148 static gboolean went_offline_nm
;
151 #if !defined(NM_CHECK_VERSION)
152 #define NM_CHECK_VERSION(x,y,z) 0
155 #ifdef HAVE_DBUS_GLIB
156 static DBusGProxy
*awn_proxy
= NULL
;
162 #ifdef HAVE_STARTUP_NOTIFICATION
163 static SnLauncheeContext
*sn_context
= NULL
;
164 static SnDisplay
*sn_display
= NULL
;
167 static gint lock_socket
= -1;
168 static gint lock_socket_tag
= 0;
169 static gchar
*x_display
= NULL
;
172 ONLINE_MODE_DONT_CHANGE
,
177 static struct RemoteCmd
{
179 gboolean receive_all
;
180 gboolean cancel_receiving
;
181 gboolean cancel_sending
;
183 const gchar
*compose_mailto
;
186 const gchar
*search_folder
;
187 const gchar
*search_type
;
188 const gchar
*search_request
;
189 gboolean search_recursive
;
191 gboolean status_full
;
193 gboolean reset_statistics
;
194 GPtrArray
*status_folders
;
195 GPtrArray
*status_full_folders
;
202 const gchar
*subscribe_uri
;
207 SessionStats session_stats
;
209 static void reset_statistics(void);
211 static void parse_cmd_opt(int argc
, char *argv
[]);
213 static gint
prohibit_duplicate_launch (void);
214 static gchar
* get_crashfile_name (void);
215 static gint
lock_socket_remove (void);
216 static void lock_socket_input_cb (gpointer data
,
218 GIOCondition condition
);
220 static void open_compose_new (const gchar
*address
,
221 GList
*attach_files
);
223 static void send_queue (void);
224 static void initial_processing (FolderItem
*item
, gpointer data
);
225 static void quit_signal_handler (int sig
);
226 static void install_basic_sighandlers (void);
227 #if (defined linux && defined SIGIO)
228 static void install_memory_sighandler (void);
230 static void exit_claws (MainWindow
*mainwin
);
232 #ifdef HAVE_NETWORKMANAGER_SUPPORT
233 static void networkmanager_state_change_cb(DBusGProxy
*proxy
, gchar
*dev
,
237 #define MAKE_DIR_IF_NOT_EXIST(dir) \
239 if (!is_dir_exist(dir)) { \
240 if (is_file_exist(dir)) { \
242 (_("File '%s' already exists.\n" \
243 "Can't create folder."), \
247 if (make_dir(dir) < 0) \
252 static MainWindow
*static_mainwindow
;
254 static gboolean emergency_exit
= FALSE
;
256 #ifdef HAVE_STARTUP_NOTIFICATION
257 static void sn_error_trap_push(SnDisplay
*display
, Display
*xdisplay
)
259 gdk_error_trap_push();
262 static void sn_error_trap_pop(SnDisplay
*display
, Display
*xdisplay
)
264 gdk_error_trap_pop();
267 static void startup_notification_complete(gboolean with_window
)
270 GtkWidget
*hack
= NULL
;
273 /* this is needed to make the startup notification leave,
274 * if we have been launched from a menu.
275 * We have to display a window, so let it be very little */
276 hack
= gtk_window_new(GTK_WINDOW_POPUP
);
277 gtk_window_move(GTK_WINDOW(hack
), 0, 0);
278 gtk_widget_set_size_request(hack
, 1, 1);
279 gtk_widget_show(hack
);
282 xdisplay
= GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
283 sn_display
= sn_display_new(xdisplay
,
286 sn_context
= sn_launchee_context_new_from_environment(sn_display
,
287 DefaultScreen(xdisplay
));
289 if (sn_context
!= NULL
) {
290 sn_launchee_context_complete(sn_context
);
291 sn_launchee_context_unref(sn_context
);
292 sn_display_unref(sn_display
);
295 gtk_widget_destroy(hack
);
298 #endif /* HAVE_STARTUP_NOTIFICATION */
300 static void claws_gtk_idle(void)
302 while(gtk_events_pending()) {
303 gtk_main_iteration();
308 static gboolean sc_starting
= FALSE
;
310 static gboolean
defer_check_all(void *data
)
312 gboolean autochk
= GPOINTER_TO_INT(data
);
314 inc_all_account_mail(static_mainwindow
, autochk
,
315 prefs_common
.newmail_notify_manu
);
319 main_window_set_menu_sensitive(static_mainwindow
);
320 toolbar_main_set_sensitive(static_mainwindow
);
325 static gboolean
defer_check(void *data
)
327 inc_mail(static_mainwindow
, prefs_common
.newmail_notify_manu
);
331 main_window_set_menu_sensitive(static_mainwindow
);
332 toolbar_main_set_sensitive(static_mainwindow
);
337 static gboolean
defer_jump(void *data
)
339 if (cmd
.receive_all
) {
340 defer_check_all(GINT_TO_POINTER(FALSE
));
341 } else if (prefs_common
.chk_on_startup
) {
342 defer_check_all(GINT_TO_POINTER(TRUE
));
343 } else if (cmd
.receive
) {
346 mainwindow_jump_to(data
, FALSE
);
349 main_window_set_menu_sensitive(static_mainwindow
);
350 toolbar_main_set_sensitive(static_mainwindow
);
355 static void chk_update_val(GtkWidget
*widget
, gpointer data
)
357 gboolean
*val
= (gboolean
*)data
;
358 *val
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
361 static gboolean
migrate_old_config(const gchar
*old_cfg_dir
, const gchar
*new_cfg_dir
, const gchar
*oldversion
)
363 gchar
*message
= g_strdup_printf(_("Configuration for %s found.\n"
364 "Do you want to migrate this configuration?"), oldversion
);
365 gchar
*message2
= g_strdup_printf(_("\n\nYour Sylpheed filtering rules can be converted by a\n"
366 "script available at %s."), TOOLS_URI
);
368 if (!strcmp(oldversion
, "Sylpheed"))
369 message
= g_strconcat(message
, message2
, NULL
);
373 GtkWidget
*window
= NULL
;
374 GtkWidget
*keep_backup_chk
;
375 gboolean backup
= TRUE
;
377 keep_backup_chk
= gtk_check_button_new_with_label (_("Keep old configuration"));
378 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(keep_backup_chk
), TRUE
);
379 CLAWS_SET_TIP(keep_backup_chk
,
380 _("Keeping a backup will allow you to go back to an "
381 "older version, but may take a while if you have "
382 "cached IMAP or News data, and will take some extra "
383 "room on your disk."));
385 g_signal_connect(G_OBJECT(keep_backup_chk
), "toggled",
386 G_CALLBACK(chk_update_val
), &backup
);
388 if (alertpanel_full(_("Migration of configuration"), message
,
389 GTK_STOCK_NO
, "+" GTK_STOCK_YES
, NULL
, FALSE
,
390 keep_backup_chk
, ALERT_QUESTION
, G_ALERTDEFAULT
) != G_ALERTALTERNATE
) {
394 /* we can either do a fast migration requiring not any extra disk
395 * space, or a slow one that copies the old configuration and leaves
399 window
= label_window_create(_("Copying configuration... This may take a while..."));
402 r
= copy_dir(old_cfg_dir
, new_cfg_dir
);
403 label_window_destroy(window
);
405 /* if copy failed, we'll remove the partially copied
408 alertpanel_error(_("Migration failed!"));
409 remove_dir_recursive(new_cfg_dir
);
412 /* fast mode failed, but we don't want backup */
413 remove_dir_recursive(old_cfg_dir
);
417 window
= label_window_create(_("Migrating configuration..."));
420 r
= g_rename(old_cfg_dir
, new_cfg_dir
);
421 label_window_destroy(window
);
423 /* if g_rename failed, we'll try to copy */
425 FILE_OP_ERROR(new_cfg_dir
, "g_rename failed, trying copy\n");
432 static int migrate_common_rc(const gchar
*old_rc
, const gchar
*new_rc
)
435 gchar
*plugin_path
, *old_plugin_path
, *new_plugin_path
;
437 gboolean err
= FALSE
;
439 oldfp
= g_fopen(old_rc
, "r");
442 newfp
= g_fopen(new_rc
, "w");
448 plugin_path
= g_strdup(get_plugin_dir());
449 new_plugin_path
= g_strdup(plugin_path
);
451 if (strstr(plugin_path
, "/claws-mail/")) {
452 gchar
*end
= g_strdup(strstr(plugin_path
, "/claws-mail/")+strlen("/claws-mail/"));
453 *(strstr(plugin_path
, "/claws-mail/")) = '\0';
454 old_plugin_path
= g_strconcat(plugin_path
, "/sylpheed-claws/", end
, NULL
);
457 old_plugin_path
= g_strdup(new_plugin_path
);
459 debug_print("replacing %s with %s\n", old_plugin_path
, new_plugin_path
);
460 while (fgets(buf
, sizeof(buf
), oldfp
)) {
461 if (strncmp(buf
, old_plugin_path
, strlen(old_plugin_path
))) {
462 err
|= (fputs(buf
, newfp
) == EOF
);
464 debug_print("->replacing %s", buf
);
465 debug_print(" with %s%s", new_plugin_path
, buf
+strlen(old_plugin_path
));
466 err
|= (fputs(new_plugin_path
, newfp
) == EOF
);
467 err
|= (fputs(buf
+strlen(old_plugin_path
), newfp
) == EOF
);
471 g_free(new_plugin_path
);
472 g_free(old_plugin_path
);
474 if (fclose(newfp
) == EOF
)
482 sc_client_set_value (MainWindow
*mainwin
,
493 prop
.num_vals
= num_vals
;
497 if (mainwin
->smc_conn
)
498 SmcSetProperties ((SmcConn
) mainwin
->smc_conn
, 1, proplist
);
501 static void sc_die_callback (SmcConn smc_conn
, SmPointer client_data
)
506 static void sc_save_complete_callback(SmcConn smc_conn
, SmPointer client_data
)
510 static void sc_shutdown_cancelled_callback (SmcConn smc_conn
, SmPointer client_data
)
512 MainWindow
*mainwin
= (MainWindow
*)client_data
;
513 if (mainwin
->smc_conn
)
514 SmcSaveYourselfDone ((SmcConn
) mainwin
->smc_conn
, TRUE
);
517 static void sc_save_yourself_callback (SmcConn smc_conn
,
518 SmPointer client_data
,
524 MainWindow
*mainwin
= (MainWindow
*)client_data
;
525 if (mainwin
->smc_conn
)
526 SmcSaveYourselfDone ((SmcConn
) mainwin
->smc_conn
, TRUE
);
529 static IceIOErrorHandler sc_ice_installed_handler
;
531 static void sc_ice_io_error_handler (IceConn connection
)
533 if (sc_ice_installed_handler
)
534 (*sc_ice_installed_handler
) (connection
);
536 static gboolean
sc_process_ice_messages (GIOChannel
*source
,
537 GIOCondition condition
,
540 IceConn connection
= (IceConn
) data
;
541 IceProcessMessagesStatus status
;
543 status
= IceProcessMessages (connection
, NULL
, NULL
);
545 if (status
== IceProcessMessagesIOError
) {
546 IcePointer context
= IceGetConnectionContext (connection
);
548 if (context
&& G_IS_OBJECT(context
)) {
549 guint disconnect_id
= g_signal_lookup ("disconnect", G_OBJECT_TYPE (context
));
551 if (disconnect_id
> 0)
552 g_signal_emit (context
, disconnect_id
, 0);
554 IceSetShutdownNegotiation (connection
, False
);
555 IceCloseConnection (connection
);
562 static void new_ice_connection (IceConn connection
, IcePointer client_data
, Bool opening
,
563 IcePointer
*watch_data
)
569 /* Make sure we don't pass on these file descriptors to any
571 fcntl(IceConnectionNumber(connection
),F_SETFD
,
572 fcntl(IceConnectionNumber(connection
),F_GETFD
,0) | FD_CLOEXEC
);
574 channel
= g_io_channel_unix_new (IceConnectionNumber (connection
));
575 input_id
= g_io_add_watch (channel
,
576 G_IO_IN
| G_IO_HUP
| G_IO_ERR
| G_IO_PRI
,
577 sc_process_ice_messages
,
579 g_io_channel_unref (channel
);
581 *watch_data
= (IcePointer
) GUINT_TO_POINTER (input_id
);
583 input_id
= GPOINTER_TO_UINT ((gpointer
) *watch_data
);
584 g_source_remove (input_id
);
588 static void sc_session_manager_connect(MainWindow
*mainwin
)
590 static gboolean connected
= FALSE
;
591 SmcCallbacks callbacks
;
593 IceIOErrorHandler default_handler
;
600 sc_ice_installed_handler
= IceSetIOErrorHandler (NULL
);
601 default_handler
= IceSetIOErrorHandler (sc_ice_io_error_handler
);
603 if (sc_ice_installed_handler
== default_handler
)
604 sc_ice_installed_handler
= NULL
;
606 IceAddConnectionWatch (new_ice_connection
, NULL
);
609 callbacks
.save_yourself
.callback
= sc_save_yourself_callback
;
610 callbacks
.die
.callback
= sc_die_callback
;
611 callbacks
.save_complete
.callback
= sc_save_complete_callback
;
612 callbacks
.shutdown_cancelled
.callback
= sc_shutdown_cancelled_callback
;
614 callbacks
.save_yourself
.client_data
=
615 callbacks
.die
.client_data
=
616 callbacks
.save_complete
.client_data
=
617 callbacks
.shutdown_cancelled
.client_data
= (SmPointer
) mainwin
;
618 if (g_getenv ("SESSION_MANAGER")) {
619 gchar error_string_ret
[256] = "";
621 mainwin
->smc_conn
= (gpointer
)
622 SmcOpenConnection (NULL
, mainwin
,
623 SmProtoMajor
, SmProtoMinor
,
624 SmcSaveYourselfProcMask
| SmcDieProcMask
|
625 SmcSaveCompleteProcMask
|
626 SmcShutdownCancelledProcMask
,
629 256, error_string_ret
);
631 if (error_string_ret
[0] || mainwin
->smc_conn
== NULL
)
632 g_warning ("While connecting to session manager:\n%s.",
636 vals
= g_new (SmPropValue
, 1);
637 vals
[0].length
= strlen(argv0
);
638 vals
[0].value
= argv0
;
639 sc_client_set_value (mainwin
, SmCloneCommand
, SmLISTofARRAY8
, 1, vals
);
640 sc_client_set_value (mainwin
, SmRestartCommand
, SmLISTofARRAY8
, 1, vals
);
641 sc_client_set_value (mainwin
, SmProgram
, SmARRAY8
, 1, vals
);
643 vals
[0].length
= strlen(g_get_user_name()?g_get_user_name():"");
644 vals
[0].value
= g_strdup(g_get_user_name()?g_get_user_name():"");
645 sc_client_set_value (mainwin
, SmUserID
, SmARRAY8
, 1, vals
);
653 static gboolean sc_exiting
= FALSE
;
654 static gboolean show_at_startup
= TRUE
;
655 static gboolean claws_crashed_bool
= FALSE
;
657 gboolean
claws_crashed(void) {
658 return claws_crashed_bool
;
661 void main_set_show_at_startup(gboolean show
)
663 show_at_startup
= show
;
667 static FILE* win32_debug_fp
=NULL
;
668 static guint win32_log_handler_app_id
;
669 static guint win32_log_handler_glib_id
;
670 static guint win32_log_handler_gtk_id
;
672 static void win32_print_stdout(const gchar
*string
)
674 if (win32_debug_fp
) {
675 fprintf(win32_debug_fp
, "%s", string
);
676 fflush(win32_debug_fp
);
680 static void win32_print_stderr(const gchar
*string
)
682 if (win32_debug_fp
) {
683 fprintf(win32_debug_fp
, "%s", string
);
684 fflush(win32_debug_fp
);
688 static void win32_log(const gchar
*log_domain
, GLogLevelFlags log_level
, const gchar
* message
, gpointer user_data
)
690 if (win32_debug_fp
) {
693 switch(log_level
& G_LOG_LEVEL_MASK
)
695 case G_LOG_LEVEL_ERROR
:
698 case G_LOG_LEVEL_CRITICAL
:
701 case G_LOG_LEVEL_WARNING
:
704 case G_LOG_LEVEL_MESSAGE
:
707 case G_LOG_LEVEL_INFO
:
710 case G_LOG_LEVEL_DEBUG
:
717 fprintf(win32_debug_fp
, "%s: %s: %s", log_domain
, type
, message
);
719 fprintf(win32_debug_fp
, "%s: %s", type
, message
);
720 fflush(win32_debug_fp
);
724 static void win32_open_log(void)
726 gchar
*logfile
= g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S
, "claws-win32.log", NULL
);
727 gchar
*oldlogfile
= g_strconcat(g_get_tmp_dir(), G_DIR_SEPARATOR_S
, "claws-win32.log.bak", NULL
);
729 if (is_file_exist(logfile
)) {
730 if (rename_force(logfile
, oldlogfile
) < 0)
731 FILE_OP_ERROR(logfile
, "rename");
733 win32_debug_fp
= g_fopen(logfile
, "w");
738 g_set_print_handler(win32_print_stdout
);
739 g_set_printerr_handler(win32_print_stdout
);
740 win32_log_handler_app_id
= g_log_set_handler(NULL
, G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
741 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
742 win32_log_handler_glib_id
= g_log_set_handler("GLib", G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
743 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
744 win32_log_handler_gtk_id
= g_log_set_handler("Gtk", G_LOG_LEVEL_MASK
| G_LOG_FLAG_FATAL
745 | G_LOG_FLAG_RECURSION
, win32_log
, NULL
);
749 static void win32_close_log(void)
753 g_log_remove_handler("", win32_log_handler_app_id
);
754 g_log_remove_handler("GLib", win32_log_handler_glib_id
);
755 g_log_remove_handler("Gtk", win32_log_handler_gtk_id
);
756 fclose(win32_debug_fp
);
762 static void main_dump_features_list(gboolean show_debug_only
)
763 /* display compiled-in features list */
765 if (show_debug_only
&& !debug_get_mode())
769 debug_print("runtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
770 gtk_major_version
, gtk_minor_version
, gtk_micro_version
,
771 glib_major_version
, glib_minor_version
, glib_micro_version
);
773 g_print("runtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
774 gtk_major_version
, gtk_minor_version
, gtk_micro_version
,
775 glib_major_version
, glib_minor_version
, glib_micro_version
);
777 debug_print("buildtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
778 GTK_MAJOR_VERSION
, GTK_MINOR_VERSION
, GTK_MICRO_VERSION
,
779 GLIB_MAJOR_VERSION
, GLIB_MINOR_VERSION
, GLIB_MICRO_VERSION
);
781 g_print("buildtime GTK+ %d.%d.%d / GLib %d.%d.%d\n",
782 GTK_MAJOR_VERSION
, GTK_MINOR_VERSION
, GTK_MICRO_VERSION
,
783 GLIB_MAJOR_VERSION
, GLIB_MINOR_VERSION
, GLIB_MICRO_VERSION
);
786 debug_print("Compiled-in features:\n");
788 g_print("Compiled-in features:\n");
791 debug_print(" compface\n");
793 g_print(" compface\n");
797 debug_print(" Enchant\n");
799 g_print(" Enchant\n");
803 debug_print(" GnuTLS\n");
805 g_print(" GnuTLS\n");
809 debug_print(" IPv6\n");
815 debug_print(" iconv\n");
821 debug_print(" JPilot\n");
823 g_print(" JPilot\n");
827 debug_print(" LDAP\n");
833 debug_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR
, LIBETPAN_VERSION_MINOR
);
835 g_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR
, LIBETPAN_VERSION_MINOR
);
839 debug_print(" libSM\n");
843 #if HAVE_NETWORKMANAGER_SUPPORT
845 debug_print(" NetworkManager\n");
847 g_print(" NetworkManager\n");
851 #ifdef HAVE_DBUS_GLIB
852 static guint dbus_item_hook_id
= -1;
853 static guint dbus_folder_hook_id
= -1;
855 static void uninstall_dbus_status_handler(void)
858 g_object_unref(awn_proxy
);
860 if (dbus_item_hook_id
!= -1)
861 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, dbus_item_hook_id
);
862 if (dbus_folder_hook_id
!= -1)
863 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST
, dbus_folder_hook_id
);
866 static void dbus_update(FolderItem
*removed_item
)
868 guint
new, unread
, unreadmarked
, marked
, total
;
869 guint replied
, forwarded
, locked
, ignored
, watched
;
871 GError
*error
= NULL
;
873 folder_count_total_msgs(&new, &unread
, &unreadmarked
, &marked
, &total
,
874 &replied
, &forwarded
, &locked
, &ignored
,
877 total
-= removed_item
->total_msgs
;
878 new -= removed_item
->new_msgs
;
879 unread
-= removed_item
->unread_msgs
;
883 buf
= g_strdup_printf("%d", new);
884 dbus_g_proxy_call(awn_proxy
, "SetInfoByName", &error
,
885 G_TYPE_STRING
, "claws-mail",
887 G_TYPE_INVALID
, G_TYPE_INVALID
);
891 dbus_g_proxy_call(awn_proxy
, "UnsetInfoByName", &error
, G_TYPE_STRING
,
892 "claws-mail", G_TYPE_INVALID
, G_TYPE_INVALID
);
895 debug_print("%s\n", error
->message
);
900 static gboolean
dbus_status_update_folder_hook(gpointer source
, gpointer data
)
902 FolderUpdateData
*hookdata
;
904 if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
)
905 dbus_update(hookdata
->item
);
912 static gboolean
dbus_status_update_item_hook(gpointer source
, gpointer data
)
919 static void install_dbus_status_handler(void)
921 GError
*tmp_error
= NULL
;
922 DBusGConnection
*connection
= dbus_g_bus_get(DBUS_BUS_SESSION
, &tmp_error
);
925 /* If calling code doesn't do error checking, at least print some debug */
926 debug_print("Failed to open connection to session bus: %s\n",
928 g_error_free(tmp_error
);
931 awn_proxy
= dbus_g_proxy_new_for_name(connection
,
932 "com.google.code.Awn",
933 "/com/google/code/Awn",
934 "com.google.code.Awn");
935 dbus_item_hook_id
= hooks_register_hook (FOLDER_ITEM_UPDATE_HOOKLIST
, dbus_status_update_item_hook
, NULL
);
936 if (dbus_item_hook_id
== -1) {
937 g_warning(_("Failed to register folder item update hook"));
938 uninstall_dbus_status_handler();
942 dbus_folder_hook_id
= hooks_register_hook (FOLDER_UPDATE_HOOKLIST
, dbus_status_update_folder_hook
, NULL
);
943 if (dbus_folder_hook_id
== -1) {
944 g_warning(_("Failed to register folder update hook"));
945 uninstall_dbus_status_handler();
951 static void reset_statistics(void)
953 /* (re-)initialize session statistics */
954 session_stats
.received
= 0;
955 session_stats
.sent
= 0;
956 session_stats
.replied
= 0;
957 session_stats
.forwarded
= 0;
958 session_stats
.time_started
= time(NULL
);
961 int main(int argc
, char *argv
[])
963 #ifdef HAVE_DBUS_GLIB
964 DBusGConnection
*connection
;
967 #ifdef HAVE_NETWORKMANAGER_SUPPORT
968 DBusGProxy
*nm_proxy
;
972 FolderView
*folderview
;
974 gboolean crash_file_present
= FALSE
;
975 gint num_folder_class
= 0;
976 gboolean asked_for_migration
= FALSE
;
977 gboolean start_done
= TRUE
;
978 GSList
*plug_list
= NULL
;
979 gboolean never_ran
= FALSE
;
980 gboolean mainwin_shown
= FALSE
;
982 START_TIMING("startup");
989 if (!claws_init(&argc
, &argv
)) {
996 prog_version
= PROG_VERSION
;
997 argv0
= g_strdup(argv
[0]);
999 parse_cmd_opt(argc
, argv
);
1003 /* check and create unix domain socket for remote operation */
1004 lock_socket
= prohibit_duplicate_launch();
1005 if (lock_socket
< 0) {
1006 #ifdef HAVE_STARTUP_NOTIFICATION
1007 if(gtk_init_check(&argc
, &argv
))
1008 startup_notification_complete(TRUE
);
1013 main_dump_features_list(TRUE
);
1014 prefs_prepare_cache();
1018 #if !GTK_CHECK_VERSION(3, 0, 0)
1021 gtk_init(&argc
, &argv
);
1022 crash_main(cmd
.crash_params
);
1028 crash_install_handlers();
1030 install_basic_sighandlers();
1031 #if (defined linux && defined SIGIO)
1032 install_memory_sighandler();
1035 if (cmd
.status
|| cmd
.status_full
|| cmd
.search
||
1036 cmd
.statistics
|| cmd
.reset_statistics
||
1037 cmd
.cancel_receiving
|| cmd
.cancel_sending
||
1039 puts("0 Claws Mail not running.");
1040 lock_socket_remove();
1046 #if !GLIB_CHECK_VERSION(2,32,0)
1047 if (!g_thread_supported())
1048 g_thread_init(NULL
);
1053 #if !GTK_CHECK_VERSION(3, 0, 0)
1056 gtk_init(&argc
, &argv
);
1059 gtk_settings_set_string_property(gtk_settings_get_default(),
1063 gtk_settings_set_long_property(gtk_settings_get_default(),
1064 "gtk-auto-mnemonics",
1069 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1070 went_offline_nm
= FALSE
;
1073 #ifdef HAVE_DBUS_GLIB
1075 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &error
);
1078 debug_print("Failed to open connection to system bus: %s\n", error
->message
);
1079 g_error_free(error
);
1082 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1083 nm_proxy
= dbus_g_proxy_new_for_name(connection
,
1084 "org.freedesktop.NetworkManager",
1085 "/org/freedesktop/NetworkManager",
1086 "org.freedesktop.NetworkManager");
1088 #if NM_CHECK_VERSION(0,8,992)
1089 dbus_g_proxy_add_signal(nm_proxy
, "StateChanged", G_TYPE_UINT
, G_TYPE_INVALID
);
1090 dbus_g_proxy_connect_signal(nm_proxy
, "StateChanged",
1091 G_CALLBACK(networkmanager_state_change_cb
),
1094 dbus_g_proxy_add_signal(nm_proxy
, "StateChange", G_TYPE_UINT
, G_TYPE_INVALID
);
1095 dbus_g_proxy_connect_signal(nm_proxy
, "StateChange",
1096 G_CALLBACK(networkmanager_state_change_cb
),
1101 install_dbus_status_handler();
1105 #if !GTK_CHECK_VERSION(3, 0, 0)
1106 gtk_widget_set_default_colormap(
1107 gdk_screen_get_system_colormap(
1108 gdk_screen_get_default()));
1111 gtkut_create_ui_manager();
1113 /* Create container for all the menus we will be adding */
1114 MENUITEM_ADDUI("/", "Menus", NULL
, GTK_UI_MANAGER_MENUBAR
);
1116 if (!g_thread_supported()) {
1117 g_error(_("g_thread is not supported by glib.\n"));
1121 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1123 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1126 /* no config dir exists. See if we can migrate an old config. */
1127 if (!is_dir_exist(RC_DIR
)) {
1128 prefs_destroy_cache();
1131 /* if one of the old dirs exist, we'll ask if the user
1132 * want to migrates, and r will be TRUE if he said yes
1133 * and migration succeeded, and FALSE otherwise.
1135 if (is_dir_exist(OLD_GTK2_RC_DIR
)) {
1136 r
= migrate_old_config(OLD_GTK2_RC_DIR
, RC_DIR
, _("Sylpheed-Claws 2.6.0 (or older)"));
1137 asked_for_migration
= TRUE
;
1138 } else if (is_dir_exist(OLDER_GTK2_RC_DIR
)) {
1139 r
= migrate_old_config(OLDER_GTK2_RC_DIR
, RC_DIR
, _("Sylpheed-Claws 1.9.15 (or older)"));
1140 asked_for_migration
= TRUE
;
1141 } else if (is_dir_exist(OLD_GTK1_RC_DIR
)) {
1142 r
= migrate_old_config(OLD_GTK1_RC_DIR
, RC_DIR
, _("Sylpheed-Claws 1.0.5 (or older)"));
1143 asked_for_migration
= TRUE
;
1144 } else if (is_dir_exist(SYLPHEED_RC_DIR
)) {
1145 r
= migrate_old_config(SYLPHEED_RC_DIR
, RC_DIR
, "Sylpheed");
1146 asked_for_migration
= TRUE
;
1149 /* If migration failed or the user didn't want to do it,
1150 * we create a new one (and we'll hit wizard later).
1152 if (r
== FALSE
&& !is_dir_exist(RC_DIR
)) {
1154 if (copy_dir(SYSCONFDIR
"/skel/.claws-mail", RC_DIR
) < 0) {
1156 if (!is_dir_exist(RC_DIR
) && make_dir(RC_DIR
) < 0) {
1169 if (!is_file_exist(RC_DIR G_DIR_SEPARATOR_S COMMON_RC
) &&
1170 is_file_exist(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC
)) {
1171 /* post 2.6 name change */
1172 migrate_common_rc(RC_DIR G_DIR_SEPARATOR_S OLD_COMMON_RC
,
1173 RC_DIR G_DIR_SEPARATOR_S COMMON_RC
);
1177 plugin_load_all("Common");
1179 userrc
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, "gtkrc-2.0", NULL
);
1180 gtk_rc_parse(userrc
);
1183 userrc
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, MENU_RC
, NULL
);
1184 gtk_accel_map_load (userrc
);
1188 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_rc_dir(), 1, win32_close_log(););
1190 CHDIR_RETURN_VAL_IF_FAIL(get_rc_dir(), 1);
1193 MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
1194 MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
1195 MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
1196 MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
1197 MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
1198 MAKE_DIR_IF_NOT_EXIST(UIDL_DIR
);
1200 crash_file_present
= is_file_exist(get_crashfile_name());
1201 /* remove temporary files */
1202 remove_all_files(get_tmp_dir());
1203 remove_all_files(get_mime_tmp_dir());
1205 if (!cmd
.crash
&& crash_file_present
)
1206 claws_crashed_bool
= TRUE
;
1208 if (is_file_exist("claws.log")) {
1209 if (rename_force("claws.log", "claws.log.bak") < 0)
1210 FILE_OP_ERROR("claws.log", "rename");
1212 set_log_file(LOG_PROTOCOL
, "claws.log");
1214 if (is_file_exist("filtering.log")) {
1215 if (rename_force("filtering.log", "filtering.log.bak") < 0)
1216 FILE_OP_ERROR("filtering.log", "rename");
1218 set_log_file(LOG_DEBUG_FILTERING
, "filtering.log");
1221 CHDIR_EXEC_CODE_RETURN_VAL_IF_FAIL(get_home_dir(), 1, win32_close_log(););
1223 CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1);
1226 folder_system_init();
1227 prefs_common_read_config();
1229 prefs_themes_init();
1231 prefs_ext_prog_init();
1232 prefs_wrapping_init();
1233 prefs_compose_writing_init();
1234 prefs_msg_colors_init();
1235 image_viewer_init();
1236 prefs_image_viewer_init();
1238 prefs_summaries_init();
1239 prefs_message_init();
1241 prefs_logging_init();
1242 prefs_receive_init();
1247 gtkaspell_checkers_init();
1248 prefs_spelling_init();
1252 if(prefs_common
.gtk_theme
&& strcmp(prefs_common
.gtk_theme
, DEFAULT_W32_GTK_THEME
))
1253 gtk_settings_set_string_property(gtk_settings_get_default(),
1255 prefs_common
.gtk_theme
,
1260 sock_set_io_timeout(prefs_common
.io_timeout_secs
);
1261 prefs_actions_read_config();
1262 prefs_display_header_read_config();
1263 /* prefs_filtering_read_config(); */
1264 #ifndef USE_NEW_ADDRBOOK
1265 addressbook_read_file();
1267 g_clear_error(&error
);
1268 if (! addressbook_start_service(&error
)) {
1269 g_warning("%s", error
->message
);
1270 g_clear_error(&error
);
1273 addressbook_install_hooks(&error
);
1276 gtkut_widget_init();
1277 stock_pixbuf_gdk(NULL
, STOCK_PIXMAP_CLAWS_MAIL_ICON
, &icon
);
1278 gtk_window_set_default_icon(icon
);
1280 folderview_initialize();
1286 mainwin
= main_window_create();
1288 if (!check_file_integrity())
1291 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1292 networkmanager_state_change_cb(nm_proxy
,NULL
,mainwin
);
1295 manage_window_focus_in(mainwin
->window
, NULL
, NULL
);
1296 folderview
= mainwin
->folderview
;
1298 gtk_cmclist_freeze(GTK_CMCLIST(mainwin
->folderview
->ctree
));
1299 folder_item_update_freeze();
1301 prefs_account_init();
1302 account_read_config_all();
1304 #ifdef HAVE_LIBETPAN
1305 imap_main_init(prefs_common
.skip_ssl_cert_check
);
1306 imap_main_set_timeout(prefs_common
.io_timeout_secs
);
1307 nntp_main_init(prefs_common
.skip_ssl_cert_check
);
1309 /* If we can't read a folder list or don't have accounts,
1310 * it means the configuration's not done. Either this is
1311 * a brand new install, either a failed/refused migration.
1312 * So we'll start the wizard.
1314 if (folder_read_list() < 0) {
1315 prefs_destroy_cache();
1317 /* if run_wizard returns FALSE it's because it's
1318 * been cancelled. We can't do much but exit.
1319 * however, if the user was asked for a migration,
1320 * we remove the newly created directory so that
1321 * he's asked again for migration on next launch.*/
1322 if (!run_wizard(mainwin
, TRUE
)) {
1323 if (asked_for_migration
)
1324 remove_dir_recursive(RC_DIR
);
1330 main_window_reflect_prefs_all_now();
1331 folder_write_list();
1335 if (!account_get_list()) {
1336 prefs_destroy_cache();
1337 if (!run_wizard(mainwin
, FALSE
)) {
1338 if (asked_for_migration
)
1339 remove_dir_recursive(RC_DIR
);
1345 if(!account_get_list()) {
1346 exit_claws(mainwin
);
1356 toolbar_main_set_sensitive(mainwin
);
1357 main_window_set_menu_sensitive(mainwin
);
1359 /* if crashed, show window early so that the user
1360 * sees what's happening */
1361 if (claws_crashed()) {
1362 main_window_popup(mainwin
);
1363 mainwin_shown
= TRUE
;
1366 account_set_missing_folder();
1367 folder_set_missing_folders();
1368 folderview_set(folderview
);
1370 prefs_matcher_read_config();
1371 quicksearch_set_search_strings(mainwin
->summaryview
->quicksearch
);
1373 /* make one all-folder processing before using claws */
1374 main_window_cursor_wait(mainwin
);
1375 folder_func_to_all_folders(initial_processing
, (gpointer
*)mainwin
);
1377 /* if claws crashed, rebuild caches */
1378 if (claws_crashed()) {
1380 debug_print("Claws Mail crashed, checking for new messages in local folders\n");
1381 folder_item_update_thaw();
1382 folderview_check_new(NULL
);
1383 folder_clean_cache_memory_force();
1384 folder_item_update_freeze();
1386 /* make the crash-indicator file */
1387 str_write_to_file("foo", get_crashfile_name());
1389 inc_autocheck_timer_init(mainwin
);
1391 /* ignore SIGPIPE signal for preventing sudden death of program */
1393 signal(SIGPIPE
, SIG_IGN
);
1395 if (cmd
.online_mode
== ONLINE_MODE_OFFLINE
) {
1396 main_window_toggle_work_offline(mainwin
, TRUE
, FALSE
);
1398 if (cmd
.online_mode
== ONLINE_MODE_ONLINE
) {
1399 main_window_toggle_work_offline(mainwin
, FALSE
, FALSE
);
1402 if (cmd
.status_folders
) {
1403 g_ptr_array_free(cmd
.status_folders
, TRUE
);
1404 cmd
.status_folders
= NULL
;
1406 if (cmd
.status_full_folders
) {
1407 g_ptr_array_free(cmd
.status_full_folders
, TRUE
);
1408 cmd
.status_full_folders
= NULL
;
1411 claws_register_idle_function(claws_gtk_idle
);
1414 prefs_toolbar_init();
1416 num_folder_class
= g_list_length(folder_get_list());
1418 plugin_load_all("GTK2");
1420 if (g_list_length(folder_get_list()) != num_folder_class
) {
1421 debug_print("new folders loaded, reloading processing rules\n");
1422 prefs_matcher_read_config();
1425 if ((plug_list
= plugin_get_unloaded_list()) != NULL
) {
1428 gint num_plugins
= 0;
1429 for (cur
= plug_list
; cur
; cur
= cur
->next
) {
1430 Plugin
*plugin
= (Plugin
*)cur
->data
;
1431 gchar
*tmp
= g_strdup_printf("%s\n%s",
1433 plugin_get_name(plugin
));
1438 main_window_cursor_normal(mainwin
);
1439 main_window_popup(mainwin
);
1440 mainwin_shown
= TRUE
;
1441 alertpanel_warning(ngettext(
1442 "The following plugin failed to load. "
1443 "Check the Plugins configuration "
1444 "for more information:\n%s",
1445 "The following plugins failed to load. "
1446 "Check the Plugins configuration "
1447 "for more information:\n%s",
1450 main_window_cursor_wait(mainwin
);
1452 g_slist_free(plug_list
);
1456 prefs_common_write_config();
1457 plugin_load_standard_plugins ();
1459 /* if not crashed, show window now */
1460 if (!mainwin_shown
) {
1461 /* apart if something told not to show */
1462 if (show_at_startup
)
1463 main_window_popup(mainwin
);
1466 if (!folder_have_mailbox()) {
1467 prefs_destroy_cache();
1468 main_window_cursor_normal(mainwin
);
1469 if (folder_get_list() != NULL
) {
1470 alertpanel_error(_("Claws Mail has detected a configured "
1471 "mailbox, but it is incomplete. It is "
1472 "possibly due to a failing IMAP account. Use "
1473 "\"Rebuild folder tree\" on the mailbox parent "
1474 "folder's context menu to try to fix it."));
1476 alertpanel_error(_("Claws Mail has detected a configured "
1477 "mailbox, but could not load it. It is "
1478 "probably provided by an out-of-date "
1479 "external plugin. Please reinstall the "
1480 "plugin and try again."));
1481 exit_claws(mainwin
);
1489 static_mainwindow
= mainwin
;
1491 #ifdef HAVE_STARTUP_NOTIFICATION
1492 startup_notification_complete(FALSE
);
1495 sc_session_manager_connect(mainwin
);
1498 folder_item_update_thaw();
1499 gtk_cmclist_thaw(GTK_CMCLIST(mainwin
->folderview
->ctree
));
1500 main_window_cursor_normal(mainwin
);
1502 if (!cmd
.target
&& prefs_common
.goto_last_folder_on_startup
&&
1503 folder_find_item_from_identifier(prefs_common
.last_opened_folder
) != NULL
&&
1505 cmd
.target
= prefs_common
.last_opened_folder
;
1508 if (cmd
.receive_all
&& !cmd
.target
) {
1510 g_timeout_add(1000, defer_check_all
, GINT_TO_POINTER(FALSE
));
1511 } else if (prefs_common
.chk_on_startup
&& !cmd
.target
) {
1513 g_timeout_add(1000, defer_check_all
, GINT_TO_POINTER(TRUE
));
1514 } else if (cmd
.receive
&& !cmd
.target
) {
1516 g_timeout_add(1000, defer_check
, NULL
);
1518 gtk_widget_grab_focus(folderview
->ctree
);
1521 open_compose_new(cmd
.compose_mailto
, cmd
.attach_files
);
1523 if (cmd
.attach_files
) {
1524 list_free_strings(cmd
.attach_files
);
1525 g_list_free(cmd
.attach_files
);
1526 cmd
.attach_files
= NULL
;
1528 if (cmd
.subscribe
) {
1529 folder_subscribe(cmd
.subscribe_uri
);
1538 g_timeout_add(500, defer_jump
, (gpointer
)cmd
.target
);
1541 prefs_destroy_cache();
1543 compose_reopen_exit_drafts();
1546 sc_starting
= FALSE
;
1547 main_window_set_menu_sensitive(mainwin
);
1548 toolbar_main_set_sensitive(mainwin
);
1551 /* register the callback of unix domain socket input */
1552 lock_socket_tag
= claws_input_add(lock_socket
,
1553 G_IO_IN
| G_IO_HUP
| G_IO_ERR
| G_IO_PRI
,
1554 lock_socket_input_cb
,
1561 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1563 g_object_unref(nm_proxy
);
1565 #ifdef HAVE_DBUS_GLIB
1566 uninstall_dbus_status_handler();
1568 dbus_g_connection_unref(connection
);
1574 exit_claws(mainwin
);
1579 static void save_all_caches(FolderItem
*item
, gpointer data
)
1586 folder_item_close(item
);
1589 folder_item_free_cache(item
, TRUE
);
1592 static void exit_claws(MainWindow
*mainwin
)
1595 gboolean have_connectivity
;
1599 debug_print("shutting down\n");
1600 inc_autocheck_timer_remove();
1602 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1603 if (prefs_common
.work_offline
&& went_offline_nm
)
1604 prefs_common
.work_offline
= FALSE
;
1607 /* save prefs for opened folder */
1608 if(mainwin
->folderview
->opened
) {
1611 item
= gtk_cmctree_node_get_row_data(
1612 GTK_CMCTREE(mainwin
->folderview
->ctree
),
1613 mainwin
->folderview
->opened
);
1615 summary_save_prefs_to_folderitem(
1616 mainwin
->folderview
->summaryview
, item
);
1617 prefs_common
.last_opened_folder
=
1618 folder_item_get_identifier(item
);
1622 /* save all state before exiting */
1623 folder_func_to_all_folders(save_all_caches
, NULL
);
1624 folder_write_list();
1626 main_window_get_size(mainwin
);
1627 main_window_get_position(mainwin
);
1629 prefs_common_write_config();
1630 account_write_config_all();
1631 #ifndef USE_NEW_ADDRBOOK
1632 addressbook_export_to_file();
1634 filename
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
, MENU_RC
, NULL
);
1635 gtk_accel_map_save(filename
);
1638 /* delete temporary files */
1639 remove_all_files(get_tmp_dir());
1640 remove_all_files(get_mime_tmp_dir());
1642 close_log_file(LOG_PROTOCOL
);
1643 close_log_file(LOG_DEBUG_FILTERING
);
1645 #ifdef HAVE_NETWORKMANAGER_SUPPORT
1646 have_connectivity
= networkmanager_is_online(NULL
);
1648 have_connectivity
= TRUE
;
1650 #ifdef HAVE_LIBETPAN
1651 imap_main_done(have_connectivity
);
1652 nntp_main_done(have_connectivity
);
1654 /* delete crashfile */
1656 claws_unlink(get_crashfile_name());
1658 lock_socket_remove();
1661 if (mainwin
->smc_conn
)
1662 SmcCloseConnection ((SmcConn
)mainwin
->smc_conn
, 0, NULL
);
1663 mainwin
->smc_conn
= NULL
;
1666 main_window_destroy_all();
1668 plugin_unload_all("GTK2");
1671 prefs_toolbar_done();
1674 #ifndef USE_NEW_ADDRBOOK
1675 addressbook_destroy();
1677 prefs_themes_done();
1679 prefs_ext_prog_done();
1680 prefs_wrapping_done();
1681 prefs_compose_writing_done();
1682 prefs_msg_colors_done();
1683 prefs_image_viewer_done();
1684 image_viewer_done();
1686 prefs_summaries_done();
1687 prefs_message_done();
1689 prefs_receive_done();
1690 prefs_logging_done();
1694 prefs_spelling_done();
1695 gtkaspell_checkers_quit();
1697 plugin_unload_all("Common");
1701 #define G_STRING_APPEND_ENCODED_URI(gstring,source) \
1703 gchar tmpbuf[BUFFSIZE]; \
1704 encode_uri(tmpbuf, BUFFSIZE, (source)); \
1705 g_string_append((gstring), tmpbuf); \
1708 #define G_PRINT_EXIT(msg) \
1714 static GString
* parse_cmd_compose_from_file(const gchar
*fn
)
1716 GString
*headers
= g_string_new(NULL
);
1717 GString
*body
= g_string_new(NULL
);
1725 if (fn
== NULL
|| *fn
== '\0')
1726 G_PRINT_EXIT(_("Missing filename\n"));
1727 isstdin
= (*fn
== '-' && *(fn
+ 1) == '\0');
1731 fp
= g_fopen(fn
, "r");
1733 G_PRINT_EXIT(_("Cannot open filename for reading\n"));
1736 while (fgets(fb
, sizeof(fb
), fp
)) {
1742 while (*h
&& *h
!= ':') { ++h
; } /* search colon */
1744 G_PRINT_EXIT(_("Malformed header\n"));
1746 while (*v
&& *v
== ' ') { ++v
; } /* trim value start */
1748 tmp
= g_ascii_strdown(fb
, -1); /* get header name */
1749 if (!strcmp(tmp
, "to")) {
1751 G_PRINT_EXIT(_("Duplicated 'To:' header\n"));
1754 g_string_append_c(headers
, '&');
1755 g_string_append(headers
, tmp
);
1756 g_string_append_c(headers
, '=');
1757 g_string_append_uri_escaped(headers
, v
, NULL
, TRUE
);
1762 G_PRINT_EXIT(_("Missing required 'To:' header\n"));
1763 g_string_append(body
, to
);
1765 g_string_append(body
, "?body=");
1766 while (fgets(fb
, sizeof(fb
), fp
)) {
1767 g_string_append_uri_escaped(body
, fb
, NULL
, TRUE
);
1771 /* append the remaining headers */
1772 g_string_append(body
, headers
->str
);
1773 g_string_free(headers
, TRUE
);
1778 #undef G_STRING_APPEND_ENCODED_URI
1781 static void parse_cmd_opt(int argc
, char *argv
[])
1786 for (i
= 1; i
< argc
; i
++) {
1787 if (!strncmp(argv
[i
], "--receive-all", 13)) {
1788 cmd
.receive_all
= TRUE
;
1789 } else if (!strncmp(argv
[i
], "--receive", 9)) {
1791 } else if (!strncmp(argv
[i
], "--cancel-receiving", 18)) {
1792 cmd
.cancel_receiving
= TRUE
;
1793 } else if (!strncmp(argv
[i
], "--cancel-sending", 16)) {
1794 cmd
.cancel_sending
= TRUE
;
1795 } else if (!strncmp(argv
[i
], "--compose-from-file", 19)) {
1796 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1798 GString
*mailto
= parse_cmd_compose_from_file(p
);
1800 cmd
.compose_mailto
= mailto
->str
;
1802 } else if (!strncmp(argv
[i
], "--compose", 9)) {
1803 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1806 cmd
.compose_mailto
= NULL
;
1807 if (p
&& *p
!= '\0' && *p
!= '-') {
1808 if (!strncmp(p
, "mailto:", 7)) {
1809 cmd
.compose_mailto
= p
+ 7;
1811 cmd
.compose_mailto
= p
;
1815 } else if (!strncmp(argv
[i
], "--subscribe", 11)) {
1816 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1817 if (p
&& *p
!= '\0' && *p
!= '-') {
1818 cmd
.subscribe
= TRUE
;
1819 cmd
.subscribe_uri
= p
;
1821 } else if (!strncmp(argv
[i
], "--attach", 8)) {
1822 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1825 while (p
&& *p
!= '\0' && *p
!= '-') {
1826 if ((file
= g_filename_from_uri(p
, NULL
, NULL
)) != NULL
) {
1827 if (!is_file_exist(file
)) {
1832 if (file
== NULL
&& *p
!= G_DIR_SEPARATOR
) {
1833 file
= g_strconcat(claws_get_startup_dir(),
1836 } else if (file
== NULL
) {
1839 ainfo
= g_new0(AttachInfo
, 1);
1841 cmd
.attach_files
= g_list_append(cmd
.attach_files
, ainfo
);
1843 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1845 } else if (!strncmp(argv
[i
], "--send", 6)) {
1847 } else if (!strncmp(argv
[i
], "--version-full", 14) ||
1848 !strncmp(argv
[i
], "-V", 2)) {
1849 g_print("Claws Mail version " VERSION
"\n");
1850 main_dump_features_list(FALSE
);
1852 } else if (!strncmp(argv
[i
], "--version", 9) ||
1853 !strncmp(argv
[i
], "-v", 2)) {
1854 g_print("Claws Mail version " VERSION
"\n");
1856 } else if (!strncmp(argv
[i
], "--status-full", 13)) {
1857 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1859 cmd
.status_full
= TRUE
;
1860 while (p
&& *p
!= '\0' && *p
!= '-') {
1861 if (!cmd
.status_full_folders
) {
1862 cmd
.status_full_folders
=
1865 g_ptr_array_add(cmd
.status_full_folders
,
1868 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1870 } else if (!strncmp(argv
[i
], "--status", 8)) {
1871 const gchar
*p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1874 while (p
&& *p
!= '\0' && *p
!= '-') {
1875 if (!cmd
.status_folders
)
1876 cmd
.status_folders
= g_ptr_array_new();
1877 g_ptr_array_add(cmd
.status_folders
,
1880 p
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1882 } else if (!strncmp(argv
[i
], "--search", 8)) {
1883 cmd
.search_folder
= (i
+1 < argc
)?argv
[i
+1]:NULL
;
1884 cmd
.search_type
= (i
+2 < argc
)?argv
[i
+2]:NULL
;
1885 cmd
.search_request
= (i
+3 < argc
)?argv
[i
+3]:NULL
;
1886 const char* rec
= (i
+4 < argc
)?argv
[i
+4]:NULL
;
1887 cmd
.search_recursive
= TRUE
;
1888 if (rec
&& (tolower(*rec
)=='n' || tolower(*rec
)=='f' || *rec
=='0'))
1889 cmd
.search_recursive
= FALSE
;
1890 if (cmd
.search_folder
&& cmd
.search_type
&& cmd
.search_request
)
1892 } else if (!strncmp(argv
[i
], "--online", 8)) {
1893 cmd
.online_mode
= ONLINE_MODE_ONLINE
;
1894 } else if (!strncmp(argv
[i
], "--offline", 9)) {
1895 cmd
.online_mode
= ONLINE_MODE_OFFLINE
;
1896 } else if (!strncmp(argv
[i
], "--toggle-debug", 14)) {
1898 } else if (!strncmp(argv
[i
], "--statistics", 12)) {
1899 cmd
.statistics
= TRUE
;
1900 } else if (!strncmp(argv
[i
], "--reset-statistics", 18)) {
1901 cmd
.reset_statistics
= TRUE
;
1902 } else if (!strncmp(argv
[i
], "--help", 6) ||
1903 !strncmp(argv
[i
], "-h", 2)) {
1904 gchar
*base
= g_path_get_basename(argv
[0]);
1905 g_print(_("Usage: %s [OPTION]...\n"), base
);
1907 g_print("%s\n", _(" --compose [address] open composition window"));
1908 g_print("%s\n", _(" --compose-from-file file\n"
1909 " open composition window with data from given file;\n"
1910 " use - as file name for reading from standard input;\n"
1911 " content format: headers first (To: required) until an\n"
1912 " empty line, then mail body until end of file."));
1913 g_print("%s\n", _(" --subscribe [uri] subscribe to the given URI if possible"));
1914 g_print("%s\n", _(" --attach file1 [file2]...\n"
1915 " open composition window with specified files\n"
1917 g_print("%s\n", _(" --receive receive new messages"));
1918 g_print("%s\n", _(" --receive-all receive new messages of all accounts"));
1919 g_print("%s\n", _(" --cancel-receiving cancel receiving of messages"));
1920 g_print("%s\n", _(" --cancel-sending cancel sending of messages"));
1921 g_print("%s\n", _(" --search folder type request [recursive]\n"
1923 " folder ex.: \"#mh/Mailbox/inbox\" or \"Mail\"\n"
1924 " type: s[ubject],f[rom],t[o],e[xtended],m[ixed] or g: tag\n"
1925 " request: search string\n"
1926 " recursive: false if arg. starts with 0, n, N, f or F"));
1928 g_print("%s\n", _(" --send send all queued messages"));
1929 g_print("%s\n", _(" --status [folder]... show the total number of messages"));
1930 g_print("%s\n", _(" --status-full [folder]...\n"
1931 " show the status of each folder"));
1932 g_print("%s\n", _(" --statistics show session statistics"));
1933 g_print("%s\n", _(" --reset-statistics reset session statistics"));
1934 g_print("%s\n", _(" --select folder[/msg] jumps to the specified folder/message\n"
1935 " folder is a folder id like 'folder/sub_folder'"));
1936 g_print("%s\n", _(" --online switch to online mode"));
1937 g_print("%s\n", _(" --offline switch to offline mode"));
1938 g_print("%s\n", _(" --exit --quit -q exit Claws Mail"));
1939 g_print("%s\n", _(" --debug debug mode"));
1940 g_print("%s\n", _(" --toggle-debug toggle debug mode"));
1941 g_print("%s\n", _(" --help -h display this help and exit"));
1942 g_print("%s\n", _(" --version -v output version information and exit"));
1943 g_print("%s\n", _(" --version-full -V output version and built-in features information and exit"));
1944 g_print("%s\n", _(" --config-dir output configuration directory"));
1945 g_print("%s\n", _(" --alternate-config-dir [dir]\n"
1946 " use specified configuration directory"));
1950 } else if (!strncmp(argv
[i
], "--crash", 7)) {
1952 cmd
.crash_params
= g_strdup((i
+1 < argc
)?argv
[i
+1]:NULL
);
1954 } else if (!strncmp(argv
[i
], "--config-dir", sizeof "--config-dir" - 1)) {
1955 g_print(RC_DIR
"\n");
1957 } else if (!strncmp(argv
[i
], "--alternate-config-dir", sizeof "--alternate-config-dir" - 1) && i
+1 < argc
) {
1958 set_rc_dir(argv
[i
+1]);
1959 } else if (!strncmp(argv
[i
], "--exit", 6) ||
1960 !strncmp(argv
[i
], "--quit", 6) ||
1961 !strncmp(argv
[i
], "-q", 2)) {
1963 } else if (!strncmp(argv
[i
], "--select", 8) && i
+1 < argc
) {
1964 cmd
.target
= argv
[i
+1];
1965 } else if (i
== 1 && argc
== 2) {
1966 /* only one parameter. Do something intelligent about it */
1967 if ((strstr(argv
[i
], "@")||!strncmp(argv
[i
], "mailto:", 7)) && !strstr(argv
[i
], "://")) {
1968 const gchar
*p
= argv
[i
];
1971 cmd
.compose_mailto
= NULL
;
1972 if (p
&& *p
!= '\0' && *p
!= '-') {
1973 if (!strncmp(p
, "mailto:", 7)) {
1974 cmd
.compose_mailto
= p
+ 7;
1976 cmd
.compose_mailto
= p
;
1979 } else if (!strncmp(argv
[i
], "file://", 7)) {
1980 cmd
.target
= argv
[i
];
1981 } else if (!strncmp(argv
[i
], "?attach=file://", strlen("?attach=file://"))) {
1983 cmd
.compose_mailto
= argv
[i
];
1984 } else if (strstr(argv
[i
], "://")) {
1985 const gchar
*p
= argv
[i
];
1986 if (p
&& *p
!= '\0' && *p
!= '-') {
1987 cmd
.subscribe
= TRUE
;
1988 cmd
.subscribe_uri
= p
;
1990 } else if (!strcmp(argv
[i
], "--sync")) {
1992 } else if (is_dir_exist(argv
[i
]) || is_file_exist(argv
[i
])) {
1993 cmd
.target
= argv
[i
];
1995 g_print(_("Unknown option\n"));
2001 if (cmd
.attach_files
&& cmd
.compose
== FALSE
) {
2003 cmd
.compose_mailto
= NULL
;
2007 static void initial_processing(FolderItem
*item
, gpointer data
)
2009 MainWindow
*mainwin
= (MainWindow
*)data
;
2012 cm_return_if_fail(item
);
2013 buf
= g_strdup_printf(_("Processing (%s)..."),
2016 : _("top level folder"));
2020 if (item
->prefs
->enable_processing
) {
2021 item
->processing_pending
= TRUE
;
2022 folder_item_apply_processing(item
);
2023 item
->processing_pending
= FALSE
;
2026 STATUSBAR_POP(mainwin
);
2029 static gboolean
draft_all_messages(void)
2031 const GList
*compose_list
= NULL
;
2033 compose_clear_exit_drafts();
2034 compose_list
= compose_get_compose_list();
2035 while (compose_list
!= NULL
) {
2036 Compose
*c
= (Compose
*)compose_list
->data
;
2037 if (!compose_draft(c
, COMPOSE_DRAFT_FOR_EXIT
))
2039 compose_list
= compose_get_compose_list();
2043 gboolean
clean_quit(gpointer data
)
2045 static gboolean firstrun
= TRUE
;
2052 /*!< Good idea to have the main window stored in a
2053 * static variable so we can check that variable
2054 * to see if we're really allowed to do things
2055 * that actually the spawner is supposed to
2056 * do (like: sending mail, composing messages).
2057 * Because, really, if we're the spawnee, and
2058 * we touch GTK stuff, we're hosed. See the
2061 /* FIXME: Use something else to signal that we're
2062 * in the original spawner, and not in a spawned
2064 if (!static_mainwindow
) {
2068 draft_all_messages();
2069 emergency_exit
= TRUE
;
2070 exit_claws(static_mainwindow
);
2076 void app_will_exit(GtkWidget
*widget
, gpointer data
)
2078 MainWindow
*mainwin
= data
;
2080 if (gtk_main_level() == 0) {
2081 debug_print("not even started\n");
2084 if (sc_exiting
== TRUE
) {
2085 debug_print("exit pending\n");
2089 debug_print("exiting\n");
2090 if (compose_get_compose_list()) {
2091 if (!draft_all_messages()) {
2092 main_window_popup(mainwin
);
2098 if (prefs_common
.warn_queued_on_exit
&& procmsg_have_queued_mails_fast()) {
2099 if (alertpanel(_("Queued messages"),
2100 _("Some unsent messages are queued. Exit now?"),
2101 GTK_STOCK_CANCEL
, GTK_STOCK_OK
, NULL
)
2102 != G_ALERTALTERNATE
) {
2103 main_window_popup(mainwin
);
2107 manage_window_focus_in(mainwin
->window
, NULL
, NULL
);
2111 #ifdef HAVE_VALGRIND
2112 if (RUNNING_ON_VALGRIND
) {
2113 summary_clear_list(mainwin
->summaryview
);
2116 if (folderview_get_selected_item(mainwin
->folderview
))
2117 folder_item_close(folderview_get_selected_item(mainwin
->folderview
));
2121 gboolean
claws_is_exiting(void)
2126 gboolean
claws_is_starting(void)
2133 * CLAWS: want this public so crash dialog can delete the
2136 gchar
*claws_get_socket_name(void)
2138 static gchar
*filename
= NULL
;
2139 gchar
*socket_dir
= NULL
;
2142 if (filename
== NULL
) {
2146 socket_dir
= g_strdup_printf("%s%cclaws-mail-%d",
2147 g_get_tmp_dir(), G_DIR_SEPARATOR
,
2153 stat_ok
= stat(socket_dir
, &st
);
2154 if (stat_ok
< 0 && errno
!= ENOENT
) {
2155 g_print("Error stat'ing socket_dir %s: %s\n",
2156 socket_dir
, strerror(errno
));
2157 } else if (stat_ok
== 0 && S_ISSOCK(st
.st_mode
)) {
2158 /* old versions used a sock in $TMPDIR/claws-mail-$UID */
2159 debug_print("Using legacy socket %s\n", socket_dir
);
2160 filename
= g_strdup(socket_dir
);
2164 if (!is_dir_exist(socket_dir
) && make_dir(socket_dir
) < 0) {
2165 g_print("Error creating socket_dir %s: %s\n",
2166 socket_dir
, strerror(errno
));
2169 md5_hex_digest(md5sum
, get_rc_dir());
2171 filename
= g_strdup_printf("%s%c%s", socket_dir
, G_DIR_SEPARATOR
,
2174 debug_print("Using control socket %s\n", filename
);
2181 static gchar
*get_crashfile_name(void)
2183 static gchar
*filename
= NULL
;
2185 if (filename
== NULL
) {
2186 filename
= g_strdup_printf("%s%cclaws-crashed",
2187 get_tmp_dir(), G_DIR_SEPARATOR
);
2193 static gint
prohibit_duplicate_launch(void)
2200 path
= claws_get_socket_name();
2201 /* Try to connect to the control socket */
2202 uxsock
= fd_connect_unix(path
);
2204 if (x_display
== NULL
)
2205 x_display
= g_strdup(g_getenv("DISPLAY"));
2212 /* If connect failed, no other process is running.
2213 * Unlink the potentially existing socket, then
2214 * open it. This has to be done locking a temporary
2215 * file to avoid the race condition where another
2216 * process could have created the socket just in
2219 socket_lock
= g_strconcat(path
, ".lock",
2221 lock_fd
= g_open(socket_lock
, O_RDWR
|O_CREAT
, 0);
2223 debug_print("Couldn't open %s: %s (%d)\n", socket_lock
,
2224 strerror(errno
), errno
);
2225 g_free(socket_lock
);
2228 if (flock(lock_fd
, LOCK_EX
) < 0) {
2229 debug_print("Couldn't lock %s: %s (%d)\n", socket_lock
,
2230 strerror(errno
), errno
);
2232 g_free(socket_lock
);
2238 debug_print("Opening socket %s\n", path
);
2239 ret
= fd_open_unix(path
);
2241 flock(lock_fd
, LOCK_UN
);
2243 claws_unlink(socket_lock
);
2244 g_free(socket_lock
);
2251 hmutex
= CreateMutexA(NULL
, FALSE
, "ClawsMail");
2253 debug_print("cannot create Mutex\n");
2256 if (GetLastError() != ERROR_ALREADY_EXISTS
) {
2257 uxsock
= fd_open_inet(50216);
2263 uxsock
= fd_connect_inet(50216);
2267 /* remote command mode */
2269 debug_print("another Claws Mail instance is already running.\n");
2271 if (cmd
.receive_all
) {
2272 fd_write_all(uxsock
, "receive_all\n", 12);
2273 } else if (cmd
.receive
) {
2274 fd_write_all(uxsock
, "receive\n", 8);
2275 } else if (cmd
.cancel_receiving
) {
2276 fd_write_all(uxsock
, "cancel_receiving\n", 17);
2277 } else if (cmd
.cancel_sending
) {
2278 fd_write_all(uxsock
, "cancel_sending\n", 15);
2279 } else if (cmd
.compose
&& cmd
.attach_files
) {
2280 gchar
*str
, *compose_str
;
2282 if (cmd
.compose_mailto
) {
2283 compose_str
= g_strdup_printf("compose_attach %s\n",
2284 cmd
.compose_mailto
);
2286 compose_str
= g_strdup("compose_attach\n");
2289 fd_write_all(uxsock
, compose_str
, strlen(compose_str
));
2290 g_free(compose_str
);
2292 for (curr
= cmd
.attach_files
; curr
!= NULL
; curr
= curr
->next
) {
2293 str
= (gchar
*) ((AttachInfo
*)curr
->data
)->file
;
2294 fd_write_all(uxsock
, str
, strlen(str
));
2295 fd_write_all(uxsock
, "\n", 1);
2298 fd_write_all(uxsock
, ".\n", 2);
2299 } else if (cmd
.compose
) {
2302 if (cmd
.compose_mailto
) {
2303 compose_str
= g_strdup_printf
2304 ("compose %s\n", cmd
.compose_mailto
);
2306 compose_str
= g_strdup("compose\n");
2309 fd_write_all(uxsock
, compose_str
, strlen(compose_str
));
2310 g_free(compose_str
);
2311 } else if (cmd
.subscribe
) {
2312 gchar
*str
= g_strdup_printf("subscribe %s\n", cmd
.subscribe_uri
);
2313 fd_write_all(uxsock
, str
, strlen(str
));
2315 } else if (cmd
.send
) {
2316 fd_write_all(uxsock
, "send\n", 5);
2317 } else if (cmd
.online_mode
== ONLINE_MODE_ONLINE
) {
2318 fd_write(uxsock
, "online\n", 6);
2319 } else if (cmd
.online_mode
== ONLINE_MODE_OFFLINE
) {
2320 fd_write(uxsock
, "offline\n", 7);
2321 } else if (cmd
.debug
) {
2322 fd_write(uxsock
, "debug\n", 7);
2323 } else if (cmd
.status
|| cmd
.status_full
) {
2324 gchar buf
[BUFFSIZE
];
2326 const gchar
*command
;
2330 command
= cmd
.status_full
? "status-full\n" : "status\n";
2331 folders
= cmd
.status_full
? cmd
.status_full_folders
:
2334 fd_write_all(uxsock
, command
, strlen(command
));
2335 for (i
= 0; folders
&& i
< folders
->len
; ++i
) {
2336 folder
= g_ptr_array_index(folders
, i
);
2337 fd_write_all(uxsock
, folder
, strlen(folder
));
2338 fd_write_all(uxsock
, "\n", 1);
2340 fd_write_all(uxsock
, ".\n", 2);
2342 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2343 buf
[sizeof(buf
) - 1] = '\0';
2344 if (!strncmp(buf
, ".\n", 2)) break;
2347 } else if (cmd
.exit
) {
2348 fd_write_all(uxsock
, "exit\n", 5);
2349 } else if (cmd
.statistics
) {
2351 fd_write(uxsock
, "statistics\n", 11);
2353 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2354 buf
[sizeof(buf
) - 1] = '\0';
2355 if (!strncmp(buf
, ".\n", 2)) break;
2358 } else if (cmd
.reset_statistics
) {
2359 fd_write(uxsock
, "reset_statistics\n", 17);
2360 } else if (cmd
.target
) {
2361 gchar
*str
= g_strdup_printf("select %s\n", cmd
.target
);
2362 fd_write_all(uxsock
, str
, strlen(str
));
2364 } else if (cmd
.search
) {
2365 gchar buf
[BUFFSIZE
];
2367 g_strdup_printf("search %s\n%s\n%s\n%c\n",
2368 cmd
.search_folder
, cmd
.search_type
, cmd
.search_request
,
2369 (cmd
.search_recursive
==TRUE
)?'1':'0');
2370 fd_write_all(uxsock
, str
, strlen(str
));
2373 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2374 buf
[sizeof(buf
) - 1] = '\0';
2375 if (!strncmp(buf
, ".\n", 2)) break;
2381 fd_write_all(uxsock
, "get_display\n", 12);
2382 memset(buf
, 0, sizeof(buf
));
2383 fd_gets(uxsock
, buf
, sizeof(buf
) - 1);
2384 buf
[sizeof(buf
) - 1] = '\0';
2385 if (strcmp2(buf
, x_display
)) {
2386 g_print("Claws Mail is already running on display %s.\n",
2390 uxsock
= fd_connect_unix(path
);
2391 fd_write_all(uxsock
, "popup\n", 6);
2394 fd_write_all(uxsock
, "popup\n", 6);
2402 static gint
lock_socket_remove(void)
2405 gchar
*filename
, *dirname
;
2407 if (lock_socket
< 0) {
2411 if (lock_socket_tag
> 0) {
2412 g_source_remove(lock_socket_tag
);
2414 fd_close(lock_socket
);
2417 filename
= claws_get_socket_name();
2418 dirname
= g_path_get_dirname(filename
);
2419 claws_unlink(filename
);
2427 static GPtrArray
*get_folder_item_list(gint sock
)
2429 gchar buf
[BUFFSIZE
];
2431 GPtrArray
*folders
= NULL
;
2434 fd_gets(sock
, buf
, sizeof(buf
) - 1);
2435 buf
[sizeof(buf
) - 1] = '\0';
2436 if (!strncmp(buf
, ".\n", 2)) {
2441 folders
= g_ptr_array_new();
2443 item
= folder_find_item_from_identifier(buf
);
2445 g_ptr_array_add(folders
, item
);
2447 g_warning("no such folder: %s\n", buf
);
2454 static void lock_socket_input_cb(gpointer data
,
2456 GIOCondition condition
)
2458 MainWindow
*mainwin
= (MainWindow
*)data
;
2460 gchar buf
[BUFFSIZE
];
2462 sock
= fd_accept(source
);
2466 fd_gets(sock
, buf
, sizeof(buf
) - 1);
2467 buf
[sizeof(buf
) - 1] = '\0';
2469 if (!strncmp(buf
, "popup", 5)) {
2470 main_window_popup(mainwin
);
2471 } else if (!strncmp(buf
, "get_display", 11)) {
2472 fd_write_all(sock
, x_display
, strlen(x_display
));
2473 } else if (!strncmp(buf
, "receive_all", 11)) {
2474 inc_all_account_mail(mainwin
, FALSE
,
2475 prefs_common
.newmail_notify_manu
);
2476 } else if (!strncmp(buf
, "receive", 7)) {
2477 inc_mail(mainwin
, prefs_common
.newmail_notify_manu
);
2478 } else if (!strncmp(buf
, "cancel_receiving", 16)) {
2481 } else if (!strncmp(buf
, "cancel_sending", 14)) {
2483 } else if (!strncmp(buf
, "compose_attach", 14)) {
2484 GList
*files
= NULL
, *curr
;
2488 mailto
= g_strdup(buf
+ strlen("compose_attach") + 1);
2489 while (fd_gets(sock
, buf
, sizeof(buf
) - 1) > 0) {
2490 buf
[sizeof(buf
) - 1] = '\0';
2492 if (!strcmp2(buf
, "."))
2495 ainfo
= g_new0(AttachInfo
, 1);
2496 ainfo
->file
= g_strdup(buf
);
2497 files
= g_list_append(files
, ainfo
);
2499 open_compose_new(mailto
, files
);
2501 curr
= g_list_first(files
);
2502 while (curr
!= NULL
) {
2503 ainfo
= (AttachInfo
*)curr
->data
;
2504 g_free(ainfo
->file
);
2510 } else if (!strncmp(buf
, "compose", 7)) {
2511 open_compose_new(buf
+ strlen("compose") + 1, NULL
);
2512 } else if (!strncmp(buf
, "subscribe", 9)) {
2513 main_window_popup(mainwin
);
2514 folder_subscribe(buf
+ strlen("subscribe") + 1);
2515 } else if (!strncmp(buf
, "send", 4)) {
2517 } else if (!strncmp(buf
, "online", 6)) {
2518 main_window_toggle_work_offline(mainwin
, FALSE
, FALSE
);
2519 } else if (!strncmp(buf
, "offline", 7)) {
2520 main_window_toggle_work_offline(mainwin
, TRUE
, FALSE
);
2521 } else if (!strncmp(buf
, "debug", 5)) {
2522 debug_set_mode(debug_get_mode() ? FALSE
: TRUE
);
2523 } else if (!strncmp(buf
, "status-full", 11) ||
2524 !strncmp(buf
, "status", 6)) {
2528 folders
= get_folder_item_list(sock
);
2529 status
= folder_get_status
2530 (folders
, !strncmp(buf
, "status-full", 11));
2531 fd_write_all(sock
, status
, strlen(status
));
2532 fd_write_all(sock
, ".\n", 2);
2534 if (folders
) g_ptr_array_free(folders
, TRUE
);
2535 } else if (!strncmp(buf
, "statistics", 10)) {
2538 g_snprintf(tmp
, sizeof(tmp
), _("Session statistics\n"));
2539 fd_write_all(sock
, tmp
, strlen(tmp
));
2541 if (prefs_common
.date_format
) {
2546 lt
= localtime(&session_stats
.time_started
);
2547 fast_strftime(date
, len
, prefs_common
.date_format
, lt
);
2548 g_snprintf(tmp
, sizeof(tmp
), _("Started: %s\n"),
2549 lt
? date
: ctime(&session_stats
.time_started
));
2551 g_snprintf(tmp
, sizeof(tmp
), _("Started: %s\n"),
2552 ctime(&session_stats
.time_started
));
2553 fd_write_all(sock
, tmp
, strlen(tmp
));
2555 fd_write_all(sock
, "\n", 1);
2557 g_snprintf(tmp
, sizeof(tmp
), _("Incoming traffic\n"));
2558 fd_write_all(sock
, tmp
, strlen(tmp
));
2560 g_snprintf(tmp
, sizeof(tmp
), _("Received messages: %d\n"),
2561 session_stats
.received
);
2562 fd_write_all(sock
, tmp
, strlen(tmp
));
2564 fd_write_all(sock
, "\n", 1);
2566 g_snprintf(tmp
, sizeof(tmp
), _("Outgoing traffic\n"));
2567 fd_write_all(sock
, tmp
, strlen(tmp
));
2569 g_snprintf(tmp
, sizeof(tmp
), _("New/redirected messages: %d\n"),
2570 session_stats
.sent
);
2571 fd_write_all(sock
, tmp
, strlen(tmp
));
2573 g_snprintf(tmp
, sizeof(tmp
), _("Replied messages: %d\n"),
2574 session_stats
.replied
);
2575 fd_write_all(sock
, tmp
, strlen(tmp
));
2577 g_snprintf(tmp
, sizeof(tmp
), _("Forwarded messages: %d\n"),
2578 session_stats
.forwarded
);
2579 fd_write_all(sock
, tmp
, strlen(tmp
));
2581 g_snprintf(tmp
, sizeof(tmp
), _("Total outgoing messages: %d\n"),
2582 (session_stats
.sent
+ session_stats
.replied
+
2583 session_stats
.forwarded
));
2584 fd_write_all(sock
, tmp
, strlen(tmp
));
2586 fd_write_all(sock
, ".\n", 2);
2587 } else if (!strncmp(buf
, "reset_statistics", 16)) {
2589 } else if (!strncmp(buf
, "select ", 7)) {
2590 const gchar
*target
= buf
+7;
2591 mainwindow_jump_to(target
, TRUE
);
2592 } else if (!strncmp(buf
, "search ", 7)) {
2593 FolderItem
* folderItem
= NULL
;
2594 GSList
*messages
= NULL
;
2595 gchar
*folder_name
= NULL
;
2596 gchar
*request
= NULL
;
2597 AdvancedSearch
*search
;
2599 AdvancedSearchType searchType
= ADVANCED_SEARCH_EXTENDED
;
2601 search
= advsearch_new();
2603 folder_name
= g_strdup(buf
+7);
2604 strretchomp(folder_name
);
2606 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) <= 0)
2608 buf
[sizeof(buf
) - 1] = '\0';
2610 switch (toupper(buf
[0])) {
2611 case 'S': searchType
= ADVANCED_SEARCH_SUBJECT
; break;
2612 case 'F': searchType
= ADVANCED_SEARCH_FROM
; break;
2613 case 'T': searchType
= ADVANCED_SEARCH_TO
; break;
2614 case 'M': searchType
= ADVANCED_SEARCH_MIXED
; break;
2615 case 'G': searchType
= ADVANCED_SEARCH_TAG
; break;
2616 case 'E': searchType
= ADVANCED_SEARCH_EXTENDED
; break;
2619 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) <= 0)
2622 buf
[sizeof(buf
) - 1] = '\0';
2623 request
= g_strdup(buf
);
2624 strretchomp(request
);
2627 if (fd_gets(sock
, buf
, sizeof(buf
) - 1) > 0)
2628 recursive
= buf
[0] != '0';
2630 buf
[sizeof(buf
) - 1] = '\0';
2632 debug_print("search: %s %i %s %i\n", folder_name
, searchType
, request
, recursive
);
2634 folderItem
= folder_find_item_from_identifier(folder_name
);
2636 if (folderItem
== NULL
) {
2637 debug_print("Unknown folder item : '%s', searching folder\n",folder_name
);
2638 Folder
* folder
= folder_find_from_path(folder_name
);
2640 folderItem
= FOLDER_ITEM(folder
->node
->data
);
2642 debug_print("Unknown folder: '%s'\n",folder_name
);
2644 debug_print("%s %s\n",folderItem
->name
, folderItem
->path
);
2647 if (folderItem
!= NULL
) {
2648 advsearch_set(search
, searchType
, request
);
2649 advsearch_search_msgs_in_folders(search
, &messages
, folderItem
, recursive
);
2651 g_print("Folder '%s' not found.\n'", folder_name
);
2655 for (cur
= messages
; cur
!= NULL
; cur
= cur
->next
) {
2656 MsgInfo
* msg
= (MsgInfo
*)cur
->data
;
2657 gchar
*file
= procmsg_get_message_file_path(msg
);
2658 fd_write_all(sock
, file
, strlen(file
));
2659 fd_write_all(sock
, "\n", 1);
2662 fd_write_all(sock
, ".\n", 2);
2665 g_free(folder_name
);
2667 advsearch_free(search
);
2668 if (messages
!= NULL
)
2669 procmsg_msg_list_free(messages
);
2670 } else if (!strncmp(buf
, "exit", 4)) {
2671 if (prefs_common
.clean_on_exit
&& !prefs_common
.ask_on_clean
) {
2672 procmsg_empty_all_trash();
2674 app_will_exit(NULL
, mainwin
);
2680 static void open_compose_new(const gchar
*address
, GList
*attach_files
)
2685 Xstrdup_a(addr
, address
, return);
2689 compose_new(NULL
, addr
, attach_files
);
2692 static void send_queue(void)
2695 gchar
*errstr
= NULL
;
2696 gboolean error
= FALSE
;
2697 for (list
= folder_get_list(); list
!= NULL
; list
= list
->next
) {
2698 Folder
*folder
= list
->data
;
2700 if (folder
->queue
) {
2701 gint res
= procmsg_send_queue
2702 (folder
->queue
, prefs_common
.savemsg
,
2706 folder_item_scan(folder
->queue
);
2714 alertpanel_error_log(_("Some errors occurred "
2715 "while sending queued messages:\n%s"), errstr
);
2718 alertpanel_error_log("Some errors occurred "
2719 "while sending queued messages.");
2723 static void quit_signal_handler(int sig
)
2725 debug_print("Quitting on signal %d\n", sig
);
2727 g_timeout_add(0, clean_quit
, NULL
);
2730 static void install_basic_sighandlers()
2734 struct sigaction act
;
2739 sigaddset(&mask
, SIGTERM
);
2742 sigaddset(&mask
, SIGINT
);
2745 sigaddset(&mask
, SIGHUP
);
2748 act
.sa_handler
= quit_signal_handler
;
2753 sigaction(SIGTERM
, &act
, 0);
2756 sigaction(SIGINT
, &act
, 0);
2759 sigaction(SIGHUP
, &act
, 0);
2762 sigprocmask(SIG_UNBLOCK
, &mask
, 0);
2763 #endif /* !G_OS_WIN32 */
2766 #if (defined linux && defined SIGIO)
2767 static int mem_notify_fd
= 0;
2769 static gboolean
clean_caches(gpointer unused
)
2771 if (static_mainwindow
&& static_mainwindow
->lock_count
> 0)
2773 debug_print("/dev/mem_notify: callback: Freeing some memory now!\n");
2774 folder_clean_cache_memory_force();
2778 static void memory_signal_handler(int sig
)
2780 debug_print("/dev/mem_notify: Kernel says we should free up some memory!\n");
2781 g_timeout_add(10, clean_caches
, NULL
);
2784 static void install_memory_sighandler()
2787 struct sigaction act
;
2790 mem_notify_fd
= g_open("/dev/mem_notify", O_RDONLY
|O_NONBLOCK
, 0);
2791 if (mem_notify_fd
== -1) {
2792 debug_print("/dev/mem_notify not available (%s)\n",
2797 fcntl(mem_notify_fd
, F_SETOWN
, getpid());
2798 flags
= fcntl(mem_notify_fd
, F_GETFL
);
2799 fcntl(mem_notify_fd
, flags
|FASYNC
);
2803 sigaddset(&mask
, SIGIO
);
2805 act
.sa_handler
= memory_signal_handler
;
2809 sigaction(SIGIO
, &act
, 0);
2811 sigprocmask(SIG_UNBLOCK
, &mask
, 0);
2813 debug_print("/dev/mem_notify: installed handler\n");
2815 #endif /* linux && SIGIO */
2817 #ifdef HAVE_NETWORKMANAGER_SUPPORT
2818 static void networkmanager_state_change_cb(DBusGProxy
*proxy
, gchar
*dev
,
2821 MainWindow
*mainWin
;
2824 if (static_mainwindow
)
2825 mainWin
= static_mainwindow
;
2827 mainWin
= (MainWindow
*)data
;
2829 if (!prefs_common
.use_networkmanager
)
2837 online
= networkmanager_is_online(&error
);
2839 if(online
&& went_offline_nm
) {
2840 went_offline_nm
= FALSE
;
2841 main_window_toggle_work_offline(mainWin
, FALSE
, FALSE
);
2842 debug_print("NetworkManager: Went online\n");
2843 log_message(LOG_PROTOCOL
, _("NetworkManager: network is online.\n"));
2846 went_offline_nm
= TRUE
;
2847 main_window_toggle_work_offline(mainWin
, TRUE
, FALSE
);
2848 debug_print("NetworkManager: Went offline\n");
2849 log_message(LOG_PROTOCOL
, _("NetworkManager: network is offline.\n"));
2853 debug_print("Failed to get online information from NetworkManager: %s\n",
2855 g_error_free(error
);
2859 debug_print("NetworkManager: Cannot change connection state because "
2860 "main window does not exist\n");
2863 /* Returns true (and sets error appropriately, if given) in case of error */
2864 gboolean
networkmanager_is_online(GError
**error
)
2866 DBusGConnection
*connection
;
2868 GError
*tmp_error
= NULL
;
2872 if (!prefs_common
.use_networkmanager
)
2877 connection
= dbus_g_bus_get(DBUS_BUS_SYSTEM
, &tmp_error
);
2880 /* If calling code doesn't do error checking, at least print some debug */
2881 if((error
== NULL
) || (*error
== NULL
))
2882 debug_print("Failed to open connection to system bus: %s\n",
2883 tmp_error
->message
);
2884 g_propagate_error(error
, tmp_error
);
2888 proxy
= dbus_g_proxy_new_for_name(connection
,
2889 "org.freedesktop.NetworkManager",
2890 "/org/freedesktop/NetworkManager",
2891 "org.freedesktop.NetworkManager");
2893 retVal
= dbus_g_proxy_call(proxy
,"state",&tmp_error
, G_TYPE_INVALID
,
2894 G_TYPE_UINT
, &state
, G_TYPE_INVALID
);
2897 g_object_unref(proxy
);
2899 dbus_g_connection_unref(connection
);
2902 /* If calling code doesn't do error checking, at least print some debug */
2903 if((error
== NULL
) || (*error
== NULL
))
2904 debug_print("Failed to get state info from NetworkManager: %s\n",
2905 tmp_error
->message
);
2906 g_propagate_error(error
, tmp_error
);
2909 #if NM_CHECK_VERSION(0,8,992)
2910 return (state
== NM_STATE_CONNECTED_LOCAL
||
2911 state
== NM_STATE_CONNECTED_SITE
||
2912 state
== NM_STATE_CONNECTED_GLOBAL
||
2913 state
== NM_STATE_UNKNOWN
);
2915 return (state
== NM_STATE_CONNECTED
||
2916 state
== NM_STATE_UNKNOWN
);