network-manager-applet r758 - in trunk: . po src/connection-editor src/vpn-properties



Author: dcbw
Date: Tue Jun 17 10:46:26 2008
New Revision: 758
URL: http://svn.gnome.org/viewvc/network-manager-applet?rev=758&view=rev

Log:
2008-06-17  Dan Williams  <dcbw redhat com>

	* src/vpn-properties/*
		- Remove, no longer used

	* src/connection-editor/Makefile.am
	  src/connection-editor/ce-vpn-wizard.glade
	  src/connection-editor/nm-connection-editor.c
	  src/connection-editor/nm-connection-editor.glade
	  src/connection-editor/nm-connection-list.c
	  src/connection-editor/page-vpn.c
	  src/connection-editor/page-vpn.h
	  src/connection-editor/vpn-helpers.c
	  src/connection-editor/vpn-helpers.h
		- Add VPN editing functionality to the connection editor using the
			new GNOME VPN UI plugin API



Added:
   trunk/src/connection-editor/ce-vpn-wizard.glade
   trunk/src/connection-editor/page-vpn.c
   trunk/src/connection-editor/page-vpn.h
   trunk/src/connection-editor/vpn-helpers.c
   trunk/src/connection-editor/vpn-helpers.h
Removed:
   trunk/src/vpn-properties/
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/po/POTFILES.in
   trunk/src/connection-editor/Makefile.am
   trunk/src/connection-editor/nm-connection-editor.c
   trunk/src/connection-editor/nm-connection-editor.glade
   trunk/src/connection-editor/nm-connection-list.c

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Tue Jun 17 10:46:26 2008
@@ -69,8 +69,9 @@
 		[dbus-glib-1 >= 0.72
 		 glib-2.0 >= 2.10
 		 NetworkManager >= 0.7.0
-		 libnm_glib
-		 libnm-util
+		 libnm_glib >= 0.7.0
+		 libnm-util >= 0.7.0
+		 libnm_glib_vpn >= 0.7.0
 		 gtk+-2.0 >= 2.10
 		 libglade-2.0
 		 gmodule-export-2.0

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Tue Jun 17 10:46:26 2008
@@ -23,6 +23,7 @@
 src/connection-editor/page-ip4.c
 src/connection-editor/page-mobile.c
 src/connection-editor/page-ppp.c
+src/connection-editor/page-vpn.c
 src/connection-editor/page-wired.c
 src/connection-editor/page-wired-security.c
 src/connection-editor/page-wireless.c
@@ -30,10 +31,9 @@
 src/connection-editor/nm-connection-editor.c
 src/connection-editor/nm-connection-editor.glade
 src/connection-editor/nm-connection-list.c
+src/connection-editor/vpn-helpers.c
 src/keyring.png
 src/main.c
-src/vpn-properties/nm-vpn-properties.c
-src/vpn-properties/nm-vpn-properties.glade
 src/vpn-password-dialog.c
 src/vpn-password-dialog.h
 src/wired-dialog.c

Modified: trunk/src/connection-editor/Makefile.am
==============================================================================
--- trunk/src/connection-editor/Makefile.am	(original)
+++ trunk/src/connection-editor/Makefile.am	Tue Jun 17 10:46:26 2008
@@ -42,7 +42,11 @@
 	mobile-wizard.h \
 	mobile-wizard.c \
 	page-ppp.h \
-	page-ppp.c
+	page-ppp.c \
+	page-vpn.h \
+	page-vpn.c \
+	vpn-helpers.h \
+	vpn-helpers.c
 
 if NO_POLKIT_GNOME
 nm_connection_editor_SOURCES += \
@@ -67,7 +71,8 @@
 	ce-page-dsl.glade \
 	ce-page-mobile.glade \
 	ce-mobile-wizard.glade \
-	ce-page-ppp.glade
+	ce-page-ppp.glade \
+	ce-vpn-wizard.glade
 
 CLEANFILES = *.bak *.gladep
 

Added: trunk/src/connection-editor/ce-vpn-wizard.glade
==============================================================================
--- (empty file)
+++ trunk/src/connection-editor/ce-vpn-wizard.glade	Tue Jun 17 10:46:26 2008
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkDialog" id="vpn_type_dialog">
+    <property name="border_width">6</property>
+    <property name="title" translatable="yes"> </property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property>
+    <property name="icon_name">gtk-dialog-question</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="vbox2">
+        <property name="visible">True</property>
+        <property name="spacing">14</property>
+        <child>
+          <widget class="GtkHBox" id="hbox2">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="spacing">12</property>
+            <child>
+              <widget class="GtkImage" id="image2">
+                <property name="visible">True</property>
+                <property name="yalign">0</property>
+                <property name="stock">gtk-dialog-question</property>
+                <property name="icon_size">6</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox3">
+                <property name="visible">True</property>
+                <property name="spacing">12</property>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;span weight="bold" size="larger"&gt;Choose a VPN Connection Type&lt;/span&gt;
+
+Select the type of VPN you wish to use for the new connection.  If the type of VPN connection you wish to create does not appear in the list, you may not have the correct VPN plugin installed.</property>
+                    <property name="use_markup">True</property>
+                    <property name="wrap">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVBox" id="vpn_vbox">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <widget class="GtkComboBox" id="vpn_type_combo">
+                        <property name="visible">True</property>
+                        <property name="items" translatable="yes"> </property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="vpn_desc_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="use_markup">True</property>
+                        <property name="wrap">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">6</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="hbuttonbox1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="label">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="create_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">Create...</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Modified: trunk/src/connection-editor/nm-connection-editor.c
==============================================================================
--- trunk/src/connection-editor/nm-connection-editor.c	(original)
+++ trunk/src/connection-editor/nm-connection-editor.c	Tue Jun 17 10:46:26 2008
@@ -59,6 +59,7 @@
 #include "page-dsl.h"
 #include "page-mobile.h"
 #include "page-ppp.h"
+#include "page-vpn.h"
 
 G_DEFINE_TYPE (NMConnectionEditor, nm_connection_editor, G_TYPE_OBJECT)
 
@@ -148,7 +149,8 @@
 
 		if (!ce_page_validate (CE_PAGE (iter->data), &error)) {
 			/* FIXME: use the error to indicate which UI widgets are invalid */
-			g_error_free (error);
+			if (error)
+				g_error_free (error);
 			goto done;
 		}
 	}
@@ -338,6 +340,9 @@
 	GtkWidget *notebook;
 	GtkWidget *label;
 
