NetworkManager r3587 - in trunk: . introspection libnm-glib system-settings/plugins system-settings/plugins/keyfile system-settings/src



Author: tambeti
Date: Tue Apr 22 14:48:02 2008
New Revision: 3587
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3587&view=rev

Log:
2008-04-22  Tambet Ingo  <tambet gmail com>

	Implement GKeyFile system settings plugin.
	Implement writing system settings (currently supported only by GKeyFile plugin).

	* system-settings/src/main.c:
	* system-settings/src/dbus-settings.c: Move the communication with plugins
	from main.c to dbus-settings.c. Makes it possible to talk to all registered
	plugins for adding/updating/removing connections.

	* system-settings/src/nm-system-config-interface.c
	(nm_system_config_interface_add_connection): Implement
	(nm_system_config_interface_update_connection): Implement.
	(nm_system_config_interface_remove_connection): Implement.

	* system-settings/plugins/keyfile/Makefile.am:
	* system-settings/plugins/keyfile/plugin.[ch]:
	* system-settings/plugins/keyfile/writer.[ch]:
	* system-settings/plugins/keyfile/reader.[ch]: Implement.

	* system-settings/plugins/Makefile.am: Add GKeyFile plugin.

	* configure.in: Generate GKeyFile Makefile.

	* libnm-glib/nm-settings.c (impl_exported_connection_get_id): Fix a memory
	corruption, need to duplicate the returned string.
	(impl_exported_connection_update): Implement.
	(impl_exported_connection_delete): Implement.

	* introspection/nm-settings-system.xml: Add "AddConnection" method.

	* introspection/nm-exported-connection.xml: Add "Update" and "Delete" methods.


Added:
   trunk/system-settings/plugins/keyfile/
   trunk/system-settings/plugins/keyfile/Makefile.am
   trunk/system-settings/plugins/keyfile/plugin.c
   trunk/system-settings/plugins/keyfile/plugin.h
   trunk/system-settings/plugins/keyfile/reader.c
   trunk/system-settings/plugins/keyfile/reader.h
   trunk/system-settings/plugins/keyfile/writer.c
   trunk/system-settings/plugins/keyfile/writer.h
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/introspection/nm-exported-connection.xml
   trunk/introspection/nm-settings-system.xml
   trunk/libnm-glib/nm-settings.c
   trunk/libnm-glib/nm-settings.h
   trunk/system-settings/plugins/Makefile.am
   trunk/system-settings/src/dbus-settings.c
   trunk/system-settings/src/dbus-settings.h
   trunk/system-settings/src/main.c
   trunk/system-settings/src/nm-system-config-interface.c
   trunk/system-settings/src/nm-system-config-interface.h

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Tue Apr 22 14:48:02 2008
@@ -308,6 +308,7 @@
 system-settings/plugins/Makefile
 system-settings/plugins/ifcfg-fedora/Makefile
 system-settings/plugins/ifcfg-suse/Makefile
+system-settings/plugins/keyfile/Makefile
 test/Makefile
 test/test-common/Makefile
 initscript/Makefile

Modified: trunk/introspection/nm-exported-connection.xml
==============================================================================
--- trunk/introspection/nm-exported-connection.xml	(original)
+++ trunk/introspection/nm-exported-connection.xml	Tue Apr 22 14:48:02 2008
@@ -18,6 +18,25 @@
             </arg>
         </method>
 
+	<method name="Update">
+	  <tp:docstring>
+	    Update the connection.
+	  </tp:docstring>
+	  <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_exported_connection_update"/>
+	  <arg name="properties" type="a{sa{sv}}" direction="in">
+	    <tp:docstring>
+	      New connection properties.
+	    </tp:docstring>
+	  </arg>
+	</method>
+
+	<method name="Delete">
+	  <tp:docstring>
+	    Delete the connection.
+	  </tp:docstring>
+	  <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_exported_connection_delete"/>
+	</method>
+
         <method name="GetSettings">
             <tp:docstring>
                 Get the settings maps describing this object.

Modified: trunk/introspection/nm-settings-system.xml
==============================================================================
--- trunk/introspection/nm-settings-system.xml	(original)
+++ trunk/introspection/nm-settings-system.xml	Tue Apr 22 14:48:02 2008
@@ -6,6 +6,18 @@
       Implemented by the system settings service to provide additional settings to NetworkManager.
     </tp:docstring>
 
+    <method name="AddConnection">
+      <tp:docstring>
+	Add new connection.
+      </tp:docstring>
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_add_connection"/>
+      <arg name="connection" type="a{sa{sv}}" direction="in">
+	<tp:docstring>
+	  Connection properties.
+	</tp:docstring>
+      </arg>
+    </method>
+
     <property name="UnmanagedDevices" type="ao" access="read">
       <tp:docstring>
         The list of HAL UDIs of devices that should not be managed by NetworkManager.

Modified: trunk/libnm-glib/nm-settings.c
==============================================================================
--- trunk/libnm-glib/nm-settings.c	(original)
+++ trunk/libnm-glib/nm-settings.c	Tue Apr 22 14:48:02 2008
@@ -107,6 +107,14 @@
 static gboolean impl_exported_connection_get_settings (NMExportedConnection *connection,
 						       GHashTable **settings,
 						       GError **error);
