2008-02-15 [colin] 3.3.0cvs13
[claws.git] / src / main.c
index 59c5d0ec0da8fea84c9017d942efeeb5bd68103a..04e39375ffeec34abd59d6381da2b512f26d2b7a 100644 (file)
 #include <sys/types.h>
 #ifdef G_OS_UNIX
 #  include <signal.h>
+#  include <errno.h>
+#  include <fcntl.h>
 #endif
 #ifdef HAVE_LIBSM
 #include <X11/SM/SMlib.h>
-#include <fcntl.h>
 #endif
 
 #include "wizard.h"
 # include <gdk/gdkx.h>
 #endif
 
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+#include <dbus/dbus-glib.h>
+#include <NetworkManager.h>
+#endif
+
 #include "claws.h"
 #include "main.h"
 #include "mainwindow.h"
 #include "tags.h"
 #ifdef HAVE_LIBETPAN
 #include "imap-thread.h"
+#include "nntp-thread.h"
 #endif
 #include "stock_pixmap.h"
 #ifdef HAVE_VALGRIND
 #include "valgrind.h"
 #endif
-#if USE_OPENSSL
+#if (defined(USE_OPENSSL) || defined (USE_GNUTLS))
 #  include "ssl.h"
 #endif
 
 #include "timing.h"
 
 #ifdef MAEMO
+#ifdef CHINOOK
+#include <hildon/hildon-banner.h>
+#include <hildon/hildon-program.h>
+#else
 #include <hildon-widgets/hildon-banner.h>
 #include <hildon-widgets/hildon-program.h>
+#endif
 #include <gtk/gtkmain.h>
 #include <libosso.h>
 #include <libgnomevfs/gnome-vfs-volume.h>
