diff -r 46cc8e302e43 -r 3404599e4dda telepathygabble/src/handles.c --- a/telepathygabble/src/handles.c Wed Mar 31 22:32:38 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,985 +0,0 @@ -/* - * handles.c - mechanism to store and retrieve handles on a connection - * Copyright (C) 2005 Collabora Ltd. - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "gheap.h" -#include "handles.h" -#include "handle-set.h" -#include "telepathy-errors.h" -#include "telepathy-helpers.h" -#include "util.h" - -#include "config.h" - -#ifdef ENABLE_HANDLE_LEAK_DEBUG -#include -#include -#include - - -typedef struct _HandleLeakTrace HandleLeakTrace; - -struct _HandleLeakTrace -{ - char **trace; - int len; -}; - -static void -handle_leak_trace_free (HandleLeakTrace *hltrace) -{ - free (hltrace->trace); - g_free (hltrace); -} - -static void -handle_leak_trace_free_gfunc (gpointer data, gpointer user_data) -{ - return handle_leak_trace_free ((HandleLeakTrace *) data); -} - -#endif /* ENABLE_HANDLE_LEAK_DEBUG */ - -/*#ifdef EMULATOR -#include "libgabble_wsd_solution.h" - - gchar** _s_handles_list_handle_strings() { return (gchar**)((libgabble_ImpurePtr()->_s_handles_list_handle_strings)); } - - #define list_handle_strings (GET_WSD_VAR_NAME(list_handle_strings,handles, s)()) - -#endif*/ - - -typedef struct _GabbleHandlePriv GabbleHandlePriv; - -struct _GabbleHandlePriv -{ - guint refcount; - gchar *string; -#ifdef ENABLE_HANDLE_LEAK_DEBUG - GSList *traces; -#endif /* ENABLE_HANDLE_LEAK_DEBUG */ - GData *datalist; -}; - -struct _GabbleHandleRepo -{ - GHashTable *contact_handles; - GHashTable *room_handles; - GData *list_handles; - GHashTable *contact_strings; - GHashTable *room_strings; - GHeap *free_contact_handles; - GHeap *free_room_handles; - guint contact_serial; - guint room_serial; - GData *client_contact_handle_sets; - GData *client_room_handle_sets; - DBusGProxy *bus_service_proxy; -}; - -//#ifndef EMULATOR -static const char *list_handle_strings[GABBLE_LIST_HANDLE_DENY] = -{ - "publish", /* GABBLE_LIST_HANDLE_PUBLISH */ - "subscribe", /* GABBLE_LIST_HANDLE_SUBSCRIBE */ - "known", /* GABBLE_LIST_HANDLE_KNOWN */ - "deny" /* GABBLE_LIST_HANDLE_DENY */ -}; -//#endif - -/* private functions */ - -static GabbleHandlePriv * -handle_priv_new () -{ - GabbleHandlePriv *priv; - - priv = g_new0 (GabbleHandlePriv, 1); - - g_datalist_init (&(priv->datalist)); - return priv; -} - -static void -handle_priv_free (GabbleHandlePriv *priv) -{ - g_assert (priv != NULL); - - g_free(priv->string); - g_datalist_clear (&(priv->datalist)); -#ifdef ENABLE_HANDLE_LEAK_DEBUG - g_slist_foreach (priv->traces, handle_leak_trace_free_gfunc, NULL); - g_slist_free (priv->traces); -#endif /* ENABLE_HANDLE_LEAK_DEBUG */ - g_free (priv); -} - -static GabbleHandlePriv * -handle_priv_lookup (GabbleHandleRepo *repo, - TpHandleType type, - GabbleHandle handle) -{ - GabbleHandlePriv *priv = NULL; - - g_assert (repo != NULL); - g_assert (gabble_handle_type_is_valid (type, NULL)); - g_assert (handle != 0); - - switch (type) { - case TP_HANDLE_TYPE_CONTACT: - priv = g_hash_table_lookup (repo->contact_handles, GINT_TO_POINTER (handle)); - break; - case TP_HANDLE_TYPE_ROOM: - priv = g_hash_table_lookup (repo->room_handles, GINT_TO_POINTER (handle)); - break; - case TP_HANDLE_TYPE_LIST: - priv = g_datalist_id_get_data (&repo->list_handles, handle); - break; - default: - g_assert_not_reached(); - } - - return priv; -} - -static GabbleHandle -gabble_handle_alloc (GabbleHandleRepo *repo, TpHandleType type) -{ - GabbleHandle ret = 0; - - g_assert (repo != NULL); - g_assert (gabble_handle_type_is_valid (type, NULL)); - - switch (type) { - case TP_HANDLE_TYPE_CONTACT: - if (g_heap_size (repo->free_contact_handles)) - ret = GPOINTER_TO_UINT (g_heap_extract_first (repo->free_contact_handles)); - else - ret = repo->contact_serial++; - break; - case TP_HANDLE_TYPE_ROOM: - if (g_heap_size (repo->free_room_handles)) - ret = GPOINTER_TO_UINT (g_heap_extract_first (repo->free_room_handles)); - else - ret = repo->room_serial++; - break; - default: - g_assert_not_reached(); - } - - return ret; -} - -static gint -handle_compare_func (gconstpointer a, gconstpointer b) -{ - GabbleHandle first = GPOINTER_TO_UINT (a); - GabbleHandle second = GPOINTER_TO_UINT (b); - - return (first == second) ? 0 : ((first < second) ? -1 : 1); -} - -static void -handle_priv_remove (GabbleHandleRepo *repo, - TpHandleType type, - GabbleHandle handle) -{ - GabbleHandlePriv *priv; - const gchar *string; - - g_assert (gabble_handle_type_is_valid (type, NULL)); - g_assert (handle != 0); - g_assert (repo != NULL); - - priv = handle_priv_lookup (repo, type, handle); - - g_assert (priv != NULL); - - string = priv->string; - - switch (type) { - case TP_HANDLE_TYPE_CONTACT: - g_hash_table_remove (repo->contact_strings, string); - g_hash_table_remove (repo->contact_handles, GINT_TO_POINTER (handle)); - if (handle == repo->contact_serial-1) - repo->contact_serial--; - else - g_heap_add (repo->free_contact_handles, GUINT_TO_POINTER (handle)); - break; - case TP_HANDLE_TYPE_ROOM: - g_hash_table_remove (repo->room_strings, string); - g_hash_table_remove (repo->room_handles, GINT_TO_POINTER (handle)); - if (handle == repo->room_serial-1) - repo->room_serial--; - else - g_heap_add (repo->free_room_handles, GUINT_TO_POINTER (handle)); - break; - case TP_HANDLE_TYPE_LIST: - g_dataset_id_remove_data (&repo->list_handles, handle); - break; - default: - g_assert_not_reached (); - } -} - -static void -handles_name_owner_changed_cb (DBusGProxy *proxy, - const gchar *name, - const gchar *old_owner, - const gchar *new_owner, - gpointer data) -{ - GabbleHandleRepo *repo = (GabbleHandleRepo *) data; - - if (old_owner && strlen (old_owner)) - { - if (!new_owner || !strlen (new_owner)) - { - g_datalist_remove_data (&repo->client_contact_handle_sets, old_owner); - g_datalist_remove_data (&repo->client_room_handle_sets, old_owner); - } - } -} - -/* public API */ - -/** - * gabble_handle_jid_is_valid - * - * Validates a jid for given handle type and returns TRUE/FALSE - * on success/failure. In the latter case further information is - * provided through error if set. - */ -gboolean -gabble_handle_jid_is_valid (TpHandleType type, const gchar *jid, GError **error) -{ - if (type == TP_HANDLE_TYPE_CONTACT || type == TP_HANDLE_TYPE_ROOM) - { - if (!strchr (jid, '@')) - { - g_debug ("%s: jid %s has no @", G_STRFUNC, jid); - - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "jid %s has no @", jid); - - return FALSE; - } - - /* FIXME: do more extensive checking */ - } - else - { - g_assert_not_reached (); - /* FIXME: add checking for other types here */ - } - - return TRUE; -} - -gboolean -gabble_handle_type_is_valid (TpHandleType type, GError **error) -{ - gboolean ret; - - if (type > TP_HANDLE_TYPE_NONE && type <= TP_HANDLE_TYPE_LIST) - { - ret = TRUE; - } - else - { - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid handle type %u", type); - ret = FALSE; - } - - return ret; -} - - -GabbleHandleRepo * -gabble_handle_repo_new () -{ - GabbleHandleRepo *repo; - GabbleHandle publish, subscribe, known, deny; - - repo = g_new0 (GabbleHandleRepo, 1); - - repo->contact_handles = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) handle_priv_free); - - repo->room_handles = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) handle_priv_free); - - repo->contact_strings = g_hash_table_new (g_str_hash, g_str_equal); - repo->room_strings = g_hash_table_new (g_str_hash, g_str_equal); - - repo->free_contact_handles = g_heap_new (handle_compare_func); - repo->free_room_handles = g_heap_new (handle_compare_func); - - repo->contact_serial = 1; - repo->room_serial = 1; - - g_datalist_init (&repo->list_handles); - - publish = GABBLE_LIST_HANDLE_PUBLISH; - g_datalist_id_set_data_full (&repo->list_handles, (GQuark) publish, - handle_priv_new(), (GDestroyNotify) handle_priv_free); - - subscribe = GABBLE_LIST_HANDLE_SUBSCRIBE; - g_datalist_id_set_data_full (&repo->list_handles, (GQuark) subscribe, - handle_priv_new(), (GDestroyNotify) handle_priv_free); - - known = GABBLE_LIST_HANDLE_KNOWN; - g_datalist_id_set_data_full (&repo->list_handles, (GQuark) known, - handle_priv_new(), (GDestroyNotify) handle_priv_free); - - deny = GABBLE_LIST_HANDLE_DENY; - g_datalist_id_set_data_full (&repo->list_handles, (GQuark) deny, - handle_priv_new(), (GDestroyNotify) handle_priv_free); - - g_datalist_init (&repo->client_contact_handle_sets); - g_datalist_init (&repo->client_room_handle_sets); - - repo->bus_service_proxy = dbus_g_proxy_new_for_name (tp_get_bus(), - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS); - - dbus_g_proxy_add_signal (repo->bus_service_proxy, - "NameOwnerChanged", - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (repo->bus_service_proxy, - "NameOwnerChanged", - G_CALLBACK (handles_name_owner_changed_cb), - repo, - NULL); - - return repo; -} - -#ifdef ENABLE_HANDLE_LEAK_DEBUG - -static void -handle_leak_debug_printbt_foreach (gpointer data, gpointer user_data) -{ - HandleLeakTrace *hltrace = (HandleLeakTrace *) data; - int i; - - for (i = 1; i < hltrace->len; i++) - { - g_message ("\t\t%s\n", hltrace->trace[i]); - } - - g_message ("\n"); -} - -static void -handle_leak_debug_printhandles_foreach (gpointer key, gpointer value, gpointer ignore) -{ - GabbleHandle handle = GPOINTER_TO_UINT (key); - GabbleHandlePriv *priv = (GabbleHandlePriv *) value; - - g_message ("\t%5u: %s (%u refs), traces:\n", handle, priv->string, priv->refcount); - - g_slist_foreach (priv->traces, handle_leak_debug_printbt_foreach, NULL); -} - -static void -handle_leak_debug_print_report (GabbleHandleRepo *repo) -{ - g_assert (repo != NULL); - - g_message ("The following contact handles were not freed:\n"); - g_hash_table_foreach (repo->contact_handles, handle_leak_debug_printhandles_foreach, NULL); - g_message ("The following room handles were not freed:\n"); - g_hash_table_foreach (repo->room_handles, handle_leak_debug_printhandles_foreach, NULL); -} - -static HandleLeakTrace * -handle_leak_debug_bt () -{ - void *bt_addresses[16]; - HandleLeakTrace *ret = g_new0 (HandleLeakTrace, 1); - - ret->len = backtrace (bt_addresses, 16); - ret->trace = backtrace_symbols (bt_addresses, ret->len); - - return ret; -} - -#define HANDLE_LEAK_DEBUG_DO(traces_slist) \ - { (traces_slist) = g_slist_append ((traces_slist), handle_leak_debug_bt ()); } - -#else /* !ENABLE_HANDLE_LEAK_DEBUG */ - -#define HANDLE_LEAK_DEBUG_DO(traces_slist) {} - -#endif /* ENABLE_HANDLE_LEAK_DEBUG */ - - -void -gabble_handle_repo_destroy (GabbleHandleRepo *repo) -{ - g_assert (repo != NULL); - g_assert (repo->contact_handles); - g_assert (repo->room_handles); - g_assert (repo->contact_strings); - g_assert (repo->room_strings); - - g_datalist_clear (&repo->client_contact_handle_sets); - g_datalist_clear (&repo->client_room_handle_sets); - -#ifdef ENABLE_HANDLE_LEAK_DEBUG - handle_leak_debug_print_report (repo); -#endif /* ENABLE_HANDLE_LEAK_DEBUG */ - - g_hash_table_destroy (repo->contact_handles); - g_hash_table_destroy (repo->room_handles); - g_hash_table_destroy (repo->contact_strings); - g_hash_table_destroy (repo->room_strings); - g_heap_destroy (repo->free_contact_handles); - g_heap_destroy (repo->free_room_handles); - g_datalist_clear (&repo->list_handles); - - dbus_g_proxy_disconnect_signal (repo->bus_service_proxy, - "NameOwnerChanged", - G_CALLBACK (handles_name_owner_changed_cb), - repo); - g_object_unref (G_OBJECT (repo->bus_service_proxy)); - - g_free (repo); -} - - -gboolean -gabble_handle_is_valid (GabbleHandleRepo *repo, TpHandleType type, GabbleHandle handle, GError **error) -{ - GArray *arr; - gboolean ret; - - arr = g_array_new (FALSE, FALSE, sizeof (GabbleHandle)); - g_array_insert_val (arr, 0, handle); - - ret = gabble_handles_are_valid (repo, type, arr, FALSE, error); - - g_array_free (arr, TRUE); - - return ret; -} - -gboolean -gabble_handles_are_valid (GabbleHandleRepo *repo, - TpHandleType type, - const GArray *array, - gboolean allow_zero, - GError **error) -{ - guint i; - - g_return_val_if_fail (repo != NULL, FALSE); - g_return_val_if_fail (array != NULL, FALSE); - - if (!gabble_handle_type_is_valid (type, error)) - return FALSE; - - for (i = 0; i < array->len; i++) - { - GabbleHandle handle = g_array_index (array, GabbleHandle, i); - - if (handle == 0) - { - if (allow_zero) - continue; - - g_debug ("someone tried to validate handle zero"); - - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid handle %u", handle); - return FALSE; - } - - if (handle_priv_lookup (repo, type, handle) == NULL) - { - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid handle %u", handle); - return FALSE; - } - } - - return TRUE; -} - - -gboolean -gabble_handle_ref (GabbleHandleRepo *repo, - TpHandleType type, - GabbleHandle handle) -{ - GabbleHandlePriv *priv; - - if (type == TP_HANDLE_TYPE_LIST) - { - if (handle >= GABBLE_LIST_HANDLE_PUBLISH && handle <= GABBLE_LIST_HANDLE_DENY) - return TRUE; - else - return FALSE; - } - - priv = handle_priv_lookup (repo, type, handle); - - if (priv == NULL) - return FALSE; - - priv->refcount++; - - HANDLE_LEAK_DEBUG_DO (priv->traces); - - return TRUE; -} - - -gboolean -gabble_handle_unref (GabbleHandleRepo *repo, - TpHandleType type, - GabbleHandle handle) -{ - GabbleHandlePriv *priv; - - if (type == TP_HANDLE_TYPE_LIST) - { - if (handle >= GABBLE_LIST_HANDLE_PUBLISH && handle <= GABBLE_LIST_HANDLE_DENY) - return TRUE; - else - return FALSE; - } - - priv = handle_priv_lookup (repo, type, handle); - - if (priv == NULL) - return FALSE; - - HANDLE_LEAK_DEBUG_DO (priv->traces); - - g_assert (priv->refcount > 0); - - priv->refcount--; - - if (priv->refcount == 0) - handle_priv_remove (repo, type, handle); - - return TRUE; -} - - -const char * -gabble_handle_inspect (GabbleHandleRepo *repo, - TpHandleType type, - GabbleHandle handle) -{ - GabbleHandlePriv *priv; - - if (type == TP_HANDLE_TYPE_LIST) - { - g_assert (handle >= GABBLE_LIST_HANDLE_PUBLISH - && handle <= GABBLE_LIST_HANDLE_DENY); - return list_handle_strings[handle-1]; - } - - priv = handle_priv_lookup (repo, type, handle); - - if (priv == NULL) - return NULL; - else - return priv->string; -} - -static GabbleHandle -_handle_lookup_by_jid (GabbleHandleRepo *repo, - const gchar *jid) -{ - GabbleHandle handle; - - handle = GPOINTER_TO_UINT (g_hash_table_lookup (repo->contact_strings, jid)); - - if (0 == handle) - return 0; - - return handle; -} - - -GabbleHandle -gabble_handle_for_contact (GabbleHandleRepo *repo, - const char *jid, - gboolean with_resource) -{ - char *username = NULL; - char *server = NULL; - char *resource = NULL; - char *clean_jid = NULL; - GabbleHandle handle = 0; - GabbleHandlePriv *priv; - - g_assert (repo != NULL); - g_assert (jid != NULL); - g_assert (*jid != '\0'); - - gabble_decode_jid (jid, &username, &server, &resource); - - if (NULL == username || '\0' == *username) - goto OUT; - - if (NULL == resource && with_resource) - goto OUT; - - if (NULL != resource) - { - clean_jid = g_strdup_printf ("%s@%s/%s", username, server, resource); - handle = _handle_lookup_by_jid (repo, clean_jid); - - if (0 != handle) - goto OUT; - } - - if (!with_resource) - { - g_free (clean_jid); - clean_jid = g_strdup_printf ("%s@%s", username, server); - handle = _handle_lookup_by_jid (repo, clean_jid); - - if (0 != handle) - goto OUT; - } - - handle = gabble_handle_alloc (repo, TP_HANDLE_TYPE_CONTACT); - priv = handle_priv_new (); - priv->string = clean_jid; - clean_jid = NULL; - g_hash_table_insert (repo->contact_handles, GINT_TO_POINTER (handle), priv); - g_hash_table_insert (repo->contact_strings, priv->string, GUINT_TO_POINTER (handle)); - - HANDLE_LEAK_DEBUG_DO (priv->traces); - -OUT: - - g_free (clean_jid); - g_free (username); - g_free (server); - g_free (resource); - return handle; -} - -gboolean -gabble_handle_for_room_exists (GabbleHandleRepo *repo, - const gchar *jid, - gboolean ignore_nick) -{ - GabbleHandle handle; - gchar *room, *service, *nick; - gchar *clean_jid; - - gabble_decode_jid (jid, &room, &service, &nick); - - if (!room || !service || room[0] == '\0') - return FALSE; - - if (ignore_nick || !nick) - clean_jid = g_strdup_printf ("%s@%s", room, service); - else - clean_jid = g_strdup_printf ("%s@%s/%s", room, service, nick); - - handle = GPOINTER_TO_UINT (g_hash_table_lookup (repo->room_strings, - clean_jid)); - - g_free (clean_jid); - g_free (room); - g_free (service); - g_free (nick); - - if (handle == 0) - return FALSE; - - return (handle_priv_lookup (repo, TP_HANDLE_TYPE_ROOM, handle) != NULL); -} - - -GabbleHandle -gabble_handle_for_room (GabbleHandleRepo *repo, - const gchar *jid) -{ - GabbleHandle handle; - gchar *room, *service, *clean_jid; - - g_assert (repo != NULL); - g_assert (jid != NULL); - g_assert (*jid != '\0'); - - handle = 0; - - room = service = NULL; - gabble_decode_jid (jid, &room, &service, NULL); - - if (room && service && *room != '\0') - { - clean_jid = g_strdup_printf ("%s@%s", room, service); - - handle = GPOINTER_TO_UINT (g_hash_table_lookup (repo->room_strings, clean_jid)); - - if (handle == 0) - { - GabbleHandlePriv *priv; - handle = gabble_handle_alloc (repo, TP_HANDLE_TYPE_ROOM); - priv = handle_priv_new (); - priv->string = clean_jid; - g_hash_table_insert (repo->room_handles, GUINT_TO_POINTER (handle), priv); - g_hash_table_insert (repo->room_strings, clean_jid, GUINT_TO_POINTER (handle)); - HANDLE_LEAK_DEBUG_DO (priv->traces); - } - else - { - g_free (clean_jid); - } - } - - g_free (room); - g_free (service); - - return handle; -} - - -GabbleHandle -gabble_handle_for_list (GabbleHandleRepo *repo, - const gchar *list) -{ - GabbleHandle handle = 0; - int i; - - g_assert (repo != NULL); - g_assert (list != NULL); - - for (i = 0; i < GABBLE_LIST_HANDLE_DENY; i++) - { - if (0 == strcmp (list_handle_strings[i], list)) - handle = (GabbleHandle) i + 1; - } - - return handle; -} - -/** - * gabble_handle_set_qdata: - * @repo: A #GabbleHandleRepo - * @type: The handle type - * @handle: A handle to set data on - * @key_id: Key id to associate data with - * @data: data to associate with handle - * @destroy: A #GDestroyNotify to call to detroy the data, - * or NULL if not needed. - * - * Associates a blob of data with a given handle and a given key - * - * If @destroy is set, then the data is freed when the handle is freed. - */ - -gboolean -gabble_handle_set_qdata (GabbleHandleRepo *repo, - TpHandleType type, GabbleHandle handle, - GQuark key_id, gpointer data, GDestroyNotify destroy) -{ - GabbleHandlePriv *priv; - priv = handle_priv_lookup (repo, type, handle); - - if (!priv) - return FALSE; - - g_datalist_id_set_data_full (&priv->datalist, key_id, data, destroy); - return TRUE; -} - -/** - * gabble_handle_get_qdata: - * @repo: A #GabbleHandleRepo - * @type: The handle type - * @handle: A handle to get data from - * @key_id: Key id of data to fetch - * - * Gets the data associated with a given key on a given handle - */ -gpointer -gabble_handle_get_qdata (GabbleHandleRepo *repo, - TpHandleType type, GabbleHandle handle, - GQuark key_id) -{ - GabbleHandlePriv *priv; - priv = handle_priv_lookup (repo, type, handle); - - if (!priv) - return NULL; - - return g_datalist_id_get_data(&priv->datalist, key_id); -} - -/** - * gabble_handle_client_hold: - * @repo: a #GabbleHandleRepo - * @client_name: D-Bus bus name of client to hold the handle for - * @handle: the handle to hold - * @type: type of handle to hold - * @error: used to return a pointer to a GError detailing any error that occurred - * - * Marks a handle as held by a given client. - * - * Returns: Whether the handle was succesfully marked as held or an error occurred. - */ - -gboolean -gabble_handle_client_hold (GabbleHandleRepo *repo, - const gchar *client_name, - GabbleHandle handle, - TpHandleType type, - GError **error) -{ - GData **handle_set_list; - GabbleHandleSet *handle_set; - - g_assert (repo != NULL); - - switch (type) - { - case TP_HANDLE_TYPE_CONTACT: - handle_set_list = &repo->client_contact_handle_sets; - break; - case TP_HANDLE_TYPE_ROOM: - handle_set_list = &repo->client_room_handle_sets; - break; - case TP_HANDLE_TYPE_LIST: - /* no-op */ - return TRUE; - default: - g_critical ("%s: called with invalid handle type %u", G_STRFUNC, type); - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid handle type %u", type); - return FALSE; - } - - if (!client_name || *client_name == '\0') - { - g_critical ("%s: called with invalid client name", G_STRFUNC); - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid client name"); - return FALSE; - } - - handle_set = (GabbleHandleSet*) g_datalist_get_data (handle_set_list, client_name); - - if (!handle_set) - { - handle_set = handle_set_new (repo, type); - g_datalist_set_data_full (handle_set_list, - client_name, - handle_set, - (GDestroyNotify) handle_set_destroy); - } - - handle_set_add (handle_set, handle); - - return TRUE; -} - -/** - * gabble_handle_client_release: - * @repo: a #GabbleHandleRepo - * @client_name: D-Bus bus name of client to release the handle for - * @handle: the handle to release - * @type: type of handle to release - * @error: used to return a pointer to a GError detailing any error that occurred - * - * Unmarks a handle as held by a given client. - * - * Returns: Whether the handle had been marked as held by the given client and now unmarked or not. - */ - -gboolean -gabble_handle_client_release (GabbleHandleRepo *repo, - const gchar *client_name, - GabbleHandle handle, - TpHandleType type, - GError **error) -{ - GData **handle_set_list; - GabbleHandleSet *handle_set; - - g_assert (repo != NULL); - - switch (type) - { - case TP_HANDLE_TYPE_CONTACT: - handle_set_list = &repo->client_contact_handle_sets; - break; - case TP_HANDLE_TYPE_ROOM: - handle_set_list = &repo->client_room_handle_sets; - break; - case TP_HANDLE_TYPE_LIST: - /* no-op */ - return TRUE; - default: - g_critical ("%s: called with invalid handle type %u", G_STRFUNC, type); - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid handle type %u", type); - return FALSE; - } - - if (!client_name || *client_name == '\0') - { - g_critical ("%s: called with invalid client name", G_STRFUNC); - g_set_error (error, TELEPATHY_ERRORS, InvalidArgument, - "invalid client name"); - return FALSE; - } - - handle_set = (GabbleHandleSet*) g_datalist_get_data (handle_set_list, client_name); - - if (!handle_set) - { - g_critical ("%s: no handle set found for the given client %s", G_STRFUNC, client_name); - g_set_error (error, TELEPATHY_ERRORS, NotAvailable, - "the given client %s wasn't holding any handles", client_name); - return FALSE; - } - - if (!handle_set_remove (handle_set, handle)) - { - g_critical ("%s: the client %s wasn't holding the handle %u", G_STRFUNC, - client_name, handle); - g_set_error (error, TELEPATHY_ERRORS, NotAvailable, - "the given client %s wasn't holding the handle %u", client_name, - handle); - return FALSE; - } - - return TRUE; -} -