summary refs log tree commit diff
path: root/libnm-glib/nm-remote-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib/nm-remote-connection.c')
-rw-r--r--libnm-glib/nm-remote-connection.c316
1 files changed, 200 insertions, 116 deletions
diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c
index 1039a7d1..57870c62 100644
--- a/libnm-glib/nm-remote-connection.c
+++ b/libnm-glib/nm-remote-connection.c
@@ -18,7 +18,7 @@
  * Boston, MA 02110-1301 USA.
  *
  * Copyright (C) 2007 - 2008 Novell, Inc.
- * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
  */
 
 #include <string.h>
@@ -29,15 +29,11 @@
 #include "nm-remote-connection.h"
 #include "nm-remote-connection-private.h"
 #include "nm-dbus-glib-types.h"
-#include "nm-exported-connection-bindings.h"
-#include "nm-settings-connection-interface.h"
+#include "nm-settings-connection-bindings.h"
 
 #define NM_REMOTE_CONNECTION_BUS "bus"
 
-static void settings_connection_interface_init (NMSettingsConnectionInterface *klass);
-
-G_DEFINE_TYPE_EXTENDED (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNECTION, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_CONNECTION_INTERFACE, settings_connection_interface_init))
+G_DEFINE_TYPE (NMRemoteConnection, nm_remote_connection, NM_TYPE_CONNECTION)
 
 enum {
 	PROP_0,
@@ -47,10 +43,18 @@ enum {
 	LAST_PROP
 };
 
+enum {
+	UPDATED,
+	REMOVED,
+	VISIBLE,
+
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
 
 typedef struct {
 	NMRemoteConnection *self;
-	DBusGProxy *proxy;
 	DBusGProxyCall *call;
 	GFunc callback;
 	gpointer user_data;
@@ -59,10 +63,10 @@ typedef struct {
 typedef struct {
 	DBusGConnection *bus;
 	DBusGProxy *proxy;
-	DBusGProxy *secrets_proxy;
 	GSList *calls;
 
 	NMRemoteConnectionInitResult init_result;
+	gboolean visible;
 	gboolean disposed;
 } NMRemoteConnectionPrivate;
 
@@ -88,161 +92,184 @@ static void
 update_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
 	RemoteCall *call = user_data;
-	NMSettingsConnectionInterfaceUpdateFunc func = (NMSettingsConnectionInterfaceUpdateFunc) call->callback;
+	NMRemoteConnectionCommitFunc func = (NMRemoteConnectionCommitFunc) call->callback;
 
-	(*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error, call->user_data);
+	(*func)(call->self, error, call->user_data);
 	remote_call_complete (call->self, call);
 }
 
-static gboolean
-update (NMSettingsConnectionInterface *connection,
-        NMSettingsConnectionInterfaceUpdateFunc callback,
-        gpointer user_data)
+/**
+ * nm_remote_connection_commit_changes:
+ * @connection: the #NMRemoteConnection
+ * @callback: (scope async): a function to be called when the commit completes
+ * @user_data: caller-specific data to be passed to @callback
+ *
+ * Save any local changes to the settings and properties of this connection and
+ * save them in the settings service.
+ **/
+void
+nm_remote_connection_commit_changes (NMRemoteConnection *self,
+                                     NMRemoteConnectionCommitFunc callback,
+                                     gpointer user_data)
 {
-	NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection);
-	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+	NMRemoteConnectionPrivate *priv;
 	GHashTable *settings = NULL;
 	RemoteCall *call;
 
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
+	g_return_if_fail (callback != NULL);
+
+	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
 	call = g_malloc0 (sizeof (RemoteCall));
 	call->self = self;
 	call->callback = (GFunc) callback;
 	call->user_data = user_data;
-	call->proxy = priv->proxy;
 
-	settings = nm_connection_to_hash (NM_CONNECTION (self));
+	settings = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ALL);
 
-	call->call = org_freedesktop_NetworkManagerSettings_Connection_update_async (priv->proxy,
-	                                                                             settings,
-	                                                                             update_cb,
-	                                                                             call);
+	call->call = org_freedesktop_NetworkManager_Settings_Connection_update_async (priv->proxy,
+	                                                                              settings,
+	                                                                              update_cb,
+	                                                                              call);
 	g_assert (call->call);
 	priv->calls = g_slist_append (priv->calls, call);
 
 	g_hash_table_destroy (settings);
-
-	return TRUE;
 }
 
 static void
 delete_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
 	RemoteCall *call = user_data;
-	NMSettingsConnectionInterfaceDeleteFunc func = (NMSettingsConnectionInterfaceDeleteFunc) call->callback;
+	NMRemoteConnectionDeleteFunc func = (NMRemoteConnectionDeleteFunc) call->callback;
 
-	(*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error, call->user_data);
+	if (func != NULL)
+		(*func)(call->self, error, call->user_data);
 	remote_call_complete (call->self, call);
 }
 
-static gboolean
-do_delete (NMSettingsConnectionInterface *connection,
-           NMSettingsConnectionInterfaceDeleteFunc callback,
-           gpointer user_data)
+/**
+ * nm_remote_connection_delete:
+ * @connection: the #NMRemoteConnection
+ * @callback: (scope async) (allow-none): a function to be called when the delete completes
+ * @user_data: caller-specific data to be passed to @callback
+ *
+ * Delete the connection.
+ **/
+void
+nm_remote_connection_delete (NMRemoteConnection *self,
+                             NMRemoteConnectionDeleteFunc callback,
+                             gpointer user_data)
 {
-	NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection);
-	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+	NMRemoteConnectionPrivate *priv;
 	RemoteCall *call;
 
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
+
+	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
 	call = g_malloc0 (sizeof (RemoteCall));
 	call->self = self;
 	call->callback = (GFunc) callback;
 	call->user_data = user_data;
-	call->proxy = priv->proxy;
 
-	call->call = org_freedesktop_NetworkManagerSettings_Connection_delete_async (priv->proxy,
-	                                                                             delete_cb,
-	                                                                             call);
+	call->call = org_freedesktop_NetworkManager_Settings_Connection_delete_async (priv->proxy,
+	                                                                              delete_cb,
+	                                                                              call);
 	g_assert (call->call);
 	priv->calls = g_slist_append (priv->calls, call);
-
-	return TRUE;
 }
 
 static void
 get_secrets_cb (DBusGProxy *proxy, GHashTable *secrets, GError *error, gpointer user_data)
 {
 	RemoteCall *call = user_data;
-	NMSettingsConnectionInterfaceGetSecretsFunc func = (NMSettingsConnectionInterfaceGetSecretsFunc) call->callback;
+	NMRemoteConnectionGetSecretsFunc func = (NMRemoteConnectionGetSecretsFunc) call->callback;
 
-	(*func)(NM_SETTINGS_CONNECTION_INTERFACE (call->self), error ? NULL : secrets, error, call->user_data);
+	(*func)(call->self, error ? NULL : secrets, error, call->user_data);
 	remote_call_complete (call->self, call);
 }
 
-static gboolean
-get_secrets (NMSettingsConnectionInterface *connection,
-             const char *setting_name,
-             const char **hints,
-             gboolean request_new,
-             NMSettingsConnectionInterfaceGetSecretsFunc callback,
-             gpointer user_data)
+/**
+ * nm_remote_connection_get_secrets:
+ * @connection: the #NMRemoteConnection
+ * @setting_name: the #NMSetting object name to get secrets for
+ * @callback: (scope async): a function to be called when the update completes
+ * @user_data: caller-specific data to be passed to @callback
+ *
+ * Request the connection's secrets.
+ **/
+void
+nm_remote_connection_get_secrets (NMRemoteConnection *self,
+                                  const char *setting_name,
+                                  NMRemoteConnectionGetSecretsFunc callback,
+                                  gpointer user_data)
 {
-	NMRemoteConnection *self = NM_REMOTE_CONNECTION (connection);
-	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+	NMRemoteConnectionPrivate *priv;
 	RemoteCall *call;
 
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_REMOTE_CONNECTION (self));
+	g_return_if_fail (callback != NULL);
+
+	priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
 	call = g_malloc0 (sizeof (RemoteCall));
 	call->self = self;
 	call->callback = (GFunc) callback;
 	call->user_data = user_data;
-	call->proxy = priv->secrets_proxy;
-
-	call->call = org_freedesktop_NetworkManagerSettings_Connection_Secrets_get_secrets_async (priv->secrets_proxy,
-	                                                                                          setting_name,
-	                                                                                          hints,
-	                                                                                          request_new,
-	                                                                                          get_secrets_cb,
-	                                                                                          call);
+
+	call->call = org_freedesktop_NetworkManager_Settings_Connection_get_secrets_async (priv->proxy,
+	                                                                                   setting_name,
+	                                                                                   get_secrets_cb,
+	                                                                                   call);
 	g_assert (call->call);
 	priv->calls = g_slist_append (priv->calls, call);
-
-	return TRUE;
 }
 
 /****************************************************************/
 
-static gboolean
+static void
 replace_settings (NMRemoteConnection *self, GHashTable *new_settings)
 {
 	GError *error = NULL;
 
-	if (!nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error)) {
-		g_warning ("%s: error updating %s connection %s settings: (%d) %s",
+	if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error))
+		g_signal_emit (self, signals[UPDATED], 0, new_settings);
+	else {
+		g_warning ("%s: error updating connection %s settings: (%d) %s",
 		           __func__,
-		           (nm_connection_get_scope (NM_CONNECTION (self)) == NM_CONNECTION_SCOPE_USER) ? "user" : "system",
 		           nm_connection_get_path (NM_CONNECTION (self)),
 		           error ? error->code : -1,
 		           (error && error->message) ? error->message : "(unknown)");
 		g_clear_error (&error);
-		return FALSE;
-	}
 
-	/* Emit update irregardless to let listeners figure out what to do with
-	 * the connection; whether to delete / ignore it or not.
-	 */
-	nm_settings_connection_interface_emit_updated (NM_SETTINGS_CONNECTION_INTERFACE (self));
-	return TRUE;
+		g_signal_emit (self, signals[REMOVED], 0);
+	}
 }
 
 static void
-get_settings_cb (DBusGProxy *proxy,
-                 GHashTable *new_settings,
-                 GError *error,
-                 gpointer user_data)
+init_get_settings_cb (DBusGProxy *proxy,
+                      GHashTable *new_settings,
+                      GError *error,
+                      gpointer user_data)
 {
 	NMRemoteConnection *self = user_data;
 	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
 	if (error) {
-		g_warning ("%s: error getting %s connection %s settings: (%d) %s",
-		           __func__,
-		           (nm_connection_get_scope (NM_CONNECTION (self)) == NM_CONNECTION_SCOPE_USER) ? "user" : "system",
-		           nm_connection_get_path (NM_CONNECTION (self)),
-		           error ? error->code : -1,
-		           (error && error->message) ? error->message : "(unknown)");
-		g_error_free (error);
-		priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR;
+		/* Connection doesn't exist, or isn't visible to this user */
+		if (dbus_g_error_has_name (error, "org.freedesktop.NetworkManager.Settings.PermissionDenied"))
+			priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_INVISIBLE;
+		else
+			priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_ERROR;
+
 		g_object_notify (G_OBJECT (self), NM_REMOTE_CONNECTION_INIT_RESULT);
 	} else {
+		priv->visible = TRUE;
 		replace_settings (self, new_settings);
 		g_hash_table_destroy (new_settings);
 		priv->init_result = NM_REMOTE_CONNECTION_INIT_RESULT_SUCCESS;
@@ -251,34 +278,64 @@ get_settings_cb (DBusGProxy *proxy,
 }
 
 static void
-updated_cb (DBusGProxy *proxy, GHashTable *settings, gpointer user_data)
+updated_get_settings_cb (DBusGProxy *proxy,
+                         GHashTable *new_settings,
+                         GError *error,
+                         gpointer user_data)
 {
-	replace_settings (NM_REMOTE_CONNECTION (user_data), settings);
+	NMRemoteConnection *self = user_data;
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
+
+	if (error) {
+		GHashTable *hash;
+
+		/* Connection is no longer visible to this user.  Let the settings
+		 * service handle this via 'visible'.  The settings service will emit
+		 * the "removed" signal for us since it handles the lifetime of this
+		 * object.
+		 */
+		hash = g_hash_table_new (g_str_hash, g_str_equal);
+		nm_connection_replace_settings (NM_CONNECTION (self), hash, NULL);
+		g_hash_table_destroy (hash);
+
+		priv->visible = FALSE;
+		g_signal_emit (self, signals[VISIBLE], 0, FALSE);
+	} else {
+		replace_settings (self, new_settings);
+		g_hash_table_destroy (new_settings);
+
+		/* Settings service will handle announcing the connection to clients */
+		if (priv->visible == FALSE) {
+			priv->visible = TRUE;
+			g_signal_emit (self, signals[VISIBLE], 0, TRUE);
+		}
+	}
 }
 
 static void
-removed_cb (DBusGProxy *proxy, gpointer user_data)
+updated_cb (DBusGProxy *proxy, gpointer user_data)
 {
-	g_signal_emit_by_name (G_OBJECT (user_data), "removed");
-}
+	NMRemoteConnection *self = NM_REMOTE_CONNECTION (user_data);
+	NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE (self);
 
-/****************************************************************/
+	/* The connection got updated; request the replacement settings */
+	org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy,
+	                                                                       updated_get_settings_cb,
+	                                                                       self);
+}
 
 static void
-settings_connection_interface_init (NMSettingsConnectionInterface *klass)
+removed_cb (DBusGProxy *proxy, gpointer user_data)
 {
-	/* interface implementation */
-	klass->update = update;
-	klass->delete = do_delete;
-	klass->get_secrets = get_secrets;
+	g_signal_emit (G_OBJECT (user_data), signals[REMOVED], 0);
 }
 
+/****************************************************************/
+
 /**
  * nm_remote_connection_new:
  * @bus: a valid and connected D-Bus connection
- * @scope: the Connection scope (either user or system)
  * @path: the D-Bus path of the connection as exported by the settings service
- *  indicated by @scope
  *
  * Creates a new object representing the remote connection.
  *
@@ -286,7 +343,6 @@ settings_connection_interface_init (NMSettingsConnectionInterface *klass)
  **/
 NMRemoteConnection *
 nm_remote_connection_new (DBusGConnection *bus,
-                          NMConnectionScope scope,
                           const char *path)
 {
 	g_return_val_if_fail (bus != NULL, NULL);
@@ -294,7 +350,6 @@ nm_remote_connection_new (DBusGConnection *bus,
 
 	return (NMRemoteConnection *) g_object_new (NM_TYPE_REMOTE_CONNECTION,
 	                                            NM_REMOTE_CONNECTION_BUS, bus,
-	                                            NM_CONNECTION_SCOPE, scope,
 	                                            NM_CONNECTION_PATH, path,
 	                                            NULL);
 }
@@ -306,7 +361,6 @@ constructor (GType type,
 {
 	GObject *object;
 	NMRemoteConnectionPrivate *priv;
-	const char *service = NM_DBUS_SERVICE_USER_SETTINGS;
 
 	object = G_OBJECT_CLASS (nm_remote_connection_parent_class)->constructor (type, n_construct_params, construct_params);
 	if (!object)
@@ -316,32 +370,22 @@ constructor (GType type,
 	g_assert (priv->bus);
 	g_assert (nm_connection_get_path (NM_CONNECTION (object)));
 
-	if (nm_connection_get_scope (NM_CONNECTION (object)) == NM_CONNECTION_SCOPE_SYSTEM)
-		service = NM_DBUS_SERVICE_SYSTEM_SETTINGS;
-
 	priv->proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                         service,
+	                                         NM_DBUS_SERVICE,
 	                                         nm_connection_get_path (NM_CONNECTION (object)),
 	                                         NM_DBUS_IFACE_SETTINGS_CONNECTION);
 	g_assert (priv->proxy);
 	dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT);
 
-	priv->secrets_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                                 service,
-	                                                 nm_connection_get_path (NM_CONNECTION (object)),
-	                                                 NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS);
-	g_assert (priv->secrets_proxy);
-	dbus_g_proxy_set_default_timeout (priv->secrets_proxy, G_MAXINT);
-
-	dbus_g_proxy_add_signal (priv->proxy, "Updated", DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->proxy, "Updated", G_TYPE_INVALID);
 	dbus_g_proxy_connect_signal (priv->proxy, "Updated", G_CALLBACK (updated_cb), object, NULL);
 
 	dbus_g_proxy_add_signal (priv->proxy, "Removed", G_TYPE_INVALID);
 	dbus_g_proxy_connect_signal (priv->proxy, "Removed", G_CALLBACK (removed_cb), object, NULL);
 
-	org_freedesktop_NetworkManagerSettings_Connection_get_settings_async (priv->proxy,
-	                                                                      get_settings_cb,
-	                                                                      object);
+	org_freedesktop_NetworkManager_Settings_Connection_get_settings_async (priv->proxy,
+	                                                                       init_get_settings_cb,
+	                                                                       object);
 	return object;
 }
 
@@ -397,7 +441,6 @@ dispose (GObject *object)
 			remote_call_complete (self, priv->calls->data);
 
 		g_object_unref (priv->proxy);
-		g_object_unref (priv->secrets_proxy);
 		dbus_g_connection_unref (priv->bus);
 	}
 
@@ -435,5 +478,46 @@ nm_remote_connection_class_init (NMRemoteConnectionClass *remote_class)
 		                    NM_REMOTE_CONNECTION_INIT_RESULT_ERROR,
 		                    NM_REMOTE_CONNECTION_INIT_RESULT_UNKNOWN,
 		                    G_PARAM_READABLE));
-}
 
+	/* Signals */
+	/**
+	 * NMRemoteConnection::updated:
+	 * @connection: a #NMConnection
+	 *
+	 * This signal is emitted when a connection changes, and it is
+	 * still visible to the user.
+	 */
+	signals[UPDATED] = 
+		g_signal_new (NM_REMOTE_CONNECTION_UPDATED,
+		              G_TYPE_FROM_CLASS (remote_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMRemoteConnectionClass, updated),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 0);
+
+	/**
+	 * NMRemoteConnection::removed:
+	 * @connection: a #NMConnection
+	 *
+	 * This signal is emitted when a connection is either deleted or becomes
+	 * invisible to the current user.
+	 */
+	signals[REMOVED] = 
+		g_signal_new (NM_REMOTE_CONNECTION_REMOVED,
+		              G_TYPE_FROM_CLASS (remote_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMRemoteConnectionClass, removed),
+	 	              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 0);
+
+	/* Private signal */
+	signals[VISIBLE] =
+		g_signal_new ("visible",
+		              G_TYPE_FROM_CLASS (remote_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__BOOLEAN,
+		              G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+}