@@ -139,6 +151,11 @@ struct _AppData {
 static GnomeVFSVolumeMonitor *volmon;
 #endif
 
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+/* Went offline due to NetworkManager */
+static gboolean went_offline_nm;
+#endif
+
 gchar *prog_version;
 gchar *argv0;
 
@@ -197,8 +214,16 @@ static void send_queue                     (void);
 static void initial_processing         (FolderItem *item, gpointer data);
 static void quit_signal_handler         (int sig);
 static void install_basic_sighandlers   (void);
+#if (defined linux && defined SIGIO)
+static void install_memory_sighandler   (void);
+#endif
 static void exit_claws                 (MainWindow *mainwin);
 
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+static void networkmanager_state_change_cb(DBusGProxy *proxy, gchar *dev,
+                                                                                                                                                                        gpointer data);
+#endif
+
 #define MAKE_DIR_IF_NOT_EXIST(dir) \
 { \
        if (!is_dir_exist(dir)) { \
@@ -230,6 +255,19 @@ void exit_event_handler(gboolean die_now, gpointer data)
 
 }
 
+/* Callback for hardware D-BUS events */
+void hw_event_handler(osso_hw_state_t *state, gpointer data)
+{
+       AppData *appdata;
+       appdata = (AppData *) data;
+
+       if (state->shutdown_ind) {
+               exit_claws(static_mainwindow);
+               hildon_banner_show_information(GTK_WIDGET(appdata->window), NULL,
+                       _("Exiting..."));
+       }
+}
+
 /* Callback for normal D-BUS messages */
 gint dbus_req_handler(const gchar * interface, const gchar * method,
                       GArray * arguments, gpointer data,
@@ -780,11 +818,108 @@ static void win32_close_log(void)
 }              
 #endif
 
+static void main_dump_features_list(gboolean show_debug_only)
+/* display compiled-in features list */
+{
+       if (show_debug_only && !debug_get_mode())
+               return;
+
+       if (show_debug_only)
+               debug_print("GTK+ %d.%d.%d / GLib %d.%d.%d\n",
+                          gtk_major_version, gtk_minor_version, gtk_micro_version,
+                          glib_major_version, glib_minor_version, glib_micro_version);
+       else
+               g_print("GTK+ %d.%d.%d / GLib %d.%d.%d\n",
+                          gtk_major_version, gtk_minor_version, gtk_micro_version,
+                          glib_major_version, glib_minor_version, glib_micro_version);
+       if (show_debug_only)
+               debug_print("Compiled-in features:\n");
+       else
+               g_print("Compiled-in features:\n");
+#if HAVE_LIBCOMPFACE
+       if (show_debug_only)
+               debug_print(" compface\n");
+       else
+               g_print(" compface\n");
+#endif
+#if USE_ASPELL
+       if (show_debug_only)
+               debug_print(" aspell\n");
+       else
+               g_print(" aspell\n");
+#endif
+#if USE_GNUTLS
+       if (show_debug_only)
+               debug_print(" gnutls\n");
+       else
+               g_print(" gnutls\n");
+#endif
+#if INET6
+       if (show_debug_only)
+               debug_print(" ipv6\n");
+       else
+               g_print(" ipv6\n");
+#endif
+#if HAVE_ICONV
+       if (show_debug_only)
+               debug_print(" iconv\n");
+       else
+               g_print(" iconv\n");
+#endif
+#if USE_JPILOT
+       if (show_debug_only)
+               debug_print(" jpilot\n");
+       else
+               g_print(" jpilot\n");
+#endif
+#if USE_LDAP
+       if (show_debug_only)
+               debug_print(" ldap\n");
+       else
+               g_print(" ldap\n");
+#endif
+#if HAVE_LIBETPAN
+       if (show_debug_only)
+               debug_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR, LIBETPAN_VERSION_MINOR);
+       else
+               g_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR, LIBETPAN_VERSION_MINOR);
+#endif
+#if USE_GNOMEPRINT
+       if (show_debug_only)
+               debug_print(" gnomeprint\n");
+       else
+               g_print(" gnomeprint\n");
+#endif
+#if HAVE_LIBSM
+       if (show_debug_only)
+               debug_print(" libsm\n");
+       else
+               g_print(" libsm\n");
+#endif
+#if HAVE_NETWORKMANAGER_SUPPORT
+       if (show_debug_only)
+               debug_print(" NetworkManager\n");
+       else
+               g_print(" NetworkManager\n");
+#endif
+#if USE_OPENSSL
+       if (show_debug_only)
+               debug_print(" openssl\n");
+       else
+               g_print(" openssl\n");
+#endif
+}
+
 int main(int argc, char *argv[])
 {
 #ifdef MAEMO
        osso_context_t *osso_context;
        osso_return_t result;
+#endif
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       DBusGConnection *connection;
+  GError *error;
+  DBusGProxy *proxy;
 #endif
        gchar *userrc;
        MainWindow *mainwin;
@@ -809,6 +944,8 @@ int main(int argc, char *argv[])
                return 0;
        }
 
+       main_dump_features_list(TRUE);
+
        prog_version = PROG_VERSION;
        argv0 = g_strdup(argv[0]);
 
@@ -829,6 +966,9 @@ int main(int argc, char *argv[])
        crash_install_handlers();
 #endif
        install_basic_sighandlers();
+#if (defined linux && defined SIGIO)
+       install_memory_sighandler();
+#endif
        sock_init();
 
        /* check and create unix domain socket for remote operation */