+	g_return_if_fail (editor != NULL);
+	g_return_if_fail (page != NULL);
+
 	notebook = glade_xml_get_widget (editor->xml, "notebook");
 	label = gtk_label_new (ce_page_get_title (page));
 	widget = ce_page_get_page (page);
@@ -386,6 +391,7 @@
 
 		add_page (editor, CE_PAGE (ce_page_ip4_new (editor->connection)));
 	} else if (!strcmp (s_con->type, NM_SETTING_VPN_SETTING_NAME)) {
+		add_page (editor, CE_PAGE (ce_page_vpn_new (editor->connection)));
 		add_page (editor, CE_PAGE (ce_page_ip4_new (editor->connection)));
 	} else if (!strcmp (s_con->type, NM_SETTING_PPPOE_SETTING_NAME)) {
 		add_page (editor, CE_PAGE (ce_page_dsl_new (editor->connection)));

Modified: trunk/src/connection-editor/nm-connection-editor.glade
==============================================================================
--- trunk/src/connection-editor/nm-connection-editor.glade	(original)
+++ trunk/src/connection-editor/nm-connection-editor.glade	Tue Jun 17 10:46:26 2008
@@ -1,854 +1,644 @@
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd";>
-
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
 <glade-interface>
-
-<widget class="GtkDialog" id="NMConnectionEditor">
-  <property name="border_width">5</property>
-  <property name="title" translatable="yes">Connection Editor</property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-  <property name="has_separator">False</property>
-
-  <child internal-child="vbox">
-    <widget class="GtkVBox" id="dialog-vbox1">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">2</property>
-
-      <child internal-child="action_area">
-	<widget class="GtkHButtonBox" id="dialog-action_area1">
-	  <property name="visible">True</property>
-	  <property name="layout_style">GTK_BUTTONBOX_END</property>
-
-	  <child>
-	    <widget class="GtkButton" id="cancel_button">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-cancel</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-6</property>
-	    </widget>
-	  </child>
-
-	  <child>
-	    <widget class="GtkButton" id="ok_button">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-ok</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-5</property>
-	    </widget>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">False</property>
-	  <property name="fill">True</property>
-	  <property name="pack_type">GTK_PACK_END</property>
-	</packing>
-      </child>
-
-      <child>
-	<widget class="GtkVBox" id="vbox1">
-	  <property name="border_width">5</property>
-	  <property name="visible">True</property>
-	  <property name="homogeneous">False</property>
-	  <property name="spacing">6</property>
-
-	  <child>
-	    <widget class="GtkHBox" id="hbox2">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">12</property>
-
-	      <child>
-		<widget class="GtkLabel" id="label40">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">Connection _name:</property>
-		  <property name="use_underline">True</property>
-		  <property name="use_markup">False</property>
-		  <property name="justify">GTK_JUSTIFY_LEFT</property>
-		  <property name="wrap">False</property>
-		  <property name="selectable">False</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		  <property name="mnemonic_widget">connection_name</property>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkEntry" id="connection_name">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="editable">True</property>
-		  <property name="visibility">True</property>
-		  <property name="max_length">0</property>
-		  <property name="text" translatable="yes"></property>
-		  <property name="has_frame">True</property>
-		  <property name="activates_default">False</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkCheckButton" id="connection_autoconnect">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label" translatable="yes">Connect _automatically</property>
-	      <property name="use_underline">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="active">True</property>
-	      <property name="inconsistent">False</property>
-	      <property name="draw_indicator">True</property>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">False</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkCheckButton" id="connection_system">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label" translatable="yes">System setting</property>
-	      <property name="use_underline">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="active">False</property>
-	      <property name="inconsistent">False</property>
-	      <property name="draw_indicator">True</property>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">False</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkNotebook" id="notebook">
-	      <property name="visible">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="show_tabs">True</property>
-	      <property name="show_border">True</property>
-	      <property name="tab_pos">GTK_POS_TOP</property>
-	      <property name="scrollable">False</property>
-	      <property name="enable_popup">False</property>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">False</property>
-	    </packing>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">True</property>
-	  <property name="fill">True</property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
-<widget class="GtkDialog" id="NMConnectionList">
-  <property name="border_width">4</property>
-  <property name="title" translatable="yes">Network Connections</property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_CENTER</property>
-  <property name="modal">False</property>
-  <property name="default_width">400</property>
-  <property name="default_height">300</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-  <property name="has_separator">False</property>
-
-  <child internal-child="vbox">
-    <widget class="GtkVBox" id="dialog-vbox2">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">4</property>
-
-      <child internal-child="action_area">
-	<widget class="GtkHButtonBox" id="dialog-action_area2">
-	  <property name="visible">True</property>
-	  <property name="layout_style">GTK_BUTTONBOX_END</property>
-
-	  <child>
-	    <widget class="GtkButton" id="closebutton1">
-	      <property name="visible">True</property>
-	      <property name="can_default">True</property>
-	      <property name="can_focus">True</property>
-	      <property name="label">gtk-close</property>
-	      <property name="use_stock">True</property>
-	      <property name="relief">GTK_RELIEF_NORMAL</property>
-	      <property name="focus_on_click">True</property>
-	      <property name="response_id">-7</property>
-	    </widget>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">False</property>
-	  <property name="fill">True</property>
-	  <property name="pack_type">GTK_PACK_END</property>
-	</packing>
-      </child>
-
-      <child>
-	<widget class="GtkNotebook" id="list_notebook">
-	  <property name="border_width">6</property>
-	  <property name="visible">True</property>
-	  <property name="can_focus">True</property>
-	  <property name="show_tabs">True</property>
-	  <property name="show_border">True</property>
-	  <property name="tab_pos">GTK_POS_TOP</property>
-	  <property name="scrollable">False</property>
-	  <property name="enable_popup">False</property>
-
-	  <child>
-	    <widget class="GtkHBox" id="wired_child">
-	      <property name="border_width">6</property>
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkScrolledWindow" id="scolledwindow1">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="shadow_type">GTK_SHADOW_IN</property>
-		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		  <child>
-		    <widget class="GtkTreeView" id="wired_list">
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="headers_visible">False</property>
-		      <property name="rules_hint">True</property>
-		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVButtonBox" id="vbuttonbox2">
-		  <property name="visible">True</property>
-		  <property name="layout_style">GTK_BUTTONBOX_START</property>
-		  <property name="spacing">6</property>
-
-		  <child>
-		    <widget class="GtkButton" id="wired_add">
-		      <property name="visible">True</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-add</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wired_edit">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-edit</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wired_delete">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-delete</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="tab_expand">False</property>
-	      <property name="tab_fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="wired_label">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">Wired</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="type">tab</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkHBox" id="wireless_child">
-	      <property name="border_width">6</property>
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkScrolledWindow" id="scrolledwindow2">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="shadow_type">GTK_SHADOW_IN</property>
-		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		  <child>
-		    <widget class="GtkTreeView" id="wireless_list">
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="headers_visible">False</property>
-		      <property name="rules_hint">True</property>
-		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVButtonBox" id="vbuttonbox3">
-		  <property name="visible">True</property>
-		  <property name="layout_style">GTK_BUTTONBOX_START</property>
-		  <property name="spacing">6</property>
-
-		  <child>
-		    <widget class="GtkButton" id="wireless_add">
-		      <property name="visible">True</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-add</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wireless_edit">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-edit</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wireless_delete">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-delete</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="tab_expand">False</property>
-	      <property name="tab_fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="wireless_label">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">Wireless</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="type">tab</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkHBox" id="wwan_child">
-	      <property name="border_width">6</property>
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkScrolledWindow" id="scrolledwindow3">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="shadow_type">GTK_SHADOW_IN</property>
-		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		  <child>
-		    <widget class="GtkTreeView" id="wwan_list">
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="headers_visible">False</property>
-		      <property name="rules_hint">True</property>
-		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVButtonBox" id="vbuttonbox4">
-		  <property name="visible">True</property>
-		  <property name="layout_style">GTK_BUTTONBOX_START</property>
-		  <property name="spacing">6</property>
-
-		  <child>
-		    <widget class="GtkButton" id="wwan_add">
-		      <property name="visible">True</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-add</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wwan_edit">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-edit</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="wwan_delete">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-delete</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="tab_expand">False</property>
-	      <property name="tab_fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="wwan_label">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">Mobile Broadband</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="type">tab</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkHBox" id="vpn_child">
-	      <property name="border_width">6</property>
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkScrolledWindow" id="scrolledwindow4">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="shadow_type">GTK_SHADOW_IN</property>
-		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		  <child>
-		    <widget class="GtkTreeView" id="vpn_list">
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="headers_visible">False</property>
-		      <property name="rules_hint">True</property>
-		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVButtonBox" id="vbuttonbox5">
-		  <property name="visible">True</property>
-		  <property name="layout_style">GTK_BUTTONBOX_START</property>
-		  <property name="spacing">6</property>
-
-		  <child>
-		    <widget class="GtkButton" id="vpn_add">
-		      <property name="visible">True</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-add</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="vpn_edit">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-edit</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="vpn_delete">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-delete</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="tab_expand">False</property>
-	      <property name="tab_fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="vpn_label">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">VPN</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="type">tab</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkHBox" id="dsl_child">
-	      <property name="border_width">6</property>
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkScrolledWindow" id="scrolledwindow5">
-		  <property name="visible">True</property>
-		  <property name="can_focus">True</property>
-		  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-		  <property name="shadow_type">GTK_SHADOW_IN</property>
-		  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
-
-		  <child>
-		    <widget class="GtkTreeView" id="dsl_list">
-		      <property name="visible">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="headers_visible">False</property>
-		      <property name="rules_hint">True</property>
-		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
-		      <property name="fixed_height_mode">False</property>
-		      <property name="hover_selection">False</property>
-		      <property name="hover_expand">False</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-
-	      <child>
-		<widget class="GtkVButtonBox" id="vbuttonbox6">
-		  <property name="visible">True</property>
-		  <property name="layout_style">GTK_BUTTONBOX_START</property>
-		  <property name="spacing">6</property>
-
-		  <child>
-		    <widget class="GtkButton" id="dsl_add">
-		      <property name="visible">True</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-add</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="dsl_edit">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-edit</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-
-		  <child>
-		    <widget class="GtkButton" id="dsl_delete">
-		      <property name="visible">True</property>
-		      <property name="sensitive">False</property>
-		      <property name="can_default">True</property>
-		      <property name="can_focus">True</property>
-		      <property name="label">gtk-delete</property>
-		      <property name="use_stock">True</property>
-		      <property name="relief">GTK_RELIEF_NORMAL</property>
-		      <property name="focus_on_click">True</property>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="tab_expand">False</property>
-	      <property name="tab_fill">True</property>
-	    </packing>
-	  </child>
-
-	  <child>
-	    <widget class="GtkLabel" id="dsl_label">
-	      <property name="visible">True</property>
-	      <property name="label" translatable="yes">DSL</property>
-	      <property name="use_underline">False</property>
-	      <property name="use_markup">False</property>
-	      <property name="justify">GTK_JUSTIFY_LEFT</property>
-	      <property name="wrap">False</property>
-	      <property name="selectable">False</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xpad">0</property>
-	      <property name="ypad">0</property>
-	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-	      <property name="width_chars">-1</property>
-	      <property name="single_line_mode">False</property>
-	      <property name="angle">0</property>
-	    </widget>
-	    <packing>
-	      <property name="type">tab</property>
-	    </packing>
-	  </child>
-	</widget>
-	<packing>
-	  <property name="padding">0</property>
-	  <property name="expand">True</property>
-	  <property name="fill">True</property>
-	</packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
+  <widget class="GtkDialog" id="NMConnectionEditor">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Connection Editor</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="spacing">12</property>
+                <child>
+                  <widget class="GtkLabel" id="label40">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Connection _name:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">connection_name</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="connection_name">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="connection_autoconnect">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Connect _automatically</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="connection_system">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">System setting</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkNotebook" id="notebook">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="ok_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="NMConnectionList">
+    <property name="border_width">4</property>
+    <property name="title" translatable="yes">Network Connections</property>
+    <property name="window_position">GTK_WIN_POS_CENTER</property>
+    <property name="default_width">400</property>
+    <property name="default_height">300</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="spacing">4</property>
+        <child>
+          <widget class="GtkNotebook" id="list_notebook">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <child>
+              <widget class="GtkHBox" id="wired_child">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scolledwindow1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="wired_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox2">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="wired_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wired_edit">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wired_delete">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="wired_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Wired</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="wireless_child">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="wireless_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox3">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="wireless_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wireless_edit">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wireless_delete">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="wireless_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Wireless</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="wwan_child">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="wwan_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox4">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="wwan_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wwan_edit">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="wwan_delete">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="wwan_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Mobile Broadband</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="vpn_child">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="vpn_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox5">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="vpn_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="vpn_edit">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="vpn_delete">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkHSeparator" id="hseparator1">
+                        <property name="visible">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="vpn_import">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">_Import</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="vpn_export">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">E_xport</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">5</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="vpn_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">VPN</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">3</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="dsl_child">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow5">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="dsl_list">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_visible">False</property>
+                        <property name="rules_hint">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox6">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="dsl_add">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-add</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="dsl_edit">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-edit</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="dsl_delete">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="can_default">True</property>
+                        <property name="label">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="dsl_label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">DSL</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">4</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="closebutton1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-7</property>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
 </glade-interface>

Modified: trunk/src/connection-editor/nm-connection-list.c
==============================================================================
--- trunk/src/connection-editor/nm-connection-list.c	(original)
+++ trunk/src/connection-editor/nm-connection-list.c	Tue Jun 17 10:46:26 2008
@@ -2,6 +2,7 @@
 /* NetworkManager Connection editor -- Connection editor for NetworkManager
  *
  * Rodrigo Moya <rodrigo gnome-db org>
+ * 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
@@ -17,7 +18,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * (C) Copyright 2004-2005 Red Hat, Inc.
+ * (C) Copyright 2007 - 2008 Red Hat, Inc.
  */
 
 #include <config.h>
@@ -53,12 +54,14 @@
 #include <nm-setting-pppoe.h>
 #include <nm-setting-ppp.h>
 #include <nm-setting-serial.h>
+#include <nm-vpn-plugin-ui-interface.h>
 
 #include "nm-connection-editor.h"
 #include "nm-connection-list.h"
 #include "gconf-helpers.h"
 #include "mobile-wizard.h"
 #include "utils.h"
+#include "vpn-helpers.h"
 
 G_DEFINE_TYPE (NMConnectionList, nm_connection_list, G_TYPE_OBJECT)
 
@@ -77,6 +80,7 @@
 typedef struct {
 	NMConnectionList *list;
 	GtkTreeView *treeview;
+	GtkWidget *button;
 } ActionInfo;
 
 enum {
@@ -569,10 +573,19 @@
 			/* user canceled; do nothing */
 		}
 	} else if (ctype == NM_TYPE_SETTING_VPN) {
-		s_con->id = get_next_available_name (list, _("VPN connection %d"));
-		s_con->type = g_strdup (NM_SETTING_VPN_SETTING_NAME);
+		char *service = NULL;
 
-		type_setting = nm_setting_vpn_new ();
+		service = vpn_ask_connection_type ();
+		if (service) {
+			NMSettingVPN *s_vpn;
+
+			s_con->id = get_next_available_name (list, _("VPN connection %d"));
+			s_con->type = g_strdup (NM_SETTING_VPN_SETTING_NAME);
+
+			type_setting = nm_setting_vpn_new ();
+			s_vpn = NM_SETTING_VPN (type_setting);
+			s_vpn->service_type = service;
+		}		
 	} else if (ctype == NM_TYPE_SETTING_PPPOE) {
 		s_con->id = get_next_available_name (list, _("DSL connection %d"));
 		s_con->type = g_strdup (NM_SETTING_PPPOE_SETTING_NAME);
@@ -853,14 +866,124 @@
 static void
 list_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 {
-	GtkWidget *button = GTK_WIDGET (user_data);
+	ActionInfo *info = (ActionInfo *) user_data;
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 
 	if (gtk_tree_selection_get_selected (selection, &model, &iter))
-		gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
+		gtk_widget_set_sensitive (info->button, TRUE);
 	else
-		gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+		gtk_widget_set_sensitive (info->button, FALSE);
+}
+
+static void
+vpn_list_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
+{
+	ActionInfo *info = (ActionInfo *) user_data;
+	NMVpnPluginUiInterface *plugin;
+	NMExportedConnection *exported;
+	NMConnection *connection = NULL;
+	NMSettingVPN *s_vpn;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	guint32 caps;
+	gboolean supported = FALSE;
+
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+		goto done;
+
+	exported = get_active_connection (info->treeview);
+	if (exported)
+		connection = nm_exported_connection_get_connection (exported);
+	if (!connection)
+		goto done;
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+	if (!s_vpn || !s_vpn->service_type)
+		goto done;
+
+	plugin = vpn_get_plugin_by_service (s_vpn->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;
+	NMExportedConnection *exported;
+	NMConnectionEditor *editor;
+	NMSettingConnection *s_con;
+	NMSettingVPN *s_vpn;
+
+	/* Basic sanity checks of the connection */
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con) {
+		s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+		nm_connection_add_setting (connection, NM_SETTING (s_con));
+	}
+	if (!s_con->id)
+		s_con->id = get_next_available_name (info->list, _("VPN connection %d"));
+	if (!s_con->type || strcmp (s_con->type, NM_SETTING_VPN_SETTING_NAME)) {
+		g_free (s_con->type);
+		s_con->type = g_strdup (NM_SETTING_VPN_SETTING_NAME);
+	}
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+	if (!s_vpn || !s_vpn->service_type || !strlen (s_vpn->service_type)) {
+		GtkWidget *dialog;
+
+		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."));
+		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;
+	}
+
+	exported = nm_exported_connection_new (connection);
+	g_object_unref (connection);
+
+	editor = nm_connection_editor_new (exported);
+	g_signal_connect (G_OBJECT (editor), "done", G_CALLBACK (add_done_cb), info);
+	g_hash_table_insert (info->list->editors, exported, 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
+export_vpn_cb (GtkButton *button, gpointer user_data)
+{
+	ActionInfo *info = (ActionInfo *) user_data;
+	NMExportedConnection *exported;
+	NMConnection *connection = NULL;
+
+	exported = get_active_connection (info->treeview);
+	if (exported)
+		connection = nm_exported_connection_get_connection (exported);
+	if (!connection)
+		return;
+
+	vpn_export (connection);
 }
 
 static void
@@ -990,44 +1113,101 @@
 	return treeview;
 }
 
+static ActionInfo *
+new_action_info (NMConnectionList *list, GtkTreeView *treeview, GtkWidget *button)
+{
+	ActionInfo *info;
+
+	info = g_malloc0 (sizeof (ActionInfo));
+	g_object_weak_ref (G_OBJECT (list), (GWeakNotify) g_free, info);
+
+	info->list = list;
+	info->treeview = treeview;
+	info->button = button;
+	return 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)
+                        const char *prefix,
+                        GtkTreeView *treeview,
+                        gboolean is_vpn)
 {
 	char *name;
 	GtkWidget *button;
 	ActionInfo *info;
 	GtkTreeSelection *selection;
 
-	info = g_new (ActionInfo, 1);
-	info->list = self;
-	info->treeview = treeview;
-
 	selection = gtk_tree_view_get_selection (treeview);
 
-	g_object_weak_ref (G_OBJECT (self), (GWeakNotify) g_free, info);
-
 	/* Add */
 	name = g_strdup_printf ("%s_add", prefix);
 	button = glade_xml_get_widget (self->gui, name);
 	g_free (name);
+	info = new_action_info (self, treeview, NULL);
 	g_signal_connect (button, "clicked", G_CALLBACK (add_connection_cb), info);
+	if (is_vpn) {
+		GHashTable *plugins;
+
+		/* disable the "Add..." button if there aren't any VPN plugins */
+		plugins = vpn_get_plugins (NULL);
+		gtk_widget_set_sensitive (button, (plugins && g_hash_table_size (plugins)));
+	}
 
 	/* Edit */
 	name = g_strdup_printf ("%s_edit", prefix);
 	button = glade_xml_get_widget (self->gui, name);
 	g_free (name);
+	info = new_action_info (self, treeview, button);
 	g_signal_connect (button, "clicked", G_CALLBACK (edit_connection_cb), info);
-	g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed_cb), button);
+	g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed_cb), info);
 	g_signal_connect (treeview, "row-activated", G_CALLBACK (connection_double_clicked_cb), info);
 
 	/* Delete */
 	name = g_strdup_printf ("%s_delete", prefix);
 	button = glade_xml_get_widget (self->gui, name);
 	g_free (name);