+
+static gboolean impl_exported_connection_update (NMExportedConnection *connection,
+									    GHashTable *new_settings,
+									    GError *err);
+
+static gboolean impl_exported_connection_delete (NMExportedConnection *connection,
+									    GError *err);
+
 static void impl_exported_connection_get_secrets (NMExportedConnection *connection,
 						      const gchar *setting_name,
 						      const gchar **hints,
@@ -169,7 +177,7 @@
 {
 	g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (connection), FALSE);
 
-	*id = (gchar *) nm_exported_connection_get_id (connection);
+	*id = g_strdup (nm_exported_connection_get_id (connection));
 	if (!*id) {
 		g_set_error (error, NM_SETTINGS_ERROR, 1,
 		             "%s.%d - Could not get connection ID.",
@@ -182,8 +190,8 @@
 
 static gboolean
 impl_exported_connection_get_settings (NMExportedConnection *connection,
-				       GHashTable **settings,
-				       GError **error)
+							    GHashTable **settings,
+							    GError **error)
 {
 	NMExportedConnectionPrivate *priv;
 
@@ -199,6 +207,32 @@
 	return TRUE;
 }
 
+static gboolean
+impl_exported_connection_update (NMExportedConnection *connection,
+						   GHashTable *new_settings,
+						   GError *err)
+{
+	if (EXPORTED_CONNECTION_CLASS (connection)->update)
+		EXPORTED_CONNECTION_CLASS (connection)->update (connection, new_settings);
+	else
+		nm_connection_replace_settings (NM_EXPORTED_CONNECTION_GET_PRIVATE (connection)->wrapped, new_settings);
+
+	nm_exported_connection_signal_updated (connection, new_settings);
+
+	return TRUE;
+}
+
+static gboolean
+impl_exported_connection_delete (NMExportedConnection *connection, GError *err)
+{
+	if (EXPORTED_CONNECTION_CLASS (connection)->delete)
+		EXPORTED_CONNECTION_CLASS (connection)->delete (connection);
+
+	nm_exported_connection_signal_removed (connection);
+
+	return TRUE;
+}
+
 static void
 impl_exported_connection_get_secrets (NMExportedConnection *connection,
                                       const gchar *setting_name,

Modified: trunk/libnm-glib/nm-settings.h
==============================================================================
--- trunk/libnm-glib/nm-settings.h	(original)
+++ trunk/libnm-glib/nm-settings.h	Tue Apr 22 14:48:02 2008
@@ -37,6 +37,11 @@
 	                              gboolean request_new,
 	                              DBusGMethodInvocation *context);
 
+	void (*update) (NMExportedConnection *connection,
+			GHashTable *new_settings);
+
+	void (*delete) (NMExportedConnection *connection);
+
 	/* signals */
 	void (* updated) (NMExportedConnection *connection, GHashTable *settings);
 	void (* removed) (NMExportedConnection *connection);

Modified: trunk/system-settings/plugins/Makefile.am
==============================================================================
--- trunk/system-settings/plugins/Makefile.am	(original)
+++ trunk/system-settings/plugins/Makefile.am	Tue Apr 22 14:48:02 2008
@@ -1,11 +1,13 @@
+SUBDIRS=keyfile
+
 if TARGET_REDHAT
-SUBDIRS=ifcfg-fedora
+SUBDIRS+=ifcfg-fedora
 endif
 
 if TARGET_SUSE
-SUBDIRS=ifcfg-suse
+SUBDIRS+=ifcfg-suse
 endif
 
 if TARGET_MANDRIVA
-SUBDIRS=ifcfg-fedora
+SUBDIRS+=ifcfg-fedora
 endif

Added: trunk/system-settings/plugins/keyfile/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/Makefile.am	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,28 @@
+
+pkglib_LTLIBRARIES = libnm-settings-plugin-keyfile.la
+
+libnm_settings_plugin_keyfile_la_SOURCES = \
+	plugin.c \
+	plugin.h \
+	reader.c \
+	reader.h \
+	writer.c \
+	writer.h
+
+libnm_settings_plugin_keyfile_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	$(GMODULE_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-I${top_srcdir}/system-settings/src \
+	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/libnm-util \
+	-DKEYFILE_DIR=\""$(sysconfdir)/NetworkManager/system_config"\"
+
+libnm_settings_plugin_keyfile_la_LDFLAGS = -module -avoid-version
+libnm_settings_plugin_keyfile_la_LIBADD = \
+	$(GLIB_LIBS) \
+	$(GMODULE_LIBS) \
+	$(GIO_LIBS) \
+	$(top_builddir)/libnm-util/libnm-util.la
+

Added: trunk/system-settings/plugins/keyfile/plugin.c
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/plugin.c	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,310 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <gmodule.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <nm-connection.h>
+#include <nm-setting.h>
+#include <nm-setting-connection.h>
+
+#include "plugin.h"
+#include "nm-system-config-interface.h"
+#include "reader.h"
+#include "writer.h"
+
+#define KEYFILE_PLUGIN_NAME "keyfile"
+#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2008 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
+
+static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
+
+G_DEFINE_TYPE_EXTENDED (SCPluginKeyfile, sc_plugin_keyfile, G_TYPE_OBJECT, 0,
+				    G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE,
+									  system_config_interface_init))
+
+#define SC_PLUGIN_KEYFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfilePrivate))
+
+typedef struct {
+	GHashTable *hash;
+
+	GFileMonitor *monitor;
+	guint monitor_id;
+
+	gboolean disposed;
+} SCPluginKeyfilePrivate;
+
+static NMConnection *
+read_one_connection (NMSystemConfigInterface *config, const char *filename)
+{
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
+	char *full_path;
+	NMConnection *connection = NULL;
+
+	full_path = g_build_filename (KEYFILE_DIR, filename, NULL);
+	connection = connection_from_file (full_path);
+	if (connection)
+		g_hash_table_insert (priv->hash, g_strdup (filename), connection);
+
+	g_free (full_path);
+
+	return connection;
+}
+
+static void
+read_connections (NMSystemConfigInterface *config)
+{
+	GDir *dir;
+	GError *err = NULL;
+
+	dir = g_dir_open (KEYFILE_DIR, 0, &err);
+	if (dir) {
+		const char *item;
+
+		while ((item = g_dir_read_name (dir)))
+			read_one_connection (config, item);
+
+		g_dir_close (dir);
+	} else {
+		g_warning ("Can not read directory '%s': %s", KEYFILE_DIR, err->message);
+		g_error_free (err);
+	}
+}
+
+static void
+delete_connection (NMSystemConfigInterface *config, NMConnection *connection)
+{
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
+	NMSettingConnection *s_con;
+	char *filename;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con)
+		return;
+
+	filename = g_build_filename (KEYFILE_DIR, s_con->id, NULL);
+
+	if (g_hash_table_lookup (priv->hash, s_con->id)) {
+		if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+			/* Monitoring takes care of the rest */
+			g_unlink (filename);
+		else
+			g_warning ("File '%s' does not exist", filename);
+	}
+
+	g_free (filename);
+}
+
+/* Monitoring */
+
+static void
+dir_changed (GFileMonitor *monitor,
+		   GFile *file,
+		   GFile *other_file,
+		   GFileMonitorEvent event_type,
+		   gpointer user_data)
+{
+	NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data);
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
+	char *name;
+	NMConnection *connection;
+
+	name = g_file_get_basename (file);
+	connection = g_hash_table_lookup (priv->hash, name);
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_DELETED:
+		if (connection) {
+			g_hash_table_remove (priv->hash, name);
+			g_signal_emit_by_name (config, "connection-removed", connection);
+		}
+		break;
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		if (connection) {
+			/* Update */
+			char *full_path;
+			NMConnection *tmp;
+
+			full_path = g_file_get_path (file);
+			tmp = connection_from_file (full_path);
+			g_free (full_path);
+
+			if (tmp) {
+				GHashTable *settings;
+
+				settings = nm_connection_to_hash (tmp);
+
+				if (nm_connection_replace_settings (connection, settings))
+					g_signal_emit_by_name (config, "connection-updated", connection);
+
+				g_hash_table_destroy (settings);
+				g_object_unref (tmp);
+			}
+		} else {
+			/* New */
+			connection = read_one_connection (config, name);
+			if (connection)
+				g_signal_emit_by_name (config, "connection-added", connection);
+		}
+		break;
+	default:
+		break;
+	}
+
+	g_free (name);
+}
+
+static void
+setup_monitoring (NMSystemConfigInterface *config)
+{
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
+	GFile *file;
+	GFileMonitor *monitor;
+
+	priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+	file = g_file_new_for_path (KEYFILE_DIR);
+	monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+
+	if (monitor) {
+		priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
+		priv->monitor = monitor;
+	}
+}
+
+static void
+hash_to_slist (gpointer key, gpointer value, gpointer user_data)
+{
+	GSList **list = (GSList **) user_data;
+
+	*list = g_slist_prepend (*list, value);
+}
+
+/* Plugin */
+
+static GSList *
+get_connections (NMSystemConfigInterface *config)
+{
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config);
+	GSList *connections = NULL;
+
+	if (!priv->hash) {
+		setup_monitoring (config);
+		read_connections (config);
+	}
+
+	g_hash_table_foreach (priv->hash, hash_to_slist, &connections);
+
+	return connections;
+}
+
+static void
+add_connection (NMSystemConfigInterface *config, NMConnection *connection)
+{
+	write_connection (connection);
+}
+
+static void
+update_connection (NMSystemConfigInterface *config, NMConnection *connection)
+{
+	write_connection (connection);
+}
+
+static void
+remove_connection (NMSystemConfigInterface *config, NMConnection *connection)
+{
+	delete_connection (config, connection);
+}
+
+/* GObject */
+
+static void
+sc_plugin_keyfile_init (SCPluginKeyfile *plugin)
+{
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+		    GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
+		g_value_set_string (value, KEYFILE_PLUGIN_NAME);
+		break;
+	case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
+		g_value_set_string (value, KEYFILE_PLUGIN_INFO);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (object);
+
+	if (priv->disposed)
+		return;
+
+	priv->disposed = TRUE;
+
+	if (priv->monitor) {
+		if (priv->monitor_id)
+			g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
+
+		g_file_monitor_cancel (priv->monitor);
+		g_object_unref (priv->monitor);
+	}
+
+	g_hash_table_destroy (priv->hash);
+
+	G_OBJECT_CLASS (sc_plugin_keyfile_parent_class)->dispose (object);
+}
+
+static void
+sc_plugin_keyfile_class_init (SCPluginKeyfileClass *req_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+	g_type_class_add_private (req_class, sizeof (SCPluginKeyfilePrivate));
+
+	object_class->dispose = dispose;
+	object_class->get_property = get_property;
+
+	g_object_class_override_property (object_class,
+							    NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
+							    NM_SYSTEM_CONFIG_INTERFACE_NAME);
+
+	g_object_class_override_property (object_class,
+							    NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
+							    NM_SYSTEM_CONFIG_INTERFACE_INFO);
+}
+
+static void
+system_config_interface_init (NMSystemConfigInterface *system_config_interface_class)
+{
+	/* interface implementation */
+	system_config_interface_class->get_connections = get_connections;
+	system_config_interface_class->add_connection = add_connection;
+	system_config_interface_class->update_connection = update_connection;
+	system_config_interface_class->remove_connection = remove_connection;
+}
+
+G_MODULE_EXPORT GObject *
+nm_system_config_factory (void)
+{
+	static SCPluginKeyfile *singleton = NULL;
+
+	if (!singleton)
+		singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL));
+	else
+		g_object_ref (singleton);
+
+	return G_OBJECT (singleton);
+}