@@ -857,6 +997,29 @@ int main(int argc, char *argv[])
        gtk_set_locale();
        gtk_init(&argc, &argv);
 
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       went_offline_nm = FALSE;
+       error = NULL;
+       proxy = NULL;
+  connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
+
+  if(!connection) {
+               debug_print("Failed to open connection to system bus: %s\n", error->message);
+               g_error_free(error);
+       }
+       else {
+               proxy = dbus_g_proxy_new_for_name(connection,
+                                                                                                                                                       "org.freedesktop.NetworkManager",
+                                                                                                                                                       "/org/freedesktop/NetworkManager",
+                                                                                                                                                       "org.freedesktop.NetworkManager");
+               dbus_g_proxy_add_signal(proxy,"StateChange", G_TYPE_UINT, G_TYPE_INVALID);
+               dbus_g_proxy_connect_signal(proxy, "StateChange",
+                                                                                                                               G_CALLBACK(networkmanager_state_change_cb),
+                                                                                                                               NULL,NULL);
+       }
+#endif
+
+
 #ifdef MAEMO
        osso_context = osso_initialize(OSSO_SERVICE, "2.8.1", TRUE, NULL);
        if (osso_context == NULL) {
@@ -1048,6 +1211,11 @@ int main(int argc, char *argv[])
        news_gtk_init();
 
        mainwin = main_window_create();
+
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+               networkmanager_state_change_cb(proxy,NULL,mainwin);
+#endif
+
 #ifdef MAEMO
        AppData *appdata;
        appdata = g_new0(AppData, 1);
@@ -1063,6 +1231,7 @@ int main(int argc, char *argv[])
                return OSSO_ERROR;
        }
 
+#ifndef CHINOOK
        /* Add handler for Exit D-BUS messages */
        result = osso_application_set_exit_cb(appdata->osso_context,
                                                exit_event_handler,
@@ -1070,6 +1239,9 @@ int main(int argc, char *argv[])
        if (result != OSSO_OK) {
                return OSSO_ERROR;
        }
+#endif
+       osso_hw_set_event_cb( appdata->osso_context,
+                               NULL, hw_event_handler, (gpointer) appdata );
 #endif
        manage_window_focus_in(mainwin->window, NULL, NULL);
        folderview = mainwin->folderview;
@@ -1085,6 +1257,7 @@ int main(int argc, char *argv[])
                                        mainwin);
 #endif
 
+
        prefs_account_init();
        account_read_config_all();
 
@@ -1144,6 +1317,7 @@ int main(int argc, char *argv[])
 #ifdef HAVE_LIBETPAN
        imap_main_init(prefs_common.skip_ssl_cert_check);
        imap_main_set_timeout(prefs_common.io_timeout_secs);
+       nntp_main_init(prefs_common.skip_ssl_cert_check);
 #endif 
        account_set_missing_folder();
        folder_set_missing_folders();
@@ -1218,7 +1392,7 @@ int main(int argc, char *argv[])
                if (show_at_startup)
                        main_window_popup(mainwin);
        }
