about summary refs log tree commit diff
path: root/libnm-glib/nm-client.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2011-05-04 21:35:41 +0200
committerMichael Biebl <biebl@debian.org>2011-05-04 21:35:41 +0200
commit9f806e97a24bba61417ae312fcc0da40914266fb (patch)
tree4a25723414ceac11b4cba0558aa16f6f4b459f4b /libnm-glib/nm-client.c
parent8baa1aca8dfd35e3190d7d5655eb83b5b901e263 (diff)
Imported Upstream version 0.8.999 upstream/0.8.999
Diffstat (limited to 'libnm-glib/nm-client.c')
-rw-r--r--libnm-glib/nm-client.c1485
1 files changed, 939 insertions, 546 deletions
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 1de7b863..644af3e4 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -28,8 +28,6 @@
 #include "nm-client.h"
 #include "nm-device-ethernet.h"
 #include "nm-device-wifi.h"
-#include "nm-gsm-device.h"
-#include "nm-cdma-device.h"
 #include "nm-device-private.h"
 #include "nm-marshal.h"
 #include "nm-types-private.h"
@@ -43,7 +41,6 @@
 
 void _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device, gboolean enabled);
 
-
 G_DEFINE_TYPE (NMClient, nm_client, NM_TYPE_OBJECT)
 
 #define NM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CLIENT, NMClientPrivate))
@@ -54,6 +51,7 @@ typedef struct {
 	DBusGProxy *client_proxy;
 	DBusGProxy *bus_proxy;
 	gboolean manager_running;
+	char *version;
 	NMState state;
 	GPtrArray *devices;
 	GPtrArray *active_connections;
@@ -61,6 +59,11 @@ typedef struct {
 	DBusGProxyCall *perm_call;
 	GHashTable *permissions;
 
+	/* Activations waiting for their NMActiveConnection
+	 * to appear and then their callback to be called.
+	 */
+	GSList *pending_activations;
+
 	gboolean have_networking_enabled;
 	gboolean networking_enabled;
 	gboolean wireless_enabled;
@@ -68,10 +71,14 @@ typedef struct {
 
 	gboolean wwan_enabled;
 	gboolean wwan_hw_enabled;
+
+	gboolean wimax_enabled;
+	gboolean wimax_hw_enabled;
 } NMClientPrivate;
 
 enum {
 	PROP_0,
+	PROP_VERSION,
 	PROP_STATE,
 	PROP_MANAGER_RUNNING,
 	PROP_NETWORKING_ENABLED,
@@ -79,6 +86,8 @@ enum {
 	PROP_WIRELESS_HARDWARE_ENABLED,
 	PROP_WWAN_ENABLED,
 	PROP_WWAN_HARDWARE_ENABLED,
+	PROP_WIMAX_ENABLED,
+	PROP_WIMAX_HARDWARE_ENABLED,
 	PROP_ACTIVE_CONNECTIONS,
 
 	LAST_PROP
@@ -152,8 +161,9 @@ update_wireless_status (NMClient *client, gboolean notify)
 	gboolean poke = FALSE;
 
 	val = _nm_object_get_boolean_property (NM_OBJECT (client),
-										  NM_DBUS_INTERFACE,
-										  "WirelessHardwareEnabled");
+	                                       NM_DBUS_INTERFACE,
+	                                       "WirelessHardwareEnabled",
+	                                       NULL);
 	if (val != priv->wireless_hw_enabled) {
 		priv->wireless_hw_enabled = val;
 		poke = TRUE;
@@ -165,8 +175,9 @@ update_wireless_status (NMClient *client, gboolean notify)
 		val = FALSE;
 	else
 		val = _nm_object_get_boolean_property (NM_OBJECT (client),
-				                              NM_DBUS_INTERFACE,
-				                              "WirelessEnabled");
+		                                       NM_DBUS_INTERFACE,
+		                                       "WirelessEnabled",
+		                                       NULL);
 	if (val != priv->wireless_enabled) {
 		priv->wireless_enabled = val;
 		poke = TRUE;
@@ -192,7 +203,8 @@ update_wwan_status (NMClient *client, gboolean notify)
 
 	val = _nm_object_get_boolean_property (NM_OBJECT (client),
 	                                       NM_DBUS_INTERFACE,
-	                                       "WwanHardwareEnabled");
+	                                       "WwanHardwareEnabled",
+	                                       NULL);
 	if (val != priv->wwan_hw_enabled) {
 		priv->wwan_hw_enabled = val;
 		if (notify)
@@ -204,7 +216,8 @@ update_wwan_status (NMClient *client, gboolean notify)
 	else {
 		val = _nm_object_get_boolean_property (NM_OBJECT (client),
 		                                       NM_DBUS_INTERFACE,
-		                                       "WwanEnabled");
+		                                       "WwanEnabled",
+		                                       NULL);
 	}
 
 	if (val != priv->wwan_enabled) {
@@ -214,6 +227,38 @@ update_wwan_status (NMClient *client, gboolean notify)
 	}
 }
 
+static void
+update_wimax_status (NMClient *client, gboolean notify)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+	gboolean val;
+
+	val = _nm_object_get_boolean_property (NM_OBJECT (client),
+	                                       NM_DBUS_INTERFACE,
+	                                       "WimaxHardwareEnabled",
+	                                       NULL);
+	if (val != priv->wimax_hw_enabled) {
+		priv->wimax_hw_enabled = val;
+		if (notify)
+			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIMAX_HARDWARE_ENABLED);
+	}
+
+	if (priv->wimax_hw_enabled == FALSE)
+		val = FALSE;
+	else {
+		val = _nm_object_get_boolean_property (NM_OBJECT (client),
+		                                       NM_DBUS_INTERFACE,
+		                                       "WimaxEnabled",
+		                                       NULL);
+	}
+
+	if (val != priv->wimax_enabled) {
+		priv->wimax_enabled = val;
+		if (notify)
+			_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_WIMAX_ENABLED);
+	}
+}
+
 static GObject *
 new_active_connection (DBusGConnection *connection, const char *path)
 {
@@ -275,12 +320,15 @@ register_for_property_changed (NMClient *client)
 {
 	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
 	const NMPropertiesChangedInfo property_changed_info[] = {
+		{ NM_CLIENT_VERSION,                   _nm_object_demarshal_generic,  &priv->version },
 		{ NM_CLIENT_STATE,                     _nm_object_demarshal_generic,  &priv->state },
 		{ NM_CLIENT_NETWORKING_ENABLED,        _nm_object_demarshal_generic,  &priv->networking_enabled },
 		{ NM_CLIENT_WIRELESS_ENABLED,          _nm_object_demarshal_generic,  &priv->wireless_enabled },
 		{ NM_CLIENT_WIRELESS_HARDWARE_ENABLED, _nm_object_demarshal_generic,  &priv->wireless_hw_enabled },
 		{ NM_CLIENT_WWAN_ENABLED,              _nm_object_demarshal_generic,  &priv->wwan_enabled },
 		{ NM_CLIENT_WWAN_HARDWARE_ENABLED,     _nm_object_demarshal_generic,  &priv->wwan_hw_enabled },
+		{ NM_CLIENT_WIMAX_ENABLED,             _nm_object_demarshal_generic,  &priv->wimax_enabled },
+		{ NM_CLIENT_WIMAX_HARDWARE_ENABLED,    _nm_object_demarshal_generic,  &priv->wimax_hw_enabled },
 		{ NM_CLIENT_ACTIVE_CONNECTIONS,        demarshal_active_connections, &priv->active_connections },
 		{ NULL },
 	};
@@ -290,10 +338,17 @@ register_for_property_changed (NMClient *client)
 	                                     property_changed_info);
 }
 
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI    "org.freedesktop.NetworkManager.enable-disable-wifi"
-#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN    "org.freedesktop.NetworkManager.enable-disable-wwan"
-#define NM_AUTH_PERMISSION_USE_USER_CONNECTIONS   "org.freedesktop.NetworkManager.use-user-connections"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK     "org.freedesktop.NetworkManager.enable-disable-network"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI        "org.freedesktop.NetworkManager.enable-disable-wifi"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN        "org.freedesktop.NetworkManager.enable-disable-wwan"
+#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX       "org.freedesktop.NetworkManager.enable-disable-wimax"
+#define NM_AUTH_PERMISSION_SLEEP_WAKE                 "org.freedesktop.NetworkManager.sleep-wake"
+#define NM_AUTH_PERMISSION_NETWORK_CONTROL            "org.freedesktop.NetworkManager.network-control"
+#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED       "org.freedesktop.NetworkManager.wifi.share.protected"
+#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN            "org.freedesktop.NetworkManager.wifi.share.open"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM     "org.freedesktop.NetworkManager.settings.modify.system"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN        "org.freedesktop.NetworkManager.settings.modify.own"
+#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME   "org.freedesktop.NetworkManager.settings.modify.hostname"
 
 static NMClientPermission
 nm_permission_to_client (const char *nm)