Added: trunk/system-settings/plugins/keyfile/plugin.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/plugin.h	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include <glib-object.h>
+
+#define SC_TYPE_PLUGIN_KEYFILE            (sc_plugin_keyfile_get_type ())
+#define SC_PLUGIN_KEYFILE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfile))
+#define SC_PLUGIN_KEYFILE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass))
+#define SC_IS_PLUGIN_KEYFILE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_KEYFILE))
+#define SC_IS_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_KEYFILE))
+#define SC_PLUGIN_KEYFILE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass))
+
+typedef struct {
+	GObject parent;
+} SCPluginKeyfile;
+
+typedef struct {
+	GObjectClass parent;
+} SCPluginKeyfileClass;
+
+GType sc_plugin_keyfile_get_type (void);
+
+GQuark keyfile_plugin_error_quark (void);
+
+#endif	/* _PLUGIN_H_ */

Added: trunk/system-settings/plugins/keyfile/reader.c
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/reader.c	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,196 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dbus/dbus-glib.h>
+#include <nm-setting.h>
+
+#include "reader.h"
+
+#define DBUS_TYPE_G_ARRAY_OF_UINT          (dbus_g_type_get_collection ("GArray", G_TYPE_UINT))
+#define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT))
+
+static void
+read_one_setting_value (NMSetting *setting,
+				    const char *key,
+				    const GValue *value,
+				    gboolean secret,
+				    gpointer user_data)
+{
+	GKeyFile *file = (GKeyFile *) user_data;
+	GType type;
+	GError *err = NULL;
+
+	if (!g_key_file_has_key (file, setting->name, key, &err)) {
+		if (err) {
+			g_warning ("Error loading setting '%s' value: %s", setting->name, err->message);
+			g_error_free (err);
+		}
+
+		return;
+	}
+
+	type = G_VALUE_TYPE (value);
+
+	if (type == G_TYPE_STRING) {
+		char *str_val;
+
+		str_val = g_key_file_get_string (file, setting->name, key, NULL);
+		g_object_set (setting, key, str_val, NULL);
+		g_free (str_val);
+	} else if (type == G_TYPE_UINT) {
+		int int_val;
+
+		int_val = g_key_file_get_integer (file, setting->name, key, NULL);
+		if (int_val < 0)
+			g_warning ("Casting negative value (%i) to uint", int_val);
+		g_object_set (setting, key, int_val, NULL);
+	} else if (type == G_TYPE_INT) {
+		int int_val;
+
+		int_val = g_key_file_get_integer (file, setting->name, key, NULL);
+		g_object_set (setting, key, int_val, NULL);
+	} else if (type == G_TYPE_BOOLEAN) {
+		gboolean bool_val;
+
+		bool_val = g_key_file_get_boolean (file, setting->name, key, NULL);
+		g_object_set (setting, key, bool_val, NULL);
+	} else if (type == G_TYPE_CHAR) {
+		int int_val;
+
+		int_val = g_key_file_get_integer (file, setting->name, key, NULL);
+		if (int_val < G_MININT8 || int_val > G_MAXINT8)
+			g_warning ("Casting value (%i) to char", int_val);
+
+		g_object_set (setting, key, int_val, NULL);
+	} else if (type == G_TYPE_UINT64) {
+		char *tmp_str;
+		guint64 uint_val;
+
+		tmp_str = g_key_file_get_value (file, setting->name, key, NULL);
+		uint_val = g_ascii_strtoull (tmp_str, NULL, 10);
+		g_object_set (setting, key, uint_val, NULL);
+ 	} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
+		gint *tmp;
+		GByteArray *array;
+		gsize length;
+		int i;
+
+		tmp = g_key_file_get_integer_list (file, setting->name, key, &length, NULL);
+
+		array = g_byte_array_sized_new (length);
+		for (i = 0; i < length; i++) {
+			int val = tmp[i];
+			unsigned char v = (unsigned char) (val & 0xFF);
+
+			if (val < 0 || val > 255)
+				g_warning ("Value out of range for a byte value");
+			else
+				g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
+		}
+
+		g_object_set (setting, key, array, NULL);
+		g_byte_array_free (array, TRUE);
+ 	} else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) {
+		gchar **sa;
+		gsize length;
+		int i;
+		GSList *list = NULL;
+
+		sa = g_key_file_get_string_list (file, setting->name, key, &length, NULL);
+		for (i = 0; i < length; i++)
+			list = g_slist_prepend (list, sa[i]);
+
+		list = g_slist_reverse (list);
+		g_object_set (setting, key, list, NULL);
+
+		g_slist_free (list);
+		g_strfreev (sa);
+	} else if (type == dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) {
+		/* FIXME */
+		g_warning ("Implement me");
+	} else if (type == DBUS_TYPE_G_UINT_ARRAY) {
+		gint *tmp;
+		GArray *array;
+		gsize length;
+		int i;
+
+		tmp = g_key_file_get_integer_list (file, setting->name, key, &length, NULL);
+
+		array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
+		for (i = 0; i < length; i++)
+			g_array_append_val (array, tmp[i]);
+
+		g_object_set (setting, key, array, NULL);
+		g_array_free (array, TRUE);
+	} else if (type == DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT) {
+		/* FIXME */
+		g_warning ("Implement me");
+	} else {
+		g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'",
+				 setting->name, key, G_VALUE_TYPE_NAME (value));
+	}
+}
+
+static NMSetting *
+read_setting (GKeyFile *file, const char *name)
+{
+	NMSetting *setting;
+
+	setting = nm_connection_create_setting (name);
+	if (setting) {
+		nm_setting_enumerate_values (setting, read_one_setting_value, file);
+	} else
+		g_warning ("Invalid setting name '%s'", name);
+
+	return setting;
+}
+
+NMConnection *
+connection_from_file (const char *filename)
+{
+	GKeyFile *key_file;
+	struct stat statbuf;
+	gboolean bad_owner, bad_permissions;
+	NMConnection *connection = NULL;
+	GError *err = NULL;
+
+	if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode))
+		return NULL;
+
+	bad_owner = getuid () != statbuf.st_uid;
+	bad_permissions = statbuf.st_mode & 0077;
+
+    if (bad_owner || bad_permissions) {
+	    g_warning ("Ignorning insecure configuration file '%s'", filename);
+	    return NULL;
+    }
+
+	key_file = g_key_file_new ();
+	if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &err)) {
+		gchar **groups;
+		gsize length;
+		int i;
+
+		connection = nm_connection_new ();
+
+		groups = g_key_file_get_groups (key_file, &length);
+		for (i = 0; i < length; i++) {
+			NMSetting *setting;
+
+			setting = read_setting (key_file, groups[i]);
+			if (setting)
+				nm_connection_add_setting (connection, setting);
+		}
+
+		g_strfreev (groups);
+	} else {
+		g_warning ("Error parsing file '%s': %s", filename, err->message);
+		g_error_free (err);
+	}
+
+	g_key_file_free (key_file);
+
+	return connection;
+}

