[network-manager-applet] connection-editor: move VPN import/export



commit b8ae895ac8018f07931a812ad56f7a07203535a1
Author: Dan Winship <danw gnome org>
Date:   Thu Mar 8 10:35:01 2012 -0500

    connection-editor: move VPN import/export
    
    Make VPN Import be an option underneath the other VPN types in the
    "Add" dialog box, and make VPN Export be a button in the connection
    editor.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=679723

 src/connection-editor/nm-connection-editor.c  |   43 +++++
 src/connection-editor/nm-connection-editor.h  |    1 +
 src/connection-editor/nm-connection-editor.ui |  154 +++++++------------
 src/connection-editor/nm-connection-list.c    |  205 -------------------------
 src/connection-editor/page-vpn.c              |   82 ++++++++++
 src/connection-editor/page-vpn.h              |    2 +
 src/connection-editor/vpn-helpers.c           |  106 +++++++------
 7 files changed, 241 insertions(+), 352 deletions(-)
---
diff --git a/src/connection-editor/nm-connection-editor.c b/src/connection-editor/nm-connection-editor.c
index 65f8ba3..904d821 100644
--- a/src/connection-editor/nm-connection-editor.c
+++ b/src/connection-editor/nm-connection-editor.c
@@ -235,6 +235,7 @@ connection_editor_validate (NMConnectionEditor *editor)
 
 done:
 	ce_polkit_button_set_master_sensitive (CE_POLKIT_BUTTON (editor->ok_button), valid);
+	gtk_widget_set_sensitive (editor->export_button, valid);
 	update_sensitivity (editor);
 }
 
@@ -298,6 +299,7 @@ nm_connection_editor_init (NMConnectionEditor *editor)
 
 	editor->window = GTK_WIDGET (gtk_builder_get_object (editor->builder, "nm-connection-editor"));
 	editor->cancel_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "cancel_button"));
+	editor->export_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "export_button"));
 	editor->all_checkbutton = GTK_WIDGET (gtk_builder_get_object (editor->builder, "system_checkbutton"));
 }
 
@@ -589,6 +591,9 @@ page_initialized (CEPage *page, GError *error, gpointer user_data)
 		gtk_container_remove (GTK_CONTAINER (parent), widget);
 	gtk_notebook_append_page (notebook, widget, label);
 
+	if (CE_IS_PAGE_VPN (page) && ce_page_vpn_can_export (CE_PAGE_VPN (page)))
+		gtk_widget_show (editor->export_button);
+
 	/* Move the page from the initializing list to the main page list */
 	editor->initializing_pages = g_slist_remove (editor->initializing_pages, page);
 	editor->pages = g_slist_append (editor->pages, page);
@@ -882,6 +887,42 @@ ok_button_clicked_cb (GtkWidget *widget, gpointer user_data)
 	g_signal_emit (self, editor_signals[EDITOR_DONE], 0, GTK_RESPONSE_OK, NULL);
 }
 
+static void
+vpn_export_get_secrets_cb (NMRemoteConnection *connection,
+                           GHashTable *secrets,
+                           GError *error,
+                           gpointer user_data)
+{
+	NMConnection *tmp;
+
+	/* We don't really care about errors; if the user couldn't authenticate
+	 * then just let them export everything except secrets.  Duplicate the
+	 * connection so that we don't let secrets sit around in the original
+	 * one.
+	 */
+	tmp = nm_connection_duplicate (NM_CONNECTION (connection));
+	g_assert (tmp);
+	if (secrets)
+		nm_connection_update_secrets (tmp, NM_SETTING_VPN_SETTING_NAME, secrets, NULL);
+	vpn_export (tmp);
+	g_object_unref (tmp);
+}
+
+static void
+export_button_clicked_cb (GtkWidget *widget, gpointer user_data)
+{
+	NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
+
+	if (NM_IS_REMOTE_CONNECTION (self->orig_connection)) {
+		/* Grab secrets if we can */
+		nm_remote_connection_get_secrets (NM_REMOTE_CONNECTION (self->orig_connection),
+		                                  NM_SETTING_VPN_SETTING_NAME,
+		                                  vpn_export_get_secrets_cb,
+		                                  self);
+	} else
+		vpn_export (self->connection);
+}
+
 void
 nm_connection_editor_run (NMConnectionEditor *self)
 {
@@ -894,6 +935,8 @@ nm_connection_editor_run (NMConnectionEditor *self)
 	                  G_CALLBACK (ok_button_clicked_cb), self);
 	g_signal_connect (G_OBJECT (self->cancel_button), "clicked",
 	                  G_CALLBACK (cancel_button_clicked_cb), self);
