/*
* simple-channel-dispatch-operation.c - a simple channel dispatch operation
* service.
*
* Copyright © 2010 Collabora Ltd.
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved.
*/
#include "config.h"
#include "simple-channel-dispatch-operation.h"
#include
#include
static void channel_dispatch_operation_iface_init (gpointer, gpointer);
G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleChannelDispatchOperation,
tp_tests_simple_channel_dispatch_operation,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_DISPATCH_OPERATION,
channel_dispatch_operation_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
tp_dbus_properties_mixin_iface_init)
)
/* TP_IFACE_CHANNEL_DISPATCH_OPERATION is implied */
static const char *CHANNEL_DISPATCH_OPERATION_INTERFACES[] = { NULL };
static const gchar *CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS[] = {
TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, };
enum
{
PROP_0,
PROP_INTERFACES,
PROP_CONNECTION,
PROP_ACCOUNT,
PROP_CHANNELS,
PROP_POSSIBLE_HANDLERS,
};
struct _SimpleChannelDispatchOperationPrivate
{
gchar *conn_path;
gchar *account_path;
/* Array of TpChannel */
GPtrArray *channels;
};
static void
tp_tests_simple_channel_dispatch_operation_handle_with (
TpSvcChannelDispatchOperation *iface,
const gchar *handler,
DBusGMethodInvocation *context)
{
if (!tp_strdiff (handler, "FAIL"))
{
GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Nope" };
dbus_g_method_return_error (context, &error);
return;
}
dbus_g_method_return (context);
}
static void
tp_tests_simple_channel_dispatch_operation_claim (
TpSvcChannelDispatchOperation *iface,
DBusGMethodInvocation *context)
{
tp_svc_channel_dispatch_operation_emit_finished (iface);
dbus_g_method_return (context);
}
static void
tp_tests_simple_channel_dispatch_operation_handle_with_time (
TpSvcChannelDispatchOperation *iface,
const gchar *handler,
gint64 user_action_timestamp,
DBusGMethodInvocation *context)
{
dbus_g_method_return (context);
}
static void
channel_dispatch_operation_iface_init (gpointer klass,
gpointer unused G_GNUC_UNUSED)
{
#define IMPLEMENT(x) tp_svc_channel_dispatch_operation_implement_##x (\
klass, tp_tests_simple_channel_dispatch_operation_##x)
IMPLEMENT(handle_with);
IMPLEMENT(claim);
IMPLEMENT(handle_with_time);
#undef IMPLEMENT
}
static void
tp_tests_simple_channel_dispatch_operation_init (TpTestsSimpleChannelDispatchOperation *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
TP_TESTS_TYPE_SIMPLE_CHANNEL_DISPATCH_OPERATION,
TpTestsSimpleChannelDispatchOperationPrivate);
self->priv->channels = g_ptr_array_new_with_free_func (
(GDestroyNotify) g_object_unref);
}
static void
tp_tests_simple_channel_dispatch_operation_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *spec)
{
TpTestsSimpleChannelDispatchOperation *self =
TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION (object);
switch (property_id) {
case PROP_INTERFACES:
g_value_set_boxed (value, CHANNEL_DISPATCH_OPERATION_INTERFACES);
break;
case PROP_ACCOUNT:
g_value_set_boxed (value, self->priv->account_path);
break;
case PROP_CONNECTION:
g_value_set_boxed (value, self->priv->conn_path);
break;
case PROP_CHANNELS:
{
GPtrArray *arr = g_ptr_array_new ();
guint i;
for (i = 0; i < self->priv->channels->len; i++)
{
TpChannel *channel = g_ptr_array_index (self->priv->channels, i);
GValue props_value = G_VALUE_INIT;
GVariant *props_variant;
/* Yay, double conversion! But this is for tests corner case */
props_variant = tp_channel_dup_immutable_properties (channel);
dbus_g_value_parse_g_variant (props_variant, &props_value);
g_ptr_array_add (arr,
tp_value_array_build (2,
DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (channel),
TP_HASH_TYPE_STRING_VARIANT_MAP,
g_value_get_boxed (&props_value),
G_TYPE_INVALID));
g_variant_unref (props_variant);
g_value_unset (&props_value);
}
g_value_take_boxed (value, arr);
}
break;
case PROP_POSSIBLE_HANDLERS:
g_value_set_boxed (value, CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
break;
}
}
static void
tp_tests_simple_channel_dispatch_operation_finalize (GObject *object)
{
TpTestsSimpleChannelDispatchOperation *self =
TP_TESTS_SIMPLE_CHANNEL_DISPATCH_OPERATION (object);
void (*finalize) (GObject *) =
G_OBJECT_CLASS (tp_tests_simple_channel_dispatch_operation_parent_class)->finalize;
g_free (self->priv->conn_path);
g_free (self->priv->account_path);
g_ptr_array_unref (self->priv->channels);
if (finalize != NULL)
finalize (object);
}
/**
* This class currently only provides the minimum for
* tp_channel_dispatch_operation_prepare to succeed. This turns out to be only a working
* Properties.GetAll().
*/
static void
tp_tests_simple_channel_dispatch_operation_class_init (TpTestsSimpleChannelDispatchOperationClass *klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
GParamSpec *param_spec;
static TpDBusPropertiesMixinPropImpl a_props[] = {
{ "Interfaces", "interfaces", NULL },
{ "Connection", "connection", NULL },
{ "Account", "account", NULL },
{ "Channels", "channels", NULL },
{ "PossibleHandlers", "possible-handlers", NULL },
{ NULL }
};
static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
{ TP_IFACE_CHANNEL_DISPATCH_OPERATION,
tp_dbus_properties_mixin_getter_gobject_properties,
NULL,
a_props
},
{ NULL },
};
g_type_class_add_private (klass, sizeof (TpTestsSimpleChannelDispatchOperationPrivate));
object_class->get_property = tp_tests_simple_channel_dispatch_operation_get_property;
object_class->finalize = tp_tests_simple_channel_dispatch_operation_finalize;
param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
"In this case we only implement ChannelDispatchOperation, so none.",
G_TYPE_STRV,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
param_spec = g_param_spec_boxed ("connection", "connection path",
"Connection path",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
param_spec = g_param_spec_boxed ("account", "account path",
"Account path",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec);
param_spec = g_param_spec_boxed ("channels", "channel paths",
"Channel paths",
TP_ARRAY_TYPE_CHANNEL_DETAILS_LIST,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_CHANNELS, param_spec);
param_spec = g_param_spec_boxed ("possible-handlers", "possible handlers",
"possible handles",
G_TYPE_STRV,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_POSSIBLE_HANDLERS,
param_spec);
klass->dbus_props_class.interfaces = prop_interfaces;
tp_dbus_properties_mixin_class_init (object_class,
G_STRUCT_OFFSET (TpTestsSimpleChannelDispatchOperationClass, dbus_props_class));
}
void
tp_tests_simple_channel_dispatch_operation_set_conn_path (
TpTestsSimpleChannelDispatchOperation *self,
const gchar *conn_path)
{
self->priv->conn_path = g_strdup (conn_path);
}
void
tp_tests_simple_channel_dispatch_operation_add_channel (
TpTestsSimpleChannelDispatchOperation *self,
TpChannel *chan)
{
g_ptr_array_add (self->priv->channels, g_object_ref (chan));
}
void
tp_tests_simple_channel_dispatch_operation_lost_channel (
TpTestsSimpleChannelDispatchOperation *self,
TpChannel *chan)
{
const gchar *path = tp_proxy_get_object_path (chan);
g_ptr_array_remove (self->priv->channels, chan);
tp_svc_channel_dispatch_operation_emit_channel_lost (self, path,
TP_ERROR_STR_NOT_AVAILABLE, "Badger");
if (self->priv->channels->len == 0)
{
/* We removed the last channel; fire Finished */
tp_svc_channel_dispatch_operation_emit_finished (self);
}
}
void
tp_tests_simple_channel_dispatch_operation_set_account_path (
TpTestsSimpleChannelDispatchOperation *self,
const gchar *account_path)
{
self->priv->account_path = g_strdup (account_path);
}