Added: trunk/system-settings/plugins/keyfile/reader.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/reader.h	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,11 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#ifndef _KEYFILE_PLUGIN_READER_H
+#define _KEYFILE_PLUGIN_READER_H
+
+#include <glib.h>
+#include <nm-connection.h>
+
+NMConnection *connection_from_file (const char *filename);
+
+#endif /* _KEYFILE_PLUGIN_READER_H */

Added: trunk/system-settings/plugins/keyfile/writer.c
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/writer.c	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dbus/dbus-glib.h>
+#include <nm-setting.h>
+#include <nm-setting-connection.h>
+
+#include "writer.h"
+
+#define DBUS_TYPE_G_ARRAY_OF_UINT          (dbus_g_type_get_collection ("GArray", G_TYPE_UINT))
+#define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT))
+
+static void
+write_setting_value (NMSetting *setting,
+				 const char *key,
+				 const GValue *value,
+				 gboolean secret,
+				 gpointer user_data)
+{
+	GKeyFile *file = (GKeyFile *) user_data;
+	GType type;
+
+	type = G_VALUE_TYPE (value);
+
+	if (type == G_TYPE_STRING) {
+		const char *str;
+
+		str = g_value_get_string (value);
+		if (str)
+			g_key_file_set_string (file, setting->name, key, str);
+	} else if (type == G_TYPE_UINT)
+		g_key_file_set_integer (file, setting->name, key, (int) g_value_get_uint (value));
+	else if (type == G_TYPE_INT)
+		g_key_file_set_integer (file, setting->name, key, g_value_get_int (value));
+	else if (type == G_TYPE_UINT64) {
+		char *numstr;
+
+		numstr = g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (value));
+		g_key_file_set_value (file, setting->name, key, numstr);
+		g_free (numstr);
+	} else if (type == G_TYPE_BOOLEAN) {
+		g_key_file_set_boolean (file, setting->name, key, g_value_get_boolean (value));
+	} else if (type == G_TYPE_CHAR) {
+		g_key_file_set_integer (file, setting->name, key, (int) g_value_get_char (value));
+	} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
+		GByteArray *array;
+
+		array = (GByteArray *) g_value_get_boxed (value);
+		if (array && array->len > 0) {
+			int *tmp_array;
+			int i;
+
+			tmp_array = g_new (gint, array->len);
+			for (i = 0; i < array->len; i++)
+				tmp_array[i] = (int) array->data[i];
+
+			g_key_file_set_integer_list (file, setting->name, key, tmp_array, array->len);
+			g_free (tmp_array);
+		}
+	} else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) {
+		GSList *list;
+		GSList *iter;
+
+		list = (GSList *) g_value_get_boxed (value);
+		if (list) {
+			char **array;
+			int i = 0;
+
+			array = g_new (char *, g_slist_length (list));
+			for (iter = list; iter; iter = iter->next)
+				array[i++] = iter->data;
+
+			g_key_file_set_string_list (file, setting->name, key, (const gchar **const) array, i);
+			g_free (array);
+		}
+	} else if (type == dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) {
+		/* FIXME */
+		g_warning ("Implement me");
+	} else if (type == DBUS_TYPE_G_UINT_ARRAY) {
+		GArray *array;
+
+		array = (GArray *) g_value_get_boxed (value);
+		if (array && array->len > 0) {
+			int *tmp_array;
+			int i;
+
+			tmp_array = g_new (gint, array->len);
+			for (i = 0; i < array->len; i++)
+				tmp_array[i] = (int) array->data[i];
+
+			g_key_file_set_integer_list (file, setting->name, key, tmp_array, array->len);
+			g_free (tmp_array);
+		}
+	} else if (type == DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT) {
+		GPtrArray *array;
+		
+		array = (GPtrArray *) g_value_get_boxed (value);
+		if (array && array->len > 0) {
+			int i, j;
+			int* list;
+
+			list = g_new (int, array->len * 3);
+
+			for (i = 0, j = 0; i < array->len; i++) {
+				GArray *tuple = g_ptr_array_index (array, i);
+
+				list[j++] = g_array_index (tuple, guint32, 0);
+				list[j++] = g_array_index (tuple, guint32, 1);
+				list[j++] = tuple->len == 3 ? g_array_index (tuple, guint32, 2) : 0;
+			}
+
+			g_key_file_set_integer_list (file, setting->name, key, list, j);
+			g_free (list);
+		}
+	} else
+		g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'", 
+				 setting->name, key, g_type_name (type));
+}
+
+gboolean
+write_connection (NMConnection *connection)
+{
+	NMSettingConnection *s_con;
+	GKeyFile *key_file;
+	char *data;
+	gsize len;
+	gboolean success = FALSE;
+	GError *err = NULL;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con)
+		return success;
+
+	key_file = g_key_file_new ();
+	nm_connection_for_each_setting_value (connection, write_setting_value, key_file);
+	data = g_key_file_to_data (key_file, &len, &err);
+
+	if (!err) {
+		char *filename;
+
+		filename = g_build_filename (KEYFILE_DIR, s_con->id, NULL);
+		g_file_set_contents (filename, data, len, &err);
+		chmod (filename, S_IRUSR | S_IWUSR);
+		chown (filename, 0, 0);
+
+		g_free (filename);
+		success = TRUE;
+	}
+
+	if (err) {
+		g_warning ("Error while saving connection: %s", err->message);
+		g_error_free (err);
+	}
+
+	g_free (data);
+	g_key_file_free (key_file);
+
+	return success;
+}

Added: trunk/system-settings/plugins/keyfile/writer.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/keyfile/writer.h	Tue Apr 22 14:48:02 2008
@@ -0,0 +1,11 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#ifndef _KEYFILE_PLUGIN_WRITER_H
+#define _KEYFILE_PLUGIN_WRITER_H
+
+#include <glib.h>
+#include <nm-connection.h>
+
+gboolean write_connection (NMConnection *connection);
+
+#endif /* _KEYFILE_PLUGIN_WRITER_H */