+	info = new_action_info (self, treeview, button);
 	g_signal_connect (button, "clicked", G_CALLBACK (delete_connection_cb), info);
-	g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed_cb), button);
+	g_signal_connect (selection, "changed", G_CALLBACK (list_selection_changed_cb), info);
+
+	/* Import */
+	name = g_strdup_printf ("%s_import", prefix);
+	button = glade_xml_get_widget (self->gui, name);
+	g_free (name);
+	if (button) {
+		gboolean import_supported = FALSE;
+
+		info = new_action_info (self, treeview, button);
+		g_signal_connect (button, "clicked", G_CALLBACK (import_vpn_cb), info);
+
+		g_hash_table_foreach (vpn_get_plugins (NULL), check_vpn_import_supported, &import_supported);
+		gtk_widget_set_sensitive (button, import_supported);
+	}
+
+	/* Export */
+	name = g_strdup_printf ("%s_export", prefix);
+	button = glade_xml_get_widget (self->gui, name);
+	g_free (name);
+	if (button) {
+		info = new_action_info (self, treeview, 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
@@ -1035,7 +1215,8 @@
 				GSList *connection_types,
 				GdkPixbuf *pixbuf,
 				const char *prefix,
-				const char *label_text)
+				const char *label_text,
+				gboolean is_vpn)
 {
 	char *name;
 	GtkWidget *child;
@@ -1061,7 +1242,7 @@
 	gtk_notebook_set_tab_label (GTK_NOTEBOOK (glade_xml_get_widget (self->gui, "list_notebook")), child, hbox);
 
 	treeview = add_connection_treeview (self, prefix);
-	add_connection_buttons (self, prefix, treeview);
+	add_connection_buttons (self, prefix, treeview, is_vpn);
 
 	for (iter = connection_types; iter; iter = iter->next)
 		g_hash_table_insert (self->treeviews, g_strdup ((const char *) iter->data), treeview);
@@ -1073,24 +1254,24 @@
 	GSList *types;
 
 	types = g_slist_append (NULL, NM_SETTING_WIRED_SETTING_NAME);
-	add_connection_tab (self, types, self->wired_icon, "wired", _("Wired"));
+	add_connection_tab (self, types, self->wired_icon, "wired", _("Wired"), FALSE);
 	g_slist_free (types);
 
 	types = g_slist_append (NULL, NM_SETTING_WIRELESS_SETTING_NAME);
-	add_connection_tab (self, types, self->wireless_icon, "wireless", _("Wireless"));
+	add_connection_tab (self, types, self->wireless_icon, "wireless", _("Wireless"), FALSE);
 	g_slist_free (types);
 
 	types = g_slist_append (NULL, NM_SETTING_GSM_SETTING_NAME);
 	types = g_slist_append (types, NM_SETTING_CDMA_SETTING_NAME);
-	add_connection_tab (self, types, self->wwan_icon, "wwan", _("Mobile Broadband"));
+	add_connection_tab (self, types, self->wwan_icon, "wwan", _("Mobile Broadband"), FALSE);
 	g_slist_free (types);
 
 	types = g_slist_append (NULL, NM_SETTING_VPN_SETTING_NAME);
-	add_connection_tab (self, types, self->vpn_icon, "vpn", _("VPN"));
+	add_connection_tab (self, types, self->vpn_icon, "vpn", _("VPN"), TRUE);
 	g_slist_free (types);
 
 	types = g_slist_append (NULL, NM_SETTING_PPPOE_SETTING_NAME);
-	add_connection_tab (self, types, self->wired_icon, "dsl", _("DSL"));
+	add_connection_tab (self, types, self->wired_icon, "dsl", _("DSL"), FALSE);
 	g_slist_free (types);
 }
 