@@ -304,8 +359,23 @@ nm_permission_to_client (const char *nm)
 		return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIFI;
 	else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN))
 		return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WWAN;
-	else if (!strcmp (nm, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS))
-		return NM_CLIENT_PERMISSION_USE_USER_CONNECTIONS;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX))
+		return NM_CLIENT_PERMISSION_ENABLE_DISABLE_WIMAX;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_SLEEP_WAKE))
+		return NM_CLIENT_PERMISSION_SLEEP_WAKE;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_NETWORK_CONTROL))
+		return NM_CLIENT_PERMISSION_NETWORK_CONTROL;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED))
+		return NM_CLIENT_PERMISSION_WIFI_SHARE_PROTECTED;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN))
+		return NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM))
+		return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN))
+		return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME))
+		return NM_CLIENT_PERMISSION_SETTINGS_MODIFY_HOSTNAME;
+
 	return NM_CLIENT_PERMISSION_NONE;
 }
 
@@ -414,495 +484,13 @@ client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
 	}
 }
 
-static GObject*
-constructor (GType type,
-		   guint n_construct_params,
-		   GObjectConstructParam *construct_params)
-{
-	NMObject *object;
-	DBusGConnection *connection;
-	NMClientPrivate *priv;
-	GError *err = NULL;
-
-	object = (NMObject *) G_OBJECT_CLASS (nm_client_parent_class)->constructor (type,
-																 n_construct_params,
-																 construct_params);
-	if (!object)
-		return NULL;
-
-	priv = NM_CLIENT_GET_PRIVATE (object);
-	connection = nm_object_get_connection (object);
-
-	priv->client_proxy = dbus_g_proxy_new_for_name (connection,
-										   NM_DBUS_SERVICE,
-										   nm_object_get_path (object),
-										   NM_DBUS_INTERFACE);
-
-	register_for_property_changed (NM_CLIENT (object));
-
-	dbus_g_proxy_add_signal (priv->client_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->client_proxy,
-						    "DeviceAdded",
-						    G_CALLBACK (client_device_added_proxy),
-						    object,
-						    NULL);
-
-	dbus_g_proxy_add_signal (priv->client_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->client_proxy,
-						    "DeviceRemoved",
-						    G_CALLBACK (client_device_removed_proxy),
-						    object,
-						    NULL);
-
-	/* Permissions */
-	dbus_g_proxy_add_signal (priv->client_proxy, "CheckPermissions", G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->client_proxy,
-	                             "CheckPermissions",
-	                             G_CALLBACK (client_recheck_permissions),
-	                             object,
-	                             NULL);
-	get_permissions_sync (NM_CLIENT (object));
-
-	priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
-										"org.freedesktop.DBus",
-										"/org/freedesktop/DBus",
-										"org.freedesktop.DBus");
-
-	dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
-						G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-						G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->bus_proxy,
-						    "NameOwnerChanged",
-						    G_CALLBACK (proxy_name_owner_changed),
-						    object, NULL);
-
-	if (!dbus_g_proxy_call (priv->bus_proxy,
-					    "NameHasOwner", &err,
-					    G_TYPE_STRING, NM_DBUS_SERVICE,
-					    G_TYPE_INVALID,
-					    G_TYPE_BOOLEAN, &priv->manager_running,
-					    G_TYPE_INVALID)) {
-		g_warning ("Error on NameHasOwner DBUS call: %s", err->message);
-		g_error_free (err);
-	}
-
-	if (priv->manager_running) {
-		update_wireless_status (NM_CLIENT (object), FALSE);
-		update_wwan_status (NM_CLIENT (object), FALSE);
-		nm_client_get_state (NM_CLIENT (object));
-	}
-
-	g_signal_connect (G_OBJECT (object), "notify::" NM_CLIENT_WIRELESS_ENABLED,
-	                  G_CALLBACK (wireless_enabled_cb), NULL);
-
-	return G_OBJECT (object);
-}
-
-static void
-free_object_array (GPtrArray **array)
-{
-	g_return_if_fail (array != NULL);
-
-	if (*array) {
-		g_ptr_array_foreach (*array, (GFunc) g_object_unref, NULL);
-		g_ptr_array_free (*array, TRUE);
-		*array = NULL;
-	}
-}
-
-static void
-dispose (GObject *object)
-{
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
-
-	if (priv->disposed) {
-		G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
-		return;
-	}
-
-	if (priv->perm_call)
-		dbus_g_proxy_cancel_call (priv->client_proxy, priv->perm_call);
-
-	g_object_unref (priv->client_proxy);
-	g_object_unref (priv->bus_proxy);
-
-	free_object_array (&priv->devices);
-	free_object_array (&priv->active_connections);
-
-	g_hash_table_destroy (priv->permissions);
-
-	G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
-}
-
-static void
-set_property (GObject *object, guint prop_id,
-		    const GValue *value, GParamSpec *pspec)
-{
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
-	gboolean b;
-
-	switch (prop_id) {
-	case PROP_WIRELESS_ENABLED:
-		b = g_value_get_boolean (value);
-		if (priv->wireless_enabled != b) {
-			priv->wireless_enabled = b;
-			_nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WIRELESS_ENABLED);
-		}
-		break;
-	case PROP_WIRELESS_HARDWARE_ENABLED:
-		b = g_value_get_boolean (value);
-		if (priv->wireless_hw_enabled != b) {
-			priv->wireless_hw_enabled = b;
-			_nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WIRELESS_HARDWARE_ENABLED);
-		}
-		break;
-	case PROP_WWAN_ENABLED:
-		b = g_value_get_boolean (value);
-		if (priv->wwan_enabled != b) {
-			priv->wwan_enabled = b;
-			_nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WWAN_ENABLED);
-		}
-		break;
-	case PROP_WWAN_HARDWARE_ENABLED:
-		b = g_value_get_boolean (value);
-		if (priv->wwan_hw_enabled != b) {
-			priv->wwan_hw_enabled = b;
-			_nm_object_queue_notify (NM_OBJECT (object), NM_CLIENT_WWAN_HARDWARE_ENABLED);
-		}
-		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)
-{
-	NMClient *self = NM_CLIENT (object);
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
-
-	switch (prop_id) {
-	case PROP_STATE:
-		g_value_set_uint (value, nm_client_get_state (self));
-		break;
-	case PROP_MANAGER_RUNNING:
-		g_value_set_boolean (value, priv->manager_running);
-		break;
-	case PROP_NETWORKING_ENABLED:
-		g_value_set_boolean (value, priv->networking_enabled);
-		break;
-	case PROP_WIRELESS_ENABLED:
-		g_value_set_boolean (value, priv->wireless_enabled);
-		break;
-	case PROP_WIRELESS_HARDWARE_ENABLED:
-		g_value_set_boolean (value, priv->wireless_hw_enabled);
-		break;
-	case PROP_WWAN_ENABLED:
-		g_value_set_boolean (value, priv->wwan_enabled);
-		break;
-	case PROP_WWAN_HARDWARE_ENABLED:
-		g_value_set_boolean (value, priv->wwan_hw_enabled);
-		break;
-	case PROP_ACTIVE_CONNECTIONS:
-		g_value_set_boxed (value, nm_client_get_active_connections (self));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-		break;
-	}
-}
-
-static void
-nm_client_class_init (NMClientClass *client_class)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (client_class);
-
-	g_type_class_add_private (client_class, sizeof (NMClientPrivate));
-
-	/* virtual methods */
-	object_class->constructor = constructor;
-	object_class->set_property = set_property;
-	object_class->get_property = get_property;
-	object_class->dispose = dispose;
-
-	/* properties */
-
-	/**
-	 * NMClient:state:
-	 *
-	 * The current daemon state.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_STATE,
-		 g_param_spec_uint (NM_CLIENT_STATE,
-						    "State",
-						    "NetworkManager state",
-						    NM_STATE_UNKNOWN, NM_STATE_DISCONNECTED, NM_STATE_UNKNOWN,
-						    G_PARAM_READABLE));
-
-	/**
-	 * NMClient::manager-running:
-	 *
-	 * Whether the daemon is running.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_MANAGER_RUNNING,
-		 g_param_spec_boolean (NM_CLIENT_MANAGER_RUNNING,
-						       "ManagerRunning",
-						       "Whether NetworkManager is running",
-						       FALSE,
-						       G_PARAM_READABLE));
-
-	/**
-	 * NMClient::networking-enabled:
-	 *
-	 * Whether networking is enabled.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_NETWORKING_ENABLED,
-		 g_param_spec_boolean (NM_CLIENT_NETWORKING_ENABLED,
-						   "NetworkingEnabled",
-						   "Is networking enabled",
-						   TRUE,
-						   G_PARAM_READABLE));
-
-	/**
-	 * NMClient::wireless-enabled:
-	 *
-	 * Whether wireless is enabled.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_WIRELESS_ENABLED,
-		 g_param_spec_boolean (NM_CLIENT_WIRELESS_ENABLED,
-						   "WirelessEnabled",
-						   "Is wireless enabled",
-						   TRUE,
-						   G_PARAM_READWRITE));
-
-	/**
-	 * NMClient::wireless-hardware-enabled:
-	 *
-	 * Whether the wireless hardware is enabled.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_WIRELESS_HARDWARE_ENABLED,
-		 g_param_spec_boolean (NM_CLIENT_WIRELESS_HARDWARE_ENABLED,
-						   "WirelessHardwareEnabled",
-						   "Is wireless hardware enabled",
-						   TRUE,
-						   G_PARAM_READABLE));
-
-	/**
-	 * NMClient::wwan-enabled:
-	 *
-	 * Whether WWAN functionality is enabled.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_WWAN_ENABLED,
-		 g_param_spec_boolean (NM_CLIENT_WWAN_ENABLED,
-		                       "WwanEnabled",
-		                       "Is WWAN enabled",
-		                       TRUE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
-	/**
-	 * NMClient::wwan-hardware-enabled:
-	 *
-	 * Whether the WWAN hardware is enabled.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_WWAN_HARDWARE_ENABLED,
-		 g_param_spec_boolean (NM_CLIENT_WWAN_HARDWARE_ENABLED,
-		                       "WwanHardwareEnabled",
-		                       "Is WWAN hardware enabled",
-		                       TRUE,
-		                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
-	/**
-	 * NMClient::active-connections:
-	 *
-	 * The active connections.
-	 **/
-	g_object_class_install_property
-		(object_class, PROP_ACTIVE_CONNECTIONS,
-		 g_param_spec_boxed (NM_CLIENT_ACTIVE_CONNECTIONS,
-						   "Active connections",
-						   "Active connections",
-						   NM_TYPE_OBJECT_ARRAY,
-						   G_PARAM_READABLE));
-
-	/* signals */
-
-	/**
-	 * NMClient::device-added:
-	 * @client: the client that received the signal
-	 * @device: the new device
-	 *
-	 * Notifies that a #NMDevice is added.
-	 **/
-	signals[DEVICE_ADDED] =
-		g_signal_new ("device-added",
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMClientClass, device_added),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__OBJECT,
-					  G_TYPE_NONE, 1,
-					  G_TYPE_OBJECT);
-
-	/**
-	 * NMClient::device-removed:
-	 * @widget: the client that received the signal
-	 * @device: the removed device
-	 *
-	 * Notifies that a #NMDevice is removed.
-	 **/
-	signals[DEVICE_REMOVED] =
-		g_signal_new ("device-removed",
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  G_STRUCT_OFFSET (NMClientClass, device_removed),
-					  NULL, NULL,
-					  g_cclosure_marshal_VOID__OBJECT,
-					  G_TYPE_NONE, 1,
-					  G_TYPE_OBJECT);
-
-	/**
-	 * NMClient::permission-changed:
-	 * @widget: the client that received the signal
-	 * @permission: a permission from #NMClientPermission
-	 * @result: the permission's result, one of #NMClientPermissionResult
-	 *
-	 * Notifies that a permission has changed
-	 **/
-	signals[PERMISSION_CHANGED] =
-		g_signal_new ("permission-changed",
-					  G_OBJECT_CLASS_TYPE (object_class),
-					  G_SIGNAL_RUN_FIRST,
-					  0, NULL, NULL,
-					  _nm_marshal_VOID__UINT_UINT,
-					  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
-}
-
-/**
- * nm_client_new:
- *
- * Creates a new #NMClient.
- *
- * Returns: a new #NMClient
- **/
-NMClient *
-nm_client_new (void)
-{
-	DBusGConnection *connection;
-	GError *err = NULL;
-
-	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
-	if (!connection) {
-		g_warning ("Couldn't connect to system bus: %s", err->message);
-		g_error_free (err);
-		return NULL;
-	}
-
-	return (NMClient *) g_object_new (NM_TYPE_CLIENT,
-									  NM_OBJECT_DBUS_CONNECTION, connection,
-									  NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
-									  NULL);
-}
-
-static void
-proxy_name_owner_changed (DBusGProxy *proxy,
-						  const char *name,
-						  const char *old_owner,
-						  const char *new_owner,
-						  gpointer user_data)
-{
-	NMClient *client = NM_CLIENT (user_data);
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	gboolean old_good = (old_owner && strlen (old_owner));
-	gboolean new_good = (new_owner && strlen (new_owner));
-	gboolean new_running = FALSE;
-
-	if (!name || strcmp (name, NM_DBUS_SERVICE))
-		return;
-
-	if (!old_good && new_good)
-		new_running = TRUE;
-	else if (old_good && !new_good)
-		new_running = FALSE;
-
-	if (new_running == priv->manager_running)
-		return;
-
-	priv->manager_running = new_running;
-	if (!priv->manager_running) {
-		priv->state = NM_STATE_UNKNOWN;
-		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
-		poke_wireless_devices_with_rf_status (client);
-		free_object_array (&priv->devices);
-		free_object_array (&priv->active_connections);
-		priv->wireless_enabled = FALSE;
-		priv->wireless_hw_enabled = FALSE;
-		priv->wwan_enabled = FALSE;
-		priv->wwan_hw_enabled = FALSE;
-	} else {
-		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
-		update_wireless_status (client, TRUE);
-		update_wwan_status (client, TRUE);
-	}
-}
-
-static void
-client_device_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
-{
-	NMClient *client = NM_CLIENT (user_data);
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	GObject *device;
-
-	device = G_OBJECT (nm_client_get_device_by_path (client, path));
-	if (!device) {
-		DBusGConnection *connection = nm_object_get_connection (NM_OBJECT (client));
-
-		device = G_OBJECT (_nm_object_cache_get (path));
-		if (device) {
-			g_ptr_array_add (priv->devices, g_object_ref (device));
-		} else {
-			device = G_OBJECT (nm_device_new (connection, path));
-			if (device)
-				g_ptr_array_add (priv->devices, device);
-		}
-	}
-
-	if (device)
-		g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
-}
-
-static void
-client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
-{
-	NMClient *client = NM_CLIENT (user_data);
-	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
-	NMDevice *device;
-
-	device = nm_client_get_device_by_path (client, path);
-	if (device) {
-		g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
-		g_ptr_array_remove (priv->devices, device);
-		g_object_unref (device);
-	}
-}
-
 /**
  * nm_client_get_devices:
  * @client: a #NMClient
  *
  * Gets all the detected devices.
  *
- * Returns: a #GPtrArray containing all the #NMDevice<!-- -->s.
+ * Returns: (transfer none) (element-type NMClient.Device): a #GPtrArray containing all the #NMDevice<!-- -->s.
  * The returned array is owned by the client and should not be modified.
  **/
 const GPtrArray *
