NetworkManager r3656 - in trunk: . system-settings/plugins/ifcfg-fedora system-settings/src



Author: dcbw
Date: Sun May 11 20:20:52 2008
New Revision: 3656
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3656&view=rev

Log:
2008-05-11  Dan Williams  <dcbw redhat com>

	Update Fedora system-settings plugin to support latest API and use
	GFileMonitor rather than home-rolled inotify code.

	* system-settings/plugins/ifcfg-fedora/Makefile.am
	  system-settings/plugins/ifcfg-fedora/common.h
	  system-settings/plugins/ifcfg-fedora/plugin.c
		- Update to latest system settings plugin API; use GIO instead of
			custom inotify code; use NMIfcfgConnection objects instead of
			ConnectionData structures tacked onto NMConnection objects

	* system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.c
	  system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.h
		- Implement an NMExportedConnection subclass mapping ifcfg files to
			connections

	* system-settings/plugins/ifcfg-fedora/reader.c
	  system-settings/plugins/ifcfg-fedora/reader.h
		- Move ifcfg parsing bits here from parser.c

	* system-settings/plugins/ifcfg-fedora/parser.c
	  system-settings/plugins/ifcfg-fedora/parser.h
		- Remove; most code moved to reader.c



Added:
   trunk/system-settings/plugins/ifcfg-fedora/common.h
   trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.c
   trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.h
   trunk/system-settings/plugins/ifcfg-fedora/reader.c
   trunk/system-settings/plugins/ifcfg-fedora/reader.h
Removed:
   trunk/system-settings/plugins/ifcfg-fedora/parser.c
   trunk/system-settings/plugins/ifcfg-fedora/parser.h
Modified:
   trunk/ChangeLog
   trunk/system-settings/plugins/ifcfg-fedora/Makefile.am
   trunk/system-settings/plugins/ifcfg-fedora/plugin.c
   trunk/system-settings/src/dbus-settings.c

Modified: trunk/system-settings/plugins/ifcfg-fedora/Makefile.am
==============================================================================
--- trunk/system-settings/plugins/ifcfg-fedora/Makefile.am	(original)
+++ trunk/system-settings/plugins/ifcfg-fedora/Makefile.am	Sun May 11 20:20:52 2008
@@ -4,10 +4,13 @@
 libnm_settings_plugin_ifcfg_fedora_la_SOURCES = \
 	shvar.c \
 	shvar.h \
-	parser.c \
-	parser.h \
 	plugin.c \
-	plugin.h
+	plugin.h \
+	nm-ifcfg-connection.c \
+	nm-ifcfg-connection.h \
+	reader.c \
+	reader.h \
+	common.h
 
 libnm_settings_plugin_ifcfg_fedora_la_CPPFLAGS = \
 	$(GLIB_CFLAGS) \
@@ -16,6 +19,7 @@
 	-DG_DISABLE_DEPRECATED \
 	-I${top_srcdir}/system-settings/src \
 	-I$(top_srcdir)/include \
+	-I$(top_srcdir)/libnm-glib \
 	-I$(top_srcdir)/libnm-util \
 	-DSYSCONFDIR=\"$(sysconfdir)\"
 
@@ -23,5 +27,14 @@
 libnm_settings_plugin_ifcfg_fedora_la_LIBADD = \
 	$(GLIB_LIBS) \
 	$(GMODULE_LIBS) \
-	$(top_builddir)/libnm-util/libnm-util.la
+	$(top_builddir)/libnm-util/libnm-util.la \
+	$(top_builddir)/libnm-glib/libnm_glib.la
+
+if NO_GIO
+libnm_settings_plugin_ifcfg_fedora_la_LIBADD += \
+	$(top_builddir)/gfilemonitor/libgfilemonitor.la
+else
+libnm_settings_plugin_ifcfg_fedora_la_LIBADD += \
+	$(GIO_LIBS)
+endif
 

Added: trunk/system-settings/plugins/ifcfg-fedora/common.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/ifcfg-fedora/common.h	Sun May 11 20:20:52 2008
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#define IFCFG_TAG "ifcfg-"
+#define KEYS_TAG "keys-"
+#define BAK_TAG ".bak"
+#define TILDE_TAG "~"
+#define ORIG_TAG ".orig"
+#define REJ_TAG ".rej"
+
+#include <glib.h>
+
+GQuark ifcfg_plugin_error_quark (void);
+
+
+#endif  /* __COMMON_H__ */
+