-       
+
        if (!folder_have_mailbox()) {
                prefs_destroy_cache();
                main_window_cursor_normal(mainwin);
@@ -1280,6 +1454,7 @@ int main(int argc, char *argv[])
 #ifdef HAVE_LIBSM
        sc_session_manager_connect(mainwin);
 #endif
+
        folder_item_update_thaw();
        gtk_clist_thaw(GTK_CLIST(mainwin->folderview->ctree));
        main_window_cursor_normal(mainwin);
@@ -1299,9 +1474,8 @@ int main(int argc, char *argv[])
        } else if (cmd.receive && !cmd.target) {
                start_done = FALSE;
                g_timeout_add(1000, defer_check, NULL);
-       } else {
-               gtk_widget_grab_focus(folderview->ctree);
-       }
+       } 
+       gtk_widget_grab_focus(folderview->ctree);
 
        if (cmd.compose) {
                open_compose_new(cmd.compose_mailto, cmd.attach_files);
@@ -1340,9 +1514,16 @@ int main(int argc, char *argv[])
 #ifdef MAEMO
        osso_deinitialize(osso_context);
 #endif
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       if(proxy)
+               g_object_unref(proxy);
+       if(connection)
+               dbus_g_connection_unref(connection);
+#endif
 #ifdef G_OS_WIN32
        win32_close_log();
 #endif
+       utils_free_regex();
        exit_claws(mainwin);
 
        return 0;
@@ -1374,6 +1555,11 @@ static void exit_claws(MainWindow *mainwin)
                main_window_empty_trash(mainwin, prefs_common.ask_on_clean);
        }
 
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+       if (prefs_common.work_offline && went_offline_nm)
+               prefs_common.work_offline = FALSE;
+#endif
+
        /* save prefs for opened folder */
        if(mainwin->folderview->opened) {
                FolderItem *item;
@@ -1407,6 +1593,7 @@ static void exit_claws(MainWindow *mainwin)
 
 #ifdef HAVE_LIBETPAN
        imap_main_done();
+       nntp_main_done();
 #endif
        /* delete crashfile */
        if (!cmd.crash)
@@ -1507,6 +1694,11 @@ static void parse_cmd_opt(int argc, char *argv[])
                        }
                } else if (!strncmp(argv[i], "--send", 6)) {
                        cmd.send = TRUE;
+               } else if (!strncmp(argv[i], "--version-full", 14) ||
+                          !strncmp(argv[i], "-V", 2)) {
+                       g_print("Claws Mail version " VERSION "\n");
+                       main_dump_features_list(FALSE);
+                       exit(0);
                } else if (!strncmp(argv[i], "--version", 9) ||
                           !strncmp(argv[i], "-v", 2)) {
                        g_print("Claws Mail version " VERSION "\n");
@@ -1565,6 +1757,7 @@ static void parse_cmd_opt(int argc, char *argv[])
                        g_print("%s\n", _("  --debug                debug mode"));
                        g_print("%s\n", _("  --help -h              display this help and exit"));
                        g_print("%s\n", _("  --version -v           output version information and exit"));
+                       g_print("%s\n", _("  --version-full -V      output version and built-in features information and exit"));
                        g_print("%s\n", _("  --config-dir           output configuration directory"));
                        g_print("%s\n", _("  --alternate-config-dir [dir]\n"
                                          "                         use specified configuration directory"));
@@ -1600,6 +1793,8 @@ static void parse_cmd_opt(int argc, char *argv[])
                                                cmd.compose_mailto = p;
                                        }
                                }
+                       } else if (!strncmp(argv[i], "file://", 7)) {
+                               cmd.target = argv[i];
                        } else if (strstr(argv[i], "://")) {
                                const gchar *p = argv[i];
                                if (p && *p != '\0' && *p != '-') {
@@ -1608,6 +1803,8 @@ static void parse_cmd_opt(int argc, char *argv[])
                                }
                        } else if (!strcmp(argv[i], "--sync")) {
                                /* gtk debug */
+                       } else if (is_dir_exist(argv[i]) || is_file_exist(argv[i])) {
+                               cmd.target = argv[i];
                        } else {
                                g_print(_("Unknown option\n"));
                                exit(1);
@@ -1635,7 +1832,9 @@ static void initial_processing(FolderItem *item, gpointer data)
 
        
        if (item->prefs->enable_processing) {
+               item->processing_pending = TRUE;
                folder_item_apply_processing(item);
+               item->processing_pending = FALSE;
        }
 
        STATUSBAR_POP(mainwin);
@@ -2094,9 +2293,150 @@ static void install_basic_sighandlers()
 #endif /* !G_OS_WIN32 */
 }
 
+#if (defined linux && defined SIGIO)
+static int mem_notify_fd = 0;
+
+static gboolean clean_caches(gpointer unused)
+{
+       if (static_mainwindow && static_mainwindow->lock_count > 0)
+               return TRUE;
+       debug_print("/dev/mem_notify: callback: Freeing some memory now!\n");
+       folder_clean_cache_memory_force();
+       return FALSE;
+}
+
+static void memory_signal_handler(int sig)
+{
+       debug_print("/dev/mem_notify: Kernel says we should free up some memory!\n");
+       g_timeout_add(10, clean_caches, NULL); 
+}
+
+static void install_memory_sighandler()
+{
+       sigset_t    mask;
+       struct sigaction act;
+       int flags;
+
+       mem_notify_fd = open("/dev/mem_notify", O_RDONLY|O_NONBLOCK);
+       if (mem_notify_fd == -1) {
+               debug_print("/dev/mem_notify not available (%s)\n", 
+                       strerror(errno));
+               return;
+       }
+       
+       fcntl(mem_notify_fd, F_SETOWN, getpid());
+       flags = fcntl(mem_notify_fd, F_GETFL);
+       fcntl(mem_notify_fd, flags|FASYNC);
+
+       sigemptyset(&mask);
+
+       sigaddset(&mask, SIGIO);
+
+       act.sa_handler = memory_signal_handler;
+       act.sa_mask    = mask;
+       act.sa_flags   = 0;
+
+       sigaction(SIGIO, &act, 0);
+
+       sigprocmask(SIG_UNBLOCK, &mask, 0);
+
+       debug_print("/dev/mem_notify: installed handler\n");
+}
+#endif /* linux && SIGIO */
+
 #ifdef MAEMO
 osso_context_t *get_osso_context(void)
 {
        return static_osso_context;
 }
 #endif
