/*
* handle-repo-static.c - mechanism to store and retrieve handles on a
* connection (implementation for handle types with a fixed list of possible
* handles)
*
* Copyright (C) 2007 Collabora Ltd.
* Copyright (C) 2007 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
*/
/**
* SECTION:handle-repo-static
* @title: TpStaticHandleRepo
* @short_description: handle repository implementation with a fixed, static
* set of handle names
* @see_also: TpHandleRepoIface, TpDynamicHandleRepo
*
* A static handle repository has a fixed, static set of allowed names;
* these handles can never be destroyed, and no more can be created, so
* no reference counting is performed.
*
* The #TpHandleRepoIface:handle-type property must be set at construction
* time.
*
* Most connection managers will use this for handles of type
* %TP_HANDLE_TYPE_LIST.
*/
#include "config.h"
#include
#include
#include
#include
enum
{
PROP_HANDLE_TYPE = 1,
PROP_HANDLE_NAMES,
};
struct _TpStaticHandleRepoClass {
GObjectClass parent_class;
};
struct _TpStaticHandleRepo {
GObject parent;
TpHandleType handle_type;
TpHandle last_handle;
gchar **handle_names;
GData **datalists;
};
static void static_repo_iface_init (gpointer g_iface,
gpointer iface_data);
G_DEFINE_TYPE_WITH_CODE (TpStaticHandleRepo, tp_static_handle_repo,
G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_HANDLE_REPO_IFACE,
static_repo_iface_init))
static void
tp_static_handle_repo_init (TpStaticHandleRepo *self)
{
self->handle_type = 0;
self->last_handle = 0;
self->handle_names = NULL;
self->datalists = NULL;
}
static void
static_finalize (GObject *object)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (object);
guint i;
if (self->datalists)
{
for (i = 0; i < self->last_handle; i++)
{
g_datalist_clear (self->datalists + i);
}
}
g_strfreev (self->handle_names);
G_OBJECT_CLASS (tp_static_handle_repo_parent_class)->finalize (object);
}
static void
static_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (object);
switch (property_id)
{
case PROP_HANDLE_TYPE:
g_value_set_uint (value, self->handle_type);
break;
case PROP_HANDLE_NAMES:
g_value_set_boxed (value, g_strdupv (self->handle_names));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
static_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (object);
TpHandle i;
switch (property_id)
{
case PROP_HANDLE_TYPE:
self->handle_type = g_value_get_uint (value);
break;
case PROP_HANDLE_NAMES:
if (self->datalists)
{
for (i = 0; i < self->last_handle; i++)
{
g_datalist_clear (self->datalists + i);
}
}
g_strfreev (self->handle_names);
self->handle_names = g_strdupv (g_value_get_boxed (value));
i = 0;
while (self->handle_names[i] != NULL)
{
i++;
}
self->last_handle = i;
g_free (self->datalists);
self->datalists = NULL;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
tp_static_handle_repo_class_init (TpStaticHandleRepoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GParamSpec *param_spec;
object_class->get_property = static_get_property;
object_class->set_property = static_set_property;
object_class->finalize = static_finalize;
g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
"handle-type");
param_spec = g_param_spec_boxed ("handle-names", "Handle names",
"The static set of handle names supported by this repo.",
G_TYPE_STRV,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_HANDLE_NAMES,
param_spec);
}
static gboolean
static_handle_is_valid (TpHandleRepoIface *irepo,
TpHandle handle,
GError **error)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (irepo);
if (handle <= 0 || handle > self->last_handle)
{
g_set_error (error, TP_ERROR, TP_ERROR_INVALID_HANDLE,
"handle %u is not a valid %s handle (type %u)",
handle, tp_handle_type_to_string (self->handle_type),
self->handle_type);
return FALSE;
}
else
{
return TRUE;
}
}
static gboolean
static_handles_are_valid (TpHandleRepoIface *irepo, const GArray *handles,
gboolean allow_zero, GError **error)
{
guint i;
g_return_val_if_fail (handles != NULL, FALSE);
for (i = 0; i < handles->len; i++)
{
TpHandle handle = g_array_index (handles, TpHandle, i);
if (handle == 0 && allow_zero)
continue;
if (!static_handle_is_valid (irepo, handle, error))
return FALSE;
}
return TRUE;
}
static TpHandle
static_ref_handle (TpHandleRepoIface *self, TpHandle handle)
{
/* nothing to do, handles in this repo are permanent */
return handle;
}
static void
static_unref_handle (TpHandleRepoIface *self, TpHandle handle)
{
/* nothing to do, handles in this repo are permanent */
}
static gboolean
static_client_hold_or_release_handle (TpHandleRepoIface *self,
const gchar *client_name,
TpHandle handle,
GError **error)
{
/* nothing to do, handles in this repo are permanent */
return TRUE;
}
static const char *
static_inspect_handle (TpHandleRepoIface *irepo, TpHandle handle)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (irepo);
if (handle <= 0 || handle > self->last_handle)
return NULL;
return self->handle_names[handle-1];
}
static TpHandle
static_lookup_handle (TpHandleRepoIface *irepo,
const char *id,
gpointer context,
GError **error)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (irepo);
guint i;
for (i = 0; i < self->last_handle; i++)
{
if (!tp_strdiff (self->handle_names[i], id))
return (TpHandle) i + 1;
}
g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
"'%s' is not one of the valid handles", id);
return 0;
}
static void
static_set_qdata (TpHandleRepoIface *repo, TpHandle handle,
GQuark key_id, gpointer data, GDestroyNotify destroy)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (repo);
guint i;
g_return_if_fail (handle > 0);
g_return_if_fail (handle <= self->last_handle);
if (!self->datalists)
{
self->datalists = g_new (GData *, self->last_handle);
for (i = 0; i < self->last_handle; i++)
{
g_datalist_init (self->datalists + i);
}
}
g_datalist_id_set_data_full (self->datalists + handle - 1, key_id, data,
destroy);
}
static gpointer
static_get_qdata (TpHandleRepoIface *repo, TpHandle handle,
GQuark key_id)
{
TpStaticHandleRepo *self = TP_STATIC_HANDLE_REPO (repo);
g_return_val_if_fail (handle > 0, NULL);
g_return_val_if_fail (handle <= self->last_handle, NULL);
/* if we have no datalists that's not a bug - it means nobody has called
* static_set_qdata yet */
if (!self->datalists)
return NULL;
return g_datalist_id_get_data (self->datalists + handle - 1, key_id);
}
static void
static_repo_iface_init (gpointer g_iface,
gpointer iface_data)
{
TpHandleRepoIfaceClass *klass = (TpHandleRepoIfaceClass *) g_iface;
klass->handle_is_valid = static_handle_is_valid;
klass->handles_are_valid = static_handles_are_valid;
klass->ref_handle = static_ref_handle;
klass->unref_handle = static_unref_handle;
klass->client_hold_handle = static_client_hold_or_release_handle;
klass->client_release_handle = static_client_hold_or_release_handle;
klass->inspect_handle = static_inspect_handle;
/* this repo is static, so lookup and ensure are identical */
klass->lookup_handle = static_lookup_handle;
klass->ensure_handle = static_lookup_handle;
klass->set_qdata = static_set_qdata;
klass->get_qdata = static_get_qdata;
}