Added: trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.c
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.c	Sun May 11 20:20:52 2008
@@ -0,0 +1,422 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include <string.h>
+#include <net/ethernet.h>
+#include <netinet/ether.h>
+
+#include <glib/gstdio.h>
+
+#include <NetworkManager.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-setting-gsm.h>
+#include <nm-setting-cdma.h>
+#include <nm-setting-pppoe.h>
+#include <nm-setting-wireless-security.h>
+#include <nm-setting-8021x.h>
+
+#include "common.h"
+#include "nm-ifcfg-connection.h"
+#include "nm-system-config-hal-manager.h"
+#include "reader.h"
+
+G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_EXPORTED_CONNECTION)
+
+#define NM_IFCFG_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionPrivate))
+
+typedef struct {
+	char *filename;
+	char *keyfile;
+
+	char *udi;
+	gboolean unmanaged;
+
+	NMSystemConfigHalManager *hal_mgr;
+	DBusGConnection *g_connection;
+	gulong daid;
+} NMIfcfgConnectionPrivate;
+
+enum {
+	PROP_0,
+	PROP_FILENAME,
+	PROP_UNMANAGED,
+	PROP_UDI,
+
+	LAST_PROP
+};
+
+static char *
+get_ether_device_udi (DBusGConnection *g_connection, GByteArray *mac, GSList *devices)
+{
+	GError *error = NULL;
+	GSList *iter;
+	char *udi = NULL;
+
+	if (!g_connection || !mac)
+		return NULL;
+
+	for (iter = devices; !udi && iter; iter = g_slist_next (iter)) {
+		DBusGProxy *dev_proxy;
+		char *address = NULL;
+
+		dev_proxy = dbus_g_proxy_new_for_name (g_connection,
+		                                       "org.freedesktop.Hal",
+		                                       iter->data,
+		                                       "org.freedesktop.Hal.Device");
+		if (!dev_proxy)
+			continue;
+
+		if (dbus_g_proxy_call_with_timeout (dev_proxy,
+		                                    "GetPropertyString", 10000, &error,
+		                                    G_TYPE_STRING, "net.address", G_TYPE_INVALID,
+		                                    G_TYPE_STRING, &address, G_TYPE_INVALID)) {		
+			struct ether_addr *dev_mac;
+
+			if (address && strlen (address)) {
+				dev_mac = ether_aton (address);
+				if (!memcmp (dev_mac->ether_addr_octet, mac->data, ETH_ALEN))
+					udi = g_strdup (iter->data);
+			}
+		} else {
+			g_error_free (error);
+			error = NULL;
+		}
+		g_free (address);
+		g_object_unref (dev_proxy);
+	}
+
+	return udi;
+}
+
+static NMDeviceType
+get_device_type_for_connection (NMConnection *connection)
+{
+	NMDeviceType devtype = DEVICE_TYPE_UNKNOWN;
+	NMSettingConnection *s_con;
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+	if (!s_con)
+		return DEVICE_TYPE_UNKNOWN;
+
+	if (   !strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME)
+	    || !strcmp (s_con->type, NM_SETTING_PPPOE_SETTING_NAME)) {
+		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED))
+			devtype = DEVICE_TYPE_802_3_ETHERNET;
+	} else if (!strcmp (s_con->type, NM_SETTING_WIRELESS_SETTING_NAME)) {
+		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS))
+			devtype = DEVICE_TYPE_802_11_WIRELESS;
+	} else if (!strcmp (s_con->type, NM_SETTING_GSM_SETTING_NAME)) {
+		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM))
+			devtype = DEVICE_TYPE_GSM;
+	} else if (!strcmp (s_con->type, NM_SETTING_CDMA_SETTING_NAME)) {
+		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA))
+			devtype = DEVICE_TYPE_CDMA;
+	}
+
+	return devtype;
+}
+
+static char *
+get_udi_for_connection (NMConnection *connection,
+                        DBusGConnection *g_connection,
+                        NMSystemConfigHalManager *hal_mgr,
+                        NMDeviceType devtype)
+{
+	NMSettingWired *s_wired;
+	NMSettingWireless *s_wireless;
+	char *udi = NULL;
+	GSList *devices = NULL;
+
+	if (devtype == DEVICE_TYPE_UNKNOWN)
+		devtype = get_device_type_for_connection (connection);
+
+	switch (devtype) {
+	case DEVICE_TYPE_802_3_ETHERNET:
+		s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
+		if (s_wired) {
+			devices = nm_system_config_hal_manager_get_devices_of_type (hal_mgr, DEVICE_TYPE_802_3_ETHERNET);
+			udi = get_ether_device_udi (g_connection, s_wired->mac_address, devices);
+		}
+		break;
+
+	case DEVICE_TYPE_802_11_WIRELESS:
+		s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
+		if (s_wireless) {
+			devices = nm_system_config_hal_manager_get_devices_of_type (hal_mgr, DEVICE_TYPE_802_11_WIRELESS);
+			udi = get_ether_device_udi (g_connection, s_wireless->mac_address, devices);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	g_slist_foreach (devices, (GFunc) g_free, NULL);
+	g_slist_free (devices);
+
+	return udi;
+}
+
+static void
+device_added_cb (NMSystemConfigHalManager *hal_mgr,
+                 const char *udi,
+                 NMDeviceType devtype,
+                 gpointer user_data)
+{
+	NMIfcfgConnection *connection = NM_IFCFG_CONNECTION (user_data);
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
+	NMConnection *wrapped;
+
+	/* Should only be called when udi is NULL */
+	g_return_if_fail (priv->udi == NULL);
+
+	wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (connection));
+	if (devtype != get_device_type_for_connection (wrapped))
+		return;
+
+	priv->udi = get_udi_for_connection (wrapped, priv->g_connection, priv->hal_mgr, devtype);
+	if (!priv->udi)
+		return;
+
+	/* If the connection is unmanaged we have to tell the plugin */
+	if (priv->unmanaged)
+		g_object_notify (G_OBJECT (connection), NM_IFCFG_CONNECTION_UNMANAGED);
+
+	g_signal_handler_disconnect (G_OBJECT (hal_mgr), priv->daid);
+	priv->daid = 0;
+}
+
+NMIfcfgConnection *
+nm_ifcfg_connection_new (const char *filename,
+                         DBusGConnection *g_connection,
+                         NMSystemConfigHalManager *hal_mgr,
+                         GError **error)
+{
+	GObject *object;
+	NMConnection *wrapped;
+	gboolean unmanaged = FALSE;
+	char *udi;
+
+	g_return_val_if_fail (filename != NULL, NULL);
+
+	wrapped = connection_from_file (filename, &unmanaged, error);
+	if (!wrapped)
+		return NULL;
+
+	udi = get_udi_for_connection (wrapped, g_connection, hal_mgr, DEVICE_TYPE_UNKNOWN);
+
+	object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
+	                                   NM_IFCFG_CONNECTION_FILENAME, filename,
+	                                   NM_IFCFG_CONNECTION_UNMANAGED, unmanaged,
+	                                   NM_IFCFG_CONNECTION_UDI, udi,
+	                                   NM_EXPORTED_CONNECTION_CONNECTION, wrapped,
+	                                   NULL);
+	if (object && !udi) {
+		NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+		priv->hal_mgr = g_object_ref (hal_mgr);
+		priv->g_connection = dbus_g_connection_ref (g_connection);
+		priv->daid = g_signal_connect (priv->hal_mgr, "device-added", G_CALLBACK (device_added_cb), object);
+	}
+
+	g_object_unref (wrapped);
+	g_free (udi);
+	return (NMIfcfgConnection *) object;
+}
+
+const char *
+nm_ifcfg_connection_get_filename (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->filename;
+}
+
+const char *
+nm_ifcfg_connection_get_udi (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->udi;
+}
+
+gboolean
+nm_ifcfg_connection_get_unmanaged (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), FALSE);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged;
+}
+
+static GHashTable *
+get_settings (NMExportedConnection *exported)
+{
+	return nm_connection_to_hash (nm_exported_connection_get_connection (exported));
+}
+
+static const char *
+get_id (NMExportedConnection *exported)
+{
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (exported)->filename;
+}
+
+static gboolean
+update (NMExportedConnection *exported, GHashTable *new_settings, GError **error)
+{
+//	write_connection (NM_IFCFG_CONNECTION (exported));
+	return TRUE;
+}
+
+static gboolean
+delete (NMExportedConnection *exported, GError **error)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (exported);
+
+	g_unlink (priv->filename);
+	if (priv->keyfile)
+		g_unlink (priv->keyfile);
+
+	return TRUE;
+}
+
+/* GObject */
+
+static void
+nm_ifcfg_connection_init (NMIfcfgConnection *connection)
+{
+}
+
+static void
+finalize (GObject *object)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+	NMConnection *wrapped;
+
+	wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (object));
+	if (wrapped)
+		nm_connection_clear_secrets (wrapped);
+
+	g_free (priv->filename);
+	g_free (priv->udi);
+
+	if (priv->hal_mgr) {
+		if (priv->daid)
+			g_signal_handler_disconnect (G_OBJECT (priv->hal_mgr), priv->daid);
+
+		g_object_unref (priv->hal_mgr);
+	}
+
+	if (priv->g_connection)
+		dbus_g_connection_unref (priv->g_connection);
+
+	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->finalize (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+		    const GValue *value, GParamSpec *pspec)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_FILENAME:
+		/* Construct only */
+		priv->filename = g_value_dup_string (value);
+		break;
+	case PROP_UNMANAGED:
+		priv->unmanaged = g_value_get_boolean (value);
+		break;
+	case PROP_UDI:
+		/* Construct only */
+		priv->udi = g_value_dup_string (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+		    GValue *value, GParamSpec *pspec)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_FILENAME:
+		g_value_set_string (value, priv->filename);
+		break;
+	case PROP_UNMANAGED:
+		g_value_set_boolean (value, priv->unmanaged);
+		break;
+	case PROP_UDI:
+		g_value_set_string (value, priv->udi);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (ifcfg_connection_class);
+	NMExportedConnectionClass *connection_class = NM_EXPORTED_CONNECTION_CLASS (ifcfg_connection_class);
+
+	g_type_class_add_private (ifcfg_connection_class, sizeof (NMIfcfgConnectionPrivate));
+
+	/* Virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->finalize     = finalize;
+
+	connection_class->get_settings = get_settings;
+	connection_class->get_id       = get_id;
+	connection_class->update       = update;
+	connection_class->delete       = delete;
+
+	/* Properties */
+	g_object_class_install_property
+		(object_class, PROP_FILENAME,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_FILENAME,
+						  "FileName",
+						  "File name",
+						  NULL,
+						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property
+		(object_class, PROP_UNMANAGED,
+		 g_param_spec_boolean (NM_IFCFG_CONNECTION_UNMANAGED,
+						  "Unmanaged",
+						  "Unmanaged",
+						  FALSE,
+						  G_PARAM_READWRITE));
+
+	g_object_class_install_property
+		(object_class, PROP_UDI,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_UDI,
+						  "UDI",
+						  "UDI",
+						  NULL,
+						  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}

Added: trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/ifcfg-fedora/nm-ifcfg-connection.h	Sun May 11 20:20:52 2008
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef NM_IFCFG_CONNECTION_H
+#define NM_IFCFG_CONNECTION_H
+
+G_BEGIN_DECLS
+
+#include <nm-settings.h>
+#include "nm-system-config-hal-manager.h"
+
+#define NM_TYPE_IFCFG_CONNECTION            (nm_ifcfg_connection_get_type ())
+#define NM_IFCFG_CONNECTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnection))
+#define NM_IFCFG_CONNECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass))
+#define NM_IS_IFCFG_CONNECTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION))
+#define NM_IS_IFCFG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION))
+#define NM_IFCFG_CONNECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass))
+
+#define NM_IFCFG_CONNECTION_FILENAME  "filename"
+#define NM_IFCFG_CONNECTION_UNMANAGED "unmanaged"
+#define NM_IFCFG_CONNECTION_UDI       "udi"
+
+typedef struct {
+	NMExportedConnection parent;
+} NMIfcfgConnection;
+
+typedef struct {
+	NMExportedConnectionClass parent;
+} NMIfcfgConnectionClass;
+
+GType nm_ifcfg_connection_get_type (void);
+
+NMIfcfgConnection *nm_ifcfg_connection_new (const char *filename,
+                                            DBusGConnection *g_connection,
+                                            NMSystemConfigHalManager *hal_mgr,
+                                            GError **error);
+
+const char *nm_ifcfg_connection_get_filename (NMIfcfgConnection *self);
+
+const char *nm_ifcfg_connection_get_udi (NMIfcfgConnection *self);
+
+gboolean nm_ifcfg_connection_get_unmanaged (NMIfcfgConnection *self);
+
+G_END_DECLS
+
+#endif /* NM_IFCFG_CONNECTION_H */

Modified: trunk/system-settings/plugins/ifcfg-fedora/plugin.c
==============================================================================
--- trunk/system-settings/plugins/ifcfg-fedora/plugin.c	(original)
+++ trunk/system-settings/plugins/ifcfg-fedora/plugin.c	Sun May 11 20:20:52 2008
@@ -16,14 +16,14 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * (C) Copyright 2007 Red Hat, Inc.
+ * (C) Copyright 2008 Red Hat, Inc.
  */
 
+#include <config.h>
 #include <gmodule.h>
 #include <glib-object.h>
 #include <glib/gi18n.h>
 #include <string.h>
-#include <sys/inotify.h>
 #include <unistd.h>
 #include <errno.h>
 #include <net/ethernet.h>
@@ -32,19 +32,18 @@
 #include <dbus/dbus-glib.h>
 
 #include <nm-setting-connection.h>
-#include <nm-setting-wired.h>
-#include <nm-setting-wireless.h>
-#include <nm-setting-gsm.h>
-#include <nm-setting-cdma.h>
-#include <nm-setting-pppoe.h>
-#include <nm-setting-wireless-security.h>
-#include <nm-setting-8021x.h>
 
+#ifndef NO_GIO
+#include <gio/gio.h>
+#else
+#include <gfilemonitor/gfilemonitor.h>
+#endif
+
+#include "common.h"
 #include "nm-dbus-glib-types.h"
 #include "plugin.h"
-#include "parser.h"
-#include "shvar.h"
 #include "nm-system-config-interface.h"
+#include "nm-ifcfg-connection.h"
 
 #define IFCFG_PLUGIN_NAME "ifcfg-fedora"
 #define IFCFG_PLUGIN_INFO "(c) 2007 - 2008 Red Hat, Inc.  To report bugs please use the NetworkManager mailing list."
@@ -61,16 +60,13 @@
 
 
 typedef struct {
-	gboolean initialized;
-
 	DBusGConnection *g_connection;
 	NMSystemConfigHalManager *hal_mgr;
 
-	GSList *connections;
+	GHashTable *connections;
 
-	int ifd;
-	int wd;
-	GHashTable *watch_table;
+	GFileMonitor *monitor;
+	guint monitor_id;
 } SCPluginIfcfgPrivate;
 
 
@@ -85,804 +81,295 @@
 	return error_quark;
 }
 