Modified: trunk/system-settings/src/dbus-settings.c
==============================================================================
--- trunk/system-settings/src/dbus-settings.c	(original)
+++ trunk/system-settings/src/dbus-settings.c	Tue Apr 22 14:48:02 2008
@@ -1,3 +1,5 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
 /* NetworkManager system settings service
  *
  * SÃren Sandmann <sandmann daimi au dk>
@@ -28,9 +30,10 @@
 
 #include "nm-dbus-glib-types.h"
 #include "dbus-settings.h"
-#include "nm-system-config-interface.h"
 #include "nm-utils.h"
 
+#define NM_SS_PLUGIN_TAG "nm-ss-plugin"
+
 static void exported_connection_get_secrets (NMExportedConnection *connection,
                                              const gchar *setting_name,
                                              const gchar **hints,
@@ -93,7 +96,7 @@
 		goto error;
 	}
 
-	plugin = g_object_get_data (G_OBJECT (connection), NM_SS_PLUGIN_TAG);
+	plugin = g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG);
 	if (!plugin) {
 		g_set_error (&error, NM_SETTINGS_ERROR, 1,
 		             "%s.%d - Connection had no plugin to ask for secrets.",
@@ -174,11 +177,21 @@
  * NMSettings
  */
 
+static gboolean
+impl_settings_add_connection (NMSysconfigSettings *self, GHashTable *hash, GError **err);
+
 #include "nm-settings-system-glue.h"
 
 typedef struct {
+	DBusGConnection *g_connection;
+	NMSystemConfigHalManager *hal_mgr;
+
+	GSList *plugins;
+	gboolean connections_loaded;
 	GSList *connections;
 	GHashTable *unmanaged_devices;
+
+	gboolean in_plugin_signal_handler;
 } NMSysconfigSettingsPrivate;
 
 G_DEFINE_TYPE (NMSysconfigSettings, nm_sysconfig_settings, NM_TYPE_SETTINGS);
@@ -204,12 +217,11 @@
 list_connections (NMSettings *settings)
 {
 	NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (settings);
-	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
 	GPtrArray *connections;
 	GSList *iter;
 
 	connections = g_ptr_array_new ();
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
+	for (iter = nm_sysconfig_settings_get_connections (self); iter; iter = g_slist_next (iter)) {
 		NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data);
 		NMConnection *connection;
 		char *path;
@@ -238,6 +250,12 @@
 
 	g_hash_table_destroy (priv->unmanaged_devices);
 
+	g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL);
+	g_slist_free (priv->plugins);
+
+	g_object_unref (priv->hal_mgr);
+	dbus_g_connection_unref (priv->g_connection);
+
 	G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object);
 }
 
@@ -367,142 +385,296 @@
 }
 
 NMSysconfigSettings *
-nm_sysconfig_settings_new (DBusGConnection *g_conn)
+nm_sysconfig_settings_new (DBusGConnection *g_conn, NMSystemConfigHalManager *hal_mgr)
 {
 	NMSysconfigSettings *settings;
+	NMSysconfigSettingsPrivate *priv;
 
-	settings = g_object_new (nm_sysconfig_settings_get_type (), NULL);
+	g_return_val_if_fail (g_conn != NULL, NULL);
+	g_return_val_if_fail (hal_mgr != NULL, NULL);
+
+	settings = g_object_new (NM_TYPE_SYSCONFIG_SETTINGS, NULL);
 	dbus_g_connection_register_g_object (g_conn, NM_DBUS_PATH_SETTINGS, G_OBJECT (settings));
+
+	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (settings);
+	priv->g_connection = dbus_g_connection_ref (g_conn);
+	priv->hal_mgr = g_object_ref (hal_mgr);
+
 	return settings;
 }
 
-void
-nm_sysconfig_settings_add_connection (NMSysconfigSettings *self,
-                                      NMConnection *connection,
-                                      DBusGConnection *g_connection)
+static void
+plugin_connection_added (NMSystemConfigInterface *config,
+					NMConnection *connection,
+					gpointer user_data)
 {
-	NMSysconfigSettingsPrivate *priv;
-	NMSysconfigExportedConnection *exported;
+	nm_sysconfig_settings_add_connection (NM_SYSCONFIG_SETTINGS (user_data), config, connection);
+}
 
-	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
-	g_return_if_fail (NM_IS_CONNECTION (connection));
+static void
+plugin_connection_removed (NMSystemConfigInterface *config,
+					  NMConnection *connection,
+					  gpointer user_data)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data);
 
-	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
-	exported = nm_sysconfig_exported_connection_new (connection, g_connection);
-	if (!exported) {
-		g_warning ("%s: couldn't export the connection!", __func__);
-		return;
-	}
+	priv->in_plugin_signal_handler = TRUE;
+	nm_sysconfig_settings_remove_connection (NM_SYSCONFIG_SETTINGS (user_data), connection);
+	priv->in_plugin_signal_handler = FALSE;
+}
 
-	priv->connections = g_slist_append (priv->connections, exported);
+static void
+plugin_connection_updated (NMSystemConfigInterface *config,
+					  NMConnection *connection,
+					  gpointer user_data)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data);
 
-	nm_settings_signal_new_connection (NM_SETTINGS (self),
-	                                   NM_EXPORTED_CONNECTION (exported));
+	priv->in_plugin_signal_handler = TRUE;
+	nm_sysconfig_settings_update_connection (NM_SYSCONFIG_SETTINGS (user_data), connection);
+	priv->in_plugin_signal_handler = FALSE;
 }
 
 static void
-remove_connection (NMSysconfigSettings *self,
-                   NMConnection *connection)
+unmanaged_devices_changed (NMSystemConfigInterface *config,
+					  gpointer user_data)
 {
-	NMSysconfigSettingsPrivate *priv;
+	NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (user_data);
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
 
-	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
-	g_return_if_fail (NM_IS_CONNECTION (connection));
+	g_hash_table_remove_all (priv->unmanaged_devices);
 
-	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		NMSysconfigExportedConnection *item = NM_SYSCONFIG_EXPORTED_CONNECTION (iter->data);
-		NMExportedConnection *exported = NM_EXPORTED_CONNECTION (item);
-		NMConnection *wrapped;
-
-		wrapped = nm_exported_connection_get_connection (exported);
-
-		if (wrapped == connection) {
-			priv->connections = g_slist_remove_link (priv->connections, iter);
-			nm_exported_connection_signal_removed (exported);
-			g_object_unref (item);
-			g_slist_free (iter);
-			break;
+	/* Ask all the plugins for their unmanaged devices */
+	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
+		GSList *udis = nm_system_config_interface_get_unmanaged_devices (NM_SYSTEM_CONFIG_INTERFACE (iter->data));
+		GSList *udi_iter;
+
+		for (udi_iter = udis; udi_iter; udi_iter = udi_iter->next) {
+			if (!g_hash_table_lookup (priv->unmanaged_devices, udi_iter->data)) {
+				g_hash_table_insert (priv->unmanaged_devices,
+								 udi_iter->data,
+								 GUINT_TO_POINTER (1));
+			} else
+				g_free (udi_iter->data);
 		}
+
+		g_slist_free (udis);
 	}
-}
 
-void
-nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings,
-                                         NMConnection *connection)
-{
-	remove_connection (settings, connection);
+	g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES);
 }
 
 void