@@ -1219,6 +1400,11 @@
 		goto error;
 	g_signal_connect (G_OBJECT (list->dialog), "response", G_CALLBACK (dialog_response_cb), list);
 
+	if (!vpn_get_plugins (&error)) {
+		g_message ("%s: failed to load VPN plugins: %s", __func__, error->message);
+		g_error_free (error);
+	}
+
 	return list;
 
 error:

Added: trunk/src/connection-editor/page-vpn.c
==============================================================================
--- (empty file)
+++ trunk/src/connection-editor/page-vpn.c	Tue Jun 17 10:46:26 2008
@@ -0,0 +1,171 @@
+/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <nm-setting-connection.h>
+#include <nm-setting-vpn.h>
+#include <nm-setting-vpn-properties.h>
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+#include <nm-vpn-plugin-ui-interface.h>
+
+#include "page-vpn.h"
+#include "nm-connection-editor.h"
+#include "vpn-helpers.h"
+
+G_DEFINE_TYPE (CEPageVpn, ce_page_vpn, CE_TYPE_PAGE)
+
+#define CE_PAGE_VPN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_VPN, CEPageVpnPrivate))
+
+typedef struct {
+	NMSettingVPN *setting;
+	NMConnection *connection; /* ugh */
+
+	NMVpnPluginUiWidgetInterface *ui;
+	gboolean valid;
+
+	gboolean disposed;
+} CEPageVpnPrivate;
+
+static void
+vpn_plugin_validity_changed_cb (NMVpnPluginUiInterface *plugin,
+                                gboolean valid,
+                                CEPageVpn *self)
+{
+	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (self);
+
+	priv->valid = valid;
+	ce_page_changed (CE_PAGE (self));
+}
+
+CEPageVpn *
+ce_page_vpn_new (NMConnection *connection)
+{
+	CEPageVpn *self;
+	CEPageVpnPrivate *priv;
+	CEPage *parent;
+	NMSettingVPN *s_vpn;
+	GError *error = NULL;
+	NMVpnPluginUiInterface *plugin;
+
+	self = CE_PAGE_VPN (g_object_new (CE_TYPE_PAGE_VPN, NULL));
+	parent = CE_PAGE (self);
+	priv = CE_PAGE_VPN_GET_PRIVATE (self);
+
+	parent->title = g_strdup (_("VPN"));
+
+	s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+	g_assert (s_vpn);
+	g_assert (s_vpn->service_type);
+
+	priv->setting = NM_SETTING_VPN (nm_setting_duplicate (NM_SETTING (s_vpn)));
+	priv->connection = connection;
+
+	plugin = vpn_get_plugin_by_service (s_vpn->service_type);
+	if (!plugin) {
+		g_warning ("%s: couldn't find VPN plugin for service '%s'!",
+		           __func__, s_vpn->service_type);
+		g_object_unref (self);
+		return NULL;
+	}
+
+	priv->ui = nm_vpn_plugin_ui_interface_ui_factory (plugin, connection, &error);
+	if (!priv->ui) {
+		g_warning ("%s: couldn't create VPN UI for service '%s': %s",
+		           __func__, s_vpn->service_type, error->message);
+		g_error_free (error);
+		g_object_unref (self);
+		return NULL;
+	}
+	g_signal_connect (priv->ui, "validity-changed",
+	                  G_CALLBACK (vpn_plugin_validity_changed_cb), self);
+
+	parent->page = GTK_WIDGET (nm_vpn_plugin_ui_widget_interface_get_widget (priv->ui));
+	if (!parent->page) {
+		g_warning ("%s: Couldn't load vpn page from the plugin.", __func__);
+		g_object_unref (self);
+		return NULL;
+	}
+	g_object_ref_sink (parent->page);
+	gtk_widget_show_all (parent->page);
+
+	return self;
+}
+
+static gboolean
+validate (CEPage *page, GError **error)
+{
+	CEPageVpn *self = CE_PAGE_VPN (page);
+	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (self);
+
+	return priv->valid;
+}
+
+static void
+update_connection (CEPage *page, NMConnection *connection)
+{
+	CEPageVpn *self = CE_PAGE_VPN (page);
+	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (self);
+
+	nm_vpn_plugin_ui_widget_interface_update_connection (priv->ui, connection);
+}
+
+static void
+ce_page_vpn_init (CEPageVpn *self)
+{
+}
+
+static void
+dispose (GObject *object)
+{
+	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (object);
+
+	if (priv->disposed)
+		return;
+
+	priv->disposed = TRUE;
+	g_object_unref (priv->setting);
+
+	if (priv->ui)
+		g_object_unref (priv->ui);
+
+	G_OBJECT_CLASS (ce_page_vpn_parent_class)->dispose (object);
+}
+
+static void
+ce_page_vpn_class_init (CEPageVpnClass *vpn_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (vpn_class);
+	CEPageClass *parent_class = CE_PAGE_CLASS (vpn_class);
+
+	g_type_class_add_private (object_class, sizeof (CEPageVpnPrivate));
+
+	/* virtual methods */
+	object_class->dispose = dispose;
+
+	parent_class->validate = validate;
+	parent_class->update_connection = update_connection;
+}