-static char *
-get_ether_device_udi (SCPluginIfcfg *plugin, GByteArray *mac, GSList *devices)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GError *error = NULL;
-	GSList *iter;
-	char *udi = NULL;
-
-	if (!priv->g_connection || !mac)
-		return NULL;
-
-	for (iter = devices; !udi && iter; iter = g_slist_next (iter)) {
-		DBusGProxy *dev_proxy;
-		char *address = NULL;
-
-		dev_proxy = dbus_g_proxy_new_for_name (priv->g_connection,
-		                                       "org.freedesktop.Hal",
-		                                       iter->data,
-		                                       "org.freedesktop.Hal.Device");
-		if (!dev_proxy)
-			continue;
-
-		if (dbus_g_proxy_call_with_timeout (dev_proxy,
-		                                    "GetPropertyString", 10000, &error,
-		                                    G_TYPE_STRING, "net.address", G_TYPE_INVALID,
-		                                    G_TYPE_STRING, &address, G_TYPE_INVALID)) {		
-			struct ether_addr *dev_mac;
-
-			if (address && strlen (address)) {
-				dev_mac = ether_aton (address);
-				if (!memcmp (dev_mac->ether_addr_octet, mac->data, ETH_ALEN))
-					udi = g_strdup (iter->data);
-			}
-		} else {
-			g_error_free (error);
-			error = NULL;
-		}
-		g_free (address);
-		g_object_unref (dev_proxy);
-	}
-
-	return udi;
-}
-
-static NMDeviceType
-get_device_type_for_connection (NMConnection *connection)
-{
-	NMDeviceType devtype = DEVICE_TYPE_UNKNOWN;
-	NMSettingConnection *s_con;
-
-	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
-	if (!s_con)
-		return DEVICE_TYPE_UNKNOWN;
-
-	if (   !strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME)
-	    || !strcmp (s_con->type, NM_SETTING_PPPOE_SETTING_NAME)) {
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED))
-			devtype = DEVICE_TYPE_802_3_ETHERNET;
-	} else if (!strcmp (s_con->type, NM_SETTING_WIRELESS_SETTING_NAME)) {
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS))
-			devtype = DEVICE_TYPE_802_11_WIRELESS;
-	} else if (!strcmp (s_con->type, NM_SETTING_GSM_SETTING_NAME)) {
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM))
-			devtype = DEVICE_TYPE_GSM;
-	} else if (!strcmp (s_con->type, NM_SETTING_CDMA_SETTING_NAME)) {
-		if (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA))
-			devtype = DEVICE_TYPE_CDMA;
-	}
-
-	return devtype;
-}
-
-static char *
-get_udi_for_connection (SCPluginIfcfg *plugin, NMConnection *connection, NMDeviceType devtype)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	NMSettingWired *s_wired;
-	NMSettingWireless *s_wireless;
-	char *udi = NULL;
-	GSList *devices = NULL;
-
-	if (devtype == DEVICE_TYPE_UNKNOWN)
-		devtype = get_device_type_for_connection (connection);
-
-	switch (devtype) {
-	case DEVICE_TYPE_802_3_ETHERNET:
-		s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED);
-		if (s_wired) {
-			devices = nm_system_config_hal_manager_get_devices_of_type (priv->hal_mgr, DEVICE_TYPE_802_3_ETHERNET);
-			udi = get_ether_device_udi (plugin, s_wired->mac_address, devices);
-		}
-		break;
-
-	case DEVICE_TYPE_802_11_WIRELESS:
-		s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
-		if (s_wireless) {
-			devices = nm_system_config_hal_manager_get_devices_of_type (priv->hal_mgr, DEVICE_TYPE_802_11_WIRELESS);
-			udi = get_ether_device_udi (plugin, s_wireless->mac_address, devices);
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	g_slist_foreach (devices, (GFunc) g_free, NULL);
-	g_slist_free (devices);
-
-	return udi;
-}
-
 static void
-device_added_cb (NMSystemConfigHalManager *hal_mgr,
-                 const char *udi,
-                 NMDeviceType devtype,
-                 gpointer user_data)
+check_unmanaged (gpointer key, gpointer data, gpointer user_data)
 {
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	GSList **list = (GSList **) user_data;
+	NMIfcfgConnection *connection = NM_IFCFG_CONNECTION (data);
+	const char *udi;
 	GSList *iter;
-	gboolean changed = FALSE;
-
-	/* Try to get the UDI for all connections that don't have a UDI yet */
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *connection = NM_CONNECTION (iter->data);
-		ConnectionData *cdata = connection_data_get (connection);
-
-		if (!cdata->udi) {
-			cdata->udi = get_udi_for_connection (plugin, connection, devtype);
-			if (cdata->udi && cdata->ignored)
-				changed = TRUE;
-		}
-	}
 
-	if (changed)
-		g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
-}
+	if (!nm_ifcfg_connection_get_unmanaged (connection))
+		return;
 
-static void
-device_removed_cb (NMSystemConfigHalManager *hal_mgr,
-                   const char *udi,
-                   NMDeviceType devtype,
-                   gpointer user_data)
-{
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GSList *iter;
-	gboolean changed = FALSE;
+	udi = nm_ifcfg_connection_get_udi (connection);
+	if (!udi)
+		return;
 
-	/* Try to get the UDI for all connections that don't have a UDI yet */
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *connection = NM_CONNECTION (iter->data);
-		ConnectionData *cdata = connection_data_get (connection);
-
-		if (cdata->udi && !strcmp (cdata->udi, udi)) {
-			g_free (cdata->udi);
-			cdata->udi = NULL;
-			if (cdata->ignored)
-				changed = TRUE;
-		}
+	/* Just return if the UDI is already in the list */
+	for (iter = *list; iter; iter = g_slist_next (iter)) {
+		if (!strcmp ((char *) iter->data, udi))
+			return;
 	}
 
-	if (changed)
-		g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+	*list = g_slist_prepend (*list, g_strdup (udi));
 }
 
 static GSList *
 get_unmanaged_devices (NMSystemConfigInterface *config)
 {
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GSList *copy = NULL, *iter;
-
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		ConnectionData *cdata = connection_data_get (NM_CONNECTION (iter->data));
-
-		if (cdata->ignored && cdata->udi)
-			copy = g_slist_append (copy, g_strdup (cdata->udi));
-	}
-	return copy;
-}
-
-struct FindInfo {
-	const char *path;
-	gboolean found;
-};
-
-static void
-find_watched_path (gpointer key, gpointer value, gpointer user_data)
-{
-	struct FindInfo *info = (struct FindInfo *) user_data;
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);	
+	GSList *list = NULL;
 
-	if (info->found)
-		return;
-
-	if (!strcmp (info->path, value)) {
-		info->found = TRUE;
-		return;
-	}
+	g_hash_table_foreach (priv->connections, check_unmanaged, &list);
+	return list;
 }
 
 static void
-watch_path (const char *path, const int inotify_fd, GHashTable *table)
+connection_unmanaged_changed (NMIfcfgConnection *connection,
+                              GParamSpec *pspec,
+                              gpointer user_data)
 {
-	int wd;
-	struct FindInfo info;
-
-	g_return_if_fail (g_path_is_absolute (path));
-
-	info.found = FALSE;
-	info.path = path;
-	g_hash_table_foreach (table, find_watched_path, &info);
-	if (info.found)
-		return;
-
-	wd = inotify_add_watch (inotify_fd, path,
-	                        IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MOVE | IN_MOVE_SELF | IN_DELETE_SELF);
-	if (wd == -1) {
-		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    inotify error watching '%s': errno %d",
-		              path, errno);
-	} else {
-		g_hash_table_insert (table, GINT_TO_POINTER (wd), g_strdup (path));
-	}
+	g_signal_emit_by_name (SC_PLUGIN_IFCFG (user_data), "unmanaged-devices-changed");
 }
 
-static NMConnection *
-build_one_connection (SCPluginIfcfg *plugin, const char *path)
+static NMIfcfgConnection *
+read_one_connection (SCPluginIfcfg *plugin, const char *filename)
 {
-	NMConnection *connection;
+	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
+	NMIfcfgConnection *connection;
 	GError *error = NULL;
 
-	g_return_val_if_fail (path != NULL, NULL);
-
-	PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", path);
+	PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", filename);
 
-	connection = parser_parse_file (path, &error);
+	connection = nm_ifcfg_connection_new (filename, priv->g_connection, priv->hal_mgr, &error);
 	if (connection) {
+		NMConnection *wrapped;
 		NMSettingConnection *s_con;
-		ConnectionData *cdata = connection_data_get (connection);
 
-		cdata->udi = get_udi_for_connection (plugin, connection, DEVICE_TYPE_UNKNOWN);
-
-		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
+		wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (connection));
+		g_assert (wrapped);
+		s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION));
 		g_assert (s_con);
 		g_assert (s_con->id);
+
+		g_hash_table_insert (priv->connections,
+		                     (gpointer) nm_ifcfg_connection_get_filename (connection),
+		                     g_object_ref (connection));
 		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    read connection '%s'", s_con->id);
+
+		if (nm_ifcfg_connection_get_unmanaged (connection)) {
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its "
+			              "device because NM_CONTROLLED was false.", s_con->id);
+			g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+		} else {
+			/* Wait for the connection to become unmanaged once it knows the
+			 * UDI of it's device, if/when the device gets plugged in.
+			 */
+			g_signal_connect (G_OBJECT (connection), "notify::unmanaged",
+			                  G_CALLBACK (connection_unmanaged_changed), plugin);
+		}
 	} else {
 		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    error: %s",
 		              error->message ? error->message : "(unknown)");
+		g_error_free (error);
 	}
 
 	return connection;
 }
 
