summary refs log tree commit diff
path: root/libnm-glib/nm-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib/nm-client.c')
-rw-r--r--libnm-glib/nm-client.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c
index 00d729a2..88fe15b5 100644
--- a/libnm-glib/nm-client.c
+++ b/libnm-glib/nm-client.c
@@ -58,6 +58,9 @@ typedef struct {
 	GPtrArray *devices;
 	GPtrArray *active_connections;
 
+	DBusGProxyCall *perm_call;
+	GHashTable *permissions;
+
 	gboolean have_networking_enabled;
 	gboolean networking_enabled;
 	gboolean wireless_enabled;
@@ -84,6 +87,7 @@ enum {
 enum {
 	DEVICE_ADDED,
 	DEVICE_REMOVED,
+	PERMISSION_CHANGED,
 
 	LAST_SIGNAL
 };
@@ -118,6 +122,8 @@ nm_client_init (NMClient *client)
 
 	priv->state = NM_STATE_UNKNOWN;
 
+	priv->permissions = g_hash_table_new (g_direct_hash, g_direct_equal);
+
 	g_signal_connect (client,
 	                  "notify::" NM_CLIENT_NETWORKING_ENABLED,
 	                  G_CALLBACK (handle_net_enabled_changed),
@@ -284,6 +290,130 @@ 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"
+
+static NMClientPermission
+nm_permission_to_client (const char *nm)
+{
+	if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK))
+		return NM_CLIENT_PERMISSION_ENABLE_DISABLE_NETWORK;
+	else if (!strcmp (nm, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI))
+		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;
+	return NM_CLIENT_PERMISSION_NONE;
+}
+
+static NMClientPermissionResult
+nm_permission_result_to_client (const char *nm)
+{
+	if (!strcmp (nm, "yes"))
+		return NM_CLIENT_PERMISSION_RESULT_YES;
+	else if (!strcmp (nm, "no"))
+		return NM_CLIENT_PERMISSION_RESULT_NO;
+	else if (!strcmp (nm, "auth"))
+		return NM_CLIENT_PERMISSION_RESULT_AUTH;
+	return NM_CLIENT_PERMISSION_RESULT_UNKNOWN;
+}
+
+static void
+update_permissions (NMClient *self, GHashTable *permissions)
+{
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer key, value;
+	NMClientPermission perm;
+	NMClientPermissionResult perm_result;
+	GList *keys, *keys_iter;
+
+	/* get list of old permissions for change notification */
+	keys = g_hash_table_get_keys (priv->permissions);
+	g_hash_table_remove_all (priv->permissions);
+
+	if (permissions) {
+		/* Process new permissions */
+		g_hash_table_iter_init (&iter, permissions);
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			perm = nm_permission_to_client ((const char *) key);
+			perm_result = nm_permission_result_to_client ((const char *) value);
+			if (perm) {
+				g_hash_table_insert (priv->permissions,
+				                     GUINT_TO_POINTER (perm),
+				                     GUINT_TO_POINTER (perm_result));
+
+				/* Remove this permission from the list of previous permissions
+				 * we'll be sending NM_CLIENT_PERMISSION_RESULT_UNKNOWN for
+				 * in the change signal since it is still a known permission.
+				 */
+				keys = g_list_remove (keys, GUINT_TO_POINTER (perm));
+			}
+		}
+	}
+
+	/* Signal changes in all updated permissions */
+	g_hash_table_iter_init (&iter, priv->permissions);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
+		               GPOINTER_TO_UINT (key),
+		               GPOINTER_TO_UINT (value));
+	}
+
+	/* And signal changes in all permissions that used to be valid but for
+	 * some reason weren't received in the last request (if any).
+	 */
+	for (keys_iter = keys; keys_iter; keys_iter = g_list_next (keys_iter)) {
+		g_signal_emit (self, signals[PERMISSION_CHANGED], 0,
+		               GPOINTER_TO_UINT (keys_iter->data),
+		               NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
+	}
+	g_list_free (keys);
+}
+
+static void
+get_permissions_sync (NMClient *self)
+{
+	gboolean success;
+	GHashTable *permissions = NULL;
+
+	success = dbus_g_proxy_call_with_timeout (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
+	                                          "GetPermissions", 3000, NULL,
+	                                          G_TYPE_INVALID,
+	                                          DBUS_TYPE_G_MAP_OF_STRING, &permissions, G_TYPE_INVALID);
+	update_permissions (self, success ? permissions : NULL);
+	if (permissions)
+		g_hash_table_destroy (permissions);
+}
+
+static void
+get_permissions_reply (DBusGProxy *proxy,
+                       GHashTable *permissions,
+                       GError *error,
+                       gpointer user_data)
+{
+	NMClient *self = NM_CLIENT (user_data);
+
+	NM_CLIENT_GET_PRIVATE (self)->perm_call = NULL;
+	update_permissions (NM_CLIENT (user_data), error ? NULL : permissions);
+}
+
+static void
+client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
+{
+	NMClient *self = NM_CLIENT (user_data);
+	NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
+
+	if (!priv->perm_call) {
+		priv->perm_call = org_freedesktop_NetworkManager_get_permissions_async (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
+	                                                                            get_permissions_reply,
+	                                                                            self);
+	}
+}
+
 static GObject*
 constructor (GType type,
 		   guint n_construct_params,
@@ -324,6 +454,15 @@ constructor (GType type,
 						    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",
@@ -381,12 +520,17 @@ dispose (GObject *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);
 }
 
@@ -626,6 +770,22 @@ nm_client_class_init (NMClientClass *client_class)
 					  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);
 }
 
 /**
@@ -1158,3 +1318,25 @@ nm_client_get_manager_running (NMClient *client)
 	return NM_CLIENT_GET_PRIVATE (client)->manager_running;
 }
 
+/**
+ * nm_client_get_permission_result:
+ * @client: a #NMClient
+ * @permission: the permission for which to return the result, one of #NMClientPermission
+ *
+ * Requests the result of a specific permission, which indicates whether the
+ * client can or cannot perform the action the permission represents
+ *
+ * Returns: the permission's result, one of #NMClientPermissionResult
+ **/
+NMClientPermissionResult
+nm_client_get_permission_result (NMClient *client, NMClientPermission permission)
+{
+	gpointer result;
+
+	g_return_val_if_fail (NM_IS_CLIENT (client), NM_CLIENT_PERMISSION_RESULT_UNKNOWN);
+
+	result = g_hash_table_lookup (NM_CLIENT_GET_PRIVATE (client)->permissions,
+	                              GUINT_TO_POINTER (permission));
+	return GPOINTER_TO_UINT (result);
+}
+