Added: trunk/src/connection-editor/page-vpn.h
==============================================================================
--- (empty file)
+++ trunk/src/connection-editor/page-vpn.h	Tue Jun 17 10:46:26 2008
@@ -0,0 +1,52 @@
+/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __PAGE_VPN_H__
+#define __PAGE_VPN_H__
+
+#include <nm-connection.h>
+
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+#include "ce-page.h"
+
+#define CE_TYPE_PAGE_VPN            (ce_page_vpn_get_type ())
+#define CE_PAGE_VPN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CE_TYPE_PAGE_VPN, CEPageVpn))
+#define CE_PAGE_VPN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CE_TYPE_PAGE_VPN, CEPageVpnClass))
+#define CE_IS_PAGE_VPN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CE_TYPE_PAGE_VPN))
+#define CE_IS_PAGE_VPN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CE_TYPE_PAGE_VPN))
+#define CE_PAGE_VPN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CE_TYPE_PAGE_VPN, CEPageVpnClass))
+
+typedef struct {
+	CEPage parent;
+} CEPageVpn;
+
+typedef struct {
+	CEPageClass parent;
+} CEPageVpnClass;
+
+GType ce_page_vpn_get_type (void);
+
+CEPageVpn *ce_page_vpn_new (NMConnection *connection);
+
+#endif  /* __PAGE_VPN_H__ */