-static NMConnection *
-handle_new_ifcfg (SCPluginIfcfg *plugin,
-                  const char *basename,
-                  const int inotify_fd,
-                  GHashTable *watch_table)
-{
-	NMConnection *connection = NULL;
-	ConnectionData *cdata;
-	char *keys_file;
-	char *path;
-
-	g_return_val_if_fail (basename != NULL, NULL);
-	g_return_val_if_fail (watch_table != NULL, NULL);
-
-	path = g_build_filename (IFCFG_DIR, basename, NULL);
-	if (!path) {
-		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "not enough memory for new connection.");
-		return NULL;
-	}
-
-	connection = build_one_connection (plugin, path);
-	if (!connection)
-		goto out;
-
-	/* Watch the file too so we can match up the watch descriptor with the
-	 * path we care about if the file is a hardlink.
-	 */
-	watch_path (path, inotify_fd, watch_table);
-
-	/* If there's a keys file watch that too */
-	keys_file = g_strdup_printf (IFCFG_DIR KEYS_TAG "%s", basename + strlen (IFCFG_TAG));
-	if (keys_file && g_file_test (keys_file, G_FILE_TEST_EXISTS))
-		watch_path (keys_file, inotify_fd, watch_table);
-	g_free (keys_file);
-
-	cdata = connection_data_get (connection);
-	if (cdata->ignored) {
-		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its "
-		              "device because NM_CONTROLLED was false.", basename);
-	}
-
-out:
-	g_free (path);
-	return connection;
-}
-
-static void
-release_one_connection (gpointer item, gpointer user_data)
-{
-	NMConnection *connection = NM_CONNECTION (item);
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
-
-	g_signal_emit_by_name (plugin, "connection-removed", connection);
-	g_object_unref (connection);
-}
-
-static void
-free_watch (gpointer key, gpointer value, gpointer user_data)
-{
-	int ifd = GPOINTER_TO_INT (user_data);
-	int wd = GPOINTER_TO_INT (value);
-
-	if (inotify_rm_watch (ifd, wd) != 0)
-		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "error removing inotify watch on %s", (char *) key);
-}
-
-static void
-clear_all_connections (SCPluginIfcfg *plugin)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-
-	/* Remove all existing connections */
-	if (priv->connections) {
-		g_slist_foreach (priv->connections, release_one_connection, plugin);
-		g_slist_free (priv->connections);
-		priv->connections = NULL;
-	}
-
-	if (priv->watch_table) {
-		g_hash_table_foreach (priv->watch_table, free_watch, GINT_TO_POINTER (priv->ifd));
-		g_hash_table_destroy (priv->watch_table);
-		priv->watch_table = NULL;
-	}
-}
-
-static void
-kill_old_auto_wired_file (void)
+static gboolean
+should_ignore_file (const char *basename, const char *tag)
 {
-	char *path;
-	const char *match = "# Written by nm-system-settings\nTYPE=Ethernet\nBOOTPROTO=dhcp\nONBOOT=yes\nUSERCTL=yes\nPEERDNS=yes\n";
-	char *contents = NULL;
-	gsize length = 0;
-
-	path = g_strdup_printf (IFCFG_DIR "/ifcfg-Auto Wired");
-	if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
-		g_free (path);
-		return;
-	}
-
-	if (!g_file_get_contents (path, &contents, &length, NULL))
-		goto out;
-
-	if (!length && !contents)
-		goto out;
-
-	if (   (length != strlen (match))
-	    && (length != (strlen (match) - 1))
-	    && (length != (strlen (match) + 1)))
-		goto out;
-
-	if (strncmp (contents, match, MIN (length, strlen (match))))
-		goto out;
+	int len, tag_len;
 
-	unlink (path);
+	g_return_val_if_fail (basename != NULL, TRUE);
+	g_return_val_if_fail (tag != NULL, TRUE);
 
-out:
-	g_free (contents);
-	g_free (path);
+	len = strlen (basename);
+	tag_len = strlen (tag);
+	if ((len > tag_len) && !strcasecmp (basename + len - tag_len, tag))
+		return TRUE;
+	return FALSE;
 }
 
 static void
-read_all_connections (SCPluginIfcfg *plugin)
+read_connections (SCPluginIfcfg *plugin)
 {
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
 	GDir *dir;
-	const char *item;
+	GError *err = NULL;
 
-	clear_all_connections (plugin);
-
-	priv->watch_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
-
-	dir = g_dir_open (IFCFG_DIR, 0, NULL);
+	dir = g_dir_open (IFCFG_DIR, 0, &err);
 	if (dir) {
+		const char *item;
+
 		while ((item = g_dir_read_name (dir))) {
-			NMConnection *connection;
-			ConnectionData *cdata;
+			char *full_path;
 
 			if (strncmp (item, IFCFG_TAG, strlen (IFCFG_TAG)))
 				continue;
 
-			connection = handle_new_ifcfg (plugin, item, priv->ifd, priv->watch_table);
-			if (connection) {
-				priv->connections = g_slist_append (priv->connections, connection);
-				cdata = connection_data_get (connection);
-				if (cdata->ignored && cdata->udi)
-					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
-			}
-		}
-		g_dir_close (dir);
-	} else {
-		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "couldn't access network config directory '" IFCFG_DIR "'.");
-	}
-
-	kill_old_auto_wired_file ();
-}
-
-static GSList *
-get_connections (NMSystemConfigInterface *config)
-{
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GSList *list = NULL, *iter;
-
-	if (!priv->initialized)
-		read_all_connections (plugin);
+			/* ignore some files */
+			if (   should_ignore_file (item, BAK_TAG)
+			    || should_ignore_file (item, TILDE_TAG)
+			    || should_ignore_file (item, ORIG_TAG)
+			    || should_ignore_file (item, REJ_TAG))
+				continue;
 
-	for (iter = priv->connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *connection = NM_CONNECTION (iter->data);
-		ConnectionData *cdata;
-
-		cdata = connection_data_get (connection);
-		if (!cdata->ignored) {
-			list = g_slist_append (list, connection);
-			cdata->exported = TRUE;
+			full_path = g_build_filename (IFCFG_DIR, item, NULL);
+			read_one_connection (plugin, full_path);
+			g_free (full_path);
 		}
-	}
 
-	return list;
-}
-
-static GValue *
-string_to_gvalue (const char *str)
-{
-	GValue *val;
-
-	val = g_slice_new0 (GValue);
-	g_value_init (val, G_TYPE_STRING);
-	g_value_set_string (val, str);
-
-	return val;
-}
-
-static void
-add_one_secret (gpointer key, gpointer data, gpointer user_data)
-{
-	g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), string_to_gvalue (data));	
-}
-
-static void
-destroy_gvalue (gpointer data)
-{
-	GValue *value = (GValue *) data;
-
-	g_value_unset (value);
-	g_slice_free (GValue, value);
-}
-
-static GHashTable *
-get_secrets (NMSystemConfigInterface *config,
-             NMConnection *connection,
-             NMSetting *setting)
-{
-	GHashTable *settings;
-	ConnectionData *cdata;
-	GHashTable *secrets;
-
-	cdata = connection_data_get (connection);
-	if (!cdata)
-		return NULL;
-
-	settings = g_hash_table_new_full (g_str_hash, g_str_equal,
-	                                  g_free, (GDestroyNotify) g_hash_table_destroy);
-
-	if (cdata->wifi_secrets) {
-		secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
-		g_hash_table_foreach (cdata->wifi_secrets, add_one_secret, secrets);
-		g_hash_table_insert (settings, g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME), secrets);
-	}
-
-	if (cdata->onex_secrets) {
-		secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_gvalue);
-		g_hash_table_foreach (cdata->onex_secrets, add_one_secret, secrets);
-		g_hash_table_insert (settings, g_strdup (NM_SETTING_802_1X_SETTING_NAME), secrets);
+		g_dir_close (dir);
+	} else {
+		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Can not read directory '%s': %s", IFCFG_DIR, err->message);
+		g_error_free (err);
 	}
-
-	/* FIXME: PPP secrets (which are actually split out into GSM/CDMA/etc */
-
-	return settings;
 }
 
-static NMConnection *
-find_connection_by_path (GSList *connections, const char *path)
-{
-	GSList *iter;
-
-	g_return_val_if_fail (path != NULL, NULL);
-
-	for (iter = connections; iter; iter = g_slist_next (iter)) {
-		NMConnection *list_connection = NM_CONNECTION (iter->data);
-		ConnectionData *cdata;
-
-		cdata = connection_data_get (list_connection);
-		g_assert (cdata);
-		if (cdata->ifcfg_path && !strcmp (cdata->ifcfg_path, path))
-			return list_connection;
-	}
-	return NULL;
-}
+/* Monitoring */
 
 static void
