From c357c61e35b9a42c062ffa49ad1b7c118dbee22f Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Sun, 12 Jun 2005 14:35:59 +0000 Subject: [PATCH] 2005-06-12 David Zeuthen * gnome/vpn-properties/nm-vpn-ui-interface.h: New file * gnome/vpn-properties/nm-vpn-properties.glade: New file * gnome/vpn-properties/nm-vpn-properties.c: New file * gnome/vpn-properties/Makefile.am: New file * src/vpn-manager/nm-vpn-manager.h: Rework prototypes to take an array of passwords * src/vpn-manager/nm-vpn-manager.c (nm_vpn_manager_activate_vpn_connection): Take an array of passwords instead of just a single one * src/vpn-manager/nm-dbus-vpn.c: (nm_dbus_vpn_get_vpn_connection_properties): Also append service_name here (nm_dbus_vpn_activate_connection): Rework to take an array of passwords * gnome/applet/vpn-password-dialog.h (nmwa_vpn_request_password): Change the interface here to give a list of passwords. Also, don't require username, but do require service * gnome/applet/vpn-password-dialog.c: Look up the VPN .name files for the binary for the auth-dialog and use that instead of putting up a dialog asking for a single password * gnome/applet/vpn-connection.[ch]: Don't remember the user_name, however do remember the service * gnome/applet/main.c (main): Setup i18n * gnome/applet/applet.c (nmwa_update_state): Add a line "VPN connection to '%s'" to the tooltip if we are connected using VPN (nmwa_menu_vpn_item_activate): Check last_attempt_success gconf key to determine whether we the auth-dialog needs to reprompt. Also cope with the fact that the auth-dialog now returns an array of passwords. (nmwa_menu_configure_vpn_item_activate): New handler for "Configure VPN..." menu item (nmwa_menu_add_vpn_menu): Add the "Configure VPN..." menu item (is_vpn_available): New function to determine if we got any NM-compatible VPN software installed (nmwa_menu_add_devices): Use is_vpn_available to add VPN menu items only if we have NM-compatible VPN software installed (nmwa_gconf_vpn_connections_notify_callback): Slightly rework the logic for detecting when VPN connections are removed * gnome/applet/applet-dbus.h: Removed the prototypes for nmwa_dbus_vpn_activate_connection, nmwa_dbus_vpn_deactivate_connection since these are defined elsewhere * gnome/applet/applet-dbus.c (set_vpn_last_attempt_status): New function used to keep track of whether the last attempt succeded (nmwa_dbus_filter): Update last_attempt according to whether the VPN connection could be established or not * gnome/applet/applet-dbus-vpn.h (nmwa_dbus_vpn_deactivate_connection): Change prototype to take an array of passwords, not just a single password * gnome/applet/applet-dbus-vpn.c (nmwa_dbus_vpn_properties_cb): Only update service, not user (nmwa_dbus_vpn_remove_one_vpn_connection): Check that applet-> dbus_active_vpn_name is not NULL before using it (nmwa_dbus_vpn_activate_connection): Send the passwords as a string array instead of assuming a single password * gnome/applet/applet-dbus-info.c: (nmi_dbus_get_vpn_connection_properties): Use the logged in user for user name; don't read from gconf * gnome/applet/Makefile.am: Also export SYSCONFDIR and VPN_NAME_FILES_DIR * gnome/Makefile.am (SUBDIRS): Add vpn-properties * configure.in: Add checks for gmodule-2.0. Generate gnome/vpn-properties/Makefile. Don't generate any Makefile's in vpn-daemons nor vpn-daemons/vpnc. We have separate autotooled projects under vpn-daemons now. See vpn-daemons/vpnc/Changelog for details * vpn-daemons/Makefile.am: Removed * vpn-daemons/README: New file to describe extensions points for VPN software git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@664 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 91 ++ Makefile.am | 2 +- configure.in | 7 +- gnome/Makefile.am | 3 +- gnome/applet/Makefile.am | 89 +- gnome/applet/applet-dbus-info.c | 28 +- gnome/applet/applet-dbus-vpn.c | 34 +- gnome/applet/applet-dbus-vpn.h | 2 +- gnome/applet/applet-dbus.c | 24 +- gnome/applet/applet-dbus.h | 3 - gnome/applet/applet.c | 119 ++- gnome/applet/main.c | 6 + gnome/applet/vpn-connection.c | 19 +- gnome/applet/vpn-connection.h | 4 +- gnome/applet/vpn-password-dialog.c | 248 +++-- gnome/applet/vpn-password-dialog.h | 5 +- gnome/vpn-properties/Makefile.am | 46 + gnome/vpn-properties/nm-vpn-properties.c | 968 +++++++++++++++++++ gnome/vpn-properties/nm-vpn-properties.glade | 339 +++++++ gnome/vpn-properties/nm-vpn-ui-interface.h | 71 ++ po/ChangeLog | 5 + po/POTFILES.in | 2 + src/vpn-manager/nm-dbus-vpn.c | 23 +- src/vpn-manager/nm-vpn-manager.c | 12 +- src/vpn-manager/nm-vpn-manager.h | 2 +- vpn-daemons/Makefile.am | 2 - vpn-daemons/README | 2 + 27 files changed, 1951 insertions(+), 205 deletions(-) create mode 100644 gnome/vpn-properties/Makefile.am create mode 100644 gnome/vpn-properties/nm-vpn-properties.c create mode 100644 gnome/vpn-properties/nm-vpn-properties.glade create mode 100644 gnome/vpn-properties/nm-vpn-ui-interface.h delete mode 100644 vpn-daemons/Makefile.am create mode 100644 vpn-daemons/README diff --git a/ChangeLog b/ChangeLog index 5cb322846..c87c4d190 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,94 @@ +2005-06-12 David Zeuthen + + * gnome/vpn-properties/nm-vpn-ui-interface.h: New file + + * gnome/vpn-properties/nm-vpn-properties.glade: New file + + * gnome/vpn-properties/nm-vpn-properties.c: New file + + * gnome/vpn-properties/Makefile.am: New file + + * src/vpn-manager/nm-vpn-manager.h: Rework prototypes to take an + array of passwords + + * src/vpn-manager/nm-vpn-manager.c + (nm_vpn_manager_activate_vpn_connection): Take an array of passwords + instead of just a single one + + * src/vpn-manager/nm-dbus-vpn.c: + (nm_dbus_vpn_get_vpn_connection_properties): Also append service_name + here + (nm_dbus_vpn_activate_connection): Rework to take an array of passwords + + * gnome/applet/vpn-password-dialog.h (nmwa_vpn_request_password): + Change the interface here to give a list of passwords. Also, don't + require username, but do require service + + * gnome/applet/vpn-password-dialog.c: Look up the VPN .name files for + the binary for the auth-dialog and use that instead of putting up a + dialog asking for a single password + + * gnome/applet/vpn-connection.[ch]: Don't remember the user_name, + however do remember the service + + * gnome/applet/main.c (main): Setup i18n + + * gnome/applet/applet.c (nmwa_update_state): Add a line "VPN + connection to '%s'" to the tooltip if we are connected using VPN + (nmwa_menu_vpn_item_activate): Check last_attempt_success gconf + key to determine whether we the auth-dialog needs to + reprompt. Also cope with the fact that the auth-dialog now returns + an array of passwords. + (nmwa_menu_configure_vpn_item_activate): New handler for + "Configure VPN..." menu item + (nmwa_menu_add_vpn_menu): Add the "Configure VPN..." menu item + (is_vpn_available): New function to determine if we got any + NM-compatible VPN software installed + (nmwa_menu_add_devices): Use is_vpn_available to add VPN menu + items only if we have NM-compatible VPN software installed + (nmwa_gconf_vpn_connections_notify_callback): Slightly rework the + logic for detecting when VPN connections are removed + + * gnome/applet/applet-dbus.h: Removed the prototypes for + nmwa_dbus_vpn_activate_connection, nmwa_dbus_vpn_deactivate_connection + since these are defined elsewhere + + * gnome/applet/applet-dbus.c (set_vpn_last_attempt_status): New + function used to keep track of whether the last attempt succeded + (nmwa_dbus_filter): Update last_attempt according to whether the + VPN connection could be established or not + + * gnome/applet/applet-dbus-vpn.h (nmwa_dbus_vpn_deactivate_connection): + Change prototype to take an array of passwords, not just a single + password + + * gnome/applet/applet-dbus-vpn.c (nmwa_dbus_vpn_properties_cb): Only + update service, not user + (nmwa_dbus_vpn_remove_one_vpn_connection): Check that applet-> + dbus_active_vpn_name is not NULL before using it + (nmwa_dbus_vpn_activate_connection): Send the passwords as a + string array instead of assuming a single password + + * gnome/applet/applet-dbus-info.c: + (nmi_dbus_get_vpn_connection_properties): Use the logged in user for + user name; don't read from gconf + + * gnome/applet/Makefile.am: Also export SYSCONFDIR and + VPN_NAME_FILES_DIR + + * gnome/Makefile.am (SUBDIRS): Add vpn-properties + + * configure.in: Add checks for gmodule-2.0. + Generate gnome/vpn-properties/Makefile. Don't generate any Makefile's + in vpn-daemons nor vpn-daemons/vpnc. We have separate autotooled + projects under vpn-daemons now. See vpn-daemons/vpnc/Changelog + for details + + * vpn-daemons/Makefile.am: Removed + + * vpn-daemons/README: New file to describe extensions points for VPN + software + 2005-06-10 Dan Williams * src/backends/NetworkManagerRedHat.c diff --git a/Makefile.am b/Makefile.am index 98fb94067..99e0252fe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = utils src dispatcher-daemon gnome vpn-daemons initscript test po +SUBDIRS = utils src dispatcher-daemon gnome initscript test po EXTRA_DIST = CONTRIBUTING NetworkManager.pc.in NetworkManager.h diff --git a/configure.in b/configure.in index 343ffab95..73f0b26a9 100644 --- a/configure.in +++ b/configure.in @@ -115,6 +115,10 @@ PKG_CHECK_MODULES(GTHREAD, gthread-2.0) AC_SUBST(GTHREAD_CFLAGS) AC_SUBST(GTHREAD_LIBS) +PKG_CHECK_MODULES(GMODULE, gmodule-2.0) +AC_SUBST(GMODULE_CFLAGS) +AC_SUBST(GMODULE_LIBS) + PKG_CHECK_MODULES(HAL, hal >= 0.2.91) AC_SUBST(HAL_CFLAGS) AC_SUBST(HAL_LIBS) @@ -277,6 +281,7 @@ gnome/applet/Makefile gnome/applet/icons/Makefile gnome/libnm_glib/libnm_glib.pc gnome/libnm_glib/Makefile +gnome/vpn-properties/Makefile test/Makefile initscript/Makefile initscript/RedHat/Makefile @@ -285,8 +290,6 @@ initscript/Debian/Makefile initscript/Slackware/Makefile po/Makefile.in NetworkManager.pc -vpn-daemons/Makefile -vpn-daemons/vpnc/Makefile ]) echo diff --git a/gnome/Makefile.am b/gnome/Makefile.am index 123897358..285bd2484 100644 --- a/gnome/Makefile.am +++ b/gnome/Makefile.am @@ -1 +1,2 @@ -SUBDIRS = applet libnm_glib +SUBDIRS = applet libnm_glib vpn-properties + diff --git a/gnome/applet/Makefile.am b/gnome/applet/Makefile.am index 4220f1cc7..c41fe9bf4 100644 --- a/gnome/applet/Makefile.am +++ b/gnome/applet/Makefile.am @@ -6,59 +6,62 @@ INCLUDES = -I${top_srcdir} -I${top_srcdir}/utils libexec_PROGRAMS = nm-applet -nm_applet_CPPFLAGS = \ - $(DBUS_CFLAGS) \ - $(GTHREAD_CFLAGS) \ - $(HAL_CFLAGS) \ - $(DBUS_GLIB_CFLAGS) \ - $(GLADE_CFLAGS) \ - $(GTK_CFLAGS) \ - $(GCONF_CFLAGS) \ - $(LIBGNOMEUI_CFLAGS) \ - $(PANEL_APPLET_CFLAGS) \ - $(GNOMEKEYRING_CFLAGS) \ - -DICONDIR=\""$(datadir)/pixmaps"\" \ - -DGLADEDIR=\""$(gladedir)"\" \ - -DDBUS_API_SUBJECT_TO_CHANGE \ - -DG_DISABLE_DEPRECATED \ - -DGDK_DISABLE_DEPRECATED \ - -DGNOME_DISABLE_DEPRECATED \ - -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ - -DVERSION=\"$(VERSION)\" \ +nm_applet_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + $(HAL_CFLAGS) \ + $(DBUS_GLIB_CFLAGS) \ + $(GLADE_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GCONF_CFLAGS) \ + $(LIBGNOMEUI_CFLAGS) \ + $(PANEL_APPLET_CFLAGS) \ + $(GNOMEKEYRING_CFLAGS) \ + -DICONDIR=\""$(datadir)/pixmaps"\" \ + -DGLADEDIR=\""$(gladedir)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DVPN_NAME_FILES_DIR=\""$(sysconfdir)/NetworkManager/VPN"\" \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED \ + -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DVERSION=\"$(VERSION)\" \ $(NULL) -nm_applet_SOURCES = \ - main.c \ - applet.c \ - applet.h \ - applet-dbus.c \ - applet-dbus.h \ +nm_applet_SOURCES = \ + main.c \ + applet.c \ + applet.h \ + applet-dbus.c \ + applet-dbus.h \ applet-dbus-devices.c \ applet-dbus-devices.h \ - applet-dbus-vpn.c \ - applet-dbus-vpn.h \ - applet-dbus-info.c \ - applet-dbus-info.h \ - wireless-network.c \ - wireless-network.h \ - nm-device.c \ - nm-device.h \ + applet-dbus-vpn.c \ + applet-dbus-vpn.h \ + applet-dbus-info.c \ + applet-dbus-info.h \ + wireless-network.c \ + wireless-network.h \ + nm-device.c \ + nm-device.h \ other-network-dialog.c \ other-network-dialog.h \ - passphrase-dialog.c \ - passphrase-dialog.h \ - menu-items.c \ - menu-items.h \ - gtkcellview.c \ - gtkcellview.h \ + passphrase-dialog.c \ + passphrase-dialog.h \ + menu-items.c \ + menu-items.h \ + gtkcellview.c \ + gtkcellview.h \ gtkcellrendererprogress.c \ gtkcellrendererprogress.h \ - eggtrayicon.c \ - eggtrayicon.h \ + eggtrayicon.c \ + eggtrayicon.h \ vpn-password-dialog.c \ vpn-password-dialog.h \ - vpn-connection.c \ - vpn-connection.h \ + vpn-connection.c \ + vpn-connection.h \ $(NULL) nm_applet_LDADD = \ diff --git a/gnome/applet/applet-dbus-info.c b/gnome/applet/applet-dbus-info.c index 42c834e18..aed1c881c 100644 --- a/gnome/applet/applet-dbus-info.c +++ b/gnome/applet/applet-dbus-info.c @@ -494,6 +494,8 @@ static DBusMessage *nmi_dbus_get_vpn_connections (NMWirelessApplet *applet, DBus dbus_error_init (&error); + /*g_debug ("entering nmi_dbus_get_vpn_connections");*/ + /* List all VPN connections that gconf knows about */ element = dir_list = gconf_client_all_dirs (applet->gconf_client, GCONF_PATH_VPN_CONNECTIONS, NULL); if (!dir_list) @@ -524,10 +526,12 @@ static DBusMessage *nmi_dbus_get_vpn_connections (NMWirelessApplet *applet, DBus const gchar *essid; essid = gconf_value_get_string (value); dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &essid); + /*g_debug ("vpnid = '%s'", essid);*/ value_added = TRUE; gconf_value_free (value); } + g_free (element->data); element = element->next; } @@ -563,7 +567,7 @@ static DBusMessage *nmi_dbus_get_vpn_connection_properties (NMWirelessApplet *ap char *escaped_name; char *name = NULL; char *service_name = NULL; - char *user_name = NULL; + const char *user_name = NULL; g_return_val_if_fail (applet != NULL, NULL); g_return_val_if_fail (message != NULL, NULL); @@ -579,12 +583,15 @@ static DBusMessage *nmi_dbus_get_vpn_connection_properties (NMWirelessApplet *ap escaped_name = gconf_escape_key (vpn_connection, strlen (vpn_connection)); + /*g_debug ("entering nmi_dbus_get_vpn_connection_properties for '%s'", escaped_name);*/ + /* User-visible name of connection */ gconf_key = g_strdup_printf ("%s/%s/name", GCONF_PATH_VPN_CONNECTIONS, escaped_name); if ((value = gconf_client_get (applet->gconf_client, gconf_key, NULL))) { name = g_strdup (gconf_value_get_string (value)); gconf_value_free (value); + /*g_debug ("name '%s'", name);*/ } g_free (gconf_key); @@ -594,32 +601,24 @@ static DBusMessage *nmi_dbus_get_vpn_connection_properties (NMWirelessApplet *ap { service_name = g_strdup (gconf_value_get_string (value)); gconf_value_free (value); + /*g_debug ("service '%s'", service_name);*/ } g_free (gconf_key); - /* User name of connection */ - gconf_key = g_strdup_printf ("%s/%s/user_name", GCONF_PATH_VPN_CONNECTIONS, escaped_name); - if ((value = gconf_client_get (applet->gconf_client, gconf_key, NULL))) - { - user_name = g_strdup (gconf_value_get_string (value)); - gconf_value_free (value); - } - g_free (gconf_key); + /* User name of connection - use the logged in user */ + user_name = g_get_user_name (); if (!name) { reply = nmwa_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", "NetworkManagerInfo::getVPNConnectionProperties could not access the name for connection '%s'", vpn_connection); + /*g_warning ("BadVPNConnectionData for '%s'", escaped_name);*/ } else if (!service_name) { reply = nmwa_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", "NetworkManagerInfo::getVPNConnectionProperties could not access the service name for connection '%s'", vpn_connection); - } - else if (!user_name) - { - reply = nmwa_dbus_create_error_message (message, NMI_DBUS_INTERFACE, "BadVPNConnectionData", - "NetworkManagerInfo::getVPNConnectionProperties could not access the user name for connection '%s'", vpn_connection); + /*g_warning ("BadVPNConnectionData for '%s'", escaped_name);*/ } else { @@ -632,7 +631,6 @@ static DBusMessage *nmi_dbus_get_vpn_connection_properties (NMWirelessApplet *ap dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &user_name); } - g_free (user_name); g_free (service_name); g_free (name); g_free (escaped_name); diff --git a/gnome/applet/applet-dbus-vpn.c b/gnome/applet/applet-dbus-vpn.c index dbf19069a..297d8d711 100644 --- a/gnome/applet/applet-dbus-vpn.c +++ b/gnome/applet/applet-dbus-vpn.c @@ -147,7 +147,8 @@ void nmwa_dbus_vpn_properties_cb (DBusPendingCall *pcall, void *user_data) VpnPropsCBData * cb_data = user_data; NMWirelessApplet * applet; const char * name; - const char * user_name; + const char * user_name; + const char * service; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); @@ -181,17 +182,19 @@ void nmwa_dbus_vpn_properties_cb (DBusPendingCall *pcall, void *user_data) goto out; } - if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_INVALID)) + if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID)) { VPNConnection * vpn; - /* If its already there, update the user_name, otherwise add it to the list */ + /* If its already there, update the service, otherwise add it to the list */ if ((vpn = nmwa_vpn_connection_find_by_name (applet->dbus_vpn_connections, name))) - nmwa_vpn_connection_set_user_name (vpn, user_name); + { + nmwa_vpn_connection_set_service (vpn, service); + } else { vpn = nmwa_vpn_connection_new (name); - nmwa_vpn_connection_set_user_name (vpn, user_name); + nmwa_vpn_connection_set_service (vpn, service); applet->dbus_vpn_connections = g_slist_append (applet->dbus_vpn_connections, vpn); } } @@ -333,7 +336,8 @@ void nmwa_dbus_vpn_remove_one_vpn_connection (NMWirelessApplet *applet, const ch if ((vpn = nmwa_vpn_connection_find_by_name (applet->dbus_vpn_connections, vpn_name))) { applet->dbus_vpn_connections = g_slist_remove (applet->dbus_vpn_connections, vpn); - if (!strcmp (applet->dbus_active_vpn_name, nmwa_vpn_connection_get_name (vpn))) + if (applet->dbus_active_vpn_name != NULL && + !strcmp (applet->dbus_active_vpn_name, nmwa_vpn_connection_get_name (vpn))) { g_free (applet->dbus_active_vpn_name); applet->dbus_active_vpn_name = NULL; @@ -461,19 +465,29 @@ static void nmwa_free_dbus_vpn_connections (NMWirelessApplet *applet) * Tell NetworkManager to activate a particular VPN connection. * */ -void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, const char *password) +void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, GSList *passwords) { DBusMessage *message; + DBusMessageIter iter; + DBusMessageIter iter_array; g_return_if_fail (connection != NULL); g_return_if_fail (name != NULL); - g_return_if_fail (password != NULL); + g_return_if_fail (passwords != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH_VPN, NM_DBUS_INTERFACE_VPN, "activateVPNConnection"))) { - nm_info ("Activating VPN connection '%s'.\n", name); + GSList *i; - dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &password, DBUS_TYPE_INVALID); + nm_info ("Activating VPN connection '%s'.\n", name); + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &name); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &iter_array); + + for (i = passwords; i != NULL; i = g_slist_next (i)) { + dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &(i->data)); + } + dbus_message_iter_close_container (&iter, &iter_array); dbus_connection_send (connection, message, NULL); } else diff --git a/gnome/applet/applet-dbus-vpn.h b/gnome/applet/applet-dbus-vpn.h index 30e4cfe21..b12efa103 100644 --- a/gnome/applet/applet-dbus-vpn.h +++ b/gnome/applet/applet-dbus-vpn.h @@ -32,7 +32,7 @@ void nmwa_dbus_vpn_update_vpn_connections (NMWirelessApplet *applet); void nmwa_dbus_vpn_remove_one_vpn_connection (NMWirelessApplet *applet, const char *vpn_name); void nmwa_dbus_vpn_get_active_vpn_connection (NMWirelessApplet *applet); -void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, const char *password); +void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, GSList *passwords); void nmwa_dbus_vpn_deactivate_connection (DBusConnection *connection); diff --git a/gnome/applet/applet-dbus.c b/gnome/applet/applet-dbus.c index 9cf00a8f0..42bf68018 100644 --- a/gnome/applet/applet-dbus.c +++ b/gnome/applet/applet-dbus.c @@ -395,6 +395,20 @@ int nmwa_dbus_call_method_string_array (DBusConnection *con, const char *path, c } +static void +set_vpn_last_attempt_status (NMWirelessApplet *applet, const char *vpn_name, gboolean last_attempt_success) +{ + char *gconf_key; + char *escaped_name; + + escaped_name = gconf_escape_key (vpn_name, strlen (vpn_name)); + + gconf_key = g_strdup_printf ("%s/%s/last_attempt_success", GCONF_PATH_VPN_CONNECTIONS, escaped_name); + gconf_client_set_bool (applet->gconf_client, gconf_key, last_attempt_success, NULL); + + g_free (gconf_key); + g_free (escaped_name); +} /* * nmwa_dbus_filter @@ -553,16 +567,22 @@ static DBusHandlerResult nmwa_dbus_filter (DBusConnection *connection, DBusMessa char *vpn_name; char *error_msg; - if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) { nmwa_schedule_vpn_failure_dialog (applet, member, vpn_name, error_msg); + /* clear the 'last_attempt_success' key in gconf so we prompt for password next time */ + set_vpn_last_attempt_status (applet, vpn_name, FALSE); + } } else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_LOGIN_BANNER)) { char *vpn_name; char *banner; - if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) + if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) { nmwa_schedule_vpn_login_banner_dialog (applet, vpn_name, banner); + /* set the 'last_attempt_success' key in gconf so we DON'T prompt for password next time */ + set_vpn_last_attempt_status (applet, vpn_name, TRUE); + } } else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceActivationFailed")) { diff --git a/gnome/applet/applet-dbus.h b/gnome/applet/applet-dbus.h index bda9b39dc..92356e22d 100644 --- a/gnome/applet/applet-dbus.h +++ b/gnome/applet/applet-dbus.h @@ -60,7 +60,4 @@ void nmwa_dbus_enable_wireless (NMWirelessApplet *applet, gboolean enabled); void nmwa_free_gui_data_model (NMWirelessApplet *applet); void nmwa_free_dbus_data_model (NMWirelessApplet *applet); -void nmwa_dbus_vpn_activate_connection (DBusConnection *connection, const char *name, const char *password); -void nmwa_dbus_vpn_deactivate_connection (DBusConnection *connection); - #endif diff --git a/gnome/applet/applet.c b/gnome/applet/applet.c index c6de48ee2..3e8fd73c8 100644 --- a/gnome/applet/applet.c +++ b/gnome/applet/applet.c @@ -42,8 +42,8 @@ #include #include -#include #include +#include #if !GTK_CHECK_VERSION(2,6,0) #include @@ -62,6 +62,7 @@ #include "menu-items.h" #include "vpn-password-dialog.h" #include "vpn-connection.h" +#include "nm-utils.h" /* Compat for GTK 2.4 and lower... */ #if (GTK_MAJOR_VERSION <= 2 && GTK_MINOR_VERSION < 6) @@ -899,6 +900,18 @@ done: if (!applet->tooltips) applet->tooltips = gtk_tooltips_new (); + + if (applet->gui_active_vpn != NULL) { + char *newtip; + char *vpntip; + + vpntip = g_strdup_printf (_("VPN connection to '%s'"), nmwa_vpn_connection_get_name (applet->gui_active_vpn)); + newtip = g_strconcat (tip, "\n", vpntip, NULL); + g_free (vpntip); + g_free (tip); + tip = newtip; + } + gtk_tooltips_set_tip (applet->tooltips, applet->event_box, tip, NULL); g_free (tip); @@ -1106,24 +1119,59 @@ static void nmwa_menu_vpn_item_activate (GtkMenuItem *item, gpointer user_data) { VPNConnection *vpn = (VPNConnection *)tag; const char *name = nmwa_vpn_connection_get_name (vpn); - char *password = NULL; + GSList *passwords; if (vpn != applet->gui_active_vpn) { - if ((password = nmwa_vpn_request_password (applet, name, nmwa_vpn_connection_get_user_name (vpn), FALSE))) + char *gconf_key; + char *escaped_name; + gboolean last_attempt_success; + gboolean reprompt; + + escaped_name = gconf_escape_key (name, strlen (name)); + gconf_key = g_strdup_printf ("%s/%s/last_attempt_success", GCONF_PATH_VPN_CONNECTIONS, escaped_name); + last_attempt_success = gconf_client_get_bool (applet->gconf_client, gconf_key, NULL); + g_free (gconf_key); + g_free (escaped_name); + + reprompt = ! last_attempt_success; /* it's obvious, but.. */ + + if ((passwords = nmwa_vpn_request_password (applet, + name, + nmwa_vpn_connection_get_service (vpn), + reprompt)) != NULL) { - nmwa_dbus_vpn_activate_connection (applet->connection, name, password); - g_free (password); + nmwa_dbus_vpn_activate_connection (applet->connection, name, passwords); + + g_slist_foreach (passwords, (GFunc)g_free, NULL); + g_slist_free (passwords); } } } } +/* + * nmwa_menu_configure_vpn_item_activate + * + * Signal function called when user clicks "Configure VPN..." + * + */ +static void nmwa_menu_configure_vpn_item_activate (GtkMenuItem *item, gpointer user_data) +{ + NMWirelessApplet *applet = (NMWirelessApplet *)user_data; + char *argv[2] = {BINDIR "/nm-vpn-properties", NULL}; + + g_return_if_fail (item != NULL); + g_return_if_fail (applet != NULL); + + g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL); +} + /* * nmwa_menu_disconnect_vpn_item_activate * - * Signal function called when user clicks on a VPN menu item + * Signal function called when user clicks "Disconnect VPN..." * */ static void nmwa_menu_disconnect_vpn_item_activate (GtkMenuItem *item, gpointer user_data) @@ -1437,6 +1485,10 @@ static void nmwa_menu_add_vpn_menu (GtkWidget *menu, NMWirelessApplet *applet) other_item = GTK_MENU_ITEM (gtk_separator_menu_item_new ()); gtk_menu_shell_append (GTK_MENU_SHELL (vpn_menu), GTK_WIDGET (other_item)); + other_item = GTK_MENU_ITEM (gtk_menu_item_new_with_label (_("Configure VPN..."))); + g_signal_connect (G_OBJECT (other_item), "activate", G_CALLBACK (nmwa_menu_configure_vpn_item_activate), applet); + gtk_menu_shell_append (GTK_MENU_SHELL (vpn_menu), GTK_WIDGET (other_item)); + other_item = GTK_MENU_ITEM (gtk_menu_item_new_with_label (_("Disconnect VPN..."))); g_signal_connect (G_OBJECT (other_item), "activate", G_CALLBACK (nmwa_menu_disconnect_vpn_item_activate), applet); if (!applet->gui_active_vpn) @@ -1450,6 +1502,27 @@ static void nmwa_menu_add_vpn_menu (GtkWidget *menu, NMWirelessApplet *applet) } +/** Returns TRUE if, and only if, we have VPN support installed + * + * Algorithm: just check whether any .name files exist in + * /etc/NetworkManager/VPN + */ +static gboolean is_vpn_available (void) +{ + GDir *dir; + gboolean result; + + result = FALSE; + if ((dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL)) != NULL) { + const char *f; + if (g_dir_read_name (dir) != NULL) + result = TRUE; + g_dir_close (dir); + } + + return result; +} + /* * nmwa_menu_add_devices * @@ -1521,8 +1594,10 @@ static void nmwa_menu_add_devices (GtkWidget *menu, NMWirelessApplet *applet) } } - nmwa_menu_add_separator_item (menu); - nmwa_menu_add_vpn_menu (menu, applet); + if (is_vpn_available ()) { + nmwa_menu_add_separator_item (menu); + nmwa_menu_add_vpn_menu (menu, applet); + } if (n_wireless_interfaces > 0) { @@ -1966,6 +2041,8 @@ static void nmwa_gconf_vpn_connections_notify_callback (GConfClient *client, gui NMWirelessApplet * applet = (NMWirelessApplet *)user_data; const char * key = NULL; + /*g_debug ("Entering nmwa_gconf_vpn_connections_notify_callback, key='%s'", gconf_entry_get_key (entry));*/ + g_return_if_fail (client != NULL); g_return_if_fail (entry != NULL); g_return_if_fail (applet != NULL); @@ -1976,21 +2053,37 @@ static void nmwa_gconf_vpn_connections_notify_callback (GConfClient *client, gui if (strncmp (GCONF_PATH_VPN_CONNECTIONS"/", key, path_len) == 0) { - char *name = g_strdup ((key + path_len)); - char *slash_pos; - char *unescaped_name; + char *name = g_strdup ((key + path_len)); + char *slash_pos; + char *unescaped_name; + char *name_path; + GConfValue *value; /* If its a key under the the VPN name, zero out the slash so we * are left with only the VPN name. */ - unescaped_name = gconf_unescape_key (name, strlen (name)); - if ((slash_pos = strchr (unescaped_name, '/'))) + if ((slash_pos = strchr (name, '/'))) *slash_pos = '\0'; + unescaped_name = gconf_unescape_key (name, strlen (name)); + + /* Check here if the name entry is gone so we can remove the conn from the UI */ + name_path = g_strdup_printf ("%s/%s/name", GCONF_PATH_VPN_CONNECTIONS, name); + gconf_client_clear_cache (client); + value = gconf_client_get (client, name_path, NULL); + if (value == NULL) { + /*g_debug ("removing '%s' from UI", name_path);*/ + nmwa_dbus_vpn_remove_one_vpn_connection (applet, unescaped_name); + } else { + gconf_value_free (value); + } + g_free (name_path); nmi_dbus_signal_update_vpn_connection (applet->connection, unescaped_name); + g_free (unescaped_name); g_free (name); } + } } diff --git a/gnome/applet/main.c b/gnome/applet/main.c index fb29e3797..ec4a68988 100644 --- a/gnome/applet/main.c +++ b/gnome/applet/main.c @@ -27,6 +27,8 @@ #include #include +#include + #include "applet.h" static void session_die (GnomeClient *client, gpointer client_data) @@ -55,6 +57,10 @@ int main (int argc, char *argv[]) g_signal_connect (client, "save_yourself", G_CALLBACK (session_save), NULL); g_signal_connect (client, "die", G_CALLBACK (session_die), NULL); + bindtextdomain (GETTEXT_PACKAGE, NULL); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + nmwa = nmwa_new (); gtk_widget_show_all (GTK_WIDGET (nmwa)); diff --git a/gnome/applet/vpn-connection.c b/gnome/applet/vpn-connection.c index 3ce47fec4..625cdfe84 100644 --- a/gnome/applet/vpn-connection.c +++ b/gnome/applet/vpn-connection.c @@ -27,7 +27,7 @@ struct VPNConnection { int refcount; char *name; - char *user_name; + char *service; }; @@ -54,7 +54,7 @@ VPNConnection *nmwa_vpn_connection_copy (VPNConnection *src_vpn) dst_vpn = g_malloc0 (sizeof (VPNConnection)); dst_vpn->refcount = 1; dst_vpn->name = g_strdup (src_vpn->name); - dst_vpn->user_name = src_vpn->user_name ? g_strdup (src_vpn->user_name) : NULL; + dst_vpn->service = src_vpn->service ? g_strdup (src_vpn->service) : NULL; return dst_vpn; } @@ -76,7 +76,7 @@ void nmwa_vpn_connection_unref (VPNConnection *vpn) if (vpn->refcount <= 0) { g_free (vpn->name); - g_free (vpn->user_name); + g_free (vpn->service); memset (vpn, 0, sizeof (VPNConnection)); g_free (vpn); } @@ -90,22 +90,21 @@ const char *nmwa_vpn_connection_get_name (VPNConnection *vpn) return vpn->name; } - -const char *nmwa_vpn_connection_get_user_name (VPNConnection *vpn) +const char *nmwa_vpn_connection_get_service (VPNConnection *vpn) { g_return_val_if_fail (vpn != NULL, NULL); - return vpn->user_name; + return vpn->service; } -void nmwa_vpn_connection_set_user_name (VPNConnection *vpn, const char *user_name) +void nmwa_vpn_connection_set_service (VPNConnection *vpn, const char *service) { g_return_if_fail (vpn != NULL); - g_return_if_fail (user_name != NULL); + g_return_if_fail (service != NULL); - g_free (vpn->user_name); - vpn->user_name = g_strdup (user_name); + g_free (vpn->service); + vpn->service = g_strdup (service); } diff --git a/gnome/applet/vpn-connection.h b/gnome/applet/vpn-connection.h index 862d0d348..347223f9c 100644 --- a/gnome/applet/vpn-connection.h +++ b/gnome/applet/vpn-connection.h @@ -31,8 +31,8 @@ void nmwa_vpn_connection_unref (VPNConnection *vpn); const char * nmwa_vpn_connection_get_name (VPNConnection *vpn); -const char * nmwa_vpn_connection_get_user_name (VPNConnection *vpn); -void nmwa_vpn_connection_set_user_name (VPNConnection *vpn, const char *user_name); +const char * nmwa_vpn_connection_get_service (VPNConnection *vpn); +void nmwa_vpn_connection_set_service (VPNConnection *vpn, const char *service); VPNConnection * nmwa_vpn_connection_find_by_name (GSList *list, const char *name); diff --git a/gnome/applet/vpn-password-dialog.c b/gnome/applet/vpn-password-dialog.c index ea26d4655..b9279519d 100644 --- a/gnome/applet/vpn-password-dialog.c +++ b/gnome/applet/vpn-password-dialog.c @@ -29,106 +29,182 @@ #include #include #include -#include -#include - -#ifndef _ -#define _(x) dgettext (GETTEXT_PACKAGE, x) -#define N_(x) x -#endif +#include #include "applet.h" #include "vpn-password-dialog.h" #include "nm-utils.h" -static gboolean lookup_pass (const char *vpn, const char *username, char **password) +static void +child_finished_cb (GPid pid, gint status, gpointer userdata) { - GList *result; + int *child_status = (gboolean *) userdata; - if (gnome_keyring_find_network_password_sync (username, - NULL, - vpn, - NULL, - "vpn", - NULL, - 0, - &result) != GNOME_KEYRING_RESULT_OK) - return FALSE; - - if (result) - { - GnomeKeyringNetworkPasswordData *data = result->data; - *password = g_strdup (data->password); - gnome_keyring_network_password_list_free (result); - return TRUE; - } - return FALSE; + *child_status = status; } -static void save_vpn_password (const char *vpn, const char *keyring, const char *username, const char *password) +static gboolean +child_stdout_data_cb (GIOChannel *source, GIOCondition condition, gpointer userdata) { - guint32 item_id; - GnomeKeyringResult keyring_result; + char *str; + GSList **passwords = (GSList **) userdata; - keyring_result = gnome_keyring_set_network_password_sync (NULL, - username, - NULL, - vpn, - NULL, - "vpn", - NULL, - 0, - password, - &item_id); + if (! (condition & G_IO_IN)) + goto out; - if (keyring_result != GNOME_KEYRING_RESULT_OK) - { - nm_warning ("Couldn't store password in keyring, code %d", - (int) keyring_result); - } -} + if (g_io_channel_read_line (source, &str, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) { + int len; -char *nmwa_vpn_request_password (NMWirelessApplet *applet, const char *vpn, const char *username, gboolean retry) -{ - GtkWidget *dialog; - char *prompt; - char *password = NULL; - - g_return_val_if_fail (applet != NULL, NULL); - g_return_val_if_fail (vpn != NULL, NULL); - g_return_val_if_fail (username != NULL, NULL); - - /* Use the system user name, since the VPN might have a different user name */ - if (!retry && lookup_pass (vpn, g_get_user_name (), &password)) - return password; - - prompt = g_strdup_printf (_("You must log in to access the Virtual Private Network '%s'."), vpn); - dialog = gnome_password_dialog_new ("", prompt, username, NULL, FALSE); - g_free (prompt); - - gnome_password_dialog_set_show_username (GNOME_PASSWORD_DIALOG (dialog), TRUE); - gnome_password_dialog_set_readonly_username (GNOME_PASSWORD_DIALOG (dialog), TRUE); - gnome_password_dialog_set_show_userpass_buttons (GNOME_PASSWORD_DIALOG (dialog), FALSE); - gnome_password_dialog_set_show_domain (GNOME_PASSWORD_DIALOG (dialog), FALSE); - gnome_password_dialog_set_show_remember (GNOME_PASSWORD_DIALOG (dialog), TRUE); - gtk_widget_show (dialog); - - if (gnome_password_dialog_run_and_block (GNOME_PASSWORD_DIALOG (dialog))) - { - password = gnome_password_dialog_get_password (GNOME_PASSWORD_DIALOG (dialog)); - switch (gnome_password_dialog_get_remember (GNOME_PASSWORD_DIALOG (dialog))) - { - case GNOME_PASSWORD_DIALOG_REMEMBER_SESSION: - save_vpn_password (vpn, "session", username, password); - break; - case GNOME_PASSWORD_DIALOG_REMEMBER_FOREVER: - save_vpn_password (vpn, NULL, username, password); - break; - default: - break; + len = strlen (str); + if (len > 0) { + /* remove terminating newline */ + str[len - 1] = '\0'; + *passwords = g_slist_append (*passwords, str); } } - gtk_widget_destroy (dialog); - return password; +out: + return TRUE; +} + +GSList * +nmwa_vpn_request_password (NMWirelessApplet *applet, const char *name, const char *service, gboolean retry) +{ + char *argv[] = {NULL /*"/usr/libexec/nm-vpnc-auth-dialog"*/, + "-n", NULL /*"davidznet42"*/, + "-s", NULL /*"org.freedesktop.vpnc"*/, + "-r", + NULL}; + GSList *passwords = NULL; + int child_stdout; + GPid child_pid; + int child_status; + GIOChannel *child_stdout_channel; + guint child_stdout_channel_eventid; + GDir *dir; + char *auth_dialog_binary; + + auth_dialog_binary = NULL; + + /* find the auth-dialog binary */ + if ((dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL)) != NULL) { + const char *f; + + while (auth_dialog_binary == NULL && (f = g_dir_read_name (dir)) != NULL) { + char *path; + GKeyFile *keyfile; + + 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)) { + char *thisservice; + + if ((thisservice = g_key_file_get_string (keyfile, + "VPN Connection", + "service", NULL)) != NULL && + strcmp (thisservice, service) == 0) { + + auth_dialog_binary = g_key_file_get_string (keyfile, + "GNOME", + "auth-dialog", NULL); + } + + g_free (thisservice); + } + g_key_file_free (keyfile); + g_free (path); + } + g_dir_close (dir); + } + + if (auth_dialog_binary == NULL) { + /* could find auth-dialog */ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Cannot start VPN connection '%s'"), + name); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Could not find the authentication dialog for VPN connection type '%s'. Contact your system administrator."), + service); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + goto out; + } + + /* Fix up parameters with what we got */ + argv[0] = auth_dialog_binary; + argv[2] = (char *) name; + argv[4] = (char *) service; + if (!retry) + argv[5] = NULL; + + nm_debug ("retry = %d", retry); + + child_status = -1; + + if (!g_spawn_async_with_pipes (NULL, /* working_directory */ + argv, /* argv */ + NULL, /* envp */ + G_SPAWN_DO_NOT_REAP_CHILD, /* flags */ + NULL, /* child_setup */ + NULL, /* user_data */ + &child_pid, /* child_pid */ + NULL, /* standard_input */ + &child_stdout, /* standard_output */ + NULL, /* standard_error */ + NULL)) { /* error */ + /* could not spawn */ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Cannot start VPN connection '%s'"), + name); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("There was a problem launching the authentication dialog for VPN connection type '%s'. Contact your system administrator."), + service); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + goto out; + } + + /* catch when child is reaped */ + g_child_watch_add (child_pid, child_finished_cb, (gpointer) &child_status); + + /* listen to what child has to say */ + child_stdout_channel = g_io_channel_unix_new (child_stdout); + child_stdout_channel_eventid = g_io_add_watch (child_stdout_channel, G_IO_IN, child_stdout_data_cb, &passwords); + g_io_channel_set_encoding (child_stdout_channel, NULL, NULL); + + /* recurse mainloop here until the child is finished (child_status is set in child_finished_cb) */ + while (child_status == -1) { + g_main_context_iteration (NULL, TRUE); + } + + g_spawn_close_pid (child_pid); + g_source_remove (child_stdout_channel_eventid); + g_io_channel_unref (child_stdout_channel); + + if (child_status != 0) { + if (passwords != NULL) { + g_slist_foreach (passwords, (GFunc)g_free, NULL); + g_slist_free (passwords); + passwords = NULL; + } + } + +out: + g_free (auth_dialog_binary); + + return passwords; } diff --git a/gnome/applet/vpn-password-dialog.h b/gnome/applet/vpn-password-dialog.h index 81b09184a..54cf9e98c 100644 --- a/gnome/applet/vpn-password-dialog.h +++ b/gnome/applet/vpn-password-dialog.h @@ -24,6 +24,9 @@ #include "applet.h" -char *nmwa_vpn_request_password (NMWirelessApplet *applet, const char *vpn, const char *username, gboolean retry); +GSList *nmwa_vpn_request_password (NMWirelessApplet *applet, + const char *name, + const char *service, + gboolean retry); #endif diff --git a/gnome/vpn-properties/Makefile.am b/gnome/vpn-properties/Makefile.am new file mode 100644 index 000000000..277f990f2 --- /dev/null +++ b/gnome/vpn-properties/Makefile.am @@ -0,0 +1,46 @@ + +bin_PROGRAMS = nm-vpn-properties + +nm_vpn_propertiesdir=$(includedir)/NetworkManager + +nm_vpn_properties_HEADERS = \ + nm-vpn-ui-interface.h + +nm_vpn_properties_SOURCES = \ + nm-vpn-properties.c \ + nm-vpn-ui-interface.h + +gladedir = $(datadir)/gnome-vpn-properties +glade_DATA = nm-vpn-properties.glade + +nm_vpn_properties_CFLAGS = \ + $(GLADE_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GCONF_CFLAGS) \ + $(GMODULE_CFLAGS) \ + $(LIBGNOMEUI_CFLAGS) \ + -DICONDIR=\""$(datadir)/pixmaps"\" \ + -DGLADEDIR=\""$(gladedir)"\" \ + -DG_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DGNOME_DISABLE_DEPRECATED \ + -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DVERSION=\"$(VERSION)\" \ + $(NULL) + +nm_vpn_properties_LDADD = \ + $(GLADE_LIBS) \ + $(GTK_LIBS) \ + $(GCONF_LIBS) \ + $(GMODULE_LIBS) \ + $(LIBGNOMEUI_LIBS) \ + $(NULL) + +CLEANFILES = $(server_DATA) *.bak *.gladep *~ + +EXTRA_DIST = \ + $(glade_DATA) \ + $(NULL) + + + diff --git a/gnome/vpn-properties/nm-vpn-properties.c b/gnome/vpn-properties/nm-vpn-properties.c new file mode 100644 index 000000000..589b81525 --- /dev/null +++ b/gnome/vpn-properties/nm-vpn-properties.c @@ -0,0 +1,968 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * nm-vpn-properties.c : GNOME UI dialogs for manipulating VPN connections + * + * Copyright (C) 2005 David Zeuthen, + * + * === + * NOTE NOTE NOTE: All source for nm-vpn-properties is licensed to you + * under your choice of the Academic Free License version 2.0, or the + * GNU General Public License version 2. + * === + * + * Licensed under the Academic Free License version 2.0 + * + * 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 + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + + +#include "nm-vpn-ui-interface.h" + + +#define NM_GCONF_VPN_CONNECTIONS_PATH "/system/networking/vpn_connections" + +static GladeXML *xml; +static GConfClient *gconf_client; + +static GtkWidget *dialog; +static GtkWindow *druid_window; +static GtkTreeView *vpn_conn_view; +static GtkListStore *vpn_conn_list; +static GtkWidget *vpn_edit; +static GtkWidget *vpn_delete; +static GnomeDruid *druid; +static GnomeDruidPageEdge *druid_confirm_page; +static GtkComboBox *vpn_type_combo_box; +static GtkVBox *vpn_type_details; +static GtkDialog *edit_dialog; + +static GSList *vpn_types; + +enum { + VPNCONN_NAME_COLUMN, + VPNCONN_GCONF_COLUMN, + VPNCONN_USER_CAN_EDIT_COLUMN, + VPNCONN_N_COLUMNS +}; + +static void +update_edit_del_sensitivity (void) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + gboolean is_editable; + + if ((selection = gtk_tree_view_get_selection (vpn_conn_view)) == NULL) + goto out; + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + goto out; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), &iter, VPNCONN_USER_CAN_EDIT_COLUMN, &is_editable, -1); + + gtk_widget_set_sensitive (vpn_edit, is_editable); + gtk_widget_set_sensitive (vpn_delete, is_editable); + +out: + ; +} + +static gboolean +add_vpn_connection (const char *conn_name, const char *service_name, GSList *conn_data, GSList *routes) +{ + int i; + char *gconf_key; + GtkTreeIter iter; + char conn_gconf_path[PATH_MAX]; + char *escaped_conn_name; + gboolean ret; + gboolean conn_user_can_edit = TRUE; + + ret = FALSE; + + escaped_conn_name = gconf_escape_key (conn_name, strlen (conn_name)); + + g_snprintf (conn_gconf_path, + sizeof (conn_gconf_path), + NM_GCONF_VPN_CONNECTIONS_PATH "/%s", + escaped_conn_name); + + if (gconf_client_dir_exists (gconf_client, conn_gconf_path, NULL)) + goto out; + + /* User-visible name of connection */ + gconf_key = g_strdup_printf ("%s/name", conn_gconf_path); + gconf_client_set_string (gconf_client, gconf_key, conn_name, NULL); + + /* Service name of connection */ + gconf_key = g_strdup_printf ("%s/service_name", conn_gconf_path); + gconf_client_set_string (gconf_client, gconf_key, service_name, NULL); + + /* vpn-daemon specific data */ + gconf_key = g_strdup_printf ("%s/vpn_data", conn_gconf_path); + { + gconf_client_set_list (gconf_client, gconf_key, GCONF_VALUE_STRING, conn_data, NULL); + } + + /* routes */ + gconf_key = g_strdup_printf ("%s/routes", conn_gconf_path); + { +/* + GSList *i; + + i = NULL; + i = g_slist_append (i, "172.16.0.0/16"); +*/ + gconf_client_set_list (gconf_client, gconf_key, GCONF_VALUE_STRING, routes, NULL); + /*g_slist_free (i);*/ + } + + gconf_client_suggest_sync (gconf_client, NULL); + + conn_user_can_edit = TRUE; + + gtk_list_store_append (vpn_conn_list, &iter); + gtk_list_store_set (vpn_conn_list, &iter, + VPNCONN_NAME_COLUMN, conn_name, + VPNCONN_GCONF_COLUMN, conn_gconf_path, + VPNCONN_USER_CAN_EDIT_COLUMN, &conn_user_can_edit, + -1); + + ret = TRUE; + +out: + g_free (escaped_conn_name); + return ret; +} + +static void +vpn_druid_vpn_validity_changed (NetworkManagerVpnUI *vpn_ui, + gboolean is_valid, + gpointer user_data) +{ + char *conn_name; + GtkTreeIter iter; + + /*printf ("vpn_druid_vpn_validity_changed %d!\n", is_valid);*/ + + conn_name = vpn_ui->get_connection_name (vpn_ui); + + /* get list of existing connection names */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (vpn_conn_list), &iter)) { + do { + char *name; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), + &iter, + VPNCONN_NAME_COLUMN, + &name, + -1); + + if (strcmp (name, conn_name) == 0) { + /*printf ("name '%s' is already in use\n", conn_name);*/ + is_valid = FALSE; + break; + } + + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (vpn_conn_list), &iter)); + } + + g_free (conn_name); + + gnome_druid_set_buttons_sensitive (druid, + TRUE, + is_valid, + TRUE, + FALSE); +} + + +static gboolean vpn_druid_vpn_type_page_next (GnomeDruidPage *druidpage, + GtkWidget *widget, + gpointer user_data) +{ + GtkWidget *w; + GtkWidget *vbox; + NetworkManagerVpnUI *vpn_ui; + + /*printf ("vpn_type_next!\n");*/ + + /* first hide existing child */ + w = g_list_nth_data (gtk_container_children (GTK_CONTAINER (vpn_type_details)), 0); + if (w != NULL) { + gtk_widget_hide (w); + } + + /* show appropriate child */ + vpn_ui = (NetworkManagerVpnUI *) g_slist_nth_data (vpn_types, gtk_combo_box_get_active (vpn_type_combo_box)); + if (vpn_ui != NULL) { + w = vpn_ui->get_widget (vpn_ui, NULL, NULL, NULL); + if (w != NULL) { + GtkWidget *old_parent; + gtk_widget_ref (w); + old_parent = gtk_widget_get_parent (w); + if (old_parent != NULL) + gtk_container_remove (GTK_CONTAINER (old_parent), w); + gtk_container_add (GTK_CONTAINER (vpn_type_details), w); + gtk_widget_unref (w); + + gtk_widget_show_all (w); + } + + vpn_ui->set_validity_changed_callback (vpn_ui, vpn_druid_vpn_validity_changed, NULL); + } + + return FALSE; +} + +static void vpn_druid_vpn_details_page_prepare (GnomeDruidPage *druidpage, + GtkWidget *widget, + gpointer user_data) +{ + /*printf ("vpn_details_prepare!\n");*/ + + gnome_druid_set_buttons_sensitive (druid, + TRUE, + FALSE, + TRUE, + FALSE); + +} + +static gboolean vpn_druid_vpn_details_page_next (GnomeDruidPage *druidpage, + GtkWidget *widget, + gpointer user_data) +{ + gboolean is_valid; + NetworkManagerVpnUI *vpn_ui; + + is_valid = FALSE; + + /*printf ("vpn_details_next!\n");*/ + + /* validate input */ + vpn_ui = (NetworkManagerVpnUI *) g_slist_nth_data (vpn_types, gtk_combo_box_get_active (vpn_type_combo_box)); + if (vpn_ui != NULL) { + is_valid = vpn_ui->is_valid (vpn_ui); + } + +out: + return !is_valid; +} + +static void vpn_druid_vpn_confirm_page_prepare (GnomeDruidPage *druidpage, + GtkWidget *widget, + gpointer user_data) +{ + NetworkManagerVpnUI *vpn_ui; + + /*printf ("vpn_confirm_prepare!\n");*/ + + vpn_ui = (NetworkManagerVpnUI *) g_slist_nth_data (vpn_types, gtk_combo_box_get_active (vpn_type_combo_box)); + if (vpn_ui != NULL) { + const char *confirm_text; + + confirm_text = vpn_ui->get_confirmation_details (vpn_ui); + + gnome_druid_page_edge_set_text (druid_confirm_page, + confirm_text); + } +} + +static gboolean vpn_druid_vpn_confirm_page_finish (GnomeDruidPage *druidpage, + GtkWidget *widget, + gpointer user_data) +{ + static int vpncon = 0; + GSList *conn_data; + GSList *conn_routes; + char *conn_name; + NetworkManagerVpnUI *vpn_ui; + + /*printf ("vpn_confirm_finish!\n");*/ + + vpn_ui = (NetworkManagerVpnUI *) g_slist_nth_data (vpn_types, gtk_combo_box_get_active (vpn_type_combo_box)); + conn_name = vpn_ui->get_connection_name (vpn_ui); + conn_data = vpn_ui->get_properties (vpn_ui); + conn_routes = vpn_ui->get_routes (vpn_ui); + + add_vpn_connection (conn_name, vpn_ui->get_service_name (vpn_ui), conn_data, conn_routes); + + gtk_widget_hide_all (GTK_WIDGET (druid_window)); +out: + return FALSE; +} + +static gboolean vpn_druid_cancel (GnomeDruid *druid, + gpointer user_data) +{ + /*printf ("vpn_druid_cancel!\n");*/ + + gtk_widget_hide_all (GTK_WIDGET (druid_window)); + return FALSE; +} + + + +static void +add_cb (GtkButton *button, gpointer user_data) +{ + GtkWidget *w; + GList *i; + GList *children; + + /*printf ("add_cb\n");*/ + + /* Bail out if we don't have any VPN implementations on our system */ + if (vpn_types == NULL || g_slist_length (vpn_types) == 0) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Cannot add VPN connection")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("No suitable VPN software was found on your system. Contact your system administrator.")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + goto out; + } + + + /* remove existing VPN widget */ + children = gtk_container_get_children (GTK_CONTAINER (vpn_type_details)); + for (i = children; i != NULL; i = g_list_next (i)) { + w = GTK_WIDGET (i->data); + g_object_ref (G_OBJECT (w)); + gtk_container_remove (GTK_CONTAINER (vpn_type_details), w); + } + g_list_free (children); + + w = glade_xml_get_widget (xml, "vpn-druid-vpn-start"); + gnome_druid_set_page (druid, GNOME_DRUID_PAGE (w)); + + gtk_widget_set_sensitive (w, TRUE); + + gtk_window_set_policy (druid_window, FALSE, FALSE, TRUE); + + gtk_widget_show_all (GTK_WIDGET (druid_window)); +out: + ; +} + + +static void +vpn_edit_vpn_validity_changed (NetworkManagerVpnUI *vpn_ui, + gboolean is_valid, + gpointer user_data) +{ + const char *orig_conn_name; + char *conn_name; + GtkTreeIter iter; + + orig_conn_name = (const char *) user_data; + + /*printf ("vpn_edit_vpn_validity_changed %d!\n", is_valid);*/ + + conn_name = vpn_ui->get_connection_name (vpn_ui); + + /* get list of existing connection names */ + if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (vpn_conn_list), &iter)) { + do { + char *name; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), + &iter, + VPNCONN_NAME_COLUMN, + &name, + -1); + + /* Can override the original name (stored in user_data, see edit_cb()) */ + if (strcmp (name, orig_conn_name) != 0) { + if (strcmp (name, conn_name) == 0) { + /*printf ("name '%s' is already in use\n", conn_name);*/ + is_valid = FALSE; + break; + } + } + + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (vpn_conn_list), &iter)); + } + + g_free (conn_name); + + gtk_dialog_set_response_sensitive (edit_dialog, GTK_RESPONSE_ACCEPT, is_valid); + +} + +static NetworkManagerVpnUI * +find_vpn_ui_by_service_name (const char *service_name) +{ + GSList *i; + + for (i = vpn_types; i != NULL; i = g_slist_next (i)) { + NetworkManagerVpnUI *vpn_ui; + + vpn_ui = i->data; + if (strcmp (vpn_ui->get_service_name (vpn_ui), service_name) == 0) + return vpn_ui; + } + + return NULL; +} + +static void +edit_cb (GtkButton *button, gpointer user_data) +{ + GtkWidget *vpn_edit_widget; + NetworkManagerVpnUI *vpn_ui; + gint result; + char *conn_gconf_path; + const char *conn_name; + const char *conn_service_name; + GSList *conn_vpn_data_gconfvalue; + GSList *conn_vpn_data; + GSList *conn_routes_gconfvalue; + GSList *conn_routes; + GSList *i; + char key[PATH_MAX]; + GtkTreeSelection *selection; + GtkTreeIter iter; + GConfValue *value; + + /*printf ("edit\n");*/ + + if ((selection = gtk_tree_view_get_selection (vpn_conn_view)) == NULL) + goto out; + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + goto out; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), + &iter, + VPNCONN_GCONF_COLUMN, + &conn_gconf_path, + -1); + + g_snprintf (key, sizeof (key), "%s/name", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + (conn_name = gconf_value_get_string (value)) == NULL) + goto out; + + g_snprintf (key, sizeof (key), "%s/service_name", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + (conn_service_name = gconf_value_get_string (value)) == NULL) + goto out; + + vpn_ui = find_vpn_ui_by_service_name (conn_service_name); + if (vpn_ui == NULL) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Cannot edit VPN connection '%s'"), + conn_name); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Could not find the UI files for VPN connection type '%s'. Contact your system administrator."), + conn_service_name); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + goto out; + } + + g_snprintf (key, sizeof (key), "%s/vpn_data", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + gconf_value_get_list_type (value) != GCONF_VALUE_STRING || + (conn_vpn_data_gconfvalue = gconf_value_get_list (value)) == NULL) + goto out; + + conn_vpn_data = NULL; + for (i = conn_vpn_data_gconfvalue; i != NULL; i = g_slist_next (i)) { + const char *value; + value = gconf_value_get_string ((GConfValue *) i->data); + conn_vpn_data = g_slist_append (conn_vpn_data, (gpointer) value); + } + + + /* routes may be an empty list */ + g_snprintf (key, sizeof (key), "%s/routes", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + gconf_value_get_list_type (value) != GCONF_VALUE_STRING) + goto out; + + conn_routes_gconfvalue = gconf_value_get_list (value); + conn_routes = NULL; + for (i = conn_routes_gconfvalue; i != NULL; i = g_slist_next (i)) { + const char *value; + value = gconf_value_get_string ((GConfValue *) i->data); + conn_routes = g_slist_append (conn_routes, (gpointer) value); + } + + + + vpn_edit_widget = vpn_ui->get_widget (vpn_ui, conn_vpn_data, conn_routes, conn_name); + + + g_slist_free (conn_vpn_data); + g_slist_free (conn_routes); + + vpn_ui->set_validity_changed_callback (vpn_ui, vpn_edit_vpn_validity_changed, (gpointer) conn_name); + + gtk_widget_reparent (vpn_edit_widget, GTK_WIDGET (edit_dialog->vbox)); + + gtk_widget_show_all (vpn_edit_widget); + /*gtk_widget_set_sensitive (vpn_edit_widget, TRUE);*/ + + /* auto-shrink our window */ + gtk_window_set_policy (GTK_WINDOW (edit_dialog), FALSE, FALSE, TRUE); + + gtk_widget_show (GTK_WIDGET (edit_dialog)); + + result = gtk_dialog_run (GTK_DIALOG (edit_dialog)); + + if (result == GTK_RESPONSE_ACCEPT) { + char *new_conn_name; + GSList *new_conn_data; + GSList *new_conn_routes; + + new_conn_name = vpn_ui->get_connection_name (vpn_ui); + new_conn_data = vpn_ui->get_properties (vpn_ui); + new_conn_routes = vpn_ui->get_routes (vpn_ui); + + if (strcmp (new_conn_name, conn_name) == 0) { + + /* same name, just update properties and routes */ + g_snprintf (key, sizeof (key), "%s/vpn_data", conn_gconf_path); + gconf_client_set_list (gconf_client, key, GCONF_VALUE_STRING, new_conn_data, NULL); + g_snprintf (key, sizeof (key), "%s/routes", conn_gconf_path); + gconf_client_set_list (gconf_client, key, GCONF_VALUE_STRING, new_conn_routes, NULL); + + gconf_client_suggest_sync (gconf_client, NULL); + } else { + + /* remove old entry */ + g_snprintf (key, sizeof (key), "%s/name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/service_name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/vpn_data", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + /* TODO: at some point remove routes and user_name */ + g_snprintf (key, sizeof (key), "%s/routes", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/user_name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + gconf_client_unset (gconf_client, conn_gconf_path, NULL); + gconf_client_suggest_sync (gconf_client, NULL); + gtk_list_store_remove (vpn_conn_list, &iter); + + /* add new entry */ + add_vpn_connection (new_conn_name, vpn_ui->get_service_name (vpn_ui), + new_conn_data, new_conn_routes); + } + + if (new_conn_data != NULL) { + g_slist_foreach (new_conn_data, (GFunc)g_free, NULL); + g_slist_free (new_conn_data); + } + if (new_conn_routes != NULL) { + g_slist_foreach (new_conn_routes, (GFunc)g_free, NULL); + g_slist_free (new_conn_routes); + } + + + } + + gtk_widget_hide (GTK_WIDGET (edit_dialog)); + +out: + ; +} + +static void +delete_cb (GtkButton *button, gpointer user_data) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + gchar *conn_gconf_path; + gchar *conn_name; + GtkWidget *dialog; + int response; + + /*printf ("delete\n");*/ + + if ((selection = gtk_tree_view_get_selection (vpn_conn_view)) == NULL) + goto out; + + if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + goto out; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), &iter, VPNCONN_NAME_COLUMN, &conn_name, -1); + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + _("Delete VPN connection \"%s\"?"), conn_name); + gtk_dialog_add_buttons (GTK_DIALOG (dialog), "_Delete", GTK_RESPONSE_OK, NULL); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("All information about the VPN connection \"%s\" will be lost and you may need your system administrator to provide information to create a new connection."), conn_name); + response = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + if (response != GTK_RESPONSE_OK) + goto out; + + gtk_tree_model_get (GTK_TREE_MODEL (vpn_conn_list), &iter, VPNCONN_GCONF_COLUMN, &conn_gconf_path, -1); + + if (conn_gconf_path != NULL) { + char key[PATH_MAX]; + + g_snprintf (key, sizeof (key), "%s/name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/service_name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/vpn_data", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + g_snprintf (key, sizeof (key), "%s/routes", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + /* TODO: remove user_name */ + g_snprintf (key, sizeof (key), "%s/user_name", conn_gconf_path); + gconf_client_unset (gconf_client, key, NULL); + gconf_client_unset (gconf_client, conn_gconf_path, NULL); + + gconf_client_suggest_sync (gconf_client, NULL); + + if (gtk_list_store_remove (vpn_conn_list, &iter)) + gtk_tree_selection_select_iter (selection, &iter); + } + + update_edit_del_sensitivity (); + +out: + ; +} + +static void +close_cb (void) +{ + gtk_widget_destroy (dialog); + gtk_main_quit (); +} + +static void get_all_vpn_connections (void) +{ + GtkTreeIter iter; + GSList *vpn_conn = NULL; + + for (vpn_conn = gconf_client_all_dirs (gconf_client, NM_GCONF_VPN_CONNECTIONS_PATH, NULL); + vpn_conn != NULL; + vpn_conn = g_slist_next (vpn_conn)) { + char key[PATH_MAX]; + GConfValue *value; + const char *conn_gconf_path; + const char *conn_name; + const char *conn_service_name; + GSList *conn_vpn_data; + GSList *i; + gboolean conn_user_can_edit = TRUE; + + conn_gconf_path = (const char *) (vpn_conn->data); + + g_snprintf (key, sizeof (key), "%s/name", conn_gconf_path); + conn_user_can_edit = gconf_client_key_is_writable (gconf_client, key, NULL); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + (conn_name = gconf_value_get_string (value)) == NULL) + goto error; + + g_snprintf (key, sizeof (key), "%s/service_name", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + (conn_service_name = gconf_value_get_string (value)) == NULL) + goto error; + + g_snprintf (key, sizeof (key), "%s/vpn_data", conn_gconf_path); + if ((value = gconf_client_get (gconf_client, key, NULL)) == NULL || + gconf_value_get_list_type (value) != GCONF_VALUE_STRING || + (conn_vpn_data = gconf_value_get_list (value)) == NULL) + goto error; + + //conn_user_can_edit = (strcmp (conn_name, "RH VPN Boston") != 0); + + gtk_list_store_append (vpn_conn_list, &iter); + gtk_list_store_set (vpn_conn_list, &iter, + VPNCONN_NAME_COLUMN, conn_name, + VPNCONN_GCONF_COLUMN, conn_gconf_path, + VPNCONN_USER_CAN_EDIT_COLUMN, conn_user_can_edit, + -1); + + /* + printf ("conn_name = '%s'\n", conn_name); + printf ("conn_service_name = '%s'\n", conn_service_name); + printf ("conn_vpn_data = {"); + { + GSList *i; + for (i = conn_vpn_data; i != NULL; i = g_slist_next (i)) { + printf ("'%s'", gconf_value_get_string ((GConfValue *) i->data)); + if (g_slist_next (i) != NULL) + printf (", "); + } + printf ("}\n"); + } + */ + +error: + g_free (vpn_conn->data); + } + +out: + ; +} + +static void +vpn_list_cursor_changed_cb (GtkTreeView *treeview, + gpointer user_data) +{ + /*printf ("*** vpn_list_cursor_changed_cb\n");*/ + + update_edit_del_sensitivity (); +} + +/* TODO: remove these once we get the GModule thing going */ +//extern NetworkManagerVpnUI* vpn_ui_factory_vpnc (void); +extern NetworkManagerVpnUI* vpn_ui_factory_dummy (void); + +static void +load_properties_module (GSList **vpn_types, const char *path) +{ + GModule *module; + NetworkManagerVpnUI* (*nm_vpn_properties_factory) (void) = NULL; + NetworkManagerVpnUI* impl; + + module = g_module_open (path, G_MODULE_BIND_LAZY); + if (module == NULL) { + g_warning ("Cannot open module '%s'", path); + goto out; + } + + if (!g_module_symbol (module, "nm_vpn_properties_factory", + (gpointer *) &nm_vpn_properties_factory)) { + + g_warning ("Cannot locate function 'nm_vpn_properties_factory' in '%s': %s", + path, g_module_error ()); + g_module_close (module); + goto out; + } + + impl = nm_vpn_properties_factory (); + if (impl == NULL) { + g_warning ("Function 'nm_vpn_properties_factory' in '%s' returned NULL", path); + g_module_close (module); + goto out; + } + + *vpn_types = g_slist_append (*vpn_types, impl); + +out: + ; +} + +#define VPN_NAME_FILES_DIR "/etc/NetworkManager/VPN" + +static void +init_app (void) +{ + GtkWidget *w; + gchar *glade_file; + char *file; + GtkTreeIter iter; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GSList *i; + NetworkManagerVpnUI *vpn_ui_interface; + GtkHBox *vpn_type_hbox1; + GDir *dir; + + /* TODO: ensure only one copy of this program is running at any time */ + + gconf_client = gconf_client_get_default (); + gconf_client_add_dir (gconf_client, NM_GCONF_VPN_CONNECTIONS_PATH, + GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-vpn-properties.glade"); + xml = glade_xml_new (glade_file, NULL, NULL); + g_free (glade_file); + + /* Load all VPN UI modules by inspecting .name files */ + vpn_types = NULL; + if ((dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL)) != NULL) { + const char *f; + + while ((f = g_dir_read_name (dir)) != NULL) { + char *path; + GKeyFile *keyfile; + + 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)) { + char *so_path; + + if ((so_path = g_key_file_get_string (keyfile, + "GNOME", + "properties", NULL)) != NULL) { + load_properties_module (&vpn_types, so_path); + g_free (so_path); + } + } + g_key_file_free (keyfile); + g_free (path); + } + g_dir_close (dir); + } + + dialog = glade_xml_get_widget (xml, "vpn-ui-properties"); + + vpn_type_details = GTK_VBOX (glade_xml_get_widget (xml, "vpn-connection-druid-details-box")); + + w = glade_xml_get_widget (xml, "add"); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (add_cb), NULL); + vpn_edit = glade_xml_get_widget (xml, "edit"); + gtk_signal_connect (GTK_OBJECT (vpn_edit), "clicked", GTK_SIGNAL_FUNC (edit_cb), NULL); + vpn_delete = glade_xml_get_widget (xml, "delete"); + gtk_signal_connect (GTK_OBJECT (vpn_delete), "clicked", GTK_SIGNAL_FUNC (delete_cb), NULL); + w = glade_xml_get_widget (xml, "close"); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (close_cb), NULL); + gtk_signal_connect (GTK_OBJECT (dialog), "delete_event", + GTK_SIGNAL_FUNC (close_cb), NULL); + + + vpn_conn_view = GTK_TREE_VIEW (glade_xml_get_widget (xml, "vpnlist")); + vpn_conn_list = gtk_list_store_new (VPNCONN_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); + + gtk_signal_connect_after (GTK_OBJECT (vpn_conn_view), "cursor-changed", + GTK_SIGNAL_FUNC (vpn_list_cursor_changed_cb), NULL); + + + get_all_vpn_connections (); + + + + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_set_attributes (column, renderer, + "text", VPNCONN_NAME_COLUMN, + NULL); + gtk_tree_view_append_column (vpn_conn_view, column); + + gtk_tree_view_set_model (vpn_conn_view, GTK_TREE_MODEL (vpn_conn_list)); + gtk_tree_view_expand_all (vpn_conn_view); + + + gtk_widget_show_all (dialog); + + /* fill in possibly choices in the druid when adding a connection */ + vpn_type_hbox1 = GTK_HBOX (glade_xml_get_widget (xml, "vpn-create-connection-druid-hbox1")); + vpn_type_combo_box = GTK_COMBO_BOX (gtk_combo_box_new_text ()); + for (i = vpn_types; i != NULL; i = g_slist_next (i)) { + NetworkManagerVpnUI *vpn_ui = i->data; + gtk_combo_box_append_text (vpn_type_combo_box, vpn_ui->get_display_name (vpn_ui)); + + } + gtk_combo_box_set_active (vpn_type_combo_box, 0); + gtk_box_pack_end (GTK_BOX (vpn_type_hbox1), GTK_WIDGET (vpn_type_combo_box), TRUE, TRUE, 0); + + + /* Druid */ + druid = GNOME_DRUID (glade_xml_get_widget (xml, "vpn-create-connection-druid")); + gtk_signal_connect (GTK_OBJECT (druid), "cancel", GTK_SIGNAL_FUNC (vpn_druid_cancel), NULL); + druid_confirm_page = GNOME_DRUID_PAGE_EDGE (glade_xml_get_widget (xml, "vpn-druid-vpn-confirm-page")); + /* use connect_after, otherwise gnome_druid_set_buttons_sensitive() won't work in prepare handlers */ + w = glade_xml_get_widget (xml, "vpn-druid-vpn-type-page"); + gtk_signal_connect_after (GTK_OBJECT (w), "next", GTK_SIGNAL_FUNC (vpn_druid_vpn_type_page_next), NULL); + w = glade_xml_get_widget (xml, "vpn-druid-vpn-details-page"); + gtk_signal_connect_after (GTK_OBJECT (w), "prepare", GTK_SIGNAL_FUNC (vpn_druid_vpn_details_page_prepare), NULL); + gtk_signal_connect_after (GTK_OBJECT (w), "next", GTK_SIGNAL_FUNC (vpn_druid_vpn_details_page_next), NULL); + w = glade_xml_get_widget (xml, "vpn-druid-vpn-confirm-page"); + gtk_signal_connect_after (GTK_OBJECT (w), "prepare", GTK_SIGNAL_FUNC (vpn_druid_vpn_confirm_page_prepare), NULL); + gtk_signal_connect_after (GTK_OBJECT (w), "finish", GTK_SIGNAL_FUNC (vpn_druid_vpn_confirm_page_finish), NULL); + + druid_window = GTK_WINDOW (glade_xml_get_widget (xml, "vpn-create-connection")); + /* reuse the widget */ + gtk_signal_connect (GTK_OBJECT (druid_window), "delete-event", + GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), NULL); + /* make the druid window modal wrt. our main window */ + gtk_window_set_modal (druid_window, TRUE); + gtk_window_set_transient_for (druid_window, GTK_WINDOW (dialog)); + + + /* Edit dialog */ + edit_dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (_("Edit VPN Connection"), + NULL, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + GTK_STOCK_APPLY, + GTK_RESPONSE_ACCEPT, + NULL)); + /* reuse the widget */ + gtk_signal_connect (GTK_OBJECT (edit_dialog), "delete-event", + GTK_SIGNAL_FUNC (gtk_widget_hide_on_delete), NULL); + + + /* update "Edit" and "Delete" for current selection */ + update_edit_del_sensitivity (); +} + + +int +main (int argc, char *argv[]) +{ + + gnome_program_init (GETTEXT_PACKAGE, VERSION, LIBGNOMEUI_MODULE, argc, argv, + GNOME_PARAM_NONE); + + glade_gnome_init (); + + bindtextdomain (GETTEXT_PACKAGE, NULL); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + init_app (); + + gtk_main (); + + return 0; +} diff --git a/gnome/vpn-properties/nm-vpn-properties.glade b/gnome/vpn-properties/nm-vpn-properties.glade new file mode 100644 index 000000000..854c032f6 --- /dev/null +++ b/gnome/vpn-properties/nm-vpn-properties.glade @@ -0,0 +1,339 @@ + + + + + + + + 5 + 400 + 300 + VPN Connections + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_CENTER + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + + + + True + False + 0 + + + + True + Manage Virtual Private Network connections + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0 + 6 + 11 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + False + False + False + False + + + + + 0 + True + True + + + + + + 6 + True + GTK_BUTTONBOX_START + 12 + + + + True + Add a new VPN connection + True + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + + + + True + Edit the selected VPN connection + True + True + gtk-edit + True + GTK_RELIEF_NORMAL + True + + + + + + True + Delete the selected VPN connection + True + True + gtk-delete + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + True + + + + + 0 + True + True + + + + + + 6 + True + GTK_BUTTONBOX_END + 0 + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + 0 + False + False + + + + + + + + Create VPN Connection + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + + + + 4 + True + False + + + + True + GNOME_EDGE_START + Create VPN Connection + This assistant will guide you through the creation of a new VPN connection to a private network. + +It will require some information, such as IP addresses and secrets, that will probably be provided by your system administrator as appropriate. + + + + + + True + Create VPN Connection - 1 of 2 + + + + 16 + True + False + 6 + + + + True + False + 0 + + + + True + Dependent on the private network you want to connect to, you need to select what type of connection you want to create. + False + False + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 12 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 12 + False + False + + + + + + True + False + 0 + + + + True + Connect to: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 12 + False + False + + + + + + + + + 0 + True + True + + + + + 0 + True + False + + + + + + + + + + True + Create VPN Connection - 2 of 2 + + + + 16 + True + False + 6 + + + + + + + + + + + + True + GNOME_EDGE_FINISH + Finish create VPN Connection + + + + + + + + diff --git a/gnome/vpn-properties/nm-vpn-ui-interface.h b/gnome/vpn-properties/nm-vpn-ui-interface.h new file mode 100644 index 000000000..aca21f560 --- /dev/null +++ b/gnome/vpn-properties/nm-vpn-ui-interface.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * nm-vpn-ui-interface.h : Public interface for VPN UI editing widgets + * + * Copyright (C) 2005 David Zeuthen, + * + * === + * NOTE NOTE NOTE: All source for nm-vpn-properties is licensed to you + * under your choice of the Academic Free License version 2.0, or the + * GNU General Public License version 2. + * === + * + * Licensed under the Academic Free License version 2.0 + * + * 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 + * + **************************************************************************/ + +#ifndef NM_VPN_UI_INTERFACE_H +#define NM_VPN_UI_INTERFACE_H + +#include + +struct _NetworkManagerVpnUI; +typedef struct _NetworkManagerVpnUI NetworkManagerVpnUI; + +typedef void (*NetworkManagerVpnUIDialogValidityCallback) (NetworkManagerVpnUI *self, + gboolean is_valid, + gpointer user_data); + + +struct _NetworkManagerVpnUI { + const char *(*get_display_name) (NetworkManagerVpnUI *self); + + const char *(*get_service_name) (NetworkManagerVpnUI *self); + + GtkWidget *(*get_widget) (NetworkManagerVpnUI *self, GSList *properties, GSList *routes, const char *connection_name); + + void (*set_validity_changed_callback) (NetworkManagerVpnUI *self, + NetworkManagerVpnUIDialogValidityCallback cb, + gpointer user_data); + + gboolean (*is_valid) (NetworkManagerVpnUI *self); + + const char *(*get_confirmation_details)(NetworkManagerVpnUI *self); + + + char *(*get_connection_name) (NetworkManagerVpnUI *self); + + GSList *(*get_properties) (NetworkManagerVpnUI *self); + + GSList *(*get_routes) (NetworkManagerVpnUI *self); + + gpointer data; +}; + +#endif /* NM_VPN_UI_INTERFACE_H */ + diff --git a/po/ChangeLog b/po/ChangeLog index 3b8507fc7..537ebac54 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,8 @@ +2005-06-12 David Zeuthen + + * POTFILES.in: Added gnome/vpn-properties/nm-vpn-properties.c and + gnome/vpn-properties/nm-vpn-properties.glade + 2005-06-10 Marcel Telka * sk.po: Updated Slovak translation. diff --git a/po/POTFILES.in b/po/POTFILES.in index edc653895..867eeebbb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,4 +12,6 @@ gnome/applet/other-network-dialog.c gnome/applet/passphrase-dialog.c gnome/applet/vpn-password-dialog.c gnome/applet/wireless-applet.glade +gnome/vpn-properties/nm-vpn-properties.c +gnome/vpn-properties/nm-vpn-properties.glade src/nm-netlink-monitor.c diff --git a/src/vpn-manager/nm-dbus-vpn.c b/src/vpn-manager/nm-dbus-vpn.c index 175b5f576..d1f208e65 100644 --- a/src/vpn-manager/nm-dbus-vpn.c +++ b/src/vpn-manager/nm-dbus-vpn.c @@ -622,9 +622,13 @@ static DBusMessage *nm_dbus_vpn_get_vpn_connection_properties (DBusConnection *c { if ((vpn_con = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) { - const char *user_name = nm_vpn_connection_get_user_name (vpn_con); + const char *user_name; + const char *service; - dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_INVALID); + user_name = nm_vpn_connection_get_user_name (vpn_con); + service = nm_vpn_service_get_service_name (nm_vpn_connection_get_service (vpn_con)); + + dbus_message_append_args (reply, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user_name, DBUS_TYPE_STRING, &service, DBUS_TYPE_INVALID); good = TRUE; } } @@ -681,7 +685,8 @@ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, DBusMessage *reply = NULL; DBusError error; const char *name; - const char *password; + char **passwords; + int num_passwords; NMVPNConnection *vpn; g_return_val_if_fail (data != NULL, NULL); @@ -689,9 +694,11 @@ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (message != NULL, NULL); + nm_info ("Entering"); + dbus_error_init (&error); - if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &password, DBUS_TYPE_INVALID)) - { + + if (dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &num_passwords, DBUS_TYPE_INVALID)) { if ((vpn = nm_vpn_manager_find_connection_by_name (data->data->vpn_manager, name))) { int item_count = -1; @@ -704,12 +711,16 @@ static DBusMessage *nm_dbus_vpn_activate_connection (DBusConnection *connection, nm_info ("Will activate VPN connection '%s', service '%s', user_name '%s', vpn_data '%s'.", name, nm_vpn_service_get_service_name (service), nm_vpn_connection_get_user_name (vpn), joined_string); - nm_vpn_manager_activate_vpn_connection (data->data->vpn_manager, vpn, password, items, item_count); + nm_vpn_manager_activate_vpn_connection (data->data->vpn_manager, vpn, passwords, num_passwords, items, item_count); g_free (joined_string); g_strfreev (items); } + } else { + nm_warning ("Cannot find name '%s'", name); } + } else { + nm_warning ("Syntax error receiving nm_dbus_vpn_activate_connection"); } return NULL; diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 8b22e9602..6acd59c3f 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -655,7 +655,7 @@ gboolean nm_vpn_manager_process_name_owner_changed (NMVPNManager *manager, const * launching that daemon if necessary. * */ -void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, const char *password, char **data_items, int count) +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, char **password_items, int password_count, char **data_items, int count) { DBusMessage *message; DBusMessage *reply; @@ -672,7 +672,7 @@ void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnect g_return_if_fail (manager->app_data != NULL); g_return_if_fail (manager->app_data->dbus_connection != NULL); g_return_if_fail (vpn != NULL); - g_return_if_fail (password != NULL); + g_return_if_fail (password_items != NULL); g_return_if_fail (data_items != NULL); nm_vpn_manager_set_active_vpn_connection (manager, NULL); @@ -708,10 +708,10 @@ void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnect user_name = nm_vpn_connection_get_user_name (vpn); dbus_message_append_args (message, DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &user_name, - DBUS_TYPE_STRING, &password, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, count, - DBUS_TYPE_INVALID); + DBUS_TYPE_STRING, &user_name, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &password_items, password_count, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data_items, count, + DBUS_TYPE_INVALID); /* Send the message to the daemon again, now that its running. */ dbus_error_init (&error); diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index f0e7c6c49..64fac40bb 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -34,7 +34,7 @@ void nm_vpn_manager_dispose (NMVPNManager *manager); NMVPNConnection * nm_vpn_manager_get_active_vpn_connection (NMVPNManager *manager); -void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, const char *password, char **data_items, int count); +void nm_vpn_manager_activate_vpn_connection (NMVPNManager *manager, NMVPNConnection *vpn, char **password_items, int password_count, char **data_items, int count); void nm_vpn_manager_deactivate_vpn_connection (NMVPNManager *manager); NMVPNConnection * nm_vpn_manager_find_connection_by_name (NMVPNManager *manager, const char *con_name); diff --git a/vpn-daemons/Makefile.am b/vpn-daemons/Makefile.am deleted file mode 100644 index ba0a3eb59..000000000 --- a/vpn-daemons/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -SUBDIRS = vpnc - diff --git a/vpn-daemons/README b/vpn-daemons/README new file mode 100644 index 000000000..8138178c9 --- /dev/null +++ b/vpn-daemons/README @@ -0,0 +1,2 @@ + +The API for the VPN extensions points should be mentioned here