diff --git a/src/gpa.c b/src/gpa.c index be8490d..bad001f 100644 --- a/src/gpa.c +++ b/src/gpa.c @@ -1,619 +1,627 @@ /* gpa.c - The GNU Privacy Assistant main file. Copyright (C) 2000-2002 G-N-U GmbH. Copyright (C) 2005, 2008, 2012, 2014, 2015 g10 Code GmbH. This file is part of GPA GPA is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GPA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "get-path.h" #include "gpa.h" #include "keymanager.h" #include "fileman.h" #include "clipboard.h" #include "cardman.h" #include "keyserver.h" #include "settingsdlg.h" #include "confdialog.h" #include "icons.h" #ifdef __MINGW32__ #include "hidewnd.h" #endif /* Global variables. */ /* The home directory of GnuPG. */ gchar *gnupg_homedir; /* True if CMS hack mode is enabled. */ gboolean cms_hack; /* True if the ticker used for card operations should not be started. */ gboolean disable_ticker; /* True if the gpgme edit FSM shall output debug messages. */ gboolean debug_edit_fsm; /* True if verbose messages are requested. */ gboolean verbose; /* Local variables. */ typedef struct { gboolean start_key_manager; gboolean start_file_manager; gboolean start_card_manager; gboolean start_clipboard; gboolean start_settings; gboolean start_only_server; gboolean stop_running_server; gboolean disable_x509; gboolean no_remote; gboolean enable_logging; gchar *options_filename; } gpa_args_t; static char *dummy_arg; static gpa_args_t args; /* The copyright notice. */ static const char *copyright = "Copyright (C) 2000-2002 Miguel Coca, G-N-U GmbH, Intevation GmbH.\n" "Copyright (C) 2005-2016 g10 Code GmbH.\n" "This program comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" "under certain conditions. See the file COPYING for details.\n"; static GtkWidget *backend_config_dialog = NULL; static void print_version (void); /* All command line options of the main application. */ static GOptionEntry option_entries[] = { { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &print_version, N_("Output version information and exit"), NULL, }, { "keyring", 'k', 0, G_OPTION_ARG_NONE, &args.start_key_manager, N_("Open key manager (default)"), NULL }, { "files", 'f', 0, G_OPTION_ARG_NONE, &args.start_file_manager, N_("Open file manager"), NULL }, #ifdef ENABLE_CARD_MANAGER { "card", 'C', 0, G_OPTION_ARG_NONE, &args.start_card_manager, N_("Open the card manager"), NULL }, #endif { "clipboard", 'c', 0, G_OPTION_ARG_NONE, &args.start_clipboard, N_("Open clipboard"), NULL }, { "settings", 's', 0, G_OPTION_ARG_NONE, &args.start_settings, N_("Open the settings dialog"), NULL }, { "daemon", 'd', 0, G_OPTION_ARG_NONE, &args.start_only_server, N_("Only start the UI server"), NULL }, { "disable-x509", 0, 0, G_OPTION_ARG_NONE, &args.disable_x509, N_("Disable support for X.509"), NULL }, { "options", 'o', 0, G_OPTION_ARG_FILENAME, &args.options_filename, N_("Read options from file"), "FILE" }, { "no-remote", 0, 0, G_OPTION_ARG_NONE, &args.no_remote, N_("Do not connect to a running instance"), NULL }, { "stop-server", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &args.stop_running_server, NULL, NULL }, /* Note: the cms option will eventually be removed. */ { "cms", 'x', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &cms_hack, NULL, NULL }, { "verbose", 'v', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &verbose, NULL, NULL }, { "disable-ticker", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &disable_ticker, NULL, NULL }, { "debug-edit-fsm", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &debug_edit_fsm, NULL, NULL }, { "enable-logging", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &args.enable_logging, NULL, NULL }, { "gpg-binary", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &dummy_arg, NULL, NULL }, { "gpgsm-binary", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &dummy_arg, NULL, NULL }, { NULL } }; /* Return a malloced string with the locale dir. Return NULL on error. */ static char * get_locale_dir (void) { #ifdef G_OS_WIN32 char name[530]; char *p; if (! GetModuleFileNameA (0, name, sizeof (name) - 30)) return NULL; - p = strrchr (name, '\\'); + + /* If installed under bin assume that share is on the same + hierarchy as the bin subdirectory. Otherwise assume that + share is a subdirectory of the gpa.exe location. */ + p = strstr (name, "\\bin\\"); + if (!p) + { + p = strrchr (name, '\\'); + } if (!p) { *name = '\\'; p = name; } p++; strcpy (p, "share\\locale"); return strdup (name); #else return strdup (LOCALEDIR); #endif } static void i18n_init (void) { #ifdef ENABLE_NLS char *tmp; gtk_set_locale (); bind_textdomain_codeset (PACKAGE, "UTF-8"); tmp = get_locale_dir (); if (tmp) { bindtextdomain (PACKAGE, tmp); free (tmp); } textdomain (PACKAGE); #endif } /* Manage the main windows and the settings dialog. */ static void quit_if_no_window (void) { if (!args.start_only_server && !gpa_key_manager_is_open () && !gpa_file_manager_is_open () && !gpa_clipboard_is_open () #ifdef ENABLE_CARD_MANAGER && !gpa_card_manager_is_open () #endif /*ENABLE_CARD_MANAGER*/ ) gpa_stop_server (); } static void close_main_window (GtkWidget *widget, gpointer param) { GtkWidget ** window = param; *window = NULL; quit_if_no_window (); } /* Show the key manager dialog. */ void gpa_open_key_manager (GtkAction *action, void *data) { GtkWidget *widget; gboolean created; widget = gpa_key_manager_get_instance (&created); if (created) g_signal_connect (G_OBJECT (widget), "destroy", G_CALLBACK (quit_if_no_window), NULL); gtk_widget_show_all (widget); gtk_window_present (GTK_WINDOW (widget)); } /* Show the clipboard dialog. */ void gpa_open_clipboard (GtkAction *action, void *data) { /* FIXME: Shouldn't this connect only happen if the instance is created the first time? Looks like a memory leak to me. Right: although the closure is ref counted an internal data object will get allocated. */ g_signal_connect (G_OBJECT (gpa_clipboard_get_instance ()), "destroy", G_CALLBACK (quit_if_no_window), NULL); gtk_widget_show_all (gpa_clipboard_get_instance ()); gtk_window_present (GTK_WINDOW (gpa_clipboard_get_instance ())); } /* Show the filemanager dialog. */ void gpa_open_filemanager (GtkAction *action, void *data) { /* FIXME: Shouldn't this connect only happen if the instance is created the first time? Looks like a memory leak to me. */ g_signal_connect (G_OBJECT (gpa_file_manager_get_instance ()), "destroy", G_CALLBACK (quit_if_no_window), NULL); gtk_widget_show_all (gpa_file_manager_get_instance ()); gtk_window_present (GTK_WINDOW (gpa_file_manager_get_instance ())); } /* Show the card manager. */ #ifdef ENABLE_CARD_MANAGER void gpa_open_cardmanager (GtkAction *action, void *data) { /* FIXME: Shouldn't this connect only happen if the instance is created the first time? Looks like a memory leak to me. */ g_signal_connect (G_OBJECT (gpa_card_manager_get_instance ()), "destroy", G_CALLBACK (quit_if_no_window), NULL); gtk_widget_show_all (gpa_card_manager_get_instance ()); gtk_window_present (GTK_WINDOW (gpa_card_manager_get_instance ())); } #endif /*ENABLE_CARD_MANAGER*/ /* Show the settings dialog. */ void gpa_open_settings_dialog (GtkAction *action, void *data) { settings_dlg_new (data); } /* Show the backend configuration dialog. */ void gpa_open_backend_config_dialog (GtkAction *action, void *data) { if (!backend_config_dialog) { backend_config_dialog = gpa_backend_config_dialog_new (); g_signal_connect (G_OBJECT (backend_config_dialog), "destroy", G_CALLBACK (close_main_window), &backend_config_dialog); gtk_widget_show_all (backend_config_dialog); } gtk_window_present (GTK_WINDOW (backend_config_dialog)); } /* Command line options. */ /* Print version information and exit. */ static void print_version (void) { printf ("%s %s\n%s", PACKAGE, VERSION, copyright); exit (0); } static void dummy_log_func (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { /* Nothing to be done. */ } /* Helper for main. */ static gpg_error_t open_requested_window (int argc, char **argv, int use_server) { gpg_error_t err = 0; int did_server = 0; int i; /* Don't open the key manager if any files are given on the command line. Ditto for the clipboard. */ if (args.start_key_manager && (optind >= argc)) { if (use_server) { did_server = 1; err = gpa_send_to_server ("START_KEYMANAGER"); } else gpa_open_key_manager (NULL, NULL); } if (args.start_clipboard && (optind >= argc)) { if (use_server) { did_server = 1; err = gpa_send_to_server ("START_CLIPBOARD"); } else gpa_open_clipboard (NULL, NULL); } if (args.start_file_manager || (optind < argc)) { /* Do not use the server if there are file args - see below. */ if (use_server && !(optind < argc)) { did_server = 1; err = gpa_send_to_server ("START_FILEMANAGER"); } else gpa_open_filemanager (NULL, NULL); } #ifdef ENABLE_CARD_MANAGER if (args.start_card_manager) { if (use_server) { did_server = 1; err = gpa_send_to_server ("START_CARDMANAGER"); } else gpa_open_cardmanager (NULL, NULL); } #endif /*ENABLE_CARD_MANAGER*/ if (args.start_settings) { if (use_server) { did_server = 1; err = gpa_send_to_server ("START_CONFDIALOG"); } else gpa_open_settings_dialog (NULL, NULL); } /* If there are any command line arguments that are not options, try to open them as files in the filemanager. However if we are to connect to a server this can't be done because the running instance may already have files in the file manager and thus we better do not add new files. Instead we start a new instance. */ if (use_server) { if (!did_server) err = -1; /* Create a new instance. */ } else { for (i = optind; i < argc; i++) gpa_file_manager_open_file (GPA_FILE_MANAGER (gpa_file_manager_get_instance ()), argv[i]); } return err; } int main (int argc, char *argv[]) { GError *err = NULL; GOptionContext *context; char *configname = NULL; char *keyservers_configname = NULL; /* Under W32 logging is disabled by default to prevent MS Windows NT from opening a console. */ #ifndef G_OS_WIN32 args.enable_logging = 1; #endif /* Set locale before option parsing for UTF-8 conversion. */ i18n_init (); /* Parse command line options. */ context = g_option_context_new (N_("[FILE...]")); #if GLIB_CHECK_VERSION (2, 12, 0) g_option_context_set_summary (context, N_("Graphical frontend to GnuPG")); g_option_context_set_description (context, N_("Please report bugs to <" PACKAGE_BUGREPORT ">.")); g_option_context_set_translation_domain (context, PACKAGE); #endif g_option_context_add_main_entries (context, option_entries, PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); if (! g_option_context_parse (context, &argc, &argv, &err)) { g_print ("option parsing failed: %s\n", err->message); exit (1); } if (!args.enable_logging) { #ifdef __MINGW32__ hide_gpa_console_window(); #endif g_log_set_handler ("Glib", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, dummy_log_func, NULL); g_log_set_handler ("Gdk", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, dummy_log_func, NULL); g_log_set_handler ("Gtk", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, dummy_log_func, NULL); } gtk_init (&argc, &argv); #ifdef G_OS_WIN32 gtk_settings_set_string_property(gtk_settings_get_default(), "gtk-theme-name", "MS-Windows", "XProperty"); #endif /* Default icon for all windows. */ gtk_window_set_default_icon_from_file (GPA_DATADIR "/gpa.png", &err); if (err) g_error_free (err); gpa_register_stock_items (); #ifdef IS_DEVELOPMENT_VERSION fprintf (stderr, "NOTE: This is a development version!\n"); #endif /* Initialize GPGME. */ gpgme_check_version (NULL); #ifdef USE_SIMPLE_GETTEXT /* FIXME */ #else #ifdef ENABLE_NLS gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); #endif #endif #ifndef G_OS_WIN32 /* Internationalisation with gtk+-2.0 wants UTF-8 instead of the character set determined by locale. */ putenv ("OUTPUT_CHARSET=utf8"); /* We don't want the SIGPIPE. I wonder why gtk_init does not set it to ignore. Nobody wants this signal. */ { struct sigaction sa; sa.sa_handler = SIG_IGN; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (SIGPIPE, &sa, NULL); } #endif /* Start the agent if needed. We need to do this because the card manager uses direct assuan commands to the agent and thus expects that the agent has been startet. */ gpa_start_agent (); gnupg_homedir = default_homedir (); /* GnuPG can not create a key if its home directory is missing. We help it out here. Should be fixed in GnuPG. */ if (! g_file_test (gnupg_homedir, G_FILE_TEST_IS_DIR)) g_mkdir (gnupg_homedir, 0700); /* Locate GPA's configuration file. */ if (! args.options_filename) configname = g_build_filename (gnupg_homedir, "gpa.conf", NULL); else configname = args.options_filename; gpa_options_set_file (gpa_options_get_instance (), configname); g_free (configname); if (args.stop_running_server) { /* If a UI server with the same name is already running, stop it. If not, do nothing. */ if (gpa_check_server () == 2) gpa_send_to_server ("KILL_UISERVER"); return 0; } /* Handle command line options. */ cms_hack = !args.disable_x509; /* Start the default component. */ if (!args.start_key_manager && !args.start_file_manager && !args.start_clipboard && !args.start_settings && !args.start_card_manager ) { /* The default action is to start the clipboard. However, if we have not yet created a key we remind the user by starting with the key manager dialog. */ if (key_manager_maybe_firsttime ()) args.start_key_manager = TRUE; else args.start_clipboard = TRUE; } /* Check whether we need to start a server or to simply open a window in an already running server. */ switch (gpa_check_server ()) { case 0: /* No running server on the expected socket. Start one. */ gpa_start_server (); break; case 1: /* An old instance or a differen UI server is already running. Do not start a server. */ break; case 2: /* An instance is already running - open the appropriate window and terminate. */ if (args.no_remote) break; if (!open_requested_window (argc, argv, 1)) return 0; /* ready */ /* Start a new instance on error. */ break; } /* Locate the list of keyservers. */ keyservers_configname = g_build_filename (gnupg_homedir, "keyservers", NULL); /* Read the list of available keyservers. */ keyserver_read_list (keyservers_configname); gpa_options_update_default_key (gpa_options_get_instance ()); /* Now, make sure there are reasonable defaults for the default key and keyserver. */ if (!is_gpg_version_at_least ("2.1.0") && !gpa_options_get_default_keyserver (gpa_options_get_instance ())) { GList *keyservers = keyserver_get_as_glist (); gpa_options_set_default_keyserver (gpa_options_get_instance (), keyservers->data); } /* Initialize the file watch facility. */ gpa_init_filewatch (); /* Startup whatever has been requested by the user. */ if (!args.start_only_server) open_requested_window (argc, argv, 0); gtk_main (); return 0; }