+	g_signal_connect (G_OBJECT (self->export_button), "clicked",
+	                  G_CALLBACK (export_button_clicked_cb), self);
 
 	nm_connection_editor_present (self);
 }
diff --git a/src/connection-editor/nm-connection-editor.h b/src/connection-editor/nm-connection-editor.h
index 250f7b9..d1cfeee 100644
--- a/src/connection-editor/nm-connection-editor.h
+++ b/src/connection-editor/nm-connection-editor.h
@@ -56,6 +56,7 @@ typedef struct {
 	GtkWidget *window;
 	GtkWidget *ok_button;
 	GtkWidget *cancel_button;
+	GtkWidget *export_button;
 	guint nag_id;
 
 	gboolean busy;
diff --git a/src/connection-editor/nm-connection-editor.ui b/src/connection-editor/nm-connection-editor.ui
index 2b0b284..bd42ff2 100644
--- a/src/connection-editor/nm-connection-editor.ui
+++ b/src/connection-editor/nm-connection-editor.ui
@@ -320,101 +320,33 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVBox" id="vbox1">
+                  <object class="GtkVButtonBox" id="vpn_button_box">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="spacing">6</property>
+                    <property name="layout_style">start</property>
                     <child>
-                      <object class="GtkVButtonBox" id="vpn_button_box">
+                      <object class="GtkButton" id="vpn_add">
+                        <property name="label">gtk-add</property>
+                        <property name="use_action_appearance">False</property>
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <property name="layout_style">start</property>
-                        <child>
-                          <object class="GtkButton" id="vpn_add">
-                            <property name="label">gtk-add</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="can_default">True</property>
-                            <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_stock">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <placeholder/>
-                        </child>
-                        <child>
-                          <placeholder/>
-                        </child>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="use_stock">True</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
-                        <property name="fill">True</property>
+                        <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkHSeparator" id="hseparator1">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
+                      <placeholder/>
                     </child>
                     <child>
-                      <object class="GtkVButtonBox" id="vpn_ix_button_box">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="spacing">6</property>
-                        <property name="layout_style">end</property>
-                        <child>
-                          <object class="GtkButton" id="vpn_import">
-                            <property name="label" translatable="yes">_Import</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="vpn_export">
-                            <property name="label" translatable="yes">E_xport</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">False</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
+                      <placeholder/>
                     </child>
                   </object>
                   <packing>
@@ -588,17 +520,46 @@
               </packing>
             </child>
             <child>
-              <object class="GtkCheckButton" id="connection_autoconnect">
-                <property name="label" translatable="yes">Connect _automatically</property>
-                <property name="use_action_appearance">False</property>
+              <object class="GtkVBox" id="vbox1">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_action_appearance">False</property>
-                <property name="use_underline">True</property>
-                <property name="xalign">0.5</property>
-                <property name="active">True</property>
-                <property name="draw_indicator">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkCheckButton" id="connection_autoconnect">
+                    <property name="label" translatable="yes">Connect _automatically</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="xalign">0</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="system_checkbutton">
+                    <property name="label" translatable="yes">A_vailable to all users</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="xalign">0</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -635,20 +596,17 @@
                 <property name="can_focus">False</property>
                 <property name="spacing">6</property>
                 <child>
-                  <object class="GtkCheckButton" id="system_checkbutton">
-                    <property name="label" translatable="yes">A_vailable to all users</property>
+                  <object class="GtkButton" id="export_button">
+                    <property name="label" translatable="yes">_Export...</property>
                     <property name="use_action_appearance">False</property>
-                    <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="receives_default">False</property>
+                    <property name="receives_default">True</property>
                     <property name="use_action_appearance">False</property>
                     <property name="use_underline">True</property>
-                    <property name="xalign">0.5</property>
-                    <property name="draw_indicator">True</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
-                    <property name="fill">False</property>
+                    <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
diff --git a/src/connection-editor/nm-connection-list.c b/src/connection-editor/nm-connection-list.c
index 09e84ea..c9a0929 100644
--- a/src/connection-editor/nm-connection-list.c
+++ b/src/connection-editor/nm-connection-list.c
@@ -42,7 +42,6 @@
 #include <nm-setting-pppoe.h>
 #include <nm-setting-ppp.h>
 #include <nm-setting-serial.h>
-#include <nm-vpn-plugin-ui-interface.h>
 #include <nm-utils.h>
 #include <nm-remote-settings.h>
 
@@ -841,169 +840,6 @@ pk_button_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 }
 
 static void
