summaryrefslogtreecommitdiffstats
path: root/panels/network/connection-editor/vpn-helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'panels/network/connection-editor/vpn-helpers.c')
-rw-r--r--panels/network/connection-editor/vpn-helpers.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/panels/network/connection-editor/vpn-helpers.c b/panels/network/connection-editor/vpn-helpers.c
new file mode 100644
index 0000000..e0358a9
--- /dev/null
+++ b/panels/network/connection-editor/vpn-helpers.c
@@ -0,0 +1,358 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <NetworkManager.h>
+
+#include "vpn-helpers.h"
+
+NMVpnEditorPlugin *
+vpn_get_plugin_by_service (const char *service)
+{
+ NMVpnPluginInfo *plugin_info;
+
+ g_return_val_if_fail (service != NULL, NULL);
+
+ plugin_info = nm_vpn_plugin_info_list_find_by_service (vpn_get_plugins (), service);
+ if (plugin_info)
+ return nm_vpn_plugin_info_get_editor_plugin (plugin_info);
+ return NULL;
+}
+
+static gint
+_sort_vpn_plugins (NMVpnPluginInfo *aa, NMVpnPluginInfo *bb)
+{
+ return strcmp (nm_vpn_plugin_info_get_name (aa), nm_vpn_plugin_info_get_name (bb));
+}
+
+GSList *
+vpn_get_plugins (void)
+{
+ static GSList *plugins = NULL;
+ GSList *p;
+
+ p = nm_vpn_plugin_info_list_load ();
+ plugins = NULL;
+ while (p) {
+ g_autoptr(NMVpnPluginInfo) plugin_info = NM_VPN_PLUGIN_INFO (p->data);
+ g_autoptr(GError) error = NULL;
+
+ /* load the editor plugin, and preserve only those NMVpnPluginInfo that can
+ * successfully load the plugin. */
+ if (nm_vpn_plugin_info_load_editor_plugin (plugin_info, &error))
+ plugins = g_slist_prepend (plugins, g_steal_pointer (&plugin_info));
+ else {
+ if ( !nm_vpn_plugin_info_get_plugin (plugin_info)
+ && nm_vpn_plugin_info_lookup_property (plugin_info, NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME, "properties")) {
+ g_message ("vpn: (%s,%s) cannot load legacy-only plugin",
+ nm_vpn_plugin_info_get_name (plugin_info),
+ nm_vpn_plugin_info_get_filename (plugin_info));
+ } else if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
+ g_message ("vpn: (%s,%s) file \"%s\" not found. Did you install the client package?",
+ nm_vpn_plugin_info_get_name (plugin_info),
+ nm_vpn_plugin_info_get_filename (plugin_info),
+ nm_vpn_plugin_info_get_plugin (plugin_info));
+ } else {
+ g_warning ("vpn: (%s,%s) could not load plugin: %s",
+ nm_vpn_plugin_info_get_name (plugin_info),
+ nm_vpn_plugin_info_get_filename (plugin_info),
+ error->message);
+ }
+ }
+ p = g_slist_delete_link (p, p);
+ }
+
+ /* sort the list of plugins alphabetically. */
+ plugins = g_slist_sort (plugins, (GCompareFunc) _sort_vpn_plugins);
+ return plugins;
+}
+
+
+typedef struct {
+ GMainLoop *mainloop;
+ gint response;
+} RunData;
+
+static void
+on_dialog_close_request_cb (GtkDialog *dialog,
+ gint response,
+ RunData *data)
+{
+ data->response = GTK_RESPONSE_CLOSE;
+ g_main_loop_quit (data->mainloop);
+}
+
+static void
+on_dialog_response_cb (GtkDialog *dialog,
+ gint response,
+ RunData *data)
+{
+ data->response = response;
+ g_main_loop_quit (data->mainloop);
+}
+
+static int
+run_dialog (GtkDialog *dialog)
+{
+ g_autoptr(GMainLoop) mainloop = NULL;
+ RunData run_data;
+ gulong response_id;
+ gulong close_id;
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+ run_data = (RunData) {
+ .response = GTK_RESPONSE_CLOSE,
+ .mainloop = mainloop,
+ };
+
+ close_id = g_signal_connect (dialog, "close-request", G_CALLBACK (on_dialog_close_request_cb), &run_data);
+ response_id = g_signal_connect_swapped (dialog, "response", G_CALLBACK (on_dialog_response_cb), &run_data);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+ g_main_loop_run (mainloop);
+
+ g_clear_signal_handler (&close_id, dialog);
+ g_clear_signal_handler (&response_id, dialog);
+
+ return run_data.response;
+}
+
+typedef struct {
+ VpnImportCallback callback;
+ gpointer user_data;
+} ActionInfo;
+
+static void
+import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
+{
+ g_autofree gchar *filename = NULL;
+ g_autoptr(GFile) file = NULL;
+ ActionInfo *info = (ActionInfo *) user_data;
+ NMConnection *connection = NULL;
+ g_autoptr(GError) error = NULL;
+ GSList *iter;
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ goto out;
+
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+ if (!file) {
+ g_warning ("%s: didn't get a filename back from the chooser!", __func__);
+ goto out;
+ }
+
+ filename = g_file_get_path (file);
+ for (iter = vpn_get_plugins (); !connection && iter; iter = iter->next) {
+ NMVpnEditorPlugin *plugin;
+
+ plugin = nm_vpn_plugin_info_get_editor_plugin (iter->data);
+ g_clear_error (&error);
+ connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
+ }
+
+ if (!connection) {
+ GtkWidget *err_dialog;
+ g_autofree gchar *bname = g_path_get_basename (filename);
+
+ err_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot import VPN connection"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (err_dialog),
+ _("The file “%s” could not be read or does not contain recognized VPN connection information\n\nError: %s."),
+ bname, error ? error->message : "unknown error");
+ run_dialog (GTK_DIALOG (err_dialog));
+ }
+
+out:
+ gtk_window_destroy (GTK_WINDOW (dialog));
+
+ info->callback (connection, info->user_data);
+ g_free (info);
+}
+
+static gboolean
+destroy_import_chooser (GtkWidget *dialog, gpointer user_data)
+{
+ ActionInfo *info = (ActionInfo *) user_data;
+
+ info->callback (NULL, info->user_data);
+ g_free (info);
+
+ return FALSE;
+}
+
+void
+vpn_import (GtkWindow *parent, VpnImportCallback callback, gpointer user_data)
+{
+ g_autoptr(GFile) home_folder = NULL;
+ GtkWidget *dialog;
+ ActionInfo *info;
+
+ dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
+ parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ home_folder = g_file_new_for_path (g_get_home_dir ());
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder, NULL);
+
+ info = g_malloc0 (sizeof (ActionInfo));
+ info->callback = callback;
+ info->user_data = user_data;
+
+ g_signal_connect (G_OBJECT (dialog), "close-request", G_CALLBACK (destroy_import_chooser), info);
+ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_vpn_from_file_cb), info);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+export_vpn_to_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
+{
+ g_autoptr(NMConnection) connection = NM_CONNECTION (user_data);
+ g_autoptr(GFile) file = NULL;
+ char *filename = NULL;
+ g_autoptr(GError) error = NULL;
+ NMVpnEditorPlugin *plugin;
+ NMSettingConnection *s_con = NULL;
+ NMSettingVpn *s_vpn = NULL;
+ const char *service_type;
+ const char *id = NULL;
+ gboolean success = FALSE;
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ goto out;
+
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
+ if (!file) {
+ g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, "no filename");
+ goto done;
+ }
+
+ filename = g_file_get_path (file);
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ int replace_response;
+ GtkWidget *replace_dialog;
+ g_autofree gchar *bname = NULL;
+
+ bname = g_path_get_basename (filename);
+ replace_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ _("A file named “%s” already exists."),
+ bname);
+ gtk_dialog_add_buttons (GTK_DIALOG (replace_dialog), _("_Replace"), GTK_RESPONSE_OK, NULL);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (replace_dialog),
+ _("Do you want to replace %s with the VPN connection you are saving?"), bname);
+ replace_response = run_dialog (GTK_DIALOG (replace_dialog));
+ gtk_window_destroy (GTK_WINDOW (replace_dialog));
+ if (replace_response != GTK_RESPONSE_OK)
+ goto out;
+ }
+
+ s_con = nm_connection_get_setting_connection (connection);
+ id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
+ if (!id) {
+ g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, "connection setting invalid");
+ goto done;
+ }
+
+ s_vpn = nm_connection_get_setting_vpn (connection);
+ service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
+
+ if (!service_type) {
+ g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, "VPN setting invalid");
+ goto done;
+ }
+
+ plugin = vpn_get_plugin_by_service (service_type);
+ if (plugin)
+ success = nm_vpn_editor_plugin_export (plugin, filename, connection, &error);
+
+done:
+ if (!success) {
+ GtkWidget *err_dialog;
+ g_autofree gchar *bname = filename ? g_path_get_basename (filename) : g_strdup ("(none)");
+
+ err_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot export VPN connection"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (err_dialog),
+ _("The VPN connection “%s” could not be exported to %s.\n\nError: %s."),
+ id ? id : "(unknown)", bname, error ? error->message : "unknown error");
+ run_dialog (GTK_DIALOG (err_dialog));
+ }
+
+out:
+ gtk_window_destroy (GTK_WINDOW (dialog));
+}
+
+void
+vpn_export (NMConnection *connection)
+{
+ g_autoptr(GFile) home_folder = NULL;
+ GtkWidget *dialog;
+ NMVpnEditorPlugin *plugin;
+ NMSettingVpn *s_vpn = NULL;
+ const char *service_type;
+
+ s_vpn = nm_connection_get_setting_vpn (connection);
+ service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
+
+ if (!service_type) {
+ g_warning ("%s: invalid VPN connection!", __func__);
+ return;
+ }
+
+ dialog = gtk_file_chooser_dialog_new (_("Export VPN connection"),
+ NULL,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Save"), GTK_RESPONSE_ACCEPT,
+ NULL);
+ home_folder = g_file_new_for_path (g_get_home_dir ());
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder, NULL);
+
+ plugin = vpn_get_plugin_by_service (service_type);
+ if (plugin) {
+ g_autofree gchar *suggested = NULL;
+
+ suggested = nm_vpn_editor_plugin_get_suggested_filename (plugin, connection);
+ if (suggested)
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), suggested);
+ }
+
+ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (export_vpn_to_file_cb), g_object_ref (connection));
+ gtk_window_present (GTK_WINDOW (dialog));
+}