-handle_connection_changed (SCPluginIfcfg *plugin,
-                           const char *basename)
+dir_changed (GFileMonitor *monitor,
+		   GFile *file,
+		   GFile *other_file,
+		   GFileMonitorEvent event_type,
+		   gpointer user_data)
 {
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	char *filename = NULL;
-	NMConnection *new_connection;
-	NMConnection *existing;
-	ConnectionData *new_cdata;
-	GHashTable *new_settings;
-	ConnectionData *existing_cdata;
-	gboolean remove = FALSE;
-
-	if (!strncmp (basename, IFCFG_TAG, strlen (IFCFG_TAG))) {
-		filename = g_strdup_printf (IFCFG_DIR "%s", basename);
-	} else if (!strncmp (basename, KEYS_TAG, strlen (KEYS_TAG))) {
-		filename = g_strdup_printf (IFCFG_DIR IFCFG_TAG "%s", basename + strlen (KEYS_TAG));
-	} else {
-		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "ignored event for '%s'.", basename);
-		return;
-	}
+	char *name;
+	NMIfcfgConnection *connection;
+	gboolean do_remove = FALSE, do_new = FALSE;
+
+	name = g_file_get_path (file);
+	connection = g_hash_table_lookup (priv->connections, name);
+
+	switch (event_type) {
+	case G_FILE_MONITOR_EVENT_DELETED:
+		if (connection) {
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name);
+			do_remove = TRUE;
+		}
+		break;
+	case G_FILE_MONITOR_EVENT_CREATED:
+	case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+		if (connection) {
+			/* Update */
+			NMIfcfgConnection *tmp;
+			GError *error = NULL;
+
+			PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", name);
+
+			tmp = (NMIfcfgConnection *) nm_ifcfg_connection_new (name, priv->g_connection, priv->hal_mgr, &error);
+			if (tmp) {
+				GHashTable *settings;
+				gboolean new_unmanaged, old_unmanaged;
+
+				old_unmanaged = nm_ifcfg_connection_get_unmanaged (NM_IFCFG_CONNECTION (connection));
+				new_unmanaged = nm_ifcfg_connection_get_unmanaged (NM_IFCFG_CONNECTION (tmp));
+
+				if (new_unmanaged) {
+					if (!old_unmanaged) {
+						/* Unexport the connection by destroying it, then re-creating it as unmanaged */
+						do_remove = do_new = TRUE;
+					}
+				} else {
+					NMConnection *old_wrapped, *new_wrapped;
+
+					if (old_unmanaged)  /* no longer unmanaged */
+						g_signal_emit_by_name (plugin, "connection-added", connection);
+
+					new_wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (tmp));
+					old_wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (connection));
+
+					/* Only update if different */
+					if (!nm_connection_compare (new_wrapped, old_wrapped, COMPARE_FLAGS_EXACT)) {
+						settings = nm_connection_to_hash (new_wrapped);
+						nm_exported_connection_update (NM_EXPORTED_CONNECTION (connection), settings, NULL);
+						g_hash_table_destroy (settings);
+					}
 
-	if (!filename) {
-		PLUGIN_WARN (IFCFG_PLUGIN_NAME, "not enough memory to update connection.");
-		return;
-	}
+					/* Update unmanaged status */
+					g_object_set (connection, "unmanaged", new_unmanaged, NULL);
+					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+				}
+				g_object_unref (tmp);
+			} else {
+				/* couldn't read connection; remove it */
 
-	/* Could return NULL if the connection got deleted */
-	new_connection = build_one_connection (plugin, filename);
+				PLUGIN_WARN (IFCFG_PLUGIN_NAME, "    error: %s",
+				             error->message ? error->message : "(unknown)");
+				g_error_free (error);
 
-	existing = find_connection_by_path (priv->connections, filename);
-	if (!existing) {
-		if (new_connection) {
-			new_cdata = connection_data_get (new_connection);
-			g_assert (new_cdata);
-
-			/* totally new connection */
-			priv->connections = g_slist_append (priv->connections, new_connection);
-			if (!new_cdata->ignored) {
-				new_cdata->exported = TRUE;
-				g_signal_emit_by_name (plugin, "connection-added", new_connection);
-			} else {
-				PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its "
-				              "device because NM_CONTROLLED was false.", basename);
-				if (new_cdata->udi)
-					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+				PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name);
+				do_remove = TRUE;
 			}
+		} else {
+			do_new = TRUE;
 		}
-		g_free (filename);
-		return;
+		break;
+	default:
+		break;
 	}
 
-	existing_cdata = connection_data_get (existing);
-	g_assert (existing_cdata);
+	if (do_remove) {
+		gboolean unmanaged = nm_ifcfg_connection_get_unmanaged (connection);
 
-	if (new_connection) {
-		/* update the settings of the existing connection for this
-		 * ifcfg file and notify listeners that something has changed.
-		 */
-		new_settings = nm_connection_to_hash (new_connection);
-		if (!nm_connection_replace_settings (existing, new_settings)) {
-			/* couldn't replace the settings for some reason; have to
-			 * remove the connection then.
-			 */
-			PLUGIN_WARN (IFCFG_PLUGIN_NAME, "couldn't update connection for '%s'.", filename);
-			remove = TRUE;
-		} else {
-			/* Success */
-			new_cdata = connection_data_get (new_connection);
-			g_assert (new_cdata);
-
-			connection_data_copy_secrets (new_cdata, existing_cdata);
-			g_free (existing_cdata->udi);
-			existing_cdata->udi = new_cdata->udi ? g_strdup (new_cdata->udi) : NULL;
-
-			if (new_cdata->ignored && !existing_cdata->ignored) {
-				/* connection now ignored */
-				PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its "
-				              "device because NM_CONTROLLED was false.", basename);
-
-				existing_cdata->ignored = TRUE;
-				g_signal_emit_by_name (plugin, "connection-removed", existing);
-				existing_cdata->exported = FALSE;
-				if (existing_cdata->udi)
-					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
-			} else if (!new_cdata->ignored && existing_cdata->ignored) {
-				/* connection no longer ignored, let the system settings
-				 * service know about it now.
-				 */
-				existing_cdata->ignored = FALSE;
-				existing_cdata->exported = TRUE;
-				if (existing_cdata->udi)
-					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
-				g_signal_emit_by_name (plugin, "connection-added", existing);
-			} else if (!new_cdata->ignored && !existing_cdata->ignored) {
-				/* connection updated and not ignored */
-				g_signal_emit_by_name (plugin, "connection-updated", existing);
-			} else if (new_cdata->ignored && existing_cdata->ignored) {
-				if (existing_cdata->udi)
-					g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
-			}
-		}
-		g_object_unref (new_connection);
-	} else {
-		remove = TRUE;
+		g_hash_table_remove (priv->connections, name);
+		nm_exported_connection_signal_removed (NM_EXPORTED_CONNECTION (connection));
+
+		/* Emit unmanaged changes _after_ removing the connection */
+		if (unmanaged)
+			g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
 	}
 
-	if (remove) {
-		priv->connections = g_slist_remove (priv->connections, existing);
-		if (!existing_cdata->ignored)
-			g_signal_emit_by_name (plugin, "connection-removed", existing);
-		else {
-			if (existing_cdata->udi)
-				g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+	if (do_new) {
+		connection = read_one_connection (plugin, name);
+		if (connection) {
+			if (!nm_ifcfg_connection_get_unmanaged (NM_IFCFG_CONNECTION (connection)))
+				g_signal_emit_by_name (plugin, "connection-added", connection);
 		}
-		g_object_unref (existing);
-		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    removed connection");
 	}
 
-	g_free (filename);
+	g_free (name);
 }
 
 static void
-handle_new_item (SCPluginIfcfg *plugin, const char *basename)
+setup_monitoring (SCPluginIfcfg *plugin)
 {
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	NMConnection *connection;
-	ConnectionData *cdata;
-	char *ifcfgfile;
-
-	if (!strncmp (basename, KEYS_TAG, strlen (KEYS_TAG))) {
-		ifcfgfile = g_strdup_printf (IFCFG_TAG "%s", basename + strlen (KEYS_TAG));
-		handle_connection_changed (plugin, ifcfgfile);
-		g_free (ifcfgfile);
-		return;
-	}
+	GFile *file;
+	GFileMonitor *monitor;
 
-	if (strncmp (basename, IFCFG_TAG, strlen (IFCFG_TAG)))
-		return;
+	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
 
-	/* New connection */
-	connection = handle_new_ifcfg (plugin, basename, priv->ifd, priv->watch_table);
-	if (!connection)
-		return;
+	file = g_file_new_for_path (IFCFG_DIR);
+	monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
 
-	cdata = connection_data_get (connection);
-	g_assert (cdata);
-
-	/* new connection */
-	priv->connections = g_slist_append (priv->connections, connection);
-	if (!cdata->ignored) {
-		cdata->exported = TRUE;
-		g_signal_emit_by_name (plugin, "connection-added", connection);
-	} else {
-		if (cdata->udi)
-			g_signal_emit_by_name (plugin, "unmanaged-devices-changed");
+	if (monitor) {
+		priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), plugin);
+		priv->monitor = monitor;
 	}
 }
 
-static gboolean
-should_ignore_file (const char *basename, const char *tag)
+static void
+hash_to_slist (gpointer key, gpointer value, gpointer user_data)
 {
-	int len, tag_len;
-
-	g_return_val_if_fail (basename != NULL, TRUE);
-	g_return_val_if_fail (tag != NULL, TRUE);
+	NMIfcfgConnection *exported = NM_IFCFG_CONNECTION (value);
+	GSList **list = (GSList **) user_data;
 
-	len = strlen (basename);
-	tag_len = strlen (tag);
-	if ((len > tag_len) && !strcasecmp (basename + len - tag_len, tag))
-		return TRUE;
-	return FALSE;
+	if (!nm_ifcfg_connection_get_unmanaged (exported))
+		*list = g_slist_prepend (*list, value);
 }
 