Added: trunk/src/connection-editor/vpn-helpers.c
==============================================================================
--- (empty file)
+++ trunk/src/connection-editor/vpn-helpers.c	Tue Jun 17 10:46:26 2008
@@ -0,0 +1,526 @@
+/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <nm-connection.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-vpn.h>
+
+#include "vpn-helpers.h"
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+#include "nm-vpn-plugin-ui-interface.h"
+
+#define VPN_NAME_FILES_DIR SYSCONFDIR"/NetworkManager/VPN"
+
+static GHashTable *plugins = NULL;
+
+NMVpnPluginUiInterface *
+vpn_get_plugin_by_service (const char *service)
+{
+	g_return_val_if_fail (service != NULL, NULL);
+
+	return g_hash_table_lookup (plugins, service);
+}
+
+GHashTable *
+vpn_get_plugins (GError **error)
+{
+	GDir *dir;
+	const char *f;
+
+	if (error)
+		g_return_val_if_fail (*error == NULL, NULL);
+
+	if (plugins)
+		return plugins;
+
+	dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL);
+	if (!dir) {
+		g_set_error (error, 0, 0, "Couldn't read VPN .name files directory " VPN_NAME_FILES_DIR ".");
+		return NULL;
+	}
+
+	plugins = g_hash_table_new_full (g_str_hash, g_str_equal,
+	                                 (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
+
+	while ((f = g_dir_read_name (dir))) {
+		char *path = NULL;
+		GKeyFile *keyfile = NULL;
+		char *so_path = NULL;
+		char *service = NULL;
+		GModule *module;
+		NMVpnPluginUiFactory factory = NULL;
+
+		if (!g_str_has_suffix (f, ".name"))
+			continue;
+
+		path = g_strdup_printf ("%s/%s", VPN_NAME_FILES_DIR, f);
+
+		keyfile = g_key_file_new ();
+		if (!g_key_file_load_from_file (keyfile, path, 0, NULL))
+			goto next;
+
+		service = g_key_file_get_string (keyfile, "VPN Connection", "service", NULL);
+		if (!service)
+			goto next;
+
+		so_path = g_key_file_get_string (keyfile,  "GNOME", "properties", NULL);
+		if (!so_path)
+			goto next;
+
+		module = g_module_open (so_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+		if (!module) {
+			g_set_error (error, 0, 0, "Cannot load the VPN plugin which provides the "
+			             "service '%s'.", service);
+			goto next;
+		}
+
+		if (g_module_symbol (module, "nm_vpn_plugin_ui_factory", (gpointer) &factory)) {
+			NMVpnPluginUiInterface *plugin;
+			GError *factory_error = NULL;
+			gboolean success = FALSE;
+
+			plugin = factory (&factory_error);
+			if (plugin) {
+				char *plug_name = NULL, *plug_service = NULL;
+
+				/* Validate plugin properties */
+				g_object_get (G_OBJECT (plugin),
+				              NM_VPN_PLUGIN_UI_INTERFACE_NAME, &plug_name,
+				              NM_VPN_PLUGIN_UI_INTERFACE_SERVICE, &plug_service,
+				              NULL);
+				if (!plug_name || !strlen (plug_name)) {
+					g_set_error (error, 0, 0, "cannot load VPN plugin in '%s': missing plugin name", 
+					             g_module_name (module));
+				} else if (!plug_service || strcmp (plug_service, service)) {
+					g_set_error (error, 0, 0, "cannot load VPN plugin in '%s': invalid service name", 
+					             g_module_name (module));
+				} else {
+					/* Success! */
+					g_object_set_data_full (G_OBJECT (plugin), "gmodule", module,
+					                        (GDestroyNotify) g_module_close);
+					g_hash_table_insert (plugins, g_strdup (service), plugin);
+					success = TRUE;
+				}
+				g_free (plug_name);
+				g_free (plug_service);
+			} else {
+				g_set_error (error, 0, 0, "cannot load VPN plugin in '%s': %s", 
+				             g_module_name (module), g_module_error ());
+			}
+
+			if (!success)
+				g_module_close (module);
+		} else {
+			g_set_error (error, 0, 0, "cannot locate nm_vpn_plugin_ui_factory() in '%s': %s", 
+			             g_module_name (module), g_module_error ());
+			g_module_close (module);
+		}
+
+	next:
+		g_free (service);
+		g_key_file_free (keyfile);
+		g_free (path);
+	}
+	g_dir_close (dir);
+
+	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;
+} ActionInfo;
+
+static void
+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;
+
+	if (response != GTK_RESPONSE_ACCEPT)
+		goto out;
+
+	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+	if (!filename) {
+		g_warning ("%s: didn't get a filename back from the chooser!", __func__);
+		goto out;
+	}
+
+	import_info.filename = filename;
+	import_info.connection = NULL;
+	import_info.error = NULL;
+	g_hash_table_foreach (plugins, try_import, (gpointer) &import_info);
+
+	connection = import_info.connection;
+	if (connection)
+		info->callback (connection, info->user_data);
+	else {
+		GtkWidget *err_dialog;
+		char *basename = g_path_get_basename (filename);
+
+		err_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 (err_dialog),
+		                                 _("The file '%s' could not be read or does not contain recognized VPN connection information\n\nError: %s."),
+		                                 basename, import_info.error ? import_info.error->message : "unknown error");
+		g_free (basename);
+		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);
+		gtk_widget_show_all (err_dialog);
+		gtk_window_present (GTK_WINDOW (err_dialog));
+	}
+
+	if (import_info.error)
+		g_error_free (import_info.error);
+
+out:
+	gtk_widget_hide (dialog);
+	gtk_widget_destroy (dialog);
+	g_free (info);
+}
+
+static void
+destroy_import_chooser (GtkWidget *dialog, gpointer user_data)
+{
+	g_free (user_data);
+	gtk_widget_destroy (dialog);
+}
+
+void
+vpn_import (VpnImportSuccessCallback callback, gpointer user_data)
+{
+	GtkWidget *dialog;
+	ActionInfo *info;
+
+	dialog = gtk_file_chooser_dialog_new (_("Select file to import"),
+	                                      NULL,
+	                                      GTK_FILE_CHOOSER_ACTION_OPEN,
+	                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                                      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+	                                      NULL);
+	info = g_malloc0 (sizeof (ActionInfo));
+	info->callback = callback;
+	info->user_data = user_data;
+
+	g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (destroy_import_chooser), info);
+	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (import_vpn_from_file_cb), info);
+	gtk_widget_show_all (dialog);
+	gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+export_vpn_to_file_cb (GtkWidget *dialog, gint response, gpointer user_data)
+{
+	NMConnection *connection = NM_CONNECTION (user_data);
+	char *filename = NULL;
+	GError *error = NULL;
+	NMVpnPluginUiInterface *plugin;
+	NMSettingConnection *s_con = NULL;
+	NMSettingVPN *s_vpn = NULL;
+	gboolean success = FALSE;
+
+	if (response != GTK_RESPONSE_ACCEPT)
+		goto out;
+
+	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+	if (!filename) {
+		g_set_error (&error, 0, 0, "no filename");
+		goto done;
+	}
+
+	if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+		int replace_response;
+		GtkWidget *replace_dialog;
+		char *basename;
+
+		basename = 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."),
+		                                         basename);
+		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?"), basename);
+		g_free (basename);
+		replace_response = gtk_dialog_run (GTK_DIALOG (replace_dialog));
+		gtk_widget_destroy (replace_dialog);
+		if (replace_response != GTK_RESPONSE_OK)
+			goto out;
+	}
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con || !s_con->id) {
+		g_set_error (&error, 0, 0, "connection setting invalid");
+		goto done;
+	}
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+	if (!s_vpn || !s_vpn->service_type) {
+		g_set_error (&error, 0, 0, "VPN setting invalid");
+		goto done;
+	}
+
+	plugin = vpn_get_plugin_by_service (s_vpn->service_type);
+	if (plugin)
+		success = nm_vpn_plugin_ui_interface_export (plugin, filename, connection, &error);
+
+done:
+	if (!success) {
+		GtkWidget *err_dialog;
+		char *basename = filename ? g_path_get_basename (filename) : g_strdup ("(none)");
+		char *id = s_con ? s_con->id : "(unknown)";
+
+		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)", basename, error ? error->message : "unknown error");
+		g_free (basename);
+		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);
+		gtk_widget_show_all (err_dialog);
+		gtk_window_present (GTK_WINDOW (err_dialog));
+	}
+
+out:
+	if (error)
+		g_error_free (error);
+	g_object_unref (connection);
+
+	gtk_widget_hide (dialog);
+	gtk_widget_destroy (dialog);
+}
+
+void
+vpn_export (NMConnection *connection)
+{
+	GtkWidget *dialog;
+	NMVpnPluginUiInterface *plugin;
+	NMSettingVPN *s_vpn = NULL;
+
+	s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+	if (!s_vpn || !s_vpn->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,
+	                                      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                                      GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+	                                      NULL);
+
+	plugin = vpn_get_plugin_by_service (s_vpn->service_type);
+	if (plugin) {
+		char *suggested = NULL;
+
+		suggested = nm_vpn_plugin_ui_interface_get_suggested_name (plugin, connection);
+		if (suggested) {
+			gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), suggested);
+			g_free (suggested);
+		}
+	}
+
+	g_signal_connect (G_OBJECT (dialog), "close", G_CALLBACK (gtk_widget_destroy), NULL);
+	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (export_vpn_to_file_cb), g_object_ref (connection));
+	gtk_widget_show_all (dialog);
+	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)
+{
+	NMVpnPluginUiInterface *aa = NM_VPN_PLUGIN_UI_INTERFACE (a);
+	NMVpnPluginUiInterface *bb = NM_VPN_PLUGIN_UI_INTERFACE (b);
+	const char *aa_desc = NULL, *bb_desc = NULL;
+
+	g_object_get (aa, NM_VPN_PLUGIN_UI_INTERFACE_NAME, &aa_desc, NULL);
+	g_object_get (bb, NM_VPN_PLUGIN_UI_INTERFACE_NAME, &bb_desc, NULL);
+
+	if (!aa_desc)
+		return -1;
+	if (!bb_desc)
+		return 1;
+
+	return strcmp (aa_desc, bb_desc);
+}
+
+#define COL_PLUGIN_DESC 0
+#define COL_PLUGIN_OBJ  1
+
+static void
+combo_changed_cb (GtkComboBox *combo, gpointer user_data)
+{
+	GtkLabel *label = GTK_LABEL (user_data);
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	NMVpnPluginUiInterface *plugin = NULL;
+	const char *desc = NULL;
+	char *tmp;
+
+	if (!gtk_combo_box_get_active_iter (combo, &iter))
+		goto error;
+
+	model = gtk_combo_box_get_model (combo);
+	if (!model)
+		goto error;
+
+	gtk_tree_model_get (model, &iter, COL_PLUGIN_OBJ, &plugin, -1);
+	if (!plugin)
+		goto error;
+
+	g_object_get (G_OBJECT (plugin), NM_VPN_PLUGIN_UI_INTERFACE_DESC, &desc, NULL);
+	if (!desc)
+		goto error;
+
+	tmp = g_strdup_printf ("<i>%s</i>", desc);
+	gtk_label_set_markup (label, tmp);
+	g_free (tmp);
+	return;
+
+error:
+	gtk_label_set_text (label, "");
+}
+
+char *
+vpn_ask_connection_type (void)
+{
+	GladeXML *xml;
+	GtkWidget *dialog, *combo, *widget;
+	GtkTreeModel *model;
+	GSList *plugin_list = NULL, *iter;
+	gint response;
+	GtkTreeIter tree_iter;
+	char *service_type = NULL;
+
+	if (!plugins || !g_hash_table_size (plugins)) {
+		g_warning ("%s: no VPN plugins could be found!", __func__);
+		return NULL;
+	}
+
+	xml = glade_xml_new (GLADEDIR "/ce-vpn-wizard.glade", "vpn_type_dialog", NULL);
+	if (!xml) {
+		g_warning ("%s: couldn't load VPN wizard glade file '%s'!",
+		           __func__, GLADEDIR "/ce-vpn-wizard.glade");
+		return NULL;
+	}
+
+	dialog = glade_xml_get_widget (xml, "vpn_type_dialog");
+	if (!dialog) {
+		g_warning ("%s: couldn't load VPN wizard dialog!", __func__);
+		g_object_unref (xml);
+		return NULL;
+	}
+
+	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);
+
+	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);
+		const char *desc;
+
+		gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter);
+		g_object_get (plugin, NM_VPN_PLUGIN_UI_INTERFACE_NAME, &desc, NULL);
+		gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter,
+		                    COL_PLUGIN_DESC, desc,
+		                    COL_PLUGIN_OBJ, plugin, -1);
+	}
+
+	combo = glade_xml_get_widget (xml, "vpn_type_combo");
+	widget = glade_xml_get_widget (xml, "vpn_desc_label");
+	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_widget_show_all (dialog);
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	if (response != GTK_RESPONSE_OK)
+		goto out;
+
+	if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &tree_iter)) {
+		NMVpnPluginUiInterface *plugin = NULL;
+
+		gtk_tree_model_get (model, &tree_iter, COL_PLUGIN_OBJ, &plugin, -1);
+		if (plugin)
+			g_object_get (G_OBJECT (plugin), NM_VPN_PLUGIN_UI_INTERFACE_SERVICE, &service_type, NULL);
+	}
+
+out:
+	gtk_widget_destroy (dialog);
+	g_object_unref (xml);
+	if (service_type)
+		return g_strdup (service_type);
+	return NULL;
+}
+

Added: trunk/src/connection-editor/vpn-helpers.h
==============================================================================
--- (empty file)
+++ trunk/src/connection-editor/vpn-helpers.h	Tue Jun 17 10:46:26 2008
@@ -0,0 +1,43 @@
+/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef _VPN_HELPERS_H_
+#define _VPN_HELPERS_H_
+
+#include <glib.h>
+#include <nm-connection.h>
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+#include <nm-vpn-plugin-ui-interface.h>
+
+GHashTable *vpn_get_plugins (GError **error);
+
+NMVpnPluginUiInterface *vpn_get_plugin_by_service (const char *service);
+
+typedef void (*VpnImportSuccessCallback) (NMConnection *connection, gpointer user_data);
+void vpn_import (VpnImportSuccessCallback callback, gpointer user_data);
+
+void vpn_export (NMConnection *connection);
+
+char *vpn_ask_connection_type (void);
+
+#endif  /* _VPN_HELPERS_H_ */



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