-nm_sysconfig_settings_update_connection (NMSysconfigSettings *self,
-                                         NMConnection *connection)
+nm_sysconfig_settings_add_plugin (NMSysconfigSettings *self,
+						    NMSystemConfigInterface *plugin)
 {
 	NMSysconfigSettingsPrivate *priv;
-	GHashTable *hash;
-	GSList *iter;
-	NMSysconfigExportedConnection *found = NULL;
+	char *pname = NULL;
+	char *pinfo = NULL;
 
 	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
-	g_return_if_fail (NM_IS_CONNECTION (connection));
+	g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin));
 
 	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		NMSysconfigExportedConnection *item = NM_SYSCONFIG_EXPORTED_CONNECTION (iter->data);
-		NMConnection *wrapped;
 
-		wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (item));
-		if (wrapped == connection) {
-			found = item;
-			break;
-		}
+	priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
+
+	g_signal_connect (plugin, "connection-added", G_CALLBACK (plugin_connection_added), self);
+	g_signal_connect (plugin, "connection-removed", G_CALLBACK (plugin_connection_removed), self);
+	g_signal_connect (plugin, "connection-updated", G_CALLBACK (plugin_connection_updated), self);
+
+	g_signal_connect (plugin, "unmanaged-devices-changed", G_CALLBACK (unmanaged_devices_changed), self);
+
+	nm_system_config_interface_init (plugin, priv->hal_mgr);
+
+	g_object_get (G_OBJECT (plugin),
+	              NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname,
+			    NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo,
+	              NULL);
+
+	g_message ("Loaded plugin %s: %s", pname, pinfo);
+	g_free (pname);
+	g_free (pinfo);
+}
+
+static void
+connection_updated (NMExportedConnection *sys_connection,
+				GHashTable *new_settings,
+				gpointer user_data)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data);
+	NMSystemConfigInterface *plugin;
+	NMConnection *connection;
+
+	if (priv->in_plugin_signal_handler)
+		return;
+
+	connection = nm_exported_connection_get_connection (sys_connection);
+	plugin = (NMSystemConfigInterface *) g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG);
+
+	if (plugin) {
+		nm_system_config_interface_update_connection (plugin, connection);
+	} else {
+		GSList *iter;
+
+		for (iter = priv->plugins; iter; iter = iter->next)
+			nm_system_config_interface_update_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection);
 	}
+}
 
-	if (!found) {
-		g_warning ("%s: cannot update unknown connection", __func__);
+static void
+connection_removed (NMExportedConnection *sys_connection,
+				gpointer user_data)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data);
+	NMSystemConfigInterface *plugin;
+	NMConnection *connection;
+
+	if (priv->in_plugin_signal_handler)
 		return;
+
+	connection = nm_exported_connection_get_connection (sys_connection);
+	plugin = (NMSystemConfigInterface *) g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG);
+
+	if (plugin) {
+		nm_system_config_interface_remove_connection (plugin, connection);
+	} else {
+		GSList *iter;
+
+		for (iter = priv->plugins; iter; iter = iter->next)
+			nm_system_config_interface_remove_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection);
 	}
+}
 
-	/* If the connection is no longer valid, it gets removed */
-	if (!nm_connection_verify (connection)) {
-		remove_connection (self, connection);
+static NMExportedConnection *
+find_existing_connection (NMSysconfigSettings *self, NMConnection *connection)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+	GSList *iter;
+
+	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
+		NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data);
+		NMConnection *wrapped = nm_exported_connection_get_connection (exported);
+
+		if (wrapped == connection)
+			return exported;
+	}
+
+	return NULL;
+}
+
+void
+nm_sysconfig_settings_add_connection (NMSysconfigSettings *self,
+							   NMSystemConfigInterface *plugin,
+							   NMConnection *connection)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+	NMSysconfigExportedConnection *exported;
+
+	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	if (find_existing_connection (self, connection)) {
+		/* A plugin is lying to us */
+		g_message ("Connection is already added, ignoring");
 		return;
 	}
 
-	hash = nm_connection_to_hash (connection);
-	nm_exported_connection_signal_updated (NM_EXPORTED_CONNECTION (found), hash);
-	g_hash_table_destroy (hash);
+	exported = nm_sysconfig_exported_connection_new (connection, priv->g_connection);
+	if (exported) {
+		priv->connections = g_slist_append (priv->connections, exported);
+
+		g_signal_connect (exported, "updated", G_CALLBACK (connection_updated), self);
+		g_signal_connect (exported, "removed", G_CALLBACK (connection_removed), self);
+
+		if (plugin)
+			g_object_set_data (G_OBJECT (exported), NM_SS_PLUGIN_TAG, plugin);
+
+		nm_settings_signal_new_connection (NM_SETTINGS (self), NM_EXPORTED_CONNECTION (exported));
+	} else
+		g_warning ("%s: couldn't export the connection!", __func__);
 }
 
-GSList *
-nm_sysconfig_settings_get_connections (NMSysconfigSettings *self)
+void
+nm_sysconfig_settings_remove_connection (NMSysconfigSettings *self,
+								 NMConnection *connection)
 {
-	g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), NULL);
+	NMExportedConnection *exported;
 
-	return NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self)->connections;
+	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	exported = find_existing_connection (self, connection);
+	if (exported) {
+		NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+
+		priv->connections = g_slist_remove (priv->connections, exported);
+		nm_exported_connection_signal_removed (exported);
+		g_object_unref (exported);
+	}
 }
 
 void
-nm_sysconfig_settings_update_unamanged_devices (NMSysconfigSettings *self,
-                                                GSList *new_list)
+nm_sysconfig_settings_update_connection (NMSysconfigSettings *self,
+								 NMConnection *connection)
 {
-	NMSysconfigSettingsPrivate *priv;
-	GSList *iter;
+	NMExportedConnection *exported;
 
 	g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	exported = find_existing_connection (self, connection);
+	if (exported) {
+		if (nm_connection_verify (connection)) {
+			GHashTable *hash;
+
+			hash = nm_connection_to_hash (connection);
+			nm_exported_connection_signal_updated (exported, hash);
+			g_hash_table_destroy (hash);
+		} else
+			/* If the connection is no longer valid, it gets removed */
+			nm_sysconfig_settings_remove_connection (self, connection);
+	} else
+		g_warning ("%s: cannot update unknown connection", __func__);
+}
+
+GSList *
+nm_sysconfig_settings_get_connections (NMSysconfigSettings *self)
+{
+	NMSysconfigSettingsPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), NULL);
 
 	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
 
-	g_hash_table_remove_all (priv->unmanaged_devices);
-	for (iter = new_list; iter; iter = g_slist_next (iter)) {
-		if (!g_hash_table_lookup (priv->unmanaged_devices, iter->data)) {
-			g_hash_table_insert (priv->unmanaged_devices,
-			                     g_strdup (iter->data),
-			                     GUINT_TO_POINTER (1));
+	if (!priv->connections_loaded) {
+		GSList *iter;
+
+		for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
+			NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+			GSList *plugin_connections;
+			GSList *elt;
+
+			plugin_connections = nm_system_config_interface_get_connections (plugin);
+
+			// FIXME: ensure connections from plugins loaded with a lower priority
+			// get rejected when they conflict with connections from a higher
+			// priority plugin.
+
+			for (elt = plugin_connections; elt; elt = g_slist_next (elt))
+				nm_sysconfig_settings_add_connection (self, plugin, NM_CONNECTION (elt->data));
+
+			g_slist_free (plugin_connections);
 		}
+
+		/* FIXME: Bad hack */
+		unmanaged_devices_changed (NULL, self);
+
+		priv->connections_loaded = TRUE;
 	}
-	g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES);
+
+	return priv->connections;
 }
 
 gboolean