+
+
+#ifdef HAVE_NETWORKMANAGER_SUPPORT
+static void networkmanager_state_change_cb(DBusGProxy *proxy, gchar *dev,
+                                                                                                                                                                        gpointer data)
+{
+       MainWindow *mainWin;
+
+       mainWin = NULL;
+       if(static_mainwindow)
+               mainWin = static_mainwindow;
+       else if(data)
+               mainWin = (MainWindow*)data;
+       
+       if(mainWin) {
+               GError *error;
+               gboolean online;
+
+               error = NULL;           
+               online = networkmanager_is_online(&error);
+               if(!error) {
+                       if(online && went_offline_nm) {
+                               went_offline_nm = FALSE;
+                               main_window_toggle_work_offline(mainWin, FALSE, FALSE);
+                               debug_print("NetworkManager: Went online\n");
+                       }
+                       else if(!online) {
+                               went_offline_nm = TRUE;
+                               main_window_toggle_work_offline(mainWin, TRUE, FALSE);
+                               debug_print("NetworkManager: Went offline\n");
+                       }
+               }
+               else {
+                       debug_print("Failed to get online information from NetworkManager: %s\n",
+                                                        error->message);
+                       g_error_free(error);
+               }
+       }
+       else
+               debug_print("NetworkManager: Cannot change connection state because "
+                                                "main window does not exist\n");
+}
+
+/* Returns true (and sets error appropriately, if given) in case of error */
+gboolean networkmanager_is_online(GError **error)
+{
+       DBusGConnection *connection;
+  DBusGProxy *proxy;
+       GError *tmp_error;
+       gboolean retVal;
+       guint32 state;
+
+       tmp_error = NULL;
+       proxy = NULL;
+  connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &tmp_error);
+
+  if(!connection) {
+               /* If calling code doesn't do error checking, at least print some debug */
+               if((error == NULL) || (*error == NULL))
+                       debug_print("Failed to open connection to system bus: %s\n",
+                                                        tmp_error->message);
+               g_propagate_error(error, tmp_error);
+               return TRUE;
+       }
+
+       proxy = dbus_g_proxy_new_for_name(connection,
+                                                                                                                                               "org.freedesktop.NetworkManager",
+                                                                                                                                               "/org/freedesktop/NetworkManager",
+                                                                                                                                               "org.freedesktop.NetworkManager");
+
+       retVal = dbus_g_proxy_call(proxy,"state",&tmp_error,G_TYPE_INVALID,
+                                                                                                                G_TYPE_UINT,&state,G_TYPE_INVALID);
+
+       if(proxy)
+               g_object_unref(proxy);
+       if(connection)
+               dbus_g_connection_unref(connection);
+
+       if(!retVal) {
+               /* If calling code doesn't do error checking, at least print some debug */
+               if((error == NULL) || (*error == NULL))
+                       debug_print("Failed to get state info from NetworkManager: %s\n",
+                                                        tmp_error->message);
+               g_propagate_error(error, tmp_error);
+               return TRUE;
+       }
+
+       return (state == NM_STATE_CONNECTED);
+}
+#endif