-vpn_list_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
-{
-	ActionInfo *info = (ActionInfo *) user_data;
-	NMVpnPluginUiInterface *plugin;
-	NMRemoteConnection *connection;
-	NMSettingVPN *s_vpn;
-	const char *service_type;
-	GtkTreeIter iter;
-	GtkTreeModel *model;
-	guint32 caps;
-	gboolean supported = FALSE;
-
-	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-		goto done;
-
-	connection = get_active_connection (info->treeview);
-	if (!connection)
-		goto done;
-
-	s_vpn = nm_connection_get_setting_vpn (NM_CONNECTION (connection));
-	service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
-
-	if (!service_type)
-		goto done;
-
-	plugin = vpn_get_plugin_by_service (service_type);
-	if (!plugin)
-		goto done;
-
-	caps = nm_vpn_plugin_ui_interface_get_capabilities (plugin);
-	if (caps & NM_VPN_PLUGIN_UI_CAPABILITY_EXPORT)
-		supported = TRUE;
-
-done:
-	gtk_widget_set_sensitive (info->button, supported);
-}
-
-static void
-import_success_cb (NMConnection *connection, gpointer user_data)
-{
-	ActionInfo *info = (ActionInfo *) user_data;
-	NMConnectionEditor *editor;
-	NMSettingConnection *s_con;
-	NMSettingVPN *s_vpn;
-	const char *service_type;
-	char *s;
-	GError *error = NULL;
-	const char *message = _("The connection editor dialog could not be initialized due to an unknown error.");
-
-	/* Basic sanity checks of the connection */
-	s_con = nm_connection_get_setting_connection (connection);
-	if (!s_con) {
-		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
-		nm_connection_add_setting (connection, NM_SETTING (s_con));
-	}
-
-	s = (char *) nm_setting_connection_get_id (s_con);
-	if (!s) {
-		GSList *connections;
-
-		connections = nm_remote_settings_list_connections (info->list->settings);
-		s = ce_page_get_next_available_name (connections, _("VPN connection %d"));
-		g_object_set (s_con, NM_SETTING_CONNECTION_ID, s, NULL);
-		g_free (s);
-
-		g_slist_free (connections);
-	}
-
-	s = (char *) nm_setting_connection_get_connection_type (s_con);
-	if (!s || strcmp (s, NM_SETTING_VPN_SETTING_NAME))
-		g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_VPN_SETTING_NAME, NULL);
-
-	s = (char *) nm_setting_connection_get_uuid (s_con);
-	if (!s) {
-		s = nm_utils_uuid_generate ();
-		g_object_set (s_con, NM_SETTING_CONNECTION_UUID, s, NULL);
-		g_free (s);
-	}
-
-	s_vpn = nm_connection_get_setting_vpn (connection);
-	service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
-
-	if (!service_type || !strlen (service_type)) {
-		GtkWidget *dialog;
-
-		g_object_unref (connection);
-
-		dialog = gtk_message_dialog_new (NULL,
-		                                 GTK_DIALOG_DESTROY_WITH_PARENT,
-		                                 GTK_MESSAGE_ERROR,
-		                                 GTK_BUTTONS_OK,
-		                                 _("Cannot import VPN connection"));
-		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-		                                 _("The VPN plugin failed to import the VPN connection correctly\n\nError: no VPN service type."));
-		gtk_window_set_transient_for (GTK_WINDOW (dialog), info->list_window);
-		g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
-		g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
-		gtk_widget_show_all (dialog);
-		gtk_window_present (GTK_WINDOW (dialog));
-		return;
-	}
-
-	editor = nm_connection_editor_new (connection, info->list->nm_client, &error);
-	if (!editor) {
-		g_object_unref (connection);
-		error_dialog (info->list_window,
-		              _("Could not edit imported connection"),
-		              "%s",
-		              (error && error->message) ? error->message : message);
-		return;
-	}
-
-	g_signal_connect (editor, "done", G_CALLBACK (add_response_cb), info);
-	g_hash_table_insert (info->list->editors, connection, editor);
-
-	nm_connection_editor_run (editor);
-}
-
-static void
-import_vpn_cb (GtkButton *button, gpointer user_data)
-{
-	vpn_import (import_success_cb, (ActionInfo *) user_data);
-}
-
-static void
-vpn_export_get_secrets_cb (NMRemoteConnection *connection,
-                           GHashTable *secrets,
-                           GError *error,
-                           gpointer user_data)
-{
-	NMConnection *tmp;
-
-	/* We don't really care about errors; if the user couldn't authenticate
-	 * then just let them export everything except secrets.  Duplicate the
-	 * connection so that we don't let secrets sit around in the original
-	 * one.
-	 */
-	tmp = nm_connection_duplicate (NM_CONNECTION (connection));
-	g_assert (tmp);
-	if (secrets)
-		nm_connection_update_secrets (tmp, NM_SETTING_VPN_SETTING_NAME, secrets, NULL);
-	vpn_export (tmp);
-	g_object_unref (tmp);
-}
-
-
-static void
-export_vpn_cb (GtkButton *button, gpointer user_data)
-{
-	ActionInfo *info = (ActionInfo *) user_data;
-	NMRemoteConnection *connection;
-
-	connection = get_active_connection (info->treeview);
-	if (connection) {
-		/* Grab secrets if we can */
-		nm_remote_connection_get_secrets (connection,
-		                                  NM_SETTING_VPN_SETTING_NAME,
-		                                  vpn_export_get_secrets_cb,
-		                                  NULL);
-	}
-}
-
-static void
 connection_double_clicked_cb (GtkTreeView *tree_view,
                               GtkTreePath *path,
                               GtkTreeViewColumn *column,
@@ -1225,19 +1061,6 @@ action_info_set_new_func (ActionInfo *info,
 }
 
 static void
-check_vpn_import_supported (gpointer key, gpointer data, gpointer user_data)
-{
-	NMVpnPluginUiInterface *plugin = NM_VPN_PLUGIN_UI_INTERFACE (data);
-	gboolean *import_supported = user_data;
-
-	if (*import_supported)
-		return;
-
-	if (nm_vpn_plugin_ui_interface_get_capabilities (plugin) & NM_VPN_PLUGIN_UI_CAPABILITY_IMPORT)
-		*import_supported = TRUE;
-}
-
-static void
 add_connection_buttons (NMConnectionList *self,
                         const char *prefix,
                         GtkTreeView *treeview,
@@ -1309,34 +1132,6 @@ add_connection_buttons (NMConnectionList *self,
 	g_signal_connect (button, "clicked", G_CALLBACK (delete_clicked), info);
 	g_signal_connect (selection, "changed", G_CALLBACK (pk_button_selection_changed_cb), info);
 	pk_button_selection_changed_cb (selection, info);
-
-	/* Import */
-	name = g_strdup_printf ("%s_import", prefix);
-	button = GTK_WIDGET (gtk_builder_get_object (self->gui, name));
-	g_free (name);
-	if (button) {
-		gboolean import_supported = FALSE;
-		GHashTable *plugins;
-
-		info = action_info_new (self, "import", ctype, treeview, GTK_WINDOW (self->dialog), button);
-		g_signal_connect (button, "clicked", G_CALLBACK (import_vpn_cb), info);
-
-		plugins = vpn_get_plugins (NULL);
-		if (plugins)
-			g_hash_table_foreach (plugins, check_vpn_import_supported, &import_supported);
-		gtk_widget_set_sensitive (button, import_supported);
-	}
-
-	/* Export */
-	name = g_strdup_printf ("%s_export", prefix);
-	button = GTK_WIDGET (gtk_builder_get_object (self->gui, name));
-	g_free (name);
-	if (button) {
-		info = action_info_new (self, "export", ctype, treeview, GTK_WINDOW (self->dialog), button);
-		g_signal_connect (button, "clicked", G_CALLBACK (export_vpn_cb), info);
-		g_signal_connect (selection, "changed", G_CALLBACK (vpn_list_selection_changed_cb), info);
-		gtk_widget_set_sensitive (button, FALSE);
-	}
 }
 
 static void
diff --git a/src/connection-editor/page-vpn.c b/src/connection-editor/page-vpn.c
index 70910eb..8e9f1a9 100644
--- a/src/connection-editor/page-vpn.c
+++ b/src/connection-editor/page-vpn.c
@@ -29,6 +29,7 @@
 
 #include <nm-setting-connection.h>
 #include <nm-setting-vpn.h>
+#include <nm-utils.h>
 
 #define NM_VPN_API_SUBJECT_TO_CHANGE
 #include <nm-vpn-plugin-ui-interface.h>
@@ -135,6 +136,14 @@ ce_page_vpn_new (NMConnection *connection,
 	return CE_PAGE (self);
 }
 
+gboolean
+ce_page_vpn_can_export (CEPageVpn *page)
+{
+	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (page);
+
+	return 	(nm_vpn_plugin_ui_interface_get_capabilities (priv->plugin) & NM_VPN_PLUGIN_UI_CAPABILITY_EXPORT) != 0;
+}
+
 static gboolean
 validate (CEPage *page, NMConnection *connection, GError **error)
 {
@@ -181,6 +190,67 @@ ce_page_vpn_class_init (CEPageVpnClass *vpn_class)
 	parent_class->validate = validate;
 }
 
+typedef struct {
+	PageNewConnectionResultFunc result_func;
+	PageGetConnectionsFunc get_connections_func;
+	gpointer user_data;
+} NewVpnInfo;
+
+static void
+import_cb (NMConnection *connection, gpointer user_data)
+{
+	NewVpnInfo *info = (NewVpnInfo *) user_data;
+	NMSettingConnection *s_con;
+	NMSettingVPN *s_vpn;
+	const char *service_type;
+	char *s;
+	GError *error = NULL;
+
+	/* Basic sanity checks of the connection */
+	s_con = nm_connection_get_setting_connection (connection);
+	if (!s_con) {
+		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+		nm_connection_add_setting (connection, NM_SETTING (s_con));
+	}
+
+	s = (char *) nm_setting_connection_get_id (s_con);
+	if (!s) {
+		GSList *connections;
+
+		connections = info->get_connections_func (info->user_data);
+		s = ce_page_get_next_available_name (connections, _("VPN connection %d"));
+		g_object_set (s_con, NM_SETTING_CONNECTION_ID, s, NULL);
+		g_free (s);
+
+		g_slist_free (connections);
+	}
+
+	s = (char *) nm_setting_connection_get_connection_type (s_con);
+	if (!s || strcmp (s, NM_SETTING_VPN_SETTING_NAME))
+		g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, NM_SETTING_VPN_SETTING_NAME, NULL);
+
+	s = (char *) nm_setting_connection_get_uuid (s_con);
+	if (!s) {
+		s = nm_utils_uuid_generate ();
+		g_object_set (s_con, NM_SETTING_CONNECTION_UUID, s, NULL);
+		g_free (s);
+	}
+
+	s_vpn = nm_connection_get_setting_vpn (connection);
+	service_type = s_vpn ? nm_setting_vpn_get_service_type (s_vpn) : NULL;
+
+	if (!service_type || !strlen (service_type)) {
+		g_object_unref (connection);
+		connection = NULL;
+
+		error = g_error_new_literal (NMA_ERROR, NMA_ERROR_GENERIC,
+		                             _("The VPN plugin failed to import the VPN connection correctly\n\nError: no VPN service type."));
+	}
+
+	info->result_func (connection, FALSE, error, info->user_data);
+	g_clear_error (&error);
+	g_slice_free (NewVpnInfo, info);
+}
 
 void
 vpn_connection_new (GtkWindow *parent,
@@ -198,6 +268,18 @@ vpn_connection_new (GtkWindow *parent,
 		return;
 	}
 
+	if (!strcmp (service, "import")) {
+		NewVpnInfo *info;
+
+		g_free (service);
+		info = g_slice_new (NewVpnInfo);
+		info->result_func = result_func;
+		info->get_connections_func = get_connections_func;
+		info->user_data = user_data;
+		vpn_import (import_cb, info);
+		return;
+	}
+
 	connection = ce_page_new_connection (_("VPN connection %d"),
 	                                     NM_SETTING_VPN_SETTING_NAME,
 	                                     FALSE,
diff --git a/src/connection-editor/page-vpn.h b/src/connection-editor/page-vpn.h
index dad5ca4..d9a4106 100644
--- a/src/connection-editor/page-vpn.h
+++ b/src/connection-editor/page-vpn.h
@@ -53,6 +53,8 @@ CEPage *ce_page_vpn_new (NMConnection *connection,
                          const char **out_secrets_setting_name,
                          GError **error);
 
+gboolean ce_page_vpn_can_export (CEPageVpn *page);
+
 void vpn_connection_new (GtkWindow *parent,
                          PageNewConnectionResultFunc result_func,
                          PageGetConnectionsFunc get_connections_func,
diff --git a/src/connection-editor/vpn-helpers.c b/src/connection-editor/vpn-helpers.c
index 55ef432..82c2e99 100644
--- a/src/connection-editor/vpn-helpers.c
+++ b/src/connection-editor/vpn-helpers.c
@@ -163,30 +163,6 @@ vpn_get_plugins (GError **error)
 	return plugins;
 }
 
-
-typedef struct {
-	char *filename;
-	NMConnection *connection;
-	GError *error;
-} VpnImportInfo;
-
-static void
-try_import (gpointer key, gpointer value, gpointer user_data)
-{
-	VpnImportInfo *info = user_data;
-	NMVpnPluginUiInterface *plugin = NM_VPN_PLUGIN_UI_INTERFACE (value);
-
-	if (info->connection)
-		return;
-
-	if (info->error) {
-		g_error_free (info->error);
-		info->error = NULL;
-	}
-
-	info->connection = nm_vpn_plugin_ui_interface_import (plugin, info->filename, &(info->error));
-}
-
 typedef struct {
 	VpnImportSuccessCallback callback;
 	gpointer user_data;
@@ -197,8 +173,11 @@ import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
 {
 	char *filename = NULL;
 	ActionInfo *info = (ActionInfo *) user_data;
-	VpnImportInfo import_info;
-	NMConnection *connection;
+	GHashTableIter iter;
+	gpointer key;
+	NMVpnPluginUiInterface *plugin;
+	NMConnection *connection = NULL;
+	GError *error = NULL;
 
 	if (response != GTK_RESPONSE_ACCEPT)
 		goto out;
@@ -209,12 +188,12 @@ import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
 		goto out;
 	}
 
-	import_info.filename = filename;
-	import_info.connection = NULL;
-	import_info.error = NULL;
-	g_hash_table_foreach (plugins, try_import, (gpointer) &import_info);
+	g_hash_table_iter_init (&iter, plugins);
+	while (!connection && g_hash_table_iter_next (&iter, &key, (gpointer *)&plugin)) {
+		g_clear_error (&error);
+		connection = nm_vpn_plugin_ui_interface_import (plugin, filename, &error);
+	}
 
-	connection = import_info.connection;
 	if (connection)
 		info->callback (connection, info->user_data);
 	else {
@@ -228,7 +207,7 @@ import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
 		                                     _("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, import_info.error ? import_info.error->message : "unknown error");
+		                                 bname, error ? error->message : "unknown error");
 		g_free (bname);
 		g_signal_connect (err_dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
 		g_signal_connect (err_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
@@ -236,8 +215,7 @@ import_vpn_from_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
 		gtk_window_present (GTK_WINDOW (err_dialog));
 	}
 
-	if (import_info.error)
-		g_error_free (import_info.error);
+	g_clear_error (&error);
 	g_free (filename);
 
 out:
@@ -266,8 +244,8 @@ vpn_import (VpnImportSuccessCallback callback, gpointer user_data)
 	                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 	                                      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
 	                                      NULL);
-        home_folder = g_get_home_dir ();
-        gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder);
+	home_folder = g_get_home_dir ();
+	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), home_folder);
 
 	info = g_malloc0 (sizeof (ActionInfo));
 	info->callback = callback;
@@ -414,14 +392,6 @@ vpn_export (NMConnection *connection)
 	gtk_window_present (GTK_WINDOW (dialog));
 }
 
-static void
-add_plugins_to_list (gpointer key, gpointer data, gpointer user_data)
-{
-	GSList **list = (GSList **) user_data;
-
-	*list = g_slist_append (*list, NM_VPN_PLUGIN_UI_INTERFACE (data));
-}
-
 static gint
 sort_plugins (gconstpointer a, gconstpointer b)
 {
@@ -448,6 +418,23 @@ sort_plugins (gconstpointer a, gconstpointer b)
 #define COL_PLUGIN_DESC 0
 #define COL_PLUGIN_OBJ  1
 
+static gboolean
+combo_row_separator_func (GtkTreeModel *model,
+                          GtkTreeIter  *iter,
+                          gpointer      data)
+{
+	char *desc;
+
+	gtk_tree_model_get (model, iter,
+	                    COL_PLUGIN_DESC, &desc,
+	                    -1);
+	if (desc) {
+		g_free (desc);
+		return FALSE;
+	} else
+		return TRUE;
+}
+
 static void
 combo_changed_cb (GtkComboBox *combo, gpointer user_data)
 {
@@ -490,11 +477,14 @@ vpn_ask_connection_type (GtkWindow *parent)
 	GtkBuilder *builder;
 	GtkWidget *dialog, *combo, *widget;
 	GtkTreeModel *model;
+	GHashTableIter hash_iter;
+	gpointer key, value;
 	GSList *plugin_list = NULL, *iter;
 	gint response;
 	GtkTreeIter tree_iter;
 	char *service_type = NULL;
 	GError *error = NULL;
+	gboolean import_supported = FALSE;
 
 	if (!plugins || !g_hash_table_size (plugins)) {
 		g_warning ("%s: no VPN plugins could be found!", __func__);
@@ -517,9 +507,12 @@ vpn_ask_connection_type (GtkWindow *parent)
 	}
 
 	model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT));
-	g_hash_table_foreach (plugins, add_plugins_to_list, &plugin_list);
 
+	g_hash_table_iter_init (&hash_iter, plugins);
+	while (g_hash_table_iter_next (&hash_iter, &key, &value))
+		plugin_list = g_slist_prepend (plugin_list, value);
 	plugin_list = g_slist_sort (plugin_list, sort_plugins);
+
 	for (iter = plugin_list; iter; iter = g_slist_next (iter)) {
 		NMVpnPluginUiInterface *plugin = NM_VPN_PLUGIN_UI_INTERFACE (iter->data);
 		char *desc;
@@ -530,6 +523,21 @@ vpn_ask_connection_type (GtkWindow *parent)
 		                    COL_PLUGIN_DESC, desc,
 		                    COL_PLUGIN_OBJ, plugin, -1);
 		g_free (desc);
+
+		if (nm_vpn_plugin_ui_interface_get_capabilities (plugin) & NM_VPN_PLUGIN_UI_CAPABILITY_IMPORT)
+			import_supported = TRUE;
+	}
+	g_slist_free (plugin_list);
+
+	if (import_supported) {
+		gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter);
+		gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter,
+		                    COL_PLUGIN_DESC, NULL,
+		                    COL_PLUGIN_OBJ, NULL, -1);
+		gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter);
+		gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter,
+		                    COL_PLUGIN_DESC, _("Import a saved VPN configuration..."),
+		                    COL_PLUGIN_OBJ, NULL, -1);
 	}
 
 	combo = GTK_WIDGET (gtk_builder_get_object (builder, "vpn_type_combo"));
@@ -537,6 +545,7 @@ vpn_ask_connection_type (GtkWindow *parent)
 	g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (combo_changed_cb), widget);
 	gtk_combo_box_set_model (GTK_COMBO_BOX (combo), model);
 	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
+	gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo), combo_row_separator_func, NULL, NULL);
 
 	gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
 	gtk_widget_show_all (dialog);
@@ -551,15 +560,14 @@ vpn_ask_connection_type (GtkWindow *parent)
 		if (plugin) {
 			g_object_get (G_OBJECT (plugin), NM_VPN_PLUGIN_UI_INTERFACE_SERVICE, &service_type, NULL);
 			g_object_unref (plugin);
-		}
+		} else
+			service_type = g_strdup ("import");
 	}
 
 out:
 	gtk_widget_destroy (dialog);
 	g_object_unref (builder);
-	if (service_type)
-		return service_type;
-	return NULL;
+	return service_type;
 }
 
 gboolean



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]