@@ -942,7 +530,7 @@ nm_client_get_devices (NMClient *client)
  *
  * Gets a #NMDevice from a #NMClient.
  *
- * Returns: the #NMDevice for the given @object_path or %NULL if none is found.
+ * Returns: (transfer none): the #NMDevice for the given @object_path or %NULL if none is found.
  **/
 NMDevice *
 nm_client_get_device_by_path (NMClient *client, const char *object_path)
@@ -970,9 +558,75 @@ nm_client_get_device_by_path (NMClient *client, const char *object_path)
 }
 
 typedef struct {
-	NMClientActivateDeviceFn fn;
+	NMClient *client;
+	NMClientActivateFn act_fn;
+	NMClientAddActivateFn add_act_fn;
+	char *active_path;
+	char *new_connection_path;
 	gpointer user_data;
-} ActivateDeviceInfo;
+} ActivateInfo;
+
+static void
+activate_info_free (ActivateInfo *info)
+{
+	g_free (info->active_path);
+	g_free (info->new_connection_path);
+	memset (info, 0, sizeof (*info));
+	g_slice_free (ActivateInfo, info);
+}
+
+static void
+activate_info_complete (ActivateInfo *info,
+                        NMActiveConnection *active,
+                        GError *error)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (info->client);
+
+	if (info->act_fn)
+		info->act_fn (info->client, error ? NULL : active, error, info->user_data);
+	else if (info->add_act_fn) {
+		info->add_act_fn (info->client,
+		                  error ? NULL : active,
+		                  error ? NULL : info->new_connection_path,
+		                  error,
+		                  info->user_data);
+	} else if (error)
+		g_warning ("Device activation failed: (%d) %s", error->code, error->message);
+
+	priv->pending_activations = g_slist_remove (priv->pending_activations, info);
+}
+
+static void
+recheck_pending_activations (NMClient *self)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+	GSList *iter;
+	const GPtrArray *active_connections;
+	int i;
+
+	active_connections = nm_client_get_active_connections (self);
+	if (!active_connections)
+		return;
+
+	/* For each active connection, look for a pending activation that has
+	 * the active connection's object path, and call its callback.
+	 */
+	for (i = 0; i < active_connections->len; i++) {
+		NMActiveConnection *active = g_ptr_array_index (active_connections, i);
+		const char *active_path = nm_object_get_path (NM_OBJECT (active));
+
+		for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) {
+			ActivateInfo *info = iter->data;
+
+			if (g_strcmp0 (info->active_path, active_path) == 0) {
+				/* Call the pending activation's callback and it all up*/
+				activate_info_complete (info, active, NULL);
+				activate_info_free (info);
+				break;
+			}
+		}
+	}
+}
 
 static void
 activate_cb (DBusGProxy *proxy,
@@ -980,63 +634,154 @@ activate_cb (DBusGProxy *proxy,
              GError *error,
              gpointer user_data)
 {
-	ActivateDeviceInfo *info = (ActivateDeviceInfo *) user_data;
-
-	if (info->fn)
-		info->fn (info->user_data, path, error);
-	else if (error)
-		nm_warning ("Device activation failed: (%d) %s", error->code, error->message);
+	ActivateInfo *info = user_data;
 
-	g_slice_free (ActivateDeviceInfo, info);
+	if (error) {
+		activate_info_complete (info, NULL, error);
+		activate_info_free (info);
+	} else {
+		info->active_path = g_strdup (path);
+		recheck_pending_activations (info->client);
+	}
 }
 
 /**
  * nm_client_activate_connection:
  * @client: a #NMClient
- * @service_name: the connection's service name
- * @connection_path: the connection's DBus path
- * @device: the #NMDevice
- * @specific_object: the device specific object (currently used only for
- * activating wireless devices and should be the #NMAccessPoint<!-- -->'s path.
- * @callback: the function to call when the call is done
- * @user_data: user data to pass to the callback function
+ * @connection: an #NMConnection
+ * @device: (allow-none): the #NMDevice
+ * @specific_object: (allow-none): the object path of a connection-type-specific
+ *   object this activation should use. This parameter is currently ignored for
+ *   wired and mobile broadband connections, and the value of NULL should be used
+ *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
+ *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
+ *   get using nm_object_get_path(), and which will be used to complete the
+ *   details of the newly added connection.
+ * @callback: (scope async) (allow-none): the function to call when the call is done
+ * @user_data: (closure): user data to pass to the callback function
  *
- * Activates a connection with the given #NMDevice.
+ * Starts a connection to a particular network using the configuration settings
+ * from @connection and the network device @device.  Certain connection types
+ * also take a "specific object" which is the object path of a connection-
+ * specific object, like an #NMAccessPoint for WiFi connections, or an
+ * #NMWimaxNsp for WiMAX connections, to which you wish to connect.  If the
+ * specific object is not given, NetworkManager can, in some cases, automatically
+ * determine which network to connect to given the settings in @connection.
  **/
 void
 nm_client_activate_connection (NMClient *client,
-					  const char *service_name,
-					  const char *connection_path,
-					  NMDevice *device,
-					  const char *specific_object,
-					  NMClientActivateDeviceFn callback,
-					  gpointer user_data)
+                               NMConnection *connection,
+                               NMDevice *device,
+                               const char *specific_object,
+                               NMClientActivateFn callback,
+                               gpointer user_data)
+{
+	NMClientPrivate *priv;
+	ActivateInfo *info;
+
+	g_return_if_fail (NM_IS_CLIENT (client));
+	if (device)
+		g_return_if_fail (NM_IS_DEVICE (device));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+
+	info = g_slice_new0 (ActivateInfo);
+	info->act_fn = callback;
+	info->user_data = user_data;
+	info->client = client;
+
+	priv = NM_CLIENT_GET_PRIVATE (client);
+	priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
+
+	org_freedesktop_NetworkManager_activate_connection_async (priv->client_proxy,
+	                                                          nm_connection_get_path (connection),
+	                                                          device ? nm_object_get_path (NM_OBJECT (device)) : "/",
+	                                                          specific_object ? specific_object : "/",
+	                                                          activate_cb,
+	                                                          info);
+}
+
+static void
+add_activate_cb (DBusGProxy *proxy,
+                 char *connection_path,
+                 char *active_path,
+                 GError *error,
+                 gpointer user_data)
+{
+	ActivateInfo *info = user_data;
+
+	if (error) {
+		activate_info_complete (info, NULL, error);
+		activate_info_free (info);
+	} else {
+		info->new_connection_path = g_strdup (connection_path);
+		info->active_path = g_strdup (active_path);
+		recheck_pending_activations (info->client);
+	}
+}
+
+/**
+ * nm_client_add_and_activate_connection:
+ * @client: a #NMClient
+ * @partial: (allow-none): an #NMConnection to add; the connection may be
+ *   partially filled (or even NULL) and will be completed by NetworkManager
+ *   using the given @device and @specific_object before being added
+ * @device: the #NMDevice
+ * @specific_object: (allow-none): the object path of a connection-type-specific
+ *   object this activation should use. This parameter is currently ignored for
+ *   wired and mobile broadband connections, and the value of NULL should be used
+ *   (ie, no specific object).  For WiFi or WiMAX connections, pass the object
+ *   path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can
+ *   get using nm_object_get_path(), and which will be used to complete the
+ *   details of the newly added connection.
+ * @callback: (scope async) (allow-none): the function to call when the call is done
+ * @user_data: (closure): user data to pass to the callback function
+ *
+ * Adds a new connection using the given details (if any) as a template,
+ * automatically filling in missing settings with the capabilities of the
+ * given device and specific object.  The new connection is then activated.
+ * Cannot be used for VPN connections at this time.
+ **/
+void
+nm_client_add_and_activate_connection (NMClient *client,
+                                       NMConnection *partial,
+                                       NMDevice *device,
+                                       const char *specific_object,
+                                       NMClientAddActivateFn callback,
+                                       gpointer user_data)
 {
-	ActivateDeviceInfo *info;
-	char *internal_so = (char *) specific_object;
+	NMClientPrivate *priv;
+	ActivateInfo *info;
+	GHashTable *hash = NULL;
 
 	g_return_if_fail (NM_IS_CLIENT (client));
 	g_return_if_fail (NM_IS_DEVICE (device));
-	g_return_if_fail (service_name != NULL);
-	g_return_if_fail (connection_path != NULL);
-
-	/* NULL specific object must be translated into "/" because D-Bus does
-	 * not have any idea of NULL object paths.
-	 */
-	if (internal_so == NULL)
-		internal_so = "/";
 
-	info = g_slice_new (ActivateDeviceInfo);
-	info->fn = callback;
+	info = g_slice_new0 (ActivateInfo);
+	info->add_act_fn = callback;
 	info->user_data = user_data;
+	info->client = client;
 
-	org_freedesktop_NetworkManager_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->client_proxy,
-											    service_name,
-											    connection_path,
-											    nm_object_get_path (NM_OBJECT (device)),
-											    internal_so,
-											    activate_cb,
-											    info);
+	if (partial)
+		hash = nm_connection_to_hash (partial, NM_SETTING_HASH_FLAG_ALL);
+	else
+		hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+	priv = NM_CLIENT_GET_PRIVATE (client);
+	priv->pending_activations = g_slist_prepend (priv->pending_activations, info);
+
+	org_freedesktop_NetworkManager_add_and_activate_connection_async (priv->client_proxy,
+	                                                                  hash,
+	                                                                  nm_object_get_path (NM_OBJECT (device)),
+	                                                                  specific_object ? specific_object : "/",
+	                                                                  add_activate_cb,
+	                                                                  info);
+	g_hash_table_unref (hash);
+}
+
+static void
+active_connections_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+	recheck_pending_activations (NM_CLIENT (object));
 }
 
 /**
@@ -1071,7 +816,8 @@ nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active)
  *
  * Gets the active connections.
  *
- * Returns: a #GPtrArray containing all the active #NMActiveConnection<!-- -->s.
+ * Returns: (transfer none) (element-type NMClient.ActiveConnection): a #GPtrArray
+*  containing all the active #NMActiveConnection<!-- -->s.
  * The returned array is owned by the client and should not be modified.
  **/
 const GPtrArray * 
