[Telepathy-commits] [telepathy-gabble/master] tube-dbus: implement exportable channel interface
Guillaume Desmottes
guillaume.desmottes at collabora.co.uk
Tue Feb 3 03:36:22 PST 2009
---
src/tube-dbus.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/tube-dbus.h | 2 +
2 files changed, 357 insertions(+), 5 deletions(-)
diff --git a/src/tube-dbus.c b/src/tube-dbus.c
index d4276f6..ce6cafb 100644
--- a/src/tube-dbus.c
+++ b/src/tube-dbus.c
@@ -28,6 +28,17 @@
#include <dbus/dbus-glib-lowlevel.h>
#include <loudmouth/loudmouth.h>
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/exportable-channel.h>
+#include <telepathy-glib/group-mixin.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-channel.h>
+#include <telepathy-glib/svc-generic.h>
+
+#include "extensions/extensions.h"
+
#define DEBUG_FLAG GABBLE_DEBUG_TUBES
#include "base64.h"
@@ -51,11 +62,32 @@
* arbitrary limit on the queue size set to 4MB. */
#define MAX_QUEUE_SIZE (4096*1024)
-static void
-tube_iface_init (gpointer g_iface, gpointer iface_data);
+static void channel_iface_init (gpointer, gpointer);
+static void tube_iface_init (gpointer g_iface, gpointer iface_data);
+static void dbustube_iface_init (gpointer g_iface, gpointer iface_data);
G_DEFINE_TYPE_WITH_CODE (GabbleTubeDBus, gabble_tube_dbus, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GABBLE_TYPE_TUBE_IFACE, tube_iface_init));
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_TUBE_IFACE, tube_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CHANNEL_TYPE_DBUS_TUBE,
+ dbustube_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CHANNEL_INTERFACE_TUBE,
+ NULL);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
+ tp_external_group_mixin_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
+
+static const gchar *gabble_tube_dbus_interfaces[] = {
+ TP_IFACE_CHANNEL_INTERFACE_GROUP,
+ /* If more interfaces are added, either keep Group as the first, or change
+ * the implementations of gabble_tube_dbus_get_interfaces () and
+ * gabble_tube_dbus_get_property () too */
+ GABBLE_IFACE_CHANNEL_INTERFACE_TUBE,
+ NULL
+};
/* signals */
enum
@@ -71,7 +103,10 @@ static guint signals[LAST_SIGNAL] = {0};
/* properties */
enum
{
- PROP_CONNECTION = 1,
+ PROP_OBJECT_PATH = 1,
+ PROP_CHANNEL_TYPE,
+ PROP_CONNECTION,
+ PROP_INTERFACES,
PROP_HANDLE,
PROP_HANDLE_TYPE,
PROP_SELF_HANDLE,
@@ -86,12 +121,18 @@ enum
PROP_DBUS_ADDRESS,
PROP_DBUS_NAME,
PROP_DBUS_NAMES,
+ PROP_CHANNEL_DESTROYED,
+ PROP_CHANNEL_PROPERTIES,
+ PROP_REQUESTED,
+ PROP_TARGET_ID,
+ PROP_INITIATOR_ID,
LAST_PROPERTY
};
struct _GabbleTubeDBusPrivate
{
GabbleConnection *conn;
+ char *object_path;
TpHandle handle;
TpHandleType handle_type;
TpHandle self_handle;
@@ -127,6 +168,8 @@ struct _GabbleTubeDBusPrivate
/* Number of bytes that will be in the next message, 0 if unknown */
guint32 reassembly_bytes_needed;
+ gboolean closed;
+
gboolean dispose_has_run;
};
@@ -272,6 +315,10 @@ do_close (GabbleTubeDBus *self)
{
GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self);
+ if (priv->closed)
+ return;
+ priv->closed = TRUE;
+
if (priv->bytestream != NULL)
{
gabble_bytestream_iface_close (priv->bytestream, NULL);
@@ -527,6 +574,7 @@ gabble_tube_dbus_finalize (GObject *object)
GabbleTubeDBus *self = GABBLE_TUBE_DBUS (object);
GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self);
+ g_free (priv->object_path);
g_free (priv->stream_id);
g_free (priv->service);
g_hash_table_destroy (priv->parameters);
@@ -542,12 +590,32 @@ gabble_tube_dbus_get_property (GObject *object,
{
GabbleTubeDBus *self = GABBLE_TUBE_DBUS (object);
GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self);
+ TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
switch (property_id)
{
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, priv->object_path);
+ break;
+ case PROP_CHANNEL_TYPE:
+ g_value_set_static_string (value,
+ GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE);
+ break;
case PROP_CONNECTION:
g_value_set_object (value, priv->conn);
break;
+ case PROP_INTERFACES:
+ if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
+ {
+ /* 1-1 tubes - omit the Group interface */
+ g_value_set_boxed (value, gabble_tube_dbus_interfaces + 1);
+ }
+ else
+ {
+ /* MUC tubes */
+ g_value_set_boxed (value, gabble_tube_dbus_interfaces);
+ }
+ break;
case PROP_HANDLE:
g_value_set_uint (value, priv->handle);
break;
@@ -590,6 +658,51 @@ gabble_tube_dbus_get_property (GObject *object,
case PROP_DBUS_NAMES:
g_value_set_boxed (value, priv->dbus_names);
break;
+ case PROP_CHANNEL_DESTROYED:
+ g_value_set_boolean (value, priv->closed);
+ break;
+ case PROP_CHANNEL_PROPERTIES:
+ g_value_take_boxed (value,
+ tp_dbus_properties_mixin_make_properties_hash (object,
+ TP_IFACE_CHANNEL, "TargetHandle",
+ TP_IFACE_CHANNEL, "TargetHandleType",
+ TP_IFACE_CHANNEL, "ChannelType",
+ TP_IFACE_CHANNEL, "TargetID",
+ TP_IFACE_CHANNEL, "InitiatorHandle",
+ TP_IFACE_CHANNEL, "InitiatorID",
+ TP_IFACE_CHANNEL, "Requested",
+ TP_IFACE_CHANNEL, "Interfaces",
+ GABBLE_IFACE_CHANNEL_INTERFACE_TUBE, "Status",
+ GABBLE_IFACE_CHANNEL_INTERFACE_TUBE, "Parameters",
+ GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE, "ServiceName",
+ NULL));
+ break;
+ case PROP_REQUESTED:
+ g_value_set_boolean (value,
+ (priv->initiator == priv->self_handle));
+ break;
+ case PROP_INITIATOR_ID:
+ {
+ TpHandleRepoIface *repo = tp_base_connection_get_handles (
+ base_conn, TP_HANDLE_TYPE_CONTACT);
+
+ /* some channel can have o.f.T.Channel.InitiatorHandle == 0 but
+ * tubes always have an initiator */
+ g_assert (priv->initiator != 0);
+
+ g_value_set_string (value,
+ tp_handle_inspect (repo, priv->initiator));
+ }
+ break;
+ case PROP_TARGET_ID:
+ {
+ TpHandleRepoIface *repo = tp_base_connection_get_handles (
+ base_conn, priv->handle_type);
+
+ g_value_set_string (value,
+ tp_handle_inspect (repo, priv->handle));
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -607,6 +720,14 @@ gabble_tube_dbus_set_property (GObject *object,
switch (property_id)
{
+ case PROP_OBJECT_PATH:
+ g_free (priv->object_path);
+ priv->object_path = g_value_dup_string (value);
+ break;
+ case PROP_CHANNEL_TYPE:
+ /* this property is writable in the interface, but not actually
+ * meaningfully changeable on this channel, so we do nothing */
+ break;
case PROP_CONNECTION:
priv->conn = g_value_get_object (value);
break;
@@ -668,6 +789,7 @@ gabble_tube_dbus_constructor (GType type,
GObject *obj;
GabbleTubeDBus *self;
GabbleTubeDBusPrivate *priv;
+ DBusGConnection *bus;
TpHandleRepoIface *contact_repo;
TpBaseConnection *base;
@@ -684,6 +806,11 @@ gabble_tube_dbus_constructor (GType type,
((TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
tp_handle_ref (contact_repo, priv->initiator);
+ bus = tp_get_bus ();
+ dbus_g_connection_register_g_object (bus, priv->object_path, obj);
+
+ DEBUG ("Registering at '%s'", priv->object_path);
+
base = (TpBaseConnection *) priv->conn;
g_assert (priv->self_handle != 0);
@@ -750,9 +877,78 @@ gabble_tube_dbus_constructor (GType type,
return obj;
}
+static gboolean
+tube_iface_props_setter (GObject *object,
+ GQuark interface,
+ GQuark name,
+ const GValue *value,
+ gpointer setter_data,
+ GError **error)
+{
+ GabbleTubeDBus *self = GABBLE_TUBE_DBUS (object);
+
+ g_return_val_if_fail (interface == GABBLE_IFACE_QUARK_CHANNEL_INTERFACE_TUBE,
+ FALSE);
+
+ if (name != g_quark_from_static_string ("Parameters"))
+ {
+ g_object_set_property (object, setter_data, value);
+ return TRUE;
+ }
+
+ if (get_tube_state (self) != GABBLE_TUBE_CHANNEL_STATE_NOT_OFFERED)
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "Can change parameters only if the tube is not offered");
+ return FALSE;
+ }
+
+ g_object_set (self, "parameters", g_value_get_boxed (value), NULL);
+
+ return TRUE;
+}
+
static void
gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class)
{
+ static TpDBusPropertiesMixinPropImpl channel_props[] = {
+ { "TargetHandleType", "handle-type", NULL },
+ { "TargetHandle", "handle", NULL },
+ { "ChannelType", "channel-type", NULL },
+ { "TargetID", "target-id", NULL },
+ { "Interfaces", "interfaces", NULL },
+ { "Requested", "requested", NULL },
+ { "InitiatorHandle", "initiator-handle", NULL },
+ { "InitiatorID", "initiator-id", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinPropImpl dbus_tube_props[] = {
+ { "ServiceName", "service", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinPropImpl tube_iface_props[] = {
+ { "Parameters", "parameters", "parameters" },
+ { "Status", "state", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_CHANNEL,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ channel_props,
+ },
+ { GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ dbus_tube_props,
+ },
+ { GABBLE_IFACE_CHANNEL_INTERFACE_TUBE,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ tube_iface_props_setter,
+ tube_iface_props,
+ },
+ { NULL }
+ };
GObjectClass *object_class = G_OBJECT_CLASS (gabble_tube_dbus_class);
GParamSpec *param_spec;
@@ -766,6 +962,10 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class)
object_class->dispose = gabble_tube_dbus_dispose;
object_class->finalize = gabble_tube_dbus_finalize;
+ g_object_class_override_property (object_class, PROP_OBJECT_PATH,
+ "object-path");
+ g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+ "channel-type");
g_object_class_override_property (object_class, PROP_CONNECTION,
"connection");
g_object_class_override_property (object_class, PROP_HANDLE,
@@ -785,6 +985,11 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class)
g_object_class_override_property (object_class, PROP_STATE,
"state");
+ g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED,
+ "channel-destroyed");
+ g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES,
+ "channel-properties");
+
/* TODO: When D-Bus tubes will be channels, this will be replaced by
* g_object_class_override_property*/
param_spec = g_param_spec_uint (
@@ -840,6 +1045,33 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_DBUS_NAMES, param_spec);
+ /* FIXME: why do we have to manually define these properties? */
+ param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
+ "Additional Channel.Interface.* interfaces",
+ 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_string ("target-id", "Target JID",
+ "The string obtained by inspecting the target handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
+
+ param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID",
+ "The string obtained by inspecting the initiator-handle",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIATOR_ID,
+ param_spec);
+
+ param_spec = g_param_spec_boolean ("requested", "Requested?",
+ "True if this channel was requested by the local user",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
+
+
signals[OPENED] =
g_signal_new ("tube-opened",
G_OBJECT_CLASS_TYPE (gabble_tube_dbus_class),
@@ -866,6 +1098,12 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class)
NULL, NULL,
gabble_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+
+ gabble_tube_dbus_class->dbus_props_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (object_class,
+ G_STRUCT_OFFSET (GabbleTubeDBusClass, dbus_props_class));
+
+ tp_external_group_mixin_init_dbus_properties (object_class);
}
static void
@@ -1091,8 +1329,15 @@ gabble_tube_dbus_new (GabbleConnection *conn,
guint id,
GabbleBytestreamIface *bytestream)
{
- GabbleTubeDBus *tube = g_object_new (GABBLE_TYPE_TUBE_DBUS,
+ GabbleTubeDBus *tube;
+ gchar *object_path;
+
+ object_path = g_strdup_printf ("%s/StreamTubeChannel_%u_%u",
+ conn->parent.object_path, handle, id);
+
+ tube = g_object_new (GABBLE_TYPE_TUBE_DBUS,
"connection", conn,
+ "object-path", object_path,
"handle", handle,
"handle-type", handle_type,
"self-handle", self_handle,
@@ -1106,6 +1351,7 @@ gabble_tube_dbus_new (GabbleConnection *conn,
if (bytestream != NULL)
g_object_set (tube, "bytestream", bytestream, NULL);
+ g_free (object_path);
return tube;
}
@@ -1336,6 +1582,92 @@ _gabble_generate_dbus_unique_name (const gchar *nick)
return result;
}
+/**
+ * gabble_tube_dbus_close_async:
+ *
+ * Implements D-Bus method Close
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_tube_dbus_close_async (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ gabble_tube_dbus_close (GABBLE_TUBE_IFACE (iface), FALSE);
+ tp_svc_channel_return_from_close (context);
+}
+
+/**
+ * gabble_tube_dbus_get_channel_type
+ *
+ * Implements D-Bus method GetChannelType
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_tube_dbus_get_channel_type (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ tp_svc_channel_return_from_get_channel_type (context,
+ GABBLE_IFACE_CHANNEL_TYPE_DBUS_TUBE);
+}
+
+/**
+ * gabble_tube_dbus_get_handle
+ *
+ * Implements D-Bus method GetHandle
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_tube_dbus_get_handle (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ GabbleTubeDBus *self = GABBLE_TUBE_DBUS (iface);
+ GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self);
+
+ tp_svc_channel_return_from_get_handle (context, priv->handle_type,
+ priv->handle);
+}
+
+/**
+ * gabble_tube_dbus_get_interfaces
+ *
+ * Implements D-Bus method GetInterfaces
+ * on interface org.freedesktop.Telepathy.Channel
+ */
+static void
+gabble_tube_dbus_get_interfaces (TpSvcChannel *iface,
+ DBusGMethodInvocation *context)
+{
+ GabbleTubeDBus *self = GABBLE_TUBE_DBUS (iface);
+ GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self);
+
+ if (priv->handle_type == TP_HANDLE_TYPE_CONTACT)
+ {
+ /* omit the Group interface */
+ tp_svc_channel_return_from_get_interfaces (context,
+ gabble_tube_dbus_interfaces + 1);
+ }
+ else
+ {
+ tp_svc_channel_return_from_get_interfaces (context,
+ gabble_tube_dbus_interfaces);
+ }
+}
+
+static void
+channel_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface;
+
+#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\
+ klass, gabble_tube_dbus_##x##suffix)
+ IMPLEMENT(close,_async);
+ IMPLEMENT(get_channel_type,);
+ IMPLEMENT(get_handle,);
+ IMPLEMENT(get_interfaces,);
+#undef IMPLEMENT
+}
+
static void
tube_iface_init (gpointer g_iface,
gpointer iface_data)
@@ -1346,3 +1678,21 @@ tube_iface_init (gpointer g_iface,
klass->close = gabble_tube_dbus_close;
klass->add_bytestream = gabble_tube_dbus_add_bytestream;
}
+
+static void
+dbustube_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ /*
+ GabbleSvcChannelTypeDBusTubeClass *klass =
+ (GabbleSvcChannelTypeDBusTubeClass *) g_iface;
+ */
+
+#define IMPLEMENT(x) gabble_svc_channel_type_dbus_tube_implement_##x (\
+ klass, gabble_tube_dbus_##x)
+ /*
+ IMPLEMENT(offer_stream_tube);
+ IMPLEMENT(accept_stream_tube);
+ */
+#undef IMPLEMENT
+}
diff --git a/src/tube-dbus.h b/src/tube-dbus.h
index c8a3258..3efaeac 100644
--- a/src/tube-dbus.h
+++ b/src/tube-dbus.h
@@ -33,6 +33,8 @@ typedef struct _GabbleTubeDBusClass GabbleTubeDBusClass;
struct _GabbleTubeDBusClass {
GObjectClass parent_class;
+
+ TpDBusPropertiesMixinClass dbus_props_class;
};
struct _GabbleTubeDBus {
--
1.5.6.5
More information about the telepathy-commits
mailing list