-static gboolean
-stuff_changed (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+static GSList *
+get_connections (NMSystemConfigInterface *config)
 {
-	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
+	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	struct inotify_event evt;
-
-	/* read the notifications from the watch descriptor */
-	while (g_io_channel_read_chars (channel, (gchar *) &evt, sizeof (struct inotify_event), NULL, NULL) == G_IO_STATUS_NORMAL) {
-		const char *path;
-		gchar filename[PATH_MAX + 1];
-
-		path = g_hash_table_lookup (priv->watch_table, GINT_TO_POINTER (evt.wd));
-
-		filename[0] = '\0';
-		if (evt.len > 0) {
-			g_io_channel_read_chars (channel,
-			                        filename,
-			                        evt.len > PATH_MAX ? PATH_MAX : evt.len,
-			                        NULL, NULL);
-		}
-
-		if (!path && !strlen (filename))
-			continue;
-
-		if (evt.wd == priv->wd) {
-			if (   strncmp (filename, IFCFG_TAG, strlen (IFCFG_TAG))
-			    && strncmp (filename, KEYS_TAG, strlen (KEYS_TAG)))
-				continue;
-
-			/* ignore some files */
-			if (   should_ignore_file (filename, BAK_TAG)
-			    || should_ignore_file (filename, TILDE_TAG)
-			    || should_ignore_file (filename, ORIG_TAG)
-			    || should_ignore_file (filename, REJ_TAG))
-				continue;
+	GSList *list = NULL;
 
-			if (evt.mask & (IN_CREATE | IN_MOVED_TO)) {
-				handle_new_item (plugin, filename);
-			} else if (evt.mask & (IN_DELETE | IN_MOVED_FROM)) {
-				/* Remove connection */
-				handle_connection_changed (plugin, filename);
-			} else if (evt.mask & IN_CLOSE_WRITE) {
-				/* Updated connection */
-				handle_connection_changed (plugin, filename);
-			}
-		} else {
-			/* Track deletions and moves of the file itself */
-			if (   (evt.mask & IN_DELETE_SELF)
-			    || ((evt.mask & IN_MOVE_SELF) && path && !g_file_test (path, G_FILE_TEST_EXISTS))) {
-				char *basename;
-
-				inotify_rm_watch (priv->ifd, evt.wd);
-				g_hash_table_remove (priv->watch_table, GINT_TO_POINTER (evt.wd));
-
-				/* Remove connection */
-				basename = g_path_get_basename (path);
-				handle_connection_changed (plugin, basename);
-				g_free (basename);
-			}
-		}
+	if (!priv->connections) {
+		setup_monitoring (plugin);
+		read_connections (plugin);
 	}
 
-	return TRUE;
-}
-
-static gboolean
-sc_plugin_inotify_init (SCPluginIfcfg *plugin, GError **error)
-{
-	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GIOChannel *channel;
-	guint source_id;
-	int ifd, wd;
-
-	ifd = inotify_init ();
-	if (ifd == -1) {
-		g_set_error (error, ifcfg_plugin_error_quark (), 0,
-		             "Couldn't initialize inotify");
-		return FALSE;
-	}
-
-	wd = inotify_add_watch (ifd, IFCFG_DIR, 
-	                        IN_CLOSE_WRITE | IN_CREATE | IN_DELETE | IN_MOVE);
-	if (wd == -1) {
-		g_set_error (error, ifcfg_plugin_error_quark (), 0,
-		             "Couldn't monitor " IFCFG_DIR);
-		close (ifd);
-		return FALSE;
-	}
-
-	priv->ifd = ifd;
-	priv->wd = wd;
-
-	/* Watch the inotify descriptor for file/directory change events */
-	channel = g_io_channel_unix_new (ifd);
-	if (!channel) {
-		g_set_error (error, ifcfg_plugin_error_quark (), 0,
-		             "Couldn't create new GIOChannel");
-		close (ifd);
-		return FALSE;
-	}
-	g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
-	g_io_channel_set_encoding (channel, NULL, NULL); 
-
-	source_id = g_io_add_watch (channel,
-	                            G_IO_IN | G_IO_ERR,
-	                            (GIOFunc) stuff_changed,
-	                            plugin);
-	g_io_channel_unref (channel);
+	g_hash_table_foreach (priv->connections, hash_to_slist, &list);
 
-	return TRUE;
+	return list;
 }
 
 static void
@@ -890,17 +377,8 @@
 {
 	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
-	GError *error = NULL;
-
-	if (!sc_plugin_inotify_init (plugin, &error)) {
-		PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "    inotify error: %s",
-		              error->message ? error->message : "(unknown)");
-		g_error_free (error);
-	}
 
 	priv->hal_mgr = g_object_ref (hal_manager);
-	g_signal_connect (priv->hal_mgr, "device-added", G_CALLBACK (device_added_cb), config);
-	g_signal_connect (priv->hal_mgr, "device-removed", G_CALLBACK (device_removed_cb), config);
 }
 
 static void
@@ -923,13 +401,22 @@
 	SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object);
 	SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
 
-	clear_all_connections (plugin);
-
 	g_object_unref (priv->hal_mgr);
 
 	if (priv->g_connection)
 		dbus_g_connection_unref (priv->g_connection);
 
+	if (priv->connections)
+		g_hash_table_destroy (priv->connections);
+
+	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_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object);
 }
 
@@ -981,7 +468,6 @@
 {
 	/* interface implementation */
 	system_config_interface_class->get_connections = get_connections;
-	system_config_interface_class->get_secrets = get_secrets;
 	system_config_interface_class->get_unmanaged_devices = get_unmanaged_devices;
 	system_config_interface_class->init = init;
 }