@@ -519,3 +691,36 @@
 	return TRUE;
 }
 
+static gboolean
+impl_settings_add_connection (NMSysconfigSettings *self, GHashTable *hash, GError **err)
+{
+	NMConnection *connection;
+
+	connection = nm_connection_new_from_hash (hash);
+	if (connection) {
+		NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+		GSList *iter;
+
+		/* Here's how it works:
+		   1) plugin writes a connection.
+		   2) plugin notices that a new connection is available for reading.
+		   3) plugin reads the new connection (the one it wrote in 1) and emits 'connection-added' signal.
+		   4) NMSysconfigSettings receives the signal and adds it to it's connection list.
+
+		   This does not work if none of the plugins is able to write, but that is sort of by design - 
+		   if the connection is not saved, it won't be available after reboot and that would be very
+		   inconsistent. Perhaps we should fail this call here as well, but with multiple plugins,
+		   it's not very clear which failures we can ignore and which ones we can't.
+		*/
+
+		for (iter = priv->plugins; iter; iter = iter->next)
+			nm_system_config_interface_add_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection);
+
+		g_object_unref (connection);
+		return TRUE;
+	} else {
+		/* Invalid connection hash */
+		/* FIXME: Set error */
+		return FALSE;
+	}
+}

Modified: trunk/system-settings/src/dbus-settings.h
==============================================================================
--- trunk/system-settings/src/dbus-settings.h	(original)
+++ trunk/system-settings/src/dbus-settings.h	Tue Apr 22 14:48:02 2008
@@ -25,7 +25,8 @@
 #include <nm-connection.h>
 #include <nm-settings.h>
 
-#define NM_SS_PLUGIN_TAG "nm-ss-plugin"
+#include "nm-system-config-interface.h"
+#include "nm-system-config-hal-manager.h"
 
 typedef struct _NMSysconfigExportedConnection NMSysconfigExportedConnection;
 typedef struct _NMSysconfigExportedConnectionClass NMSysconfigExportedConnectionClass;
@@ -85,11 +86,15 @@
 
 GType nm_sysconfig_settings_get_type (void);
 
-NMSysconfigSettings *nm_sysconfig_settings_new (DBusGConnection *g_conn);
+NMSysconfigSettings *nm_sysconfig_settings_new (DBusGConnection *g_conn,
+						NMSystemConfigHalManager *hal_mgr);
+
+void nm_sysconfig_settings_add_plugin     (NMSysconfigSettings *settings,
+					   NMSystemConfigInterface *plugin);
 
 void nm_sysconfig_settings_add_connection (NMSysconfigSettings *settings,
-                                           NMConnection *connection,
-                                           DBusGConnection *g_connection);
+					   NMSystemConfigInterface *plugin,
+                                           NMConnection *connection);
 
 void nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings,
                                               NMConnection *connection);

Modified: trunk/system-settings/src/main.c
==============================================================================
--- trunk/system-settings/src/main.c	(original)
+++ trunk/system-settings/src/main.c	Tue Apr 22 14:48:02 2008
@@ -47,8 +47,6 @@
 #include "nm-system-config-hal-manager-private.h"
 #include "nm-system-config-interface.h"
 
-#define NM_SS_CONNECTIONS_TAG "nm-ss-connections"
-
 typedef struct {
 	DBusConnection *connection;
 	DBusGConnection *g_connection;
@@ -60,8 +58,6 @@
 	NMSysconfigSettings *settings;
 	GMainLoop *loop;
 
-	GSList *plugins;   /* In priority order */
-
 	GHashTable *wired_devices;
 } Application;
 
@@ -84,71 +80,6 @@
 	return error_quark;
 }
 
-
-
-static void
-connection_added_cb (NMSystemConfigInterface *config,
-                     NMConnection *connection,
-                     Application *app)
-{
-	GSList **connections;
-
-	connections = g_object_get_data (G_OBJECT (config), NM_SS_CONNECTIONS_TAG);
-	*connections = g_slist_append (*connections, connection);
-
-	nm_sysconfig_settings_add_connection (app->settings, connection, app->g_connection);
-}
-
-static void
-connection_removed_cb (NMSystemConfigInterface *config,
-                       NMConnection *connection,
-                       Application *app)
-{
-	GSList **connections;
-
-	connections = g_object_get_data (G_OBJECT (config), NM_SS_CONNECTIONS_TAG);
-	*connections = g_slist_remove (*connections, connection);
-
-	nm_sysconfig_settings_remove_connection (app->settings, connection);
-}
-
-static void
-connection_updated_cb (NMSystemConfigInterface *config,
-                       NMConnection *connection,
-                       Application *app)
-{
-	nm_sysconfig_settings_update_connection (app->settings, connection);
-}
-
-static void
-unmanaged_devices_changed_cb (NMSystemConfigInterface *config,
-                              Application *app)
-{
-	GSList *udis = NULL, *temp, *iter;
-
-	/* Ask all the plugins for their unmanaged devices */
-	for (iter = app->plugins; iter; iter = g_slist_next (iter)) {
-		temp = nm_system_config_interface_get_unmanaged_devices (NM_SYSTEM_CONFIG_INTERFACE (iter->data));
-		udis = g_slist_concat (udis, temp);
-	}
-
-	nm_sysconfig_settings_update_unamanged_devices (app->settings, udis);
-	g_slist_foreach (udis, (GFunc) g_free, NULL);
-	g_slist_free (udis);
-}
-
-static void
-register_plugin (Application *app, NMSystemConfigInterface *plugin)
-{
-	g_signal_connect (plugin, "connection-added", (GCallback) connection_added_cb, app);
-	g_signal_connect (plugin, "connection-removed", (GCallback) connection_removed_cb, app);
-	g_signal_connect (plugin, "connection-updated", (GCallback) connection_updated_cb, app);
-
-	g_signal_connect (plugin, "unmanaged-devices-changed", (GCallback) unmanaged_devices_changed_cb, app);
-
-	nm_system_config_interface_init (plugin, app->hal_mgr);
-}
-
 static GObject *
 find_plugin (GSList *list, const char *pname)
 {
@@ -171,7 +102,7 @@
 	return NULL;
 }
 
-static GSList *
+static gboolean
 load_plugins (Application *app, const char *plugins, GError **error)
 {
 	GSList *list = NULL;
@@ -180,7 +111,7 @@
 
 	plist = g_strsplit (plugins, ",", 0);
 	if (!plist)
-		return NULL;
+		return FALSE;
 
 	for (pname = plist; *pname; pname++) {
 		GModule *plugin;
@@ -225,44 +156,17 @@
 		}
 
 		g_module_make_resident (plugin);
-		g_object_set_data_full (obj, "nm-ss-plugin", plugin, (GDestroyNotify) g_module_close);
-		register_plugin (app, NM_SYSTEM_CONFIG_INTERFACE (obj));
+		g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
+		nm_sysconfig_settings_add_plugin (app->settings, NM_SYSTEM_CONFIG_INTERFACE (obj));
 		list = g_slist_append (list, obj);
 	}
-	
-	g_strfreev (plist);
-	return list;
-}
 
