/* Helper to hold Telepathy handles.
*
* Copyright (C) 2008 Collabora Ltd.
* Copyright (C) 2008 Nokia Corporation
*
* 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 "config.h"
#include "telepathy-glib/connection-internal.h"
#include
#include
#define DEBUG_FLAG TP_DEBUG_HANDLES
#include "telepathy-glib/debug-internal.h"
/**
* tp_connection_unref_handles:
* @self: a connection
* @handle_type: a handle type
* @n_handles: the number of handles in @handles
* @handles: (array length=n_handles): an array of @n_handles handles
*
* Do nothing. In versions of telepathy-glib prior to 0.13.8,
* this released a reference to the handles in @handles.
*
* Deprecated: This is no-op so can be safely removed.
*/
void
tp_connection_unref_handles (TpConnection *self G_GNUC_UNUSED,
TpHandleType handle_type G_GNUC_UNUSED,
guint n_handles G_GNUC_UNUSED,
const TpHandle *handles G_GNUC_UNUSED)
{
}
typedef struct {
TpHandleType handle_type;
GArray *handles;
gpointer user_data;
GDestroyNotify destroy;
TpConnectionHoldHandlesCb callback;
} HoldHandlesContext;
static void
hold_handles_context_free (gpointer p)
{
HoldHandlesContext *context = p;
if (context->destroy != NULL)
context->destroy (context->user_data);
g_array_unref (context->handles);
g_slice_free (HoldHandlesContext, context);
}
/**
* TpConnectionHoldHandlesCb:
* @connection: the connection
* @handle_type: the handle type that was passed to
* tp_connection_hold_handles()
* @n_handles: the number of handles that were passed to
* tp_connection_hold_handles() on success, or 0 on failure
* @handles: a copy of the array of @n_handles handles that was passed to
* tp_connection_hold_handles() on success, or %NULL on failure
* @error: %NULL on success, or an error on failure
* @user_data: the same arbitrary pointer that was passed to
* tp_connection_hold_handles()
* @weak_object: the same object that was passed to
* tp_connection_hold_handles()
*
* Signature of the callback called when tp_connection_hold_handles() succeeds
* or fails.
*
* On success, the caller has a reference to each handle in @handles.
*
* Since telepathy-glib version 0.13.8,
* the handles will remain valid until @connection becomes invalid
* (signalled by #TpProxy::invalidated). In earlier versions, they could be
* released with tp_connection_unref_handles().
*
* For convenience, the handle type and handles requested by the caller are
* passed through to this callback on success, so the caller does not have to
* include them in @user_data.
*
* Deprecated: See tp_connection_hold_handles().
*/
static void
connection_held_handles (TpConnection *self,
const GError *error,
gpointer user_data,
GObject *weak_object)
{
HoldHandlesContext *context = user_data;
g_object_ref (self);
if (error == NULL)
{
DEBUG ("%u handles of type %u", context->handles->len,
context->handle_type);
/* On the Telepathy side, we have held these handles (at least once).
* That's all we need. */
context->callback (self, context->handle_type, context->handles->len,
(const TpHandle *) context->handles->data, NULL,
context->user_data, weak_object);
}
else
{
DEBUG ("%u handles of type %u failed: %s %u: %s",
context->handles->len, context->handle_type,
g_quark_to_string (error->domain), error->code, error->message);
context->callback (self, context->handle_type, 0, NULL, error,
context->user_data, weak_object);
}
g_object_unref (self);
}
/**
* tp_connection_hold_handles:
* @self: a connection
* @timeout_ms: the timeout in milliseconds, or -1 to use the default
* @handle_type: the handle type
* @n_handles: the number of handles in @handles (must be at least 1)
* @handles: (array length=n_handles): an array of handles
* @callback: called on success or failure (unless @weak_object has become
* unreferenced)
* @user_data: arbitrary user-supplied data
* @destroy: called to destroy @user_data after calling @callback, or when
* @weak_object becomes unreferenced (whichever occurs sooner)
* @weak_object: if not %NULL, an object to be weakly referenced: if it is
* destroyed, @callback will not be called
*
* Hold (ensure a reference to) the given handles, if they are valid.
*
* If they are valid, the callback will later be called with the given
* handles; if not all of them are valid, the callback will be called with
* an error.
*
* This function, along with tp_connection_unref_handles(),
* tp_connection_get_contact_attributes() and #TpContact, keeps a client-side
* reference count of handles; you should not use the RequestHandles,
* HoldHandles and GetContactAttributes D-Bus methods directly as well as these
* functions.
*
* Deprecated: Holding handles is not needed with Connection Managers having
* immortal handles (any Connection Manager using telepathy-glib >= 0.13.8).
* Other Connection Managers are considered deprecated, clients wanting to
* still support them should continue using this deprecated function.
*/
void
tp_connection_hold_handles (TpConnection *self,
gint timeout_ms,
TpHandleType handle_type,
guint n_handles,
const TpHandle *handles,
TpConnectionHoldHandlesCb callback,
gpointer user_data,
GDestroyNotify destroy,
GObject *weak_object)
{
HoldHandlesContext *context;
g_return_if_fail (TP_IS_CONNECTION (self));
g_return_if_fail (handle_type > TP_HANDLE_TYPE_NONE);
g_return_if_fail (handle_type < TP_NUM_HANDLE_TYPES);
g_return_if_fail (n_handles >= 1);
g_return_if_fail (callback != NULL);
context = g_slice_new0 (HoldHandlesContext);
context->handle_type = handle_type;
context->user_data = user_data;
context->destroy = destroy;
context->handles = g_array_sized_new (FALSE, FALSE, sizeof (guint),
n_handles);
g_array_append_vals (context->handles, handles, n_handles);
context->callback = callback;
tp_cli_connection_call_hold_handles (self, timeout_ms, handle_type,
context->handles, connection_held_handles,
context, hold_handles_context_free, weak_object);
}
typedef struct {
TpHandleType handle_type;
guint n_ids;
gchar **ids;
gpointer user_data;
GDestroyNotify destroy;
TpConnectionRequestHandlesCb callback;
} RequestHandlesContext;
static void
request_handles_context_free (gpointer p)
{
RequestHandlesContext *context = p;
g_strfreev (context->ids);
if (context->destroy != NULL)
context->destroy (context->user_data);
g_slice_free (RequestHandlesContext, context);
}
/**
* TpConnectionRequestHandlesCb:
* @connection: the connection
* @handle_type: the handle type that was passed to
* tp_connection_request_handles()
* @n_handles: the number of IDs that were passed to
* tp_connection_request_handles() on success, or 0 on failure
* @handles: (element-type uint) (array length=n_handles): the @n_handles
* handles corresponding to @ids, in the same order, or %NULL on failure
* @ids: (element-type utf8) (array length=n_handles): a copy of the array of
* @n_handles IDs that was passed to tp_connection_request_handles() on
* success, or %NULL on failure
* @error: %NULL on success, or an error on failure
* @user_data: the same arbitrary pointer that was passed to
* tp_connection_request_handles()
* @weak_object: the same object that was passed to
* tp_connection_request_handles()
*
* Signature of the callback called when tp_connection_request_handles()
* succeeds or fails.
*
* On success, the caller has a reference to each handle in @handles.
*
* Since telepathy-glib version 0.13.8,
* the handles will remain valid until @connection becomes invalid
* (signalled by #TpProxy::invalidated). In earlier versions, they could be
* released with tp_connection_unref_handles().
*
* For convenience, the handle type and IDs requested by the caller are
* passed through to this callback, so the caller does not have to include
* them in @user_data.
*
* Deprecated: See tp_connection_request_handles().
*/
static void
connection_requested_handles (TpConnection *self,
const GArray *handles,
const GError *error,
gpointer user_data,
GObject *weak_object)
{
RequestHandlesContext *context = user_data;
g_object_ref (self);
if (error == NULL)
{
if (G_UNLIKELY (g_strv_length (context->ids) != handles->len))
{
const gchar *cm = tp_proxy_get_bus_name ((TpProxy *) self);
GError *e = g_error_new (TP_DBUS_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
"Connection manager %s is broken: we asked for %u "
"handles but RequestHandles returned %u",
cm, g_strv_length (context->ids), handles->len);
/* This CM is bad and wrong. We can't trust it to get anything
* right. */
WARNING ("%s", e->message);
context->callback (self, context->handle_type, 0, NULL, NULL,
e, context->user_data, weak_object);
g_error_free (e);
return;
}
DEBUG ("%u handles of type %u", handles->len,
context->handle_type);
/* On the Telepathy side, we have held these handles (at least once).
* That's all we need. */
context->callback (self, context->handle_type, handles->len,
(const TpHandle *) handles->data,
(const gchar * const *) context->ids,
NULL, context->user_data, weak_object);
}
else
{
DEBUG ("%u handles of type %u failed: %s %u: %s",
g_strv_length (context->ids), context->handle_type,
g_quark_to_string (error->domain), error->code, error->message);
context->callback (self, context->handle_type, 0, NULL, NULL, error,
context->user_data, weak_object);
}
g_object_unref (self);
}
/**
* tp_connection_request_handles:
* @self: a connection
* @timeout_ms: the timeout in milliseconds, or -1 to use the default
* @handle_type: the handle type
* @ids: (array zero-terminated=1): an array of string identifiers for which
* handles are required, terminated by %NULL (must not be %NULL or empty)
* @callback: called on success or failure (unless @weak_object has become
* unreferenced)
* @user_data: arbitrary user-supplied data
* @destroy: called to destroy @user_data after calling @callback, or when
* @weak_object becomes unreferenced (whichever occurs sooner)
* @weak_object: if not %NULL, an object to be weakly referenced: if it is
* destroyed, @callback will not be called
*
* Request the handles corresponding to the given identifiers, and if they
* are valid, hold (ensure a reference to) the corresponding handles.
*
* If they are valid, the callback will later be called with the given
* handles; if not all of them are valid, the callback will be called with
* an error.
*
* Deprecated: If @handle_type is TP_HANDLE_TYPE_CONTACT, use
* tp_connection_dup_contact_by_id_async() instead. For channel requests,
* use tp_account_channel_request_set_target_id() instead.
*/
void
tp_connection_request_handles (TpConnection *self,
gint timeout_ms,
TpHandleType handle_type,
const gchar * const *ids,
TpConnectionRequestHandlesCb callback,
gpointer user_data,
GDestroyNotify destroy,
GObject *weak_object)
{
RequestHandlesContext *context;
g_return_if_fail (TP_IS_CONNECTION (self));
g_return_if_fail (handle_type > TP_HANDLE_TYPE_NONE);
g_return_if_fail (handle_type < TP_NUM_HANDLE_TYPES);
g_return_if_fail (ids != NULL);
g_return_if_fail (ids[0] != NULL);
g_return_if_fail (callback != NULL);
context = g_slice_new0 (RequestHandlesContext);
context->handle_type = handle_type;
context->ids = g_strdupv ((GStrv) ids);
context->user_data = user_data;
context->destroy = destroy;
context->callback = callback;
tp_cli_connection_call_request_handles (self, timeout_ms, handle_type,
(const gchar **) context->ids, connection_requested_handles,
context, request_handles_context_free, weak_object);
}
/**
* tp_connection_get_contact_attributes:
* @self: a connection
* @timeout_ms: the timeout in milliseconds, or -1 to use the default
* @n_handles: the number of handles in @handles (must be at least 1)
* @handles: (array length=n_handles): an array of handles
* @interfaces: a #GStrv of interfaces
* @hold: if %TRUE, the callback will hold one reference to each valid handle
* @callback: (type GObject.Callback): called on success or
* failure (unless @weak_object has become unreferenced)
* @user_data: arbitrary user-supplied data
* @destroy: called to destroy @user_data after calling @callback, or when
* @weak_object becomes unreferenced (whichever occurs sooner)
* @weak_object: if not %NULL, an object to be weakly referenced: if it is
* destroyed, @callback will not be called
*
* Return (via a callback) any number of attributes of the given handles.
*
* Since telepathy-glib version 0.13.8,
* the handles will remain valid until @connection becomes invalid
* (signalled by #TpProxy::invalidated). In earlier versions, if @hold
* was %TRUE, the callback would hold a reference to them which could be
* released with tp_connection_unref_handles().
*
* This is a thin wrapper around the GetContactAttributes D-Bus method, and
* should be used in preference to
* tp_cli_connection_interface_contacts_call_get_contact_attributes(); mixing this
* function, tp_connection_hold_handles(), tp_connection_unref_handles(), and
* #TpContact with direct use of the RequestHandles, HoldHandles and
* GetContactAttributes D-Bus methods is unwise, as #TpConnection and
* #TpContact perform client-side reference counting of handles.
* The #TpContact API provides a higher-level abstraction which should
* usually be used instead.
*
* @callback will later be called with the attributes of those of the given
* handles that were valid. Invalid handles are simply omitted from the
* parameter to the callback.
*
* If @hold is %TRUE, the @callback is given one reference to each handle
* that appears as a key in the callback's @attributes parameter.
*
* Deprecated: Use tp_simple_client_factory_ensure_contact() instead.
*/
void
tp_connection_get_contact_attributes (TpConnection *self,
gint timeout_ms,
guint n_handles,
const TpHandle *handles,
const gchar * const *interfaces,
gboolean hold,
tp_cli_connection_interface_contacts_callback_for_get_contact_attributes callback,
gpointer user_data,
GDestroyNotify destroy,
GObject *weak_object)
{
GArray *a;
guint i;
DEBUG ("%u handles", n_handles);
for (i = 0; i < n_handles; i++)
DEBUG ("- %u", handles[i]);
g_return_if_fail (TP_IS_CONNECTION (self));
g_return_if_fail (n_handles >= 1);
g_return_if_fail (handles != NULL);
g_return_if_fail (callback != NULL);
a = g_array_sized_new (FALSE, FALSE, sizeof (guint), n_handles);
g_array_append_vals (a, handles, n_handles);
/* We ignore @hold, and always hold the handles anyway */
tp_cli_connection_interface_contacts_call_get_contact_attributes (self, -1,
a, (const gchar **) interfaces, TRUE, callback,
user_data, destroy, weak_object);
g_array_unref (a);
}
/**
* tp_connection_get_contact_list_attributes:
* @self: a connection
* @timeout_ms: the timeout in milliseconds (using a large timeout is
* recommended)
* @interfaces: a #GStrv of interfaces
* @hold: if %TRUE, the callback will hold one reference to each handle it
* receives
* @callback: (type GObject.Callback): called on success or
* failure (unless @weak_object has become unreferenced)
* @user_data: arbitrary user-supplied data
* @destroy: called to destroy @user_data after calling @callback, or when
* @weak_object becomes unreferenced (whichever occurs sooner)
* @weak_object: if not %NULL, an object to be weakly referenced: if it is
* destroyed, @callback will not be called
*
* Return (via a callback) the contacts on the contact list and any number of
* their attributes.
*
* Since telepathy-glib version 0.13.8,
* the handles will remain valid until @connection becomes invalid
* (signalled by #TpProxy::invalidated). In earlier versions, if @hold
* was %TRUE, the callback would hold a reference to them which could be
* released with tp_connection_unref_handles().
*
* This is a thin wrapper around the RequestContactList D-Bus method,
* and should be used in preference to lower-level functions; it is similar
* to tp_connection_get_contact_attributes().
*
* The #TpContact API provides a higher-level abstraction which should
* usually be used instead.
*
* If @hold is %TRUE, the @callback is given a reference to each handle
* that appears as a key in the callback's @attributes parameter.
*
* Deprecated: Use tp_connection_dup_contact_list() instead.
*/
void
tp_connection_get_contact_list_attributes (TpConnection *self,
gint timeout_ms,
const gchar * const *interfaces,
gboolean hold,
tp_cli_connection_interface_contacts_callback_for_get_contact_attributes callback,
gpointer user_data,
GDestroyNotify destroy,
GObject *weak_object)
{
g_return_if_fail (TP_IS_CONNECTION (self));
g_return_if_fail (callback != NULL);
/* We ignore @hold, and always hold the handles anyway */
tp_cli_connection_interface_contact_list_call_get_contact_list_attributes (
self, -1, (const gchar **) interfaces, TRUE,
callback, user_data, destroy, weak_object);
}