Added: trunk/system-settings/plugins/ifcfg-fedora/reader.c
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/ifcfg-fedora/reader.c	Sun May 11 20:20:52 2008
@@ -0,0 +1,905 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <sys/inotify.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <netinet/ether.h>
+
+#ifndef __user
+#define __user
+#endif
+#include <linux/types.h>
+#include <wireless.h>
+#undef __user
+
+#include <glib.h>
+#include <nm-connection.h>
+#include <NetworkManager.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+#include <nm-setting-wired.h>
+#include <nm-setting-wireless.h>
+#include <nm-utils.h>
+
+#include "common.h"
+#include "shvar.h"
+
+#include "reader.h"
+
+#define TYPE_ETHERNET "Ethernet"
+#define TYPE_WIRELESS "Wireless"
+
+static char *
+get_ifcfg_name (const char *file)
+{
+	char *ifcfg_name;
+	char *basename;
+
+	basename = g_path_get_basename (file);
+	if (!basename)
+		return NULL;
+
+	ifcfg_name = g_strdup (basename + strlen (IFCFG_TAG));
+	g_free (basename);
+	return ifcfg_name;
+}
+
+static gboolean
+get_int (const char *str, int *value)
+{
+	char *e;
+
+	*value = strtol (str, &e, 0);
+	if (*e != '\0')
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMSetting *
+make_connection_setting (const char *file,
+                         shvarFile *ifcfg,
+                         const char *type,
+                         const char *suggested)
+{
+	NMSettingConnection *s_con;
+	char *ifcfg_name = NULL;
+
+	ifcfg_name = get_ifcfg_name (file);
+	if (!ifcfg_name)
+		return NULL;
+
+	s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+
+ 	if (suggested) {
+		/* For cosmetic reasons, if the suggested name is the same as
+		 * the ifcfg files name, don't use it.
+		 */
+		if (strcmp (ifcfg_name, suggested))
+			s_con->id = g_strdup_printf ("System %s (%s)", suggested, ifcfg_name);
+	}
+
+	if (!s_con->id)
+		s_con->id = g_strdup_printf ("System %s", ifcfg_name);
+
+	s_con->type = g_strdup (type);
+
+	/* Be somewhat conservative about autoconnect */
+	if (svTrueValue (ifcfg, "ONBOOT", FALSE))
+		s_con->autoconnect = TRUE;
+
+	g_free (ifcfg_name);
+	return (NMSetting *) s_con;
+}
+
+static void
+get_one_ip4_addr (shvarFile *ifcfg,
+                  const char *tag,
+                  guint32 *out_addr,
+                  GError **error)
+{
+	char *value = NULL;
+	struct in_addr ip4_addr;
+
+	g_return_if_fail (ifcfg != NULL);
+	g_return_if_fail (tag != NULL);
+	g_return_if_fail (out_addr != NULL);
+	g_return_if_fail (error != NULL);
+	g_return_if_fail (*error == NULL);
+
+	value = svGetValue (ifcfg, tag);
+	if (!value)
+		return;
+
+	if (inet_pton (AF_INET, value, &ip4_addr))
+		*out_addr = ip4_addr.s_addr;
+	else {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Invalid %s IP4 address '%s'", tag, value);
+	}
+	g_free (value);
+}
+
+#define GET_ONE_DNS(tag) \
+	{ \
+		guint32 dns = 0; \
+		get_one_ip4_addr (ifcfg, tag, &dns, error); \
+		if (*error) \
+			goto error; \
+		if (dns) \
+			g_array_append_val (s_ip4->dns, dns); \
+	}
+		
+
+static NMSetting *
+make_ip4_setting (shvarFile *ifcfg, GError **error)
+{
+	NMSettingIP4Config *s_ip4 = NULL;
+	char *value = NULL;
+	NMSettingIP4Address tmp = { 0, 0, 0 };
+	char *method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
+
+	value = svGetValue (ifcfg, "BOOTPROTO");
+	if (value && (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")))
+		method = NM_SETTING_IP4_CONFIG_METHOD_DHCP;
+
+	if (value && !g_ascii_strcasecmp (value, "autoip")) {
+		method = NM_SETTING_IP4_CONFIG_METHOD_AUTOIP;
+		goto done;
+	}
+
+	get_one_ip4_addr (ifcfg, "IPADDR", &tmp.address, error);
+	if (*error)
+		goto error;
+
+	get_one_ip4_addr (ifcfg, "GATEWAY", &tmp.gateway, error);
+	if (*error)
+		goto error;
+
+	get_one_ip4_addr (ifcfg, "NETMASK", &tmp.netmask, error);
+	if (*error)
+		goto error;
+
+
+done:
+	s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+	s_ip4->method = g_strdup (method);
+	if (tmp.address || tmp.netmask || tmp.gateway) {
+		NMSettingIP4Address *addr;
+		addr = g_new0 (NMSettingIP4Address, 1);
+		memcpy (addr, &tmp, sizeof (NMSettingIP4Address));
+		s_ip4->addresses = g_slist_append (s_ip4->addresses, addr);
+	}
+
+	/* No DNS for autoip */
+	if (g_ascii_strcasecmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTOIP)) {
+		s_ip4->dns = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
+
+		GET_ONE_DNS("DNS1");
+		GET_ONE_DNS("DNS2");
+		GET_ONE_DNS("DNS3");
+
+		if (s_ip4->dns && !s_ip4->dns->len) {
+			g_array_free (s_ip4->dns, TRUE);
+			s_ip4->dns = NULL;
+		}
+
+		/* DNS searches */
+		value = svGetValue (ifcfg, "SEARCH");
+		if (value) {
+			char **searches = NULL;
+
+			searches = g_strsplit (value, " ", 0);
+			if (searches) {
+				char **item;
+				for (item = searches; *item; item++)
+					s_ip4->dns_search = g_slist_append (s_ip4->dns_search, *item);
+				g_free (searches);
+			}
+		}
+	}
+
+	return NM_SETTING (s_ip4);
+
+error:
+	g_free (value);
+	if (s_ip4)
+		g_object_unref (s_ip4);
+	return NULL;
+}
+
+/*
+ * utils_bin2hexstr
+ *
+ * Convert a byte-array into a hexadecimal string.
+ *
+ * Code originally by Alex Larsson <alexl redhat com> and
+ *  copyright Red Hat, Inc. under terms of the LGPL.
+ *
+ */
+static char *
+utils_bin2hexstr (const char *bytes, int len, int final_len)
+{
+	static char	hex_digits[] = "0123456789abcdef";
+	char *		result;
+	int			i;
+
+	g_return_val_if_fail (bytes != NULL, NULL);
+	g_return_val_if_fail (len > 0, NULL);
+	g_return_val_if_fail (len < 256, NULL);	/* Arbitrary limit */
+
+	result = g_malloc0 (len * 2 + 1);
+	for (i = 0; i < len; i++)
+	{
+		result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
+		result[2*i+1] = hex_digits[bytes[i] & 0xf];
+	}
+	/* Cut converted key off at the correct length for this cipher type */
+	if (final_len > -1)
+		result[final_len] = '\0';
+
+	return result;
+}
+
+static gboolean
+read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error)
+{
+	char *value = NULL;
+	struct ether_addr *mac;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (array != NULL, FALSE);
+	g_return_val_if_fail (*array == NULL, FALSE);
+	g_return_val_if_fail (error != NULL, FALSE);
+	g_return_val_if_fail (*error == NULL, FALSE);
+
+	value = svGetValue (ifcfg, "HWADDR");
+	if (!value || !strlen (value)) {
+		g_free (value);
+		return TRUE;
+	}
+
+	mac = ether_aton (value);
+	if (!mac) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "The MAC address '%s' was invalid.", value);
+		goto error;
+	}
+
+	*array = g_byte_array_sized_new (ETH_ALEN);
+	g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN);
+
+	return TRUE;
+
+error:
+	g_free (value);
+	if (*array) {
+		g_byte_array_free (*array, TRUE);
+		*array = NULL;
+	}
+	return FALSE;
+}
+
+static gboolean
+add_one_wep_key (shvarFile *ifcfg,
+                 const char *shvar_key,
+                 guint8 key_idx,
+                 NMSettingWirelessSecurity *s_wsec,
+                 GError **error)
+{
+	char *key = NULL;
+	char *value = NULL;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (ifcfg != NULL, FALSE);
+	g_return_val_if_fail (shvar_key != NULL, FALSE);
+	g_return_val_if_fail (key_idx <= 3, FALSE);
+	g_return_val_if_fail (s_wsec != NULL, FALSE);
+
+	value = svGetValue (ifcfg, shvar_key);
+	if (!value || !strlen (value)) {
+		g_free (value);
+		return TRUE;
+	}
+
+	/* Validate keys */
+	if (strlen (value) == 10 || strlen (value) == 26) {
+		/* Hexadecimal WEP key */
+		char *p = value;
+
+		while (*p) {
+			if (!g_ascii_isxdigit (*p)) {
+				g_set_error (error, ifcfg_plugin_error_quark (), 0,
+				             "Invalid hexadecimal WEP key.");
+				goto out;
+			}
+			p++;
+		}
+		key = g_strdup (value);
+	} else if (strlen (value) == 5 || strlen (value) == 13) {
+		/* ASCII passphrase */
+		char *p = value;
+
+		while (*p) {
+			if (!isascii ((int) (*p))) {
+				g_set_error (error, ifcfg_plugin_error_quark (), 0,
+				             "Invalid ASCII WEP passphrase.");
+				goto out;
+			}
+			p++;
+		}
+
+		key = utils_bin2hexstr (value, strlen (value), strlen (value) * 2);
+	} else {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid WEP key length.");
+	}
+
+	if (key) {
+		if (key_idx == 0)
+			s_wsec->wep_key0 = key;
+		else if (key_idx == 1)
+			s_wsec->wep_key1 = key;
+		else if (key_idx == 2)
+			s_wsec->wep_key2 = key;
+		else if (key_idx == 3)
+			s_wsec->wep_key3 = key;
+		else
+			g_assert_not_reached ();
+		success = TRUE;
+	}
+
+out:
+	g_free (value);
+	return success;
+}
+
+static shvarFile *
+get_keys_ifcfg (const char *parent)
+{
+	char *ifcfg_name;
+	char *keys_file = NULL;
+	char *tmp = NULL;
+	shvarFile *ifcfg = NULL;
+
+	ifcfg_name = get_ifcfg_name (parent);
+	if (!ifcfg_name)
+		return NULL;
+
+	tmp = g_path_get_dirname (parent);
+	if (!tmp)
+		goto out;
+
+	keys_file = g_strdup_printf ("%s/" KEYS_TAG "%s", tmp, ifcfg_name);
+	if (!keys_file)
+		goto out;
+
+	ifcfg = svNewFile (keys_file);
+
+out:
+	g_free (keys_file);
+	g_free (tmp);
+	g_free (ifcfg_name);
+	return ifcfg;
+}
+
+static gboolean
+read_wep_keys (shvarFile *ifcfg,
+               guint8 def_idx,
+               NMSettingWirelessSecurity *s_wsec,
+               GError **error)
+{
+	if (!add_one_wep_key (ifcfg, "KEY1", 0, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY2", 1, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY3", 2, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY4", 3, s_wsec, error))
+		return FALSE;
+	if (!add_one_wep_key (ifcfg, "KEY", def_idx, s_wsec, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static NMSetting *
+make_wireless_security_setting (shvarFile *ifcfg,
+                                const char *file,
+                                GError **error)
+{
+	NMSettingWirelessSecurity *s_wireless_sec;
+	char *value;
+	shvarFile *keys_ifcfg = NULL;
+	int default_key_idx = 0;
+
+	s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
+
+	value = svGetValue (ifcfg, "DEFAULTKEY");
+	if (value) {
+		gboolean success;
+
+		success = get_int (value, &default_key_idx);
+		if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
+			default_key_idx--;  /* convert to [0...3] */
+			s_wireless_sec->wep_tx_keyidx = default_key_idx;
+		} else {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Invalid default WEP key '%s'", value);
+	 		g_free (value);
+			goto error;
+		}
+ 		g_free (value);
+	}
+
+	/* Read keys in the ifcfg file */
+	if (!read_wep_keys (ifcfg, default_key_idx, s_wireless_sec, error))
+		goto error;
+
+	/* Try to get keys from the "shadow" key file */
+	keys_ifcfg = get_keys_ifcfg (file);
+	if (keys_ifcfg) {
+		if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wireless_sec, error)) {
+			svCloseFile (keys_ifcfg);
+			goto error;
+		}
+		svCloseFile (keys_ifcfg);
+	}
+
+	/* If there's a default key, ensure that key exists */
+	if ((default_key_idx == 1) && !s_wireless_sec->wep_key1) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Default WEP key index was 2, but no valid KEY2 exists.");
+		goto error;
+	} else if ((default_key_idx == 2) && !s_wireless_sec->wep_key2) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Default WEP key index was 3, but no valid KEY3 exists.");
+		goto error;
+	} else if ((default_key_idx == 3) && !s_wireless_sec->wep_key3) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Default WEP key index was 4, but no valid KEY4 exists.");
+		goto error;
+	}
+
+	value = svGetValue (ifcfg, "SECURITYMODE");
+	if (value) {
+		char *lcase;
+
+		lcase = g_ascii_strdown (value, -1);
+		g_free (value);
+
+		if (!strcmp (lcase, "open")) {
+			s_wireless_sec->auth_alg = g_strdup ("open");
+		} else if (!strcmp (lcase, "restricted")) {
+			s_wireless_sec->auth_alg = g_strdup ("shared");
+		} else {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Invalid WEP authentication algoritm '%s'",
+			             lcase);
+			g_free (lcase);
+			goto error;
+		}
+		g_free (lcase);
+	}
+
+	if (   !s_wireless_sec->wep_key0
+	    && !s_wireless_sec->wep_key1
+	    && !s_wireless_sec->wep_key2
+	    && !s_wireless_sec->wep_key3
+	    && !s_wireless_sec->wep_tx_keyidx) {
+		if (s_wireless_sec->auth_alg && !strcmp (s_wireless_sec->auth_alg, "shared")) {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "WEP Shared Key authentication is invalid for "
+			             "unencrypted connections.");
+			goto error;
+		}
+
+		/* Unencrypted */
+		g_object_unref (s_wireless_sec);
+		s_wireless_sec = NULL;
+	} else {
+		// FIXME: WEP-only for now
+		s_wireless_sec->key_mgmt = g_strdup ("none");
+	}
+
+	return (NMSetting *) s_wireless_sec;
+
+error:
+	if (s_wireless_sec)
+		g_object_unref (s_wireless_sec);
+	return NULL;
+}
+
+
+static NMSetting *
+make_wireless_setting (shvarFile *ifcfg,
+                       NMSetting *security,
+                       GError **error)
+{
+	NMSettingWireless *s_wireless;
+	char *value;
+
+	s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
+
+	value = svGetValue (ifcfg, "ESSID");
+	if (value) {
+		gsize len = strlen (value);
+
+		if (len > 32 || len == 0) {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
+			             value, len);
+			goto error;
+		}
+
+		s_wireless->ssid = g_byte_array_sized_new (strlen (value));
+		g_byte_array_append (s_wireless->ssid, (const guint8 *) value, len);
+		g_free (value);
+	} else {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0, "Missing SSID");
+		goto error;
+	}
+
+	value = svGetValue (ifcfg, "MODE");
+	if (value) {
+		char *lcase;
+
+		lcase = g_ascii_strdown (value, -1);
+		g_free (value);
+
+		if (!strcmp (lcase, "ad-hoc")) {
+			s_wireless->mode = g_strdup ("adhoc");
+		} else if (!strcmp (lcase, "managed")) {
+			s_wireless->mode = g_strdup ("infrastructure");
+		} else {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Invalid mode '%s' (not ad-hoc or managed)",
+			             lcase);
+			g_free (lcase);
+			goto error;
+		}
+		g_free (lcase);
+	}
+
+	if (security)
+		s_wireless->security = g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
+
+	if (!read_mac_address (ifcfg, &s_wireless->mac_address, error)) {
+		g_object_unref (s_wireless);
+		s_wireless = NULL;
+	}
+
+	// FIXME: channel/freq, other L2 parameters like RTS
+
+	return NM_SETTING (s_wireless);
+
+error:
+	if (s_wireless)
+		g_object_unref (s_wireless);
+	return NULL;
+}
+
+static NMConnection *
+wireless_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wireless_setting = NULL;
+	NMSettingWireless *tmp;
+	NMSetting *security_setting = NULL;
+	char *printable_ssid = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+	g_return_val_if_fail (error != NULL, NULL);
+	g_return_val_if_fail (*error == NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	/* Wireless security */
+	security_setting = make_wireless_security_setting (ifcfg, file, error);
+	if (*error)
+		goto error;
+	if (security_setting)
+		nm_connection_add_setting (connection, security_setting);
+
+	/* Wireless */
+	wireless_setting = make_wireless_setting (ifcfg, security_setting, error);
+	if (!wireless_setting)
+		goto error;
+
+	nm_connection_add_setting (connection, wireless_setting);
+
+	tmp = NM_SETTING_WIRELESS (wireless_setting);
+	printable_ssid = nm_utils_ssid_to_utf8 ((const char *) tmp->ssid->data,
+	                                        (guint32) tmp->ssid->len);
+
+	con_setting = make_connection_setting (file, ifcfg,
+	                                       NM_SETTING_WIRELESS_SETTING_NAME,
+	                                       printable_ssid);
+	if (!con_setting) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Failed to create connection setting.");
+		goto error;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	if (!nm_connection_verify (connection)) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Connection from %s was invalid.", file);
+		goto error;
+	}
+
+	return connection;
+
+error:
+	g_free (printable_ssid);
+	g_object_unref (connection);
+	if (con_setting)
+		g_object_unref (con_setting);
+	if (wireless_setting)
+		g_object_unref (wireless_setting);
+	return NULL;
+}
+
+static NMSetting *
+make_wired_setting (shvarFile *ifcfg, GError **error)
+{
+	NMSettingWired *s_wired;
+	char *value;
+	int mtu;
+
+	s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
+
+	value = svGetValue (ifcfg, "MTU");
+	if (value) {
+		if (get_int (value, &mtu)) {
+			if (mtu >= 0 && mtu < 65536)
+				s_wired->mtu = mtu;
+		} else {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Invalid MTU '%s'", value);
+			g_object_unref (s_wired);
+			s_wired = NULL;
+		}
+		g_free (value);
+	}
+
+	if (!read_mac_address (ifcfg, &s_wired->mac_address, error)) {
+		g_object_unref (s_wired);
+		s_wired = NULL;
+	}
+
+	return (NMSetting *) s_wired;
+}
+
+static NMConnection *
+wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **error)
+{
+	NMConnection *connection = NULL;
+	NMSetting *con_setting = NULL;
+	NMSetting *wired_setting = NULL;
+
+	g_return_val_if_fail (file != NULL, NULL);
+	g_return_val_if_fail (ifcfg != NULL, NULL);
+
+	connection = nm_connection_new ();
+	if (!connection) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Failed to allocate new connection for %s.", file);
+		return NULL;
+	}
+
+	con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL);
+	if (!con_setting) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Failed to create connection setting.");
+		goto error;
+	}
+	nm_connection_add_setting (connection, con_setting);
+
+	wired_setting = make_wired_setting (ifcfg, error);
+	if (!wired_setting)
+		goto error;
+
+	nm_connection_add_setting (connection, wired_setting);
+
+	if (!nm_connection_verify (connection)) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Connection from %s was invalid.", file);
+		goto error;
+	}
+
+	return connection;
+
+error:
+	g_object_unref (connection);
+	if (con_setting)
+		g_object_unref (con_setting);
+	if (wired_setting)
+		g_object_unref (wired_setting);
+	return NULL;
+}
+
+static gboolean
+is_wireless_device (const char *iface, gboolean *is_wireless)
+{
+	int fd;
+	struct iw_range range;
+	struct iwreq wrq;
+	gboolean success = FALSE;
+
+	g_return_val_if_fail (iface != NULL, FALSE);
+	g_return_val_if_fail (is_wireless != NULL, FALSE);
+
+	*is_wireless = FALSE;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (!fd)
+		return FALSE;
+
+	memset (&wrq, 0, sizeof (struct iwreq));
+	memset (&range, 0, sizeof (struct iw_range));
+	strncpy (wrq.ifr_name, iface, IFNAMSIZ);
+	wrq.u.data.pointer = (caddr_t) &range;
+	wrq.u.data.length = sizeof (struct iw_range);
+
+	if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) {
+		if (errno == EOPNOTSUPP)
+			success = TRUE;
+		goto out;
+	}
+
+	*is_wireless = TRUE;
+	success = TRUE;
+
+out:
+	close (fd);
+	return success;
+}
+
+NMConnection *
+connection_from_file (const char *filename, gboolean *ignored, GError **error)
+{
+	NMConnection *connection = NULL;
+	shvarFile *parsed;
+	char *type;
+	char *nmc = NULL;
+	NMSetting *s_ip4;
+	char *ifcfg_name = NULL;
+
+	g_return_val_if_fail (filename != NULL, NULL);
+	g_return_val_if_fail (ignored != NULL, NULL);
+
+	ifcfg_name = get_ifcfg_name (filename);
+	if (!ifcfg_name) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Ignoring connection '%s' because it's not an ifcfg file.", filename);
+		return NULL;
+	}
+	g_free (ifcfg_name);
+
+	parsed = svNewFile (filename);
+	if (!parsed) {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Couldn't parse file '%s'", filename);
+		return NULL;
+	}
+
+	type = svGetValue (parsed, "TYPE");
+	if (!type) {
+		char *device;
+		gboolean is_wireless = FALSE;
+
+		/* If no type, if the device has wireless extensions, it's wifi,
+		 * otherwise it's ethernet.
+		 */
+		device = svGetValue (parsed, "DEVICE");
+		if (!device) {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "File '%s' had neither TYPE nor DEVICE keys.", filename);
+			goto done;
+		}
+
+		if (!strcmp (device, "lo")) {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "Ignoring loopback device config.");
+			g_free (device);
+			goto done;
+		}
+
+		/* Test wireless extensions */
+		if (!is_wireless_device (device, &is_wireless)) {
+			g_set_error (error, ifcfg_plugin_error_quark (), 0,
+			             "File '%s' specified device '%s', but the device's "
+			             "type could not be determined.", filename, device);
+			g_free (device);
+			goto done;
+		}
+
+		if (is_wireless)
+			type = g_strdup (TYPE_WIRELESS);
+		else
+			type = g_strdup (TYPE_ETHERNET);
+
+		g_free (device);
+	}
+
+	nmc = svGetValue (parsed, "NM_CONTROLLED");
+	if (nmc) {
+		char *lower;
+
+		lower = g_ascii_strdown (nmc, -1);
+		g_free (nmc);
+
+		if (!strcmp (lower, "no") || !strcmp (lower, "n") || !strcmp (lower, "false"))
+			*ignored = TRUE;
+		g_free (lower);
+	}
+
+	if (!strcmp (type, TYPE_ETHERNET))
+		connection = wired_connection_from_ifcfg (filename, parsed, error);
+	else if (!strcmp (type, TYPE_WIRELESS))
+		connection = wireless_connection_from_ifcfg (filename, parsed, error);
+	else {
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Unknown connection type '%s'", type);
+	}
+
+	g_free (type);
+
+	if (!connection)
+		goto done;
+
+	s_ip4 = make_ip4_setting (parsed, error);
+	if (*error) {
+		g_object_unref (connection);
+		connection = NULL;
+		goto done;
+	} else if (s_ip4) {
+		nm_connection_add_setting (connection, s_ip4);
+	}
+
+	if (!nm_connection_verify (connection)) {
+		g_object_unref (connection);
+		connection = NULL;
+		g_set_error (error, ifcfg_plugin_error_quark (), 0,
+		             "Connection was invalid");
+	}
+
+done:
+	svCloseFile (parsed);
+	return connection;
+}
+
+

