diff options
-rw-r--r-- | src/media-factory.c | 540 | ||||
-rw-r--r-- | src/sip-media-channel.c | 55 |
2 files changed, 394 insertions, 201 deletions
diff --git a/src/media-factory.c b/src/media-factory.c index 203252e..8350ccb 100644 --- a/src/media-factory.c +++ b/src/media-factory.c @@ -1,6 +1,6 @@ /* * media-factory.c - Media channel factory for SIP connection manager - * Copyright (C) 2007 Collabora Ltd. + * Copyright (C) 2007-2008 Collabora Ltd. * Copyright (C) 2007-2008 Nokia Corporation * * This work is free software; you can redistribute it and/or @@ -22,7 +22,8 @@ #include <string.h> -#include <telepathy-glib/svc-connection.h> +#include <telepathy-glib/channel-manager.h> +#include <telepathy-glib/dbus.h> #include <telepathy-glib/interfaces.h> #include "sip-connection.h" @@ -33,12 +34,14 @@ #define DEBUG_FLAG TPSIP_DEBUG_CONNECTION #include "debug.h" -static void factory_iface_init (gpointer, gpointer); +static void channel_manager_iface_init (gpointer, gpointer); +static void tpsip_media_factory_constructed (GObject *object); +static void tpsip_media_factory_close_all (TpsipMediaFactory *fac); G_DEFINE_TYPE_WITH_CODE (TpsipMediaFactory, tpsip_media_factory, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_FACTORY_IFACE, - factory_iface_init)) + G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, + channel_manager_iface_init)) enum { @@ -58,6 +61,9 @@ struct _TpsipMediaFactoryPrivate /* for unique channel object paths, currently always increments */ guint channel_index; + gulong status_changed_id; + gulong invite_received_id; + gchar *stun_server; guint16 stun_port; @@ -88,17 +94,23 @@ tpsip_media_factory_dispose (GObject *object) priv->dispose_has_run = TRUE; - tp_channel_factory_iface_close_all (TP_CHANNEL_FACTORY_IFACE (object)); - + tpsip_media_factory_close_all (fac); g_assert (priv->channels == NULL); - g_free (priv->stun_server); - if (G_OBJECT_CLASS (tpsip_media_factory_parent_class)->dispose) G_OBJECT_CLASS (tpsip_media_factory_parent_class)->dispose (object); } static void +tpsip_media_factory_finalize (GObject *object) +{ + TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (object); + TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); + + g_free (priv->stun_server); +} + +static void tpsip_media_factory_get_property (GObject *object, guint property_id, GValue *value, @@ -157,9 +169,11 @@ tpsip_media_factory_class_init (TpsipMediaFactoryClass *klass) g_type_class_add_private (klass, sizeof (TpsipMediaFactoryPrivate)); + object_class->constructed = tpsip_media_factory_constructed; object_class->get_property = tpsip_media_factory_get_property; object_class->set_property = tpsip_media_factory_set_property; object_class->dispose = tpsip_media_factory_dispose; + object_class->finalize = tpsip_media_factory_finalize; param_spec = g_param_spec_object ("connection", "TpsipConnection object", "SIP connection that owns this media channel factory", @@ -182,68 +196,49 @@ tpsip_media_factory_class_init (TpsipMediaFactoryClass *klass) } static void -tpsip_media_factory_close_one (gpointer data, gpointer user_data) +tpsip_media_factory_close_all (TpsipMediaFactory *fac) { - tpsip_media_channel_close (TPSIP_MEDIA_CHANNEL(data)); - g_object_unref (data); -} - -static void -tpsip_media_factory_close_all (TpChannelFactoryIface *iface) -{ - TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface); TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); - GPtrArray *channels; - channels = priv->channels; - priv->channels = NULL; - if (channels) + if (priv->status_changed_id != 0) { - g_ptr_array_foreach (channels, tpsip_media_factory_close_one, NULL); - g_ptr_array_free (channels, TRUE); + g_signal_handler_disconnect (priv->conn, + priv->status_changed_id); + priv->status_changed_id = 0; } -} - -struct _ForeachData -{ - TpChannelFunc foreach; - gpointer user_data; -}; - -static void -_foreach_slave (gpointer channel, gpointer user_data) -{ - struct _ForeachData *data = (struct _ForeachData *)user_data; - TpChannelIface *chan = TP_CHANNEL_IFACE (channel); - data->foreach (chan, data->user_data); -} + if (priv->channels != NULL) + { + GPtrArray *channels; + guint i; -static void -tpsip_media_factory_foreach (TpChannelFactoryIface *iface, - TpChannelFunc foreach, - gpointer user_data) -{ - TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface); - TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); + channels = priv->channels; + priv->channels = NULL; - struct _ForeachData data = { foreach, user_data }; + for (i = 0; i < channels->len; i++) + { + TpsipMediaChannel *chan = g_ptr_array_index (channels, i); + g_object_unref (chan); + } - g_ptr_array_foreach (priv->channels, _foreach_slave, &data); + g_ptr_array_free (channels, TRUE); + } } /** - * channel_closed: - * + * media_channel_closed_cb: * Signal callback for when a media channel is closed. Removes the references * that #TpsipMediaFactory holds to them. */ static void -channel_closed (TpsipMediaChannel *chan, gpointer user_data) +media_channel_closed_cb (TpsipMediaChannel *chan, gpointer user_data) { TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (user_data); TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); + tp_channel_manager_emit_channel_closed_for_object (fac, + TP_EXPORTABLE_CHANNEL (chan)); + if (priv->channels) { g_ptr_array_remove_fast (priv->channels, chan); @@ -257,12 +252,9 @@ channel_closed (TpsipMediaChannel *chan, gpointer user_data) * Creates a new empty TpsipMediaChannel. */ static TpsipMediaChannel * -tpsip_media_factory_new_channel (TpsipMediaFactory *fac, - gpointer request, - TpHandleType handle_type, - TpHandle handle, - TpHandle initiator, - GError **error) +new_media_channel (TpsipMediaFactory *fac, + TpHandle initiator, + TpHandle maybe_peer) { TpsipMediaFactoryPrivate *priv; TpsipMediaChannel *chan = NULL; @@ -275,29 +267,6 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac, priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); conn = (TpBaseConnection *)priv->conn; - switch (handle_type) - { - case TP_HANDLE_TYPE_CONTACT: - if (!tp_handle_is_valid ( - tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT), - handle, error)) - goto err; - break; - case TP_HANDLE_TYPE_NONE: - if (handle != 0) - { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "TargetHandle must be zero or omitted if TargetHandleType is " - "NONE"); - goto err; - } - break; - default: - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "SIP media channels can not be created with this handle type"); - goto err; - } - object_path = g_strdup_printf ("%s/MediaChannel%u", conn->object_path, priv->channel_index++); @@ -311,7 +280,7 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac, chan = g_object_new (TPSIP_TYPE_MEDIA_CHANNEL, "connection", priv->conn, "object-path", object_path, - "handle", handle, + "handle", maybe_peer, "initiator", initiator, "nat-traversal", nat_traversal, NULL); @@ -325,86 +294,11 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac, g_object_set ((GObject *) chan, "stun-port", priv->stun_port, NULL); } - if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != initiator) - { - g_assert (initiator == conn->self_handle); - - if (!_tpsip_media_channel_add_member ((GObject *) chan, - handle, "", error)) - goto err; - } - - g_signal_connect (chan, "closed", (GCallback) channel_closed, fac); + g_signal_connect (chan, "closed", G_CALLBACK (media_channel_closed_cb), fac); g_ptr_array_add (priv->channels, chan); - tp_channel_factory_iface_emit_new_channel (fac, (TpChannelIface *)chan, - request); - return chan; - -err: - if (chan != NULL) - g_object_unref (chan); - return NULL; -} - -static TpChannelFactoryRequestStatus -tpsip_media_factory_request (TpChannelFactoryIface *iface, - const gchar *chan_type, - TpHandleType handle_type, - TpHandle handle, - gpointer request, - TpChannelIface **ret, - GError **error_ret) -{ - TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface); - TpsipMediaFactoryPrivate *priv; - TpChannelIface *chan; - TpChannelFactoryRequestStatus status = TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR; - TpBaseConnection *base_conn; - GError *error = NULL; - - if (strcmp (chan_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) - { - return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED; - } - - priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); - base_conn = (TpBaseConnection *)priv->conn; - - chan = (TpChannelIface *) tpsip_media_factory_new_channel (fac, - request, - handle_type, - handle, - base_conn->self_handle, - &error); - if (chan != NULL) - { - *ret = chan; - status = TP_CHANNEL_FACTORY_REQUEST_STATUS_CREATED; - } - else - { - g_assert (error != NULL); - switch (error->code) - { - case TP_ERROR_INVALID_HANDLE: - case TP_ERROR_INVALID_ARGUMENT: - status = TP_CHANNEL_FACTORY_REQUEST_STATUS_INVALID_HANDLE; - break; - case TP_ERROR_NOT_AVAILABLE: - status = TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_AVAILABLE; - break; - default: - status = TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR; - } - if (error_ret != NULL) - *error_ret = error; - else - g_error_free (error); - } - return status; } static gboolean @@ -416,7 +310,6 @@ tpsip_nua_i_invite_cb (TpBaseConnection *conn, TpsipMediaChannel *channel; TpHandleRepoIface *contact_repo; TpHandle handle; - GError *error = NULL; /* figure out a handle for the identity */ @@ -433,23 +326,9 @@ tpsip_nua_i_invite_cb (TpBaseConnection *conn, DEBUG("Got incoming invite from <%s>", tp_handle_inspect (contact_repo, handle)); - channel = tpsip_media_factory_new_channel ( - fac, - NULL, - TP_HANDLE_TYPE_CONTACT, - handle, - handle, - &error); - if (channel) - { - tpsip_media_channel_receive_invite (channel, ev->nua_handle); - } - else - { - g_warning ("creation of SIP media channel failed: %s", error->message); - g_error_free (error); - nua_respond (ev->nua_handle, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); - } + channel = new_media_channel (fac, handle, handle); + + tpsip_media_channel_receive_invite (channel, ev->nua_handle); tp_handle_unref (contact_repo, handle); @@ -457,38 +336,305 @@ tpsip_nua_i_invite_cb (TpBaseConnection *conn, } static void -tpsip_media_factory_connected (TpChannelFactoryIface *iface) +connection_status_changed_cb (TpsipConnection *conn, + guint status, + guint reason, + TpsipMediaFactory *self) { - TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface); - TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); + TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self); - g_signal_connect (priv->conn, - "nua-event::nua_i_invite", - G_CALLBACK (tpsip_nua_i_invite_cb), - fac); + switch (status) + { + case TP_CONNECTION_STATUS_CONNECTED: + + priv->invite_received_id = g_signal_connect (conn, + "nua-event::nua_i_invite", + G_CALLBACK (tpsip_nua_i_invite_cb), self); + + break; + case TP_CONNECTION_STATUS_DISCONNECTED: + + tpsip_media_factory_close_all (self); + + g_signal_handler_disconnect (conn, priv->invite_received_id); + priv->invite_received_id = 0; + + break; + default: + break; + } } static void -tpsip_media_factory_disconnected (TpChannelFactoryIface *iface) +tpsip_media_factory_constructed (GObject *object) { - TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface); + TpsipMediaFactory *self = TPSIP_MEDIA_FACTORY (object); + TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self); + GObjectClass *parent_object_class = + G_OBJECT_CLASS (tpsip_media_factory_parent_class); + + if (parent_object_class->constructed != NULL) + parent_object_class->constructed (object); + + priv->status_changed_id = g_signal_connect (priv->conn, + "status-changed", (GCallback) connection_status_changed_cb, object); +} + +static void +tpsip_media_factory_foreach_channel (TpChannelManager *manager, + TpExportableChannelFunc foreach, + gpointer user_data) +{ + TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (manager); TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac); + guint i; + + for (i = 0; i < priv->channels->len; i++) + { + TpExportableChannel *channel = TP_EXPORTABLE_CHANNEL ( + g_ptr_array_index (priv->channels, i)); + + foreach (channel, user_data); + } +} + +static const gchar * const media_channel_fixed_properties[] = { + TP_IFACE_CHANNEL ".ChannelType", + TP_IFACE_CHANNEL ".TargetHandleType", + NULL +}; + +static const gchar * const named_channel_allowed_properties[] = { + TP_IFACE_CHANNEL ".TargetHandle", + TP_IFACE_CHANNEL ".TargetID", + NULL +}; + +static const gchar * const anon_channel_allowed_properties[] = { + NULL +}; + +static void +tpsip_media_factory_foreach_channel_class (TpChannelManager *manager, + TpChannelManagerChannelClassFunc func, + gpointer user_data) +{ + GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) tp_g_value_slice_free); + GValue *value, *handle_type_value; + + value = tp_g_value_slice_new (G_TYPE_STRING); + g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); + g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value); + + handle_type_value = tp_g_value_slice_new (G_TYPE_UINT); + /* no uint value yet - we'll change it for each channel class */ + g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", + handle_type_value); + + g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_NONE); + func (manager, table, anon_channel_allowed_properties, user_data); + + g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_CONTACT); + func (manager, table, named_channel_allowed_properties, user_data); + + g_hash_table_destroy (table); +} + +typedef enum +{ + METHOD_REQUEST, + METHOD_CREATE, + METHOD_ENSURE, +} RequestMethod; + +static gboolean +tpsip_media_factory_requestotron (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties, + RequestMethod method) +{ + TpsipMediaFactory *self = TPSIP_MEDIA_FACTORY (manager); + TpsipMediaFactoryPrivate *priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (self); + TpBaseConnection *conn = (TpBaseConnection *) priv->conn; + TpHandleType handle_type; + TpHandle handle; + TpsipMediaChannel *channel = NULL; + GError *error = NULL; + GSList *request_tokens; + gboolean require_target_handle; + gboolean add_peer_to_remote_pending; + + /* Supported modes of operation: + * - RequestChannel(None, 0): + * channel is anonymous; + * caller uses RequestStreams to set the peer and start the call. + * - RequestChannel(Contact, n) where n != 0: + * channel has TargetHandle=n; + * n is in remote pending; + * call is started when caller calls RequestStreams. + * - CreateChannel({THT: Contact, TH: n}): + * channel has TargetHandle=n + * n is not in the group interface at all + * call is started when caller calls RequestStreams. + * - EnsureChannel({THT: Contact, TH: n}): + * look for a channel whose peer is n, and return that if found with + * whatever properties and group membership it has; + * otherwise the same as into CreateChannel + */ + switch (method) + { + case METHOD_REQUEST: + require_target_handle = FALSE; + add_peer_to_remote_pending = TRUE; + break; + case METHOD_CREATE: + case METHOD_ENSURE: + require_target_handle = TRUE; + add_peer_to_remote_pending = FALSE; + break; + default: + g_assert_not_reached (); + } + + if (tp_strdiff (tp_asv_get_string (request_properties, + TP_IFACE_CHANNEL ".ChannelType"), + TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) + return FALSE; + + handle_type = tp_asv_get_uint32 (request_properties, + TP_IFACE_CHANNEL ".TargetHandleType", NULL); + + handle = tp_asv_get_uint32 (request_properties, + TP_IFACE_CHANNEL ".TargetHandle", NULL); + + switch (handle_type) + { + case TP_HANDLE_TYPE_NONE: + if (handle != 0) + { + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "TargetHandle must be zero or omitted if TargetHandleType is " + "NONE"); + goto error; + } + + if (require_target_handle) + { + g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "A valid Contact handle must be provided when requesting a media " + "channel"); + goto error; + } + + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + media_channel_fixed_properties, anon_channel_allowed_properties, + &error)) + goto error; - g_signal_handlers_disconnect_by_func (priv->conn, - G_CALLBACK (tpsip_nua_i_invite_cb), - fac); + channel = new_media_channel (self, conn->self_handle, 0); + break; + + case TP_HANDLE_TYPE_CONTACT: + if (!tp_handle_is_valid ( + tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT), + handle, &error)) + goto error; + + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + media_channel_fixed_properties, named_channel_allowed_properties, + &error)) + goto error; + + if (method == METHOD_ENSURE) + { + guint i; + TpHandle peer = 0; + + for (i = 0; i < priv->channels->len; i++) + { + channel = g_ptr_array_index (priv->channels, i); + g_object_get (channel, "peer", &peer, NULL); + + if (peer == handle) + { + tp_channel_manager_emit_request_already_satisfied (self, + request_token, TP_EXPORTABLE_CHANNEL (channel)); + return TRUE; + } + } + } + + channel = new_media_channel (self, conn->self_handle, handle); + + if (add_peer_to_remote_pending) + { + if (!_tpsip_media_channel_add_member ((GObject *) channel, handle, + "", &error)) + { + tpsip_media_channel_close (channel); + goto error; + } + } + + break; + + default: + return FALSE; + } + + g_assert (channel != NULL); + + request_tokens = g_slist_prepend (NULL, request_token); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (channel), request_tokens); + g_slist_free (request_tokens); + + return TRUE; + +error: + tp_channel_manager_emit_request_failed (self, request_token, + error->domain, error->code, error->message); + g_error_free (error); + return TRUE; +} + +static gboolean +tpsip_media_factory_request_channel (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + return tpsip_media_factory_requestotron (manager, request_token, + request_properties, METHOD_REQUEST); +} + +static gboolean +tpsip_media_factory_create_channel (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + return tpsip_media_factory_requestotron (manager, request_token, + request_properties, METHOD_CREATE); +} + +static gboolean +tpsip_media_factory_ensure_channel (TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + return tpsip_media_factory_requestotron (manager, request_token, + request_properties, METHOD_ENSURE); } static void -factory_iface_init (gpointer g_iface, gpointer iface_data) +channel_manager_iface_init (gpointer g_iface, + gpointer iface_data) { - TpChannelFactoryIfaceClass *klass = (TpChannelFactoryIfaceClass *) g_iface; - -#define IMPLEMENT(x) klass->x = tpsip_media_factory_##x - IMPLEMENT(close_all); - IMPLEMENT(foreach); - IMPLEMENT(request); - IMPLEMENT(connected); - IMPLEMENT(disconnected); -#undef IMPLEMENT + TpChannelManagerIface *iface = g_iface; + + iface->foreach_channel = tpsip_media_factory_foreach_channel; + iface->foreach_channel_class = tpsip_media_factory_foreach_channel_class; + iface->request_channel = tpsip_media_factory_request_channel; + iface->create_channel = tpsip_media_factory_create_channel; + iface->ensure_channel = tpsip_media_factory_ensure_channel; } diff --git a/src/sip-media-channel.c b/src/sip-media-channel.c index 57012f1..eb57ad5 100644 --- a/src/sip-media-channel.c +++ b/src/sip-media-channel.c @@ -31,9 +31,8 @@ #include <telepathy-glib/channel-iface.h> #include <telepathy-glib/dbus.h> #include <telepathy-glib/errors.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/exportable-channel.h> #include <telepathy-glib/interfaces.h> -#include <telepathy-glib/intset.h> #include <telepathy-glib/svc-channel.h> #include <tpsip/event-target.h> @@ -72,6 +71,7 @@ G_DEFINE_TYPE_WITH_CODE (TpsipMediaChannel, tpsip_media_channel, hold_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA, streamed_media_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); static const gchar *tpsip_media_channel_interfaces[] = { @@ -95,8 +95,11 @@ enum PROP_TARGET_ID, PROP_INITIATOR, PROP_INITIATOR_ID, + PROP_PEER, PROP_REQUESTED, PROP_INTERFACES, + PROP_CHANNEL_DESTROYED, + PROP_CHANNEL_PROPERTIES, /* Telepathy properties (see below too) */ PROP_NAT_TRAVERSAL, PROP_STUN_SERVER, @@ -113,7 +116,7 @@ enum NUM_TP_PROPS }; -const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] = +static const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] = { { "nat-traversal", G_TYPE_STRING }, { "stun-server", G_TYPE_STRING }, @@ -277,6 +280,11 @@ tpsip_media_channel_class_init (TpsipMediaChannelClass *klass) g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); + g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, + "channel-destroyed"); + g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, + "channel-properties"); + param_spec = g_param_spec_object ("connection", "TpsipConnection object", "SIP connection object that owns this SIP media channel object.", TPSIP_TYPE_CONNECTION, @@ -376,8 +384,30 @@ tpsip_media_channel_get_property (GObject *object, TP_HANDLE_TYPE_CONTACT : TP_HANDLE_TYPE_NONE); break; case PROP_TARGET_ID: - g_value_set_static_string (value, ""); + if (priv->handle != 0) + { + TpHandleRepoIface *repo = tp_base_connection_get_handles ( + base_conn, TP_HANDLE_TYPE_CONTACT); + + g_value_set_string (value, tp_handle_inspect (repo, priv->initiator)); + } + else + g_value_set_static_string (value, ""); break; + case PROP_PEER: + { + TpHandle peer = 0; + + if (priv->handle != 0) + peer = priv->handle; + else if (priv->session != NULL) + g_object_get (priv->session, + "peer", &peer, + NULL); + + g_value_set_uint (value, peer); + break; + } case PROP_INITIATOR: g_value_set_uint (value, priv->initiator); break; @@ -395,6 +425,21 @@ tpsip_media_channel_get_property (GObject *object, case PROP_INTERFACES: g_value_set_static_boxed (value, tpsip_media_channel_interfaces); 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, "ChannelType", + TP_IFACE_CHANNEL, "TargetHandleType", + TP_IFACE_CHANNEL, "TargetHandle", + TP_IFACE_CHANNEL, "TargetID", + TP_IFACE_CHANNEL, "InitiatorHandle", + TP_IFACE_CHANNEL, "InitiatorID", + TP_IFACE_CHANNEL, "Requested", + NULL)); + break; default: /* Some properties live in the mixin */ { @@ -445,6 +490,8 @@ tpsip_media_channel_set_property (GObject *object, priv->object_path = g_value_dup_string (value); break; case PROP_HANDLE: + /* XXX: this property is defined as writable, + * but don't set it after construction, mmkay? */ /* we don't ref it here because we don't necessarily have access to the * contact repo yet - instead we ref it in constructed. */ priv->handle = g_value_get_uint (value); |