-static void
-print_plugin_info (gpointer item, gpointer user_data)
-{
-	NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (item);
-	char *pname;
-	char *pinfo;
-
-	g_object_get (G_OBJECT (plugin),
-	              NM_SYSTEM_CONFIG_INTERFACE_NAME,
-	              &pname,
-	              NULL);
-
-	g_object_get (G_OBJECT (plugin),
-	              NM_SYSTEM_CONFIG_INTERFACE_INFO,
-	              &pinfo,
-	              NULL);
-
-	g_message ("   %s: %s", pname, pinfo);
-	g_free (pname);
-	g_free (pinfo);
-}
+	g_strfreev (plist);
 
-static void
-free_plugin_connections (gpointer data)
-{
-	GSList **connections = (GSList **) data;
+	g_slist_foreach (list, (GFunc) g_object_unref, NULL);
+	g_slist_free (list);
 
-	g_slist_foreach (*connections, (GFunc) g_object_unref, NULL);
-	g_slist_free (*connections);
+	return TRUE;
 }
 
 static gboolean
@@ -271,34 +175,6 @@
 	Application *app = (Application *) user_data;
 	GSList *devs, *iter;
 
-	g_return_val_if_fail (app != NULL, FALSE);
-
-	for (iter = app->plugins; iter; iter = g_slist_next (iter)) {
-		NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
-		GSList *plugin_connections, **connections;
-		GSList *elt;
-
-		plugin_connections = nm_system_config_interface_get_connections (plugin);
-
-		connections = g_malloc0 (sizeof (GSList *));
-		g_object_set_data_full (G_OBJECT (plugin), NM_SS_CONNECTIONS_TAG,
-		                        connections, free_plugin_connections);
-
-		// FIXME: ensure connections from plugins loaded with a lower priority
-		// get rejected when they conflict with connections from a higher
-		// priority plugin.
-
-		for (elt = plugin_connections; elt; elt = g_slist_next (elt)) {
-			g_object_ref (NM_CONNECTION (elt->data));
-			g_object_set_data (G_OBJECT (elt->data), NM_SS_PLUGIN_TAG, plugin);
-			connection_added_cb (NM_SYSTEM_CONFIG_INTERFACE (plugin), NM_CONNECTION (elt->data), app);
-		}
-
-		g_slist_free (plugin_connections);
-	}
-
-	unmanaged_devices_changed_cb (NULL, app);
-
 	/* Grab wired devices to make default DHCP connections for them if needed */
 	devs = nm_system_config_hal_manager_get_devices_of_type (app->hal_mgr, DEVICE_TYPE_802_3_ETHERNET);
 	for (iter = devs; iter; iter = g_slist_next (iter))
@@ -480,9 +356,8 @@
 	g_byte_array_append (s_wired->mac_address, info->mac->data, ETH_ALEN);
 	nm_connection_add_setting (info->connection, NM_SETTING (s_wired));
 
-	nm_sysconfig_settings_add_connection (info->app->settings,
-	                                      info->connection,
-	                                      info->app->g_connection);
+	nm_sysconfig_settings_add_connection (info->app->settings, NULL, info->connection);
+
 	return FALSE;
 
 ignore:
@@ -782,27 +657,23 @@
 	if (!dbus_init (app))
 		return -1;
 
-	app->settings = nm_sysconfig_settings_new (app->g_connection);
+	app->hal_mgr = nm_system_config_hal_manager_get (app->g_connection);
+	app->settings = nm_sysconfig_settings_new (app->g_connection, app->hal_mgr);
 
 	app->wired_devices = g_hash_table_new_full (g_str_hash, g_str_equal,
 	                                            g_free, wired_device_info_destroy);
-	app->hal_mgr = nm_system_config_hal_manager_get (app->g_connection);
 	g_signal_connect (G_OBJECT (app->hal_mgr), "device-added",
 	                  G_CALLBACK (device_added_cb), app);
 	g_signal_connect (G_OBJECT (app->hal_mgr), "device-removed",
 	                  G_CALLBACK (device_removed_cb), app);
 
 	/* Load the plugins; fail if a plugin is not found. */
-	app->plugins = load_plugins (app, plugins, &error);
+	load_plugins (app, plugins, &error);
 	if (error) {
-		g_slist_foreach (app->plugins, (GFunc) g_object_unref, NULL);
-		g_slist_free (app->plugins);
 		g_warning ("Error: %d - %s", error->code, error->message);
 		return -1;
 	}
 	g_free (plugins);
-	g_message ("Loaded plugins:");
-	g_slist_foreach (app->plugins, print_plugin_info, NULL);
 
 	g_idle_add (load_stuff, app);
 
@@ -810,9 +681,6 @@
 
 	g_hash_table_destroy (app->wired_devices);
 
-	g_slist_foreach (app->plugins, (GFunc) g_object_unref, NULL);
-	g_slist_free (app->plugins);
-
 	g_object_unref (app->settings);
 	g_object_unref (app->hal_mgr);
 

Modified: trunk/system-settings/src/nm-system-config-interface.c
==============================================================================
--- trunk/system-settings/src/nm-system-config-interface.c	(original)
+++ trunk/system-settings/src/nm-system-config-interface.c	Tue Apr 22 14:48:02 2008
@@ -161,3 +161,35 @@
 	return NULL;
 }
 
+void
+nm_system_config_interface_add_connection (NMSystemConfigInterface *config,
+								   NMConnection *connection)
+{
+	g_return_if_fail (config != NULL);
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection)
+		NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection);
+}
+
+void
+nm_system_config_interface_update_connection (NMSystemConfigInterface *config,
+									 NMConnection *connection)
+{
+	g_return_if_fail (config != NULL);
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->update_connection)
+		NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->update_connection (config, connection);
+}
+
+void
+nm_system_config_interface_remove_connection (NMSystemConfigInterface *config,
+									 NMConnection *connection)
+{
+	g_return_if_fail (config != NULL);
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->remove_connection)
+		NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->remove_connection (config, connection);
+}

Modified: trunk/system-settings/src/nm-system-config-interface.h
==============================================================================
--- trunk/system-settings/src/nm-system-config-interface.h	(original)
+++ trunk/system-settings/src/nm-system-config-interface.h	Tue Apr 22 14:48:02 2008
@@ -99,6 +99,22 @@
 	 */
 	GSList * (*get_unmanaged_devices) (NMSystemConfigInterface *config);
 
+	/*
+	 * Add a new connection.
+	 */
+	void     (*add_connection) (NMSystemConfigInterface *config, NMConnection *connection);
+
+	/*
+	 * Update the connection.
+	 */
+	void     (*update_connection) (NMSystemConfigInterface *config, NMConnection *connection);
+
+	/*
+	 * Remove the connection.
+	 */
+	void     (*remove_connection) (NMSystemConfigInterface *config, NMConnection *connection);
+
+
 	/* Signals */
 
 	/* Emitted when a new connection has been found by the plugin */
@@ -127,6 +143,15 @@
 
 GSList *nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *config);
 
+void nm_system_config_interface_add_connection (NMSystemConfigInterface *config,
+						NMConnection *connection);
+
+void nm_system_config_interface_update_connection (NMSystemConfigInterface *config,
+						   NMConnection *connection);
+
+void nm_system_config_interface_remove_connection (NMSystemConfigInterface *config,
+						   NMConnection *connection);
+
 G_END_DECLS
 
 #endif	/* NM_SYSTEM_CONFIG_INTERFACE_H */



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