@@ -1092,11 +838,12 @@ nm_client_get_active_connections (NMClient *client)
 	if (!_nm_object_get_property (NM_OBJECT (client),
 	                             "org.freedesktop.NetworkManager",
 	                             "ActiveConnections",
-	                             &value)) {
+	                             &value,
+	                             NULL)) {
 		return NULL;
 	}
 
-	demarshal_active_connections (NM_OBJECT (client), NULL, &value, &priv->active_connections);	
+	demarshal_active_connections (NM_OBJECT (client), NULL, &value, &priv->active_connections);
 	g_value_unset (&value);
 
 	return handle_ptr_array_return (priv->active_connections);
@@ -1213,6 +960,92 @@ nm_client_wwan_hardware_get_enabled (NMClient *client)
 }
 
 /**
+ * nm_client_wimax_get_enabled:
+ * @client: a #NMClient
+ *
+ * Determines whether WiMAX is enabled.
+ *
+ * Returns: %TRUE if WiMAX is enabled
+ **/
+gboolean
+nm_client_wimax_get_enabled (NMClient *client)
+{
+	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+
+	return NM_CLIENT_GET_PRIVATE (client)->wimax_enabled;
+}
+
+/**
+ * nm_client_wimax_set_enabled:
+ * @client: a #NMClient
+ * @enabled: %TRUE to enable WiMAX
+ *
+ * Enables or disables WiMAX devices.
+ **/
+void
+nm_client_wimax_set_enabled (NMClient *client, gboolean enabled)
+{
+	GValue value = {0,};
+
+	g_return_if_fail (NM_IS_CLIENT (client));
+
+	g_value_init (&value, G_TYPE_BOOLEAN);
+	g_value_set_boolean (&value, enabled);
+
+	_nm_object_set_property (NM_OBJECT (client),
+	                         NM_DBUS_INTERFACE,
+	                         "WimaxEnabled",
+	                         &value);
+}
+
+/**
+ * nm_client_wimax_hardware_get_enabled:
+ * @client: a #NMClient
+ *
+ * Determines whether the WiMAX hardware is enabled.
+ *
+ * Returns: %TRUE if the WiMAX hardware is enabled
+ **/
+gboolean
+nm_client_wimax_hardware_get_enabled (NMClient *client)
+{
+	g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
+
+	return NM_CLIENT_GET_PRIVATE (client)->wimax_hw_enabled;
+}
+
+/**
+ * nm_client_get_version:
+ * @client: a #NMClient
+ *
+ * Gets NetworkManager version.
+ *
+ * Returns: string with the version
+ **/
+const char *
+nm_client_get_version (NMClient *client)
+{
+	NMClientPrivate *priv;
+	GError *err = NULL;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
+
+	priv = NM_CLIENT_GET_PRIVATE (client);
+
+	if (!priv->manager_running)
+		return NULL;
+
+	if (!priv->version)
+		priv->version = _nm_object_get_string_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "Version", &err);
+
+	/* TODO: we don't pass the error to the caller yet, maybe later */
+	if (err)
+		g_error_free (err);
+
+	return priv->version;
+}
+
+/**
  * nm_client_get_state:
  * @client: a #NMClient
  *
@@ -1233,7 +1066,7 @@ nm_client_get_state (NMClient *client)
 		return NM_STATE_UNKNOWN;
 
 	if (priv->state == NM_STATE_UNKNOWN)
-		priv->state = _nm_object_get_uint_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "State");
+		priv->state = _nm_object_get_uint_property (NM_OBJECT (client), NM_DBUS_INTERFACE, "State", NULL);
 
 	return priv->state;
 }
@@ -1259,7 +1092,8 @@ nm_client_networking_get_enabled (NMClient *client)
 		if (!priv->networking_enabled) {
 			priv->networking_enabled = _nm_object_get_boolean_property (NM_OBJECT (client),
 			                                                            NM_DBUS_INTERFACE,
-			                                                            "NetworkingEnabled");
+			                                                            "NetworkingEnabled",
+			                                                            NULL);
 			priv->have_networking_enabled = TRUE;
 		}
 	}
@@ -1340,3 +1174,562 @@ nm_client_get_permission_result (NMClient *client, NMClientPermission permission
 	return GPOINTER_TO_UINT (result);
 }
 
+/****************************************************************/
+
+static void
+free_object_array (GPtrArray **array)
+{
+	g_return_if_fail (array != NULL);
+
+	if (*array) {
+		g_ptr_array_foreach (*array, (GFunc) g_object_unref, NULL);
+		g_ptr_array_free (*array, TRUE);
+		*array = NULL;
+	}
+}
+
+static void
+proxy_name_owner_changed (DBusGProxy *proxy,
+						  const char *name,
+						  const char *old_owner,
+						  const char *new_owner,
+						  gpointer user_data)
+{
+	NMClient *client = NM_CLIENT (user_data);
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+	gboolean old_good = (old_owner && strlen (old_owner));
+	gboolean new_good = (new_owner && strlen (new_owner));
+	gboolean new_running = FALSE;
+
+	if (!name || strcmp (name, NM_DBUS_SERVICE))
+		return;
+
+	if (!old_good && new_good)
+		new_running = TRUE;
+	else if (old_good && !new_good)
+		new_running = FALSE;
+
+	if (new_running == priv->manager_running)
+		return;
+
+	priv->manager_running = new_running;
+	if (!priv->manager_running) {
+		priv->state = NM_STATE_UNKNOWN;
+		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
+		poke_wireless_devices_with_rf_status (client);
+		free_object_array (&priv->devices);
+		free_object_array (&priv->active_connections);
+		priv->wireless_enabled = FALSE;
+		priv->wireless_hw_enabled = FALSE;
+		priv->wwan_enabled = FALSE;
+		priv->wwan_hw_enabled = FALSE;
+		priv->wimax_enabled = FALSE;
+		priv->wimax_hw_enabled = FALSE;
+	} else {
+		_nm_object_queue_notify (NM_OBJECT (client), NM_CLIENT_MANAGER_RUNNING);
+		update_wireless_status (client, TRUE);
+		update_wwan_status (client, TRUE);
+		update_wimax_status (client, TRUE);
+	}
+}
+
+static void
+client_device_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
+{
+	NMClient *client = NM_CLIENT (user_data);
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+	GObject *device;
+
+	device = G_OBJECT (nm_client_get_device_by_path (client, path));
+	if (!device) {
+		DBusGConnection *connection = nm_object_get_connection (NM_OBJECT (client));
+
+		device = G_OBJECT (_nm_object_cache_get (path));
+		if (device) {
+			g_ptr_array_add (priv->devices, device);
+		} else {
+			device = G_OBJECT (nm_device_new (connection, path));
+			if (device)
+				g_ptr_array_add (priv->devices, device);
+		}
+	}
+
+	if (device)
+		g_signal_emit (client, signals[DEVICE_ADDED], 0, device);
+}
+
+static void
+client_device_removed_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
+{
+	NMClient *client = NM_CLIENT (user_data);
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (client);
+	NMDevice *device;
+
+	device = nm_client_get_device_by_path (client, path);
+	if (device) {
+		g_signal_emit (client, signals[DEVICE_REMOVED], 0, device);
+		g_ptr_array_remove (priv->devices, device);
+		g_object_unref (device);
+	}
+}
+
+/****************************************************************/
+
+/**
+ * nm_client_new:
+ *
+ * Creates a new #NMClient.
+ *
+ * Returns: a new #NMClient
+ **/
+NMClient *
+nm_client_new (void)
+{
+	DBusGConnection *connection;
+	GError *err = NULL;
+
+#ifdef LIBNM_GLIB_TEST
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &err);
+#else
+	connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
+#endif
+	if (!connection) {
+		g_warning ("Couldn't connect to system bus: %s", err->message);
+		g_error_free (err);
+		return NULL;
+	}
+
+	return (NMClient *) g_object_new (NM_TYPE_CLIENT,
+									  NM_OBJECT_DBUS_CONNECTION, connection,
+									  NM_OBJECT_DBUS_PATH, NM_DBUS_PATH,
+									  NULL);
+}
+
+static GObject*
+constructor (GType type,
+		   guint n_construct_params,
+		   GObjectConstructParam *construct_params)
+{
+	NMObject *object;
+	DBusGConnection *connection;
+	NMClientPrivate *priv;
+	GError *err = NULL;
+
+	object = (NMObject *) G_OBJECT_CLASS (nm_client_parent_class)->constructor (type,
+																 n_construct_params,
+																 construct_params);
+	if (!object)
+		return NULL;
+
+	priv = NM_CLIENT_GET_PRIVATE (object);
+	connection = nm_object_get_connection (object);
+
+	priv->client_proxy = dbus_g_proxy_new_for_name (connection,
+										   NM_DBUS_SERVICE,
+										   nm_object_get_path (object),
+										   NM_DBUS_INTERFACE);
+
+	register_for_property_changed (NM_CLIENT (object));
+
+	dbus_g_proxy_add_signal (priv->client_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->client_proxy,
+						    "DeviceAdded",
+						    G_CALLBACK (client_device_added_proxy),
+						    object,
+						    NULL);
+
+	dbus_g_proxy_add_signal (priv->client_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->client_proxy,
+						    "DeviceRemoved",
+						    G_CALLBACK (client_device_removed_proxy),
+						    object,
+						    NULL);
+
+	/* Permissions */
+	dbus_g_proxy_add_signal (priv->client_proxy, "CheckPermissions", G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->client_proxy,
+	                             "CheckPermissions",
+	                             G_CALLBACK (client_recheck_permissions),
+	                             object,
+	                             NULL);
+	get_permissions_sync (NM_CLIENT (object));
+
+	priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
+	                                             DBUS_SERVICE_DBUS,
+	                                             DBUS_PATH_DBUS,
+	                                             DBUS_INTERFACE_DBUS);
+
+	dbus_g_proxy_add_signal (priv->bus_proxy, "NameOwnerChanged",
+						G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+						G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->bus_proxy,
+						    "NameOwnerChanged",
+						    G_CALLBACK (proxy_name_owner_changed),
+						    object, NULL);
+
+	if (!dbus_g_proxy_call (priv->bus_proxy,
+					    "NameHasOwner", &err,
+					    G_TYPE_STRING, NM_DBUS_SERVICE,
+					    G_TYPE_INVALID,
+					    G_TYPE_BOOLEAN, &priv->manager_running,
+					    G_TYPE_INVALID)) {
+		g_warning ("Error on NameHasOwner DBUS call: %s", err->message);
+		g_error_free (err);
+	}
+
+	if (priv->manager_running) {
+		update_wireless_status (NM_CLIENT (object), FALSE);
+		update_wwan_status (NM_CLIENT (object), FALSE);
+		update_wimax_status (NM_CLIENT (object), FALSE);
+		nm_client_get_state (NM_CLIENT (object));
+	}
+
+	g_signal_connect (G_OBJECT (object), "notify::" NM_CLIENT_WIRELESS_ENABLED,
+	                  G_CALLBACK (wireless_enabled_cb), NULL);
+
+	g_signal_connect (object, "notify::" NM_CLIENT_ACTIVE_CONNECTIONS,
+	                  G_CALLBACK (active_connections_changed_cb), NULL);
+
+	return G_OBJECT (object);
+}
+
+static void
+dispose (GObject *object)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+
+	if (priv->disposed) {
+		G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
+		return;
+	}
+
+	if (priv->perm_call)
+		dbus_g_proxy_cancel_call (priv->client_proxy, priv->perm_call);
+
+	g_object_unref (priv->client_proxy);
+	g_object_unref (priv->bus_proxy);
+
+	free_object_array (&priv->devices);
+	free_object_array (&priv->active_connections);
+
+	g_slist_foreach (priv->pending_activations, (GFunc) activate_info_free, NULL);
+	g_slist_free (priv->pending_activations);
+
+	g_hash_table_destroy (priv->permissions);
+
+	G_OBJECT_CLASS (nm_client_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+
+	g_free (priv->version);
+
+	G_OBJECT_CLASS (nm_client_parent_class)->finalize (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+		    const GValue *value, GParamSpec *pspec)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (object);
+	gboolean b;
+
+	switch (prop_id) {
+	case PROP_NETWORKING_ENABLED:
+		b = g_value_get_boolean (value);
+		if (priv->networking_enabled != b) {
+			nm_client_networking_set_enabled (NM_CLIENT (object), b);
+			/* Let the property value flip when we get the change signal from NM */
+		}
+		break;
+	case PROP_WIRELESS_ENABLED:
+		b = g_value_get_boolean (value);
+		if (priv->wireless_enabled != b) {
+			nm_client_wireless_set_enabled (NM_CLIENT (object), b);
+			/* Let the property value flip when we get the change signal from NM */
+		}
+		break;
+	case PROP_WWAN_ENABLED:
+		b = g_value_get_boolean (value);
+		if (priv->wwan_enabled != b) {
+			nm_client_wwan_set_enabled (NM_CLIENT (object), b);
+			/* Let the property value flip when we get the change signal from NM */
+		}
+		break;
+	case PROP_WIMAX_ENABLED:
+		b = g_value_get_boolean (value);
+		if (priv->wimax_enabled != b) {
+			nm_client_wimax_set_enabled (NM_CLIENT (object), b);
+			/* Let the property value flip when we get the change signal from NM */
+		}
+		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)
+{
+	NMClient *self = NM_CLIENT (object);
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+
+	switch (prop_id) {
+	case PROP_VERSION:
+		g_value_set_string (value, nm_client_get_version (self));
+		break;
+	case PROP_STATE:
+		g_value_set_uint (value, nm_client_get_state (self));
+		break;
+	case PROP_MANAGER_RUNNING:
+		g_value_set_boolean (value, priv->manager_running);
+		break;
+	case PROP_NETWORKING_ENABLED:
+		g_value_set_boolean (value, nm_client_networking_get_enabled (self));
+		break;
+	case PROP_WIRELESS_ENABLED:
+		g_value_set_boolean (value, priv->wireless_enabled);
+		break;
+	case PROP_WIRELESS_HARDWARE_ENABLED:
+		g_value_set_boolean (value, priv->wireless_hw_enabled);
+		break;
+	case PROP_WWAN_ENABLED:
+		g_value_set_boolean (value, priv->wwan_enabled);
+		break;
+	case PROP_WWAN_HARDWARE_ENABLED:
+		g_value_set_boolean (value, priv->wwan_hw_enabled);
+		break;
+	case PROP_WIMAX_ENABLED:
+		g_value_set_boolean (value, priv->wimax_enabled);
+		break;
+	case PROP_WIMAX_HARDWARE_ENABLED:
+		g_value_set_boolean (value, priv->wimax_hw_enabled);
+		break;
+	case PROP_ACTIVE_CONNECTIONS:
+		g_value_set_boxed (value, nm_client_get_active_connections (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_client_class_init (NMClientClass *client_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (client_class);
+
+	g_type_class_add_private (client_class, sizeof (NMClientPrivate));
+
+	/* virtual methods */
+	object_class->constructor = constructor;
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+
+	/* properties */
+
+	/**
+	 * NMClient:version:
+	 *
+	 * The NetworkManager version.
+	 **/
+	g_object_class_install_property (object_class, PROP_VERSION,
+	                                 g_param_spec_string (NM_CLIENT_VERSION,
+	                                                      "Version",
+	                                                      "NetworkManager version",
+	                                                       NULL,
+	                                                       G_PARAM_READABLE));
+
+	/**
+	 * NMClient:state:
+	 *
+	 * The current daemon state.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_STATE,
+		 g_param_spec_uint (NM_CLIENT_STATE,
+						    "State",
+						    "NetworkManager state",
+						    NM_STATE_UNKNOWN, NM_STATE_CONNECTED_GLOBAL, NM_STATE_UNKNOWN,
+						    G_PARAM_READABLE));
+
+	/**
+	 * NMClient::manager-running:
+	 *
+	 * Whether the daemon is running.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_MANAGER_RUNNING,
+		 g_param_spec_boolean (NM_CLIENT_MANAGER_RUNNING,
+						       "ManagerRunning",
+						       "Whether NetworkManager is running",
+						       FALSE,
+						       G_PARAM_READABLE));
+
+	/**
+	 * NMClient::networking-enabled:
+	 *
+	 * Whether networking is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_NETWORKING_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_NETWORKING_ENABLED,
+						   "NetworkingEnabled",
+						   "Is networking enabled",
+						   TRUE,
+						   G_PARAM_READWRITE));
+
+	/**
+	 * NMClient::wireless-enabled:
+	 *
+	 * Whether wireless is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WIRELESS_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WIRELESS_ENABLED,
+						   "WirelessEnabled",
+						   "Is wireless enabled",
+						   FALSE,
+						   G_PARAM_READWRITE));
+
+	/**
+	 * NMClient::wireless-hardware-enabled:
+	 *
+	 * Whether the wireless hardware is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WIRELESS_HARDWARE_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WIRELESS_HARDWARE_ENABLED,
+						   "WirelessHardwareEnabled",
+						   "Is wireless hardware enabled",
+						   TRUE,
+						   G_PARAM_READABLE));
+
+	/**
+	 * NMClient::wwan-enabled:
+	 *
+	 * Whether WWAN functionality is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WWAN_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WWAN_ENABLED,
+		                       "WwanEnabled",
+		                       "Is WWAN enabled",
+		                       FALSE,
+		                       G_PARAM_READWRITE));
+
+	/**
+	 * NMClient::wwan-hardware-enabled:
+	 *
+	 * Whether the WWAN hardware is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WWAN_HARDWARE_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WWAN_HARDWARE_ENABLED,
+		                       "WwanHardwareEnabled",
+		                       "Is WWAN hardware enabled",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
+	/**
+	 * NMClient::wimax-enabled:
+	 *
+	 * Whether WiMAX functionality is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WIMAX_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WIMAX_ENABLED,
+		                       "WimaxEnabled",
+		                       "Is WiMAX enabled",
+		                       FALSE,
+		                       G_PARAM_READWRITE));
+
+	/**
+	 * NMClient::wimax-hardware-enabled:
+	 *
+	 * Whether the WiMAX hardware is enabled.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_WIMAX_HARDWARE_ENABLED,
+		 g_param_spec_boolean (NM_CLIENT_WIMAX_HARDWARE_ENABLED,
+		                       "WimaxHardwareEnabled",
+		                       "Is WiMAX hardware enabled",
+		                       FALSE,
+		                       G_PARAM_READABLE));
+
+	/**
+	 * NMClient::active-connections:
+	 *
+	 * The active connections.
+	 * Type: GPtrArray<NMClient.ActiveConnection>
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_ACTIVE_CONNECTIONS,
+		 g_param_spec_boxed (NM_CLIENT_ACTIVE_CONNECTIONS,
+						   "Active connections",
+						   "Active connections",
+						   NM_TYPE_OBJECT_ARRAY,
+						   G_PARAM_READABLE));
+
+	/* signals */
+
+	/**
+	 * NMClient::device-added:
+	 * @client: the client that received the signal
+	 * @device: (type NMClient.Device): the new device
+	 *
+	 * Notifies that a #NMDevice is added.
+	 **/
+	signals[DEVICE_ADDED] =
+		g_signal_new ("device-added",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMClientClass, device_added),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  G_TYPE_OBJECT);
+
+	/**
+	 * NMClient::device-removed:
+	 * @widget: the client that received the signal
+	 * @device: (type NMClient.Device): the removed device
+	 *
+	 * Notifies that a #NMDevice is removed.
+	 **/
+	signals[DEVICE_REMOVED] =
+		g_signal_new ("device-removed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  G_STRUCT_OFFSET (NMClientClass, device_removed),
+					  NULL, NULL,
+					  g_cclosure_marshal_VOID__OBJECT,
+					  G_TYPE_NONE, 1,
+					  G_TYPE_OBJECT);
+
+	/**
+	 * NMClient::permission-changed:
+	 * @widget: the client that received the signal
+	 * @permission: a permission from #NMClientPermission
+	 * @result: the permission's result, one of #NMClientPermissionResult
+	 *
+	 * Notifies that a permission has changed
+	 **/
+	signals[PERMISSION_CHANGED] =
+		g_signal_new ("permission-changed",
+					  G_OBJECT_CLASS_TYPE (object_class),
+					  G_SIGNAL_RUN_FIRST,
+					  0, NULL, NULL,
+					  _nm_marshal_VOID__UINT_UINT,
+					  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
+}
+