Added: trunk/system-settings/plugins/ifcfg-fedora/reader.h
==============================================================================
--- (empty file)
+++ trunk/system-settings/plugins/ifcfg-fedora/reader.h	Sun May 11 20:20:52 2008
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager system settings service
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2008 Red Hat, Inc.
+ */
+
+#ifndef __READER_H__
+#define __READER_H__
+
+#include <glib.h>
+#include <nm-connection.h>
+
+NMConnection *connection_from_file (const char *filename, gboolean *ignored, GError **error);
+
+#endif  /* __READER_H__ */

Modified: trunk/system-settings/src/dbus-settings.c
==============================================================================
--- trunk/system-settings/src/dbus-settings.c	(original)
+++ trunk/system-settings/src/dbus-settings.c	Sun May 11 20:20:52 2008
@@ -70,6 +70,38 @@
 };
 
 static void
+load_connections (NMSysconfigSettings *self)
+{
+	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+	GSList *iter;
+
+	if (priv->connections_loaded)
+		return;
+
+	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, NM_EXPORTED_CONNECTION (elt->data));
+
+		g_slist_free (plugin_connections);
+	}
+
+	/* FIXME: Bad hack */
+	unmanaged_devices_changed (NULL, self);
+
+	priv->connections_loaded = TRUE;
+}
+
+static void
 hash_keys_to_slist (gpointer key, gpointer val, gpointer user_data)
 {
 	GSList **list = (GSList **) user_data;
@@ -84,31 +116,7 @@
 	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
 	GSList *list = NULL;
 
-	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, NM_EXPORTED_CONNECTION (elt->data));
-
-			g_slist_free (plugin_connections);
-		}
-
-		/* FIXME: Bad hack */
-		unmanaged_devices_changed (NULL, self);
-
-		priv->connections_loaded = TRUE;
-	}
+	load_connections (self);
 
 	g_hash_table_foreach (priv->connections, hash_keys_to_slist, &list);
 
@@ -195,6 +203,8 @@
 	NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
 	GPtrArray *devices;
 
+	load_connections (self);
+
  	devices = g_ptr_array_sized_new (3);
 	g_hash_table_foreach (priv->unmanaged_devices, (GHFunc) add_one_unmanaged_device, devices);
 	return devices;
@@ -406,6 +416,9 @@
 	g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), FALSE);
 
 	priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
+
+	load_connections (self);
+
 	if (g_hash_table_lookup (priv->unmanaged_devices, udi))
 		return FALSE;
 	return TRUE;



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