diff options
Diffstat (limited to 'libnm-glib/nm-remote-connection.c')
-rw-r--r-- | libnm-glib/nm-remote-connection.c | 316 |
1 files changed, 200 insertions, 116 deletions
diff --git a/libnm-glib/nm-remote-connection.c b/libnm-glib/nm-remote-connection.c index 1039a7d18..57870c624 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); +} |