diff options
author | Tom Swindell <t.swindell@rubyx.co.uk> | 2013-04-04 13:08:06 +0000 |
---|---|---|
committer | Tom Swindell <t.swindell@rubyx.co.uk> | 2013-04-04 13:08:06 +0000 |
commit | 554ca78811f56e91bb2a5941603e05dcaa0233a4 (patch) | |
tree | be527a8ebb712f55152294a1d4ae22da77298a89 | |
parent | 41a3143837ee5fcabf7959cae1fec17a7a0ff5ae (diff) |
Update to new tp base classes and interfaces
Signed-off-by: Tom Swindell <t.swindell@rubyx.co.uk>
-rw-r--r-- | src/Makefile.am | 10 | ||||
-rw-r--r-- | src/base-call-channel.c | 754 | ||||
-rw-r--r-- | src/base-call-channel.h | 119 | ||||
-rw-r--r-- | src/base-call-content.c | 434 | ||||
-rw-r--r-- | src/base-call-content.h | 97 | ||||
-rw-r--r-- | src/base-call-stream.c | 351 | ||||
-rw-r--r-- | src/base-call-stream.h | 87 | ||||
-rw-r--r-- | src/ring-call-channel.h | 1 | ||||
-rw-r--r-- | src/ring-call-content.c | 20 | ||||
-rw-r--r-- | src/ring-call-content.h | 11 | ||||
-rw-r--r-- | src/ring-call-member.c | 597 | ||||
-rw-r--r-- | src/ring-call-member.h | 73 | ||||
-rw-r--r-- | src/ring-call-stream.c | 11 | ||||
-rw-r--r-- | src/ring-call-stream.h | 18 | ||||
-rw-r--r-- | src/ring-connection.c | 1 | ||||
-rw-r--r-- | src/ring-connection.h | 5 | ||||
-rw-r--r-- | src/ring-util.c | 1 | ||||
-rw-r--r-- | src/ring-util.h | 2 | ||||
-rw-r--r-- | src/util.c | 525 | ||||
-rw-r--r-- | src/util.h | 110 |
20 files changed, 1572 insertions, 1655 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 24353ff..d9e1a60 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,8 +42,9 @@ test_ring_LDADD = \ libtpring_la_SOURCES = \ base-call-channel.h base-call-channel.c \ - base-call-content.h base-call-content.c \ - base-call-stream.h base-call-stream.c \ + ring-call-content.h ring-call-content.c \ + ring-call-stream.h ring-call-stream.c \ + ring-call-member.h ring-call-member.c \ ring-connection-manager.h ring-connection-manager.c \ ring-protocol.h ring-protocol.c \ ring-connection.h ring-connection.c \ @@ -57,11 +58,10 @@ libtpring_la_SOURCES = \ ring-member-channel.h ring-member-channel.c \ ring-conference-manager.h ring-conference-manager.c \ ring-conference-channel.h ring-conference-channel.c \ - ring-call-content.h ring-call-content.c \ - ring-call-stream.h ring-call-stream.c \ ring-param-spec.h ring-param-spec.c \ ring-emergency-service.h ring-emergency-service.c \ - ring-util.h ring-util.c + ring-util.h ring-util.c \ + util.h util.c TP_EXTLIB = TP_EXTLIB += $(top_builddir)/ring-extensions/libtpextensions.a diff --git a/src/base-call-channel.c b/src/base-call-channel.c index 9812268..52af824 100644 --- a/src/base-call-channel.c +++ b/src/base-call-channel.c @@ -1,7 +1,8 @@ /* - * base-call-channel.c - Source for GabbleBaseCallChannel + * base-call-channel.c - Source for RingBaseCallChannel * Copyright © 2009–2010 Collabora Ltd. * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,189 +19,86 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include <stdio.h> #include <stdlib.h> #include <gio/gio.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> -#include "base-call-channel.h" -#include "base-call-content.h" +#include "util.h" +#include "ring-call-content.h" +#include "ring-call-member.h" +#include "base-call-channel.h" #include "ring-connection.h" +/* #define DEBUG_FLAG RING_DEBUG_MEDIA -#include "ring-debug.h" +#include "debug.h" +*/ -static void call_iface_init (gpointer, gpointer); -static void gabble_base_call_channel_close (TpBaseChannel *base); +G_DEFINE_TYPE(RingBaseCallChannel, ring_base_call_channel, + TP_TYPE_BASE_MEDIA_CALL_CHANNEL); -G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallChannel, gabble_base_call_channel, - TP_TYPE_BASE_CHANNEL, - G_IMPLEMENT_INTERFACE (TP_TYPE_BASE_MEDIA_CALL_CHANNEL, - call_iface_init) -); +static void ring_base_call_channel_hangup ( + TpBaseCallChannel *base, + guint reason, + const gchar *detailed_reason, + const gchar *message); -static const gchar *gabble_base_call_channel_interfaces[] = { - NULL -}; +static void ring_base_call_channel_close (TpBaseChannel *base); /* properties */ enum { PROP_OBJECT_PATH_PREFIX = 1, - - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_MUTABLE_CONTENTS, - PROP_HARDWARE_STREAMING, - PROP_CONTENTS, - - PROP_CALL_STATE, - PROP_CALL_FLAGS, - PROP_CALL_STATE_DETAILS, - PROP_CALL_STATE_REASON, - - PROP_CALL_MEMBERS, - LAST_PROPERTY }; -enum -{ - ENDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0, }; - - /* private structure */ -struct _GabbleBaseCallChannelPrivate +struct _RingBaseCallChannelPrivate { gchar *object_path_prefix; gboolean dispose_has_run; - GList *contents; - - TpCallState state; - TpCallFlags flags; - GHashTable *details; - GValueArray *reason; - - /* handle -> TpCallMemberFlags hash */ + /* handle -> CallMember object hash */ GHashTable *members; }; static void -gabble_base_call_channel_constructed (GObject *obj) +ring_base_call_channel_init (RingBaseCallChannel *self) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (obj); - TpBaseChannel *base = TP_BASE_CHANNEL (self); - - if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed - != NULL) - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->constructed (obj); - - if (tp_base_channel_is_requested (base)) - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_PENDING_INITIATOR); - else - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_INITIALISING); -} - -static void -gabble_base_call_channel_init (GabbleBaseCallChannel *self) -{ - GabbleBaseCallChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelPrivate); + RingBaseCallChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + RING_TYPE_BASE_CALL_CHANNEL, RingBaseCallChannelPrivate); self->priv = priv; - priv->reason = tp_value_array_build (3, - G_TYPE_UINT, 0, - G_TYPE_UINT, 0, - G_TYPE_STRING, "", - G_TYPE_INVALID); - - priv->details = tp_asv_new (NULL, NULL); - - priv->members = g_hash_table_new (NULL, NULL); + priv->members = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, g_object_unref); } -static void gabble_base_call_channel_dispose (GObject *object); -static void gabble_base_call_channel_finalize (GObject *object); +static void ring_base_call_channel_dispose (GObject *object); +static void ring_base_call_channel_finalize (GObject *object); static void -gabble_base_call_channel_get_property (GObject *object, +ring_base_call_channel_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; - GabbleBaseCallChannelClass *klass = GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; switch (property_id) { case PROP_OBJECT_PATH_PREFIX: g_value_set_string (value, priv->object_path_prefix); break; - case PROP_INITIAL_AUDIO: - g_value_set_boolean (value, self->initial_audio); - break; - case PROP_INITIAL_VIDEO: - g_value_set_boolean (value, self->initial_video); - break; - case PROP_MUTABLE_CONTENTS: - g_value_set_boolean (value, klass->mutable_contents); - break; - case PROP_CONTENTS: - { - GPtrArray *arr = g_ptr_array_sized_new (2); - GList *l; - - for (l = priv->contents; l != NULL; l = g_list_next (l)) - { - GabbleBaseCallContent *c = GABBLE_BASE_CALL_CONTENT (l->data); - g_ptr_array_add (arr, - (gpointer) gabble_base_call_content_get_object_path (c)); - } - - g_value_set_boxed (value, arr); - g_ptr_array_free (arr, TRUE); - break; - } - case PROP_HARDWARE_STREAMING: - g_value_set_boolean (value, klass->hardware_streaming); - break; - case PROP_CALL_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_CALL_FLAGS: - g_value_set_uint (value, priv->flags); - break; - case PROP_CALL_STATE_DETAILS: - g_value_set_boxed (value, priv->details); - break; - case PROP_CALL_STATE_REASON: - g_value_set_boxed (value, priv->reason); - break; - case PROP_CALL_MEMBERS: - g_value_set_boxed (value, priv->members); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -208,25 +106,19 @@ gabble_base_call_channel_get_property (GObject *object, } static void -gabble_base_call_channel_set_property (GObject *object, +ring_base_call_channel_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; switch (property_id) { case PROP_OBJECT_PATH_PREFIX: priv->object_path_prefix = g_value_dup_string (value); break; - case PROP_INITIAL_AUDIO: - self->initial_audio = g_value_get_boolean (value); - break; - case PROP_INITIAL_VIDEO: - self->initial_video = g_value_get_boolean (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -234,10 +126,10 @@ gabble_base_call_channel_set_property (GObject *object, } static gchar * -gabble_base_call_channel_get_object_path_suffix (TpBaseChannel *base) +ring_base_call_channel_get_object_path_suffix (TpBaseChannel *base) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (base); + RingBaseCallChannelPrivate *priv = self->priv; g_assert (priv->object_path_prefix != NULL); @@ -245,70 +137,30 @@ gabble_base_call_channel_get_object_path_suffix (TpBaseChannel *base) } static void -gabble_base_call_channel_fill_immutable_properties ( - TpBaseChannel *chan, - GHashTable *properties) +ring_base_call_channel_class_init ( + RingBaseCallChannelClass *ring_base_call_channel_class) { - TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_parent_class) - ->fill_immutable_properties (chan, properties); - - tp_dbus_properties_mixin_fill_properties_hash ( - G_OBJECT (chan), properties, - TP_IFACE_CHANNEL_TYPE_CALL, "InitialAudio", - TP_IFACE_CHANNEL_TYPE_CALL, "InitialVideo", - TP_IFACE_CHANNEL_TYPE_CALL, "MutableContents", - TP_IFACE_CHANNEL_TYPE_CALL, "HardwareStreaming", - NULL); -} - -static void -gabble_base_call_channel_class_init ( - GabbleBaseCallChannelClass *gabble_base_call_channel_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (gabble_base_call_channel_class); + GObjectClass *object_class = G_OBJECT_CLASS (ring_base_call_channel_class); TpBaseChannelClass *base_channel_class = - TP_BASE_CHANNEL_CLASS (gabble_base_call_channel_class); + TP_BASE_CHANNEL_CLASS (ring_base_call_channel_class); + TpBaseCallChannelClass *tp_base_call_channel_class = + TP_BASE_CALL_CHANNEL_CLASS (ring_base_call_channel_class); GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl call_props[] = { - { "CallMembers", "call-members", NULL }, - { "MutableContents", "mutable-contents", NULL }, - { "InitialAudio", "initial-audio", NULL }, - { "InitialVideo", "initial-video", NULL }, - { "Contents", "contents", NULL }, - { "HardwareStreaming", "hardware-streaming", NULL }, - { "CallState", "call-state", NULL }, - { "CallFlags", "call-flags", NULL }, - { "CallStateReason", "call-state-reason", NULL }, - { "CallStateDetails", "call-state-details", NULL }, - { NULL } - }; - - g_type_class_add_private (gabble_base_call_channel_class, - sizeof (GabbleBaseCallChannelPrivate)); - - object_class->constructed = gabble_base_call_channel_constructed; - - object_class->get_property = gabble_base_call_channel_get_property; - object_class->set_property = gabble_base_call_channel_set_property; - - object_class->dispose = gabble_base_call_channel_dispose; - object_class->finalize = gabble_base_call_channel_finalize; - - base_channel_class->channel_type = TP_IFACE_CHANNEL_TYPE_CALL; - base_channel_class->interfaces = gabble_base_call_channel_interfaces; + + g_type_class_add_private (ring_base_call_channel_class, + sizeof (RingBaseCallChannelPrivate)); + + object_class->get_property = ring_base_call_channel_get_property; + object_class->set_property = ring_base_call_channel_set_property; + + object_class->dispose = ring_base_call_channel_dispose; + object_class->finalize = ring_base_call_channel_finalize; + base_channel_class->get_object_path_suffix = - gabble_base_call_channel_get_object_path_suffix; - base_channel_class->fill_immutable_properties = - gabble_base_call_channel_fill_immutable_properties; - base_channel_class->close = gabble_base_call_channel_close; - - signals[ENDED] = g_signal_new ("ended", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + ring_base_call_channel_get_object_path_suffix; + base_channel_class->close = ring_base_call_channel_close; + + tp_base_call_channel_class->hangup = ring_base_call_channel_hangup; param_spec = g_param_spec_string ("object-path-prefix", "Object path prefix", "prefix of the object path", @@ -316,446 +168,162 @@ gabble_base_call_channel_class_init ( G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_OBJECT_PATH_PREFIX, param_spec); - - param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", - "Whether the channel initially contained an audio stream", - FALSE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, - param_spec); - - param_spec = g_param_spec_boolean ("initial-video", "InitialVideo", - "Whether the channel initially contained an video stream", - FALSE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - param_spec = g_param_spec_boolean ("mutable-contents", "MutableContents", - "Whether the set of streams on this channel are mutable once requested", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MUTABLE_CONTENTS, - param_spec); - - param_spec = g_param_spec_boxed ("contents", "Contents", - "The contents of the channel", - TP_ARRAY_TYPE_OBJECT_PATH_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONTENTS, - param_spec); - - param_spec = g_param_spec_boolean ("hardware-streaming", "HardwareStreaming", - "True if all the streaming is done by hardware", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_HARDWARE_STREAMING, - param_spec); - - param_spec = g_param_spec_uint ("call-state", "CallState", - "The status of the call", - TP_CALL_STATE_UNKNOWN, - NUM_TP_CALL_STATES, - TP_CALL_STATE_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE, param_spec); - - param_spec = g_param_spec_uint ("call-flags", "CallFlags", - "Flags representing the status of the call", - 0, G_MAXUINT, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_FLAGS, - param_spec); - - param_spec = g_param_spec_boxed ("call-state-reason", "CallStateReason", - "The reason why the call is in the current state", - TP_STRUCT_TYPE_CALL_STATE_REASON, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE_REASON, - param_spec); - - param_spec = g_param_spec_boxed ("call-state-details", "CallStateDetails", - "The reason why the call is in the current state", - TP_HASH_TYPE_QUALIFIED_PROPERTY_VALUE_MAP, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_STATE_DETAILS, - param_spec); - - param_spec = g_param_spec_boxed ("call-members", "CallMembers", - "The members", - TP_HASH_TYPE_CALL_MEMBER_MAP, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CALL_MEMBERS, - param_spec); - - tp_dbus_properties_mixin_implement_interface (object_class, - TP_IFACE_QUARK_CHANNEL_TYPE_CALL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - call_props); } void -gabble_base_call_channel_dispose (GObject *object) +ring_base_call_channel_dispose (GObject *object) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; if (priv->dispose_has_run) return; self->priv->dispose_has_run = TRUE; - g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, NULL); - g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); - tp_clear_pointer (&priv->contents, g_list_free); - tp_clear_pointer (&priv->members, g_hash_table_unref); - if (G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose) - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->dispose (object); + if (G_OBJECT_CLASS (ring_base_call_channel_parent_class)->dispose) + G_OBJECT_CLASS (ring_base_call_channel_parent_class)->dispose (object); } void -gabble_base_call_channel_finalize (GObject *object) +ring_base_call_channel_finalize (GObject *object) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (object); - GabbleBaseCallChannelPrivate *priv = self->priv; + RingBaseCallChannel *self = RING_BASE_CALL_CHANNEL (object); + RingBaseCallChannelPrivate *priv = self->priv; - g_hash_table_unref (priv->details); - g_value_array_free (priv->reason); - g_free (self->priv->object_path_prefix); + g_free (priv->object_path_prefix); - G_OBJECT_CLASS (gabble_base_call_channel_parent_class)->finalize (object); + G_OBJECT_CLASS (ring_base_call_channel_parent_class)->finalize (object); } -void -gabble_base_call_channel_set_state (GabbleBaseCallChannel *self, - TpCallState state) +RingCallContent * +ring_base_call_channel_add_content (RingBaseCallChannel *self, + const gchar *name, + TpCallContentDisposition disposition) { - GabbleBaseCallChannelPrivate *priv = self->priv; - - DEBUG ("changing from %u to %u", priv->state, state); - - if (state == priv->state) - return; - - /* signal when going to the ended state */ - if (state == TP_CALL_STATE_ENDED) - g_signal_emit (self, signals[ENDED], 0); - - priv->state = state; - - if (priv->state != TP_CALL_STATE_INITIALISING) - priv->flags &= ~TP_CALL_FLAG_LOCALLY_RINGING; - - if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) - tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, - priv->flags, priv->reason, priv->details); -} - -TpCallState -gabble_base_call_channel_get_state (GabbleBaseCallChannel *self) -{ - return self->priv->state; -} - -void -gabble_base_call_channel_update_flags (GabbleBaseCallChannel *self, - TpCallFlags set_flags, - TpCallFlags clear_flags) -{ - GabbleBaseCallChannelPrivate *priv = self->priv; - TpCallFlags old_flags = priv->flags; - - priv->flags = (old_flags | set_flags) & ~clear_flags; - DEBUG ("was %u; set %u and cleared %u; now %u", old_flags, set_flags, - clear_flags, priv->flags); - - if (priv->flags != old_flags) - tp_svc_channel_type_call_emit_call_state_changed (self, priv->state, - priv->flags, priv->reason, priv->details); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + gchar *object_path; + TpBaseCallContent *content; + gchar *escaped; + + /* FIXME could clash when other party in a one-to-one call creates a stream + * with the same media type and name */ + escaped = tp_escape_as_identifier (name); + object_path = g_strdup_printf ("%s/Content_%s", + tp_base_channel_get_object_path (base), + escaped); + g_free (escaped); + + content = g_object_new (RING_TYPE_CALL_CONTENT, + "connection", tp_base_channel_get_connection (base), + "object-path", object_path, + "disposition", disposition, + //"media-type", wocky_jingle_media_type_to_tp (mtype), + "name", name, + NULL); + + g_free (object_path); + + tp_base_call_channel_add_content (TP_BASE_CALL_CHANNEL (self), + content); + + return RING_CALL_CONTENT (content); } -static gboolean -base_call_channel_update_member (GabbleBaseCallChannel *self, - TpHandle contact, - TpCallMemberFlags set_flags, - TpCallMemberFlags clear_flags, - TpCallMemberFlags *new_flags) +static void +call_member_flags_changed_cb (RingCallMember *member, + TpCallMemberFlags flags, + gpointer user_data) { - gpointer old_flags_p; - - DEBUG ("updating member #%u, setting %u and clearing %u", contact, set_flags, - clear_flags); - - if (g_hash_table_lookup_extended (self->priv->members, - GUINT_TO_POINTER (contact), NULL, &old_flags_p)) - { - TpCallMemberFlags old_flags = GPOINTER_TO_UINT (old_flags_p); - - *new_flags = (old_flags | set_flags) & ~clear_flags; - - DEBUG ("previous flags: %u; new flags: %u", old_flags, *new_flags); - - if (old_flags == *new_flags) - return FALSE; - } - else - { - *new_flags = set_flags & ~clear_flags; - DEBUG ("not previously a member; new flags: %u", *new_flags); - } + TpBaseCallChannel *base = TP_BASE_CALL_CHANNEL (user_data); - g_hash_table_insert (self->priv->members, GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (*new_flags)); - return TRUE; + tp_base_call_channel_update_member_flags (base, + ring_call_member_get_handle (member), + flags, + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); } -gboolean -gabble_base_call_channel_update_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - TpCallMemberFlags set_flags, - TpCallMemberFlags clear_flags, - ...) +RingCallMember * +ring_base_call_channel_get_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle) { - GHashTable *updates = g_hash_table_new (NULL, NULL); - gboolean updated = FALSE; - va_list args; - - va_start (args, clear_flags); - - do - { - TpCallMemberFlags new_flags; - - if (base_call_channel_update_member (self, contact, set_flags, - clear_flags, &new_flags)) - { - g_hash_table_insert (updates, - GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (new_flags)); - updated = TRUE; - } - - contact = va_arg (args, TpHandle); - - if (contact != 0) - { - set_flags = va_arg (args, TpCallMemberFlags); - clear_flags = va_arg (args, TpCallMemberFlags); - } - } - while (contact != 0); - - if (updated) - { - GArray *empty = g_array_new (FALSE, FALSE, sizeof (TpHandle)); - - tp_svc_channel_type_call_emit_call_members_changed (self, updates, NULL, - empty, empty); - g_array_unref (empty); - } - - g_hash_table_unref (updates); - return updated; + return g_hash_table_lookup (self->priv->members, GUINT_TO_POINTER (handle)); } -gboolean -gabble_base_call_channel_remove_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - ...) +RingCallMember * +ring_base_call_channel_ensure_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle) { - GArray *removed = g_array_new (FALSE, FALSE, sizeof (TpHandle)); - gboolean updated = FALSE; - va_list args; + RingBaseCallChannelPrivate *priv = self->priv; + RingCallMember *m; - va_start (args, contact); - - do + m = g_hash_table_lookup (priv->members, GUINT_TO_POINTER (handle)); + if (m == NULL) { - if (g_hash_table_remove (self->priv->members, GUINT_TO_POINTER (contact))) - { - g_array_append_val (removed, contact); - updated = TRUE; - } - - contact = va_arg (args, TpHandle); - } - while (contact != 0); - - if (updated) - { - GHashTable *empty = g_hash_table_new (NULL, NULL); - - tp_svc_channel_type_call_emit_call_members_changed (self, empty, - removed); - g_hash_table_unref (empty); + m = RING_CALL_MEMBER (g_object_new (RING_TYPE_CALL_MEMBER, + "target", handle, + "call", self, + NULL)); + g_hash_table_insert (priv->members, GUINT_TO_POINTER (handle), m); + + tp_base_call_channel_update_member_flags (TP_BASE_CALL_CHANNEL (self), + ring_call_member_get_handle (m), + ring_call_member_get_flags (m), + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); + + ring_signal_connect_weak (m, "flags-changed", + G_CALLBACK (call_member_flags_changed_cb), G_OBJECT (self)); } - g_array_unref (removed); - return updated; + return m; } void -gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, - GabbleBaseCallContent *content) +ring_base_call_channel_remove_member (RingBaseCallChannel *self, + RingCallMember *member) { - self->priv->contents = g_list_prepend (self->priv->contents, - g_object_ref (content)); + TpHandle h = ring_call_member_get_handle (member); - if (tp_base_channel_is_registered (TP_BASE_CHANNEL (self))) - tp_svc_channel_type_call_emit_content_added (self, - gabble_base_call_content_get_object_path (content), - gabble_base_call_content_get_media_type (content)); -} - -static void -gabble_base_call_channel_close (TpBaseChannel *base) -{ - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (base); - GabbleBaseCallChannelPrivate *priv = self->priv; - - DEBUG ("Closing media channel %s", tp_base_channel_get_object_path (base)); - - /* shutdown all our contents */ - g_list_foreach (priv->contents, (GFunc) gabble_base_call_content_deinit, - NULL); - g_list_foreach (priv->contents, (GFunc) g_object_unref, NULL); - tp_clear_pointer (&priv->contents, g_list_free); - - tp_base_channel_destroyed (base); -} - -static void -gabble_base_call_channel_ringing (TpSvcChannelTypeCall *iface, - DBusGMethodInvocation *context) -{ - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelPrivate *priv = self->priv; - TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); + g_assert (g_hash_table_lookup (self->priv->members, + GUINT_TO_POINTER (h))== member); - if (tp_base_channel_is_requested (tp_base)) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Call was requested. Ringing doesn't make sense." }; - dbus_g_method_return_error (context, &e); - } - else if (priv->state != TP_CALL_STATE_INITIALISING) - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Call is not in the right state for Ringing." }; - dbus_g_method_return_error (context, &e); - } - else - { - if ((priv->flags & TP_CALL_FLAG_LOCALLY_RINGING) == 0) - { - DEBUG ("Client is ringing"); - priv->flags |= TP_CALL_FLAG_LOCALLY_RINGING; - gabble_base_call_channel_set_state (self, priv->state); - } - - tp_svc_channel_type_call_return_from_ringing (context); - } + ring_call_member_shutdown (member); + tp_base_call_channel_remove_member (TP_BASE_CALL_CHANNEL (self), + ring_call_member_get_handle (member), + 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); + g_hash_table_remove (self->priv->members, GUINT_TO_POINTER (h)); } static void -gabble_base_call_channel_accept (TpSvcChannelTypeCall *iface, - DBusGMethodInvocation *context) +ring_base_call_channel_shutdown_all_members (RingBaseCallChannel *self) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelPrivate *priv = self->priv; - GabbleBaseCallChannelClass *base_class = - GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); - TpBaseChannel *tp_base = TP_BASE_CHANNEL (self); - - DEBUG ("Client accepted the call"); + GHashTableIter iter; + gpointer value; - if (tp_base_channel_is_requested (tp_base)) - { - if (priv->state == TP_CALL_STATE_PENDING_INITIATOR) - { - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_INITIALISING); - } - else - { - DEBUG ("Invalid state for Accept: Channel requested and " - "state == %d", priv->state); - goto err; - } - } - else if (priv->state < TP_CALL_STATE_ACCEPTED) - { - gabble_base_call_channel_set_state (self, - TP_CALL_STATE_ACCEPTED); - } - else - { - DEBUG ("Invalid state for Accept: state == %d", priv->state); - goto err; - } - - if (base_class->accept != NULL) - base_class->accept (self); - - tp_svc_channel_type_call_return_from_accept (context); - return; - -err: - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Invalid state for Accept" }; - dbus_g_method_return_error (context, &e); - } + g_hash_table_iter_init (&iter, self->priv->members); + while (g_hash_table_iter_next (&iter, NULL, &value)) + ring_call_member_shutdown (RING_CALL_MEMBER (value)); } static void -gabble_base_call_channel_hangup (TpSvcChannelTypeCall *iface, - guint reason, - const gchar *detailed_reason, - const gchar *message, - DBusGMethodInvocation *context) +ring_base_call_channel_hangup (TpBaseCallChannel *base, + guint reason, + const gchar *detailed_reason, + const gchar *message) { - GabbleBaseCallChannel *self = GABBLE_BASE_CALL_CHANNEL (iface); - GabbleBaseCallChannelClass *base_class = - GABBLE_BASE_CALL_CHANNEL_GET_CLASS (self); - - if (base_class->hangup) - base_class->hangup (self, reason, detailed_reason, message); - - gabble_base_call_channel_set_state ( GABBLE_BASE_CALL_CHANNEL (self), - TP_CALL_STATE_ENDED); - - tp_svc_channel_type_call_return_from_hangup (context); + ring_base_call_channel_shutdown_all_members ( + RING_BASE_CALL_CHANNEL (base)); } static void -gabble_base_call_channel_add_content_dbus (RingSvcChannelTypeCall *iface, - const gchar *name, - TpMediaStreamType mtype, - DBusGMethodInvocation *context) +ring_base_call_channel_close (TpBaseChannel *base) { - GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "Contents cannot be added; only a single audio content is supported" }; + ring_base_call_channel_shutdown_all_members ( + RING_BASE_CALL_CHANNEL (base)); - dbus_g_method_return_error (context, &e); -} - - -static void -call_iface_init (gpointer g_iface, gpointer iface_data) -{ - RingSvcChannelTypeCallClass *klass = g_iface; - -#define IMPLEMENT(x, suffix) ring_svc_channel_type_call_implement_##x (\ - klass, gabble_base_call_channel_##x##suffix) - IMPLEMENT(ringing,); - IMPLEMENT(accept,); - IMPLEMENT(hangup,); - IMPLEMENT(add_content, _dbus); -#undef IMPLEMENT + TP_BASE_CHANNEL_CLASS (ring_base_call_channel_parent_class)->close (base); } diff --git a/src/base-call-channel.h b/src/base-call-channel.h index c82fe90..0660f98 100644 --- a/src/base-call-channel.h +++ b/src/base-call-channel.h @@ -1,7 +1,8 @@ /* - * base-call-channel.h - Header for GabbleBaseCallChannel + * base-call-channel.h - Header for RingBaseCallChannel * Copyright © 2009–2010 Collabora Ltd. * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,87 +19,77 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __GABBLE_BASE_CALL_CHANNEL_H__ -#define __GABBLE_BASE_CALL_CHANNEL_H__ +#ifndef __RING_BASE_CALL_CHANNEL_H__ +#define __RING_BASE_CALL_CHANNEL_H__ #include <glib-object.h> -#include <ring-extensions/ring-extensions.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> -#include <telepathy-glib/base-channel.h> - -#include "base-call-content.h" +#include "ring-call-content.h" +#include "ring-call-member.h" G_BEGIN_DECLS -typedef struct _GabbleBaseCallChannel GabbleBaseCallChannel; -typedef struct _GabbleBaseCallChannelPrivate GabbleBaseCallChannelPrivate; -typedef struct _GabbleBaseCallChannelClass GabbleBaseCallChannelClass; - -struct _GabbleBaseCallChannelClass { - TpBaseChannelClass parent_class; - - gboolean hardware_streaming; - gboolean mutable_contents; +typedef struct _RingBaseCallChannel RingBaseCallChannel; +typedef struct _RingBaseCallChannelPrivate RingBaseCallChannelPrivate; +typedef struct _RingBaseCallChannelClass RingBaseCallChannelClass; - void (*accept) (GabbleBaseCallChannel *self); - void (*hangup) (GabbleBaseCallChannel *self, - guint reason, - const gchar *detailed_reason, - const gchar *message); +struct _RingBaseCallChannelClass { + TpBaseMediaCallChannelClass parent_class; }; -struct _GabbleBaseCallChannel { - TpBaseChannel parent; +struct _RingBaseCallChannel { + TpBaseMediaCallChannel parent; - gboolean initial_audio; - gboolean initial_video; - - GabbleBaseCallChannelPrivate *priv; + RingBaseCallChannelPrivate *priv; }; -GType gabble_base_call_channel_get_type (void); +GType ring_base_call_channel_get_type (void); /* TYPE MACROS */ -#define GABBLE_TYPE_BASE_CALL_CHANNEL \ - (gabble_base_call_channel_get_type ()) -#define GABBLE_BASE_CALL_CHANNEL(obj) \ +#define RING_TYPE_BASE_CALL_CHANNEL \ + (ring_base_call_channel_get_type ()) +#define RING_BASE_CALL_CHANNEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannel)) -#define GABBLE_BASE_CALL_CHANNEL_CLASS(klass) \ + RING_TYPE_BASE_CALL_CHANNEL, RingBaseCallChannel)) +#define RING_BASE_CALL_CHANNEL_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), \ - GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelClass)) -#define GABBLE_IS_BASE_CALL_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_CHANNEL)) -#define GABBLE_IS_BASE_CALL_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_CHANNEL)) -#define GABBLE_BASE_CALL_CHANNEL_GET_CLASS(obj) \ + RING_TYPE_BASE_CALL_CHANNEL, RingBaseCallChannelClass)) +#define RING_IS_BASE_CALL_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RING_TYPE_BASE_CALL_CHANNEL)) +#define RING_IS_BASE_CALL_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), RING_TYPE_BASE_CALL_CHANNEL)) +#define RING_BASE_CALL_CHANNEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - GABBLE_TYPE_BASE_CALL_CHANNEL, GabbleBaseCallChannelClass)) - -TpCallState gabble_base_call_channel_get_state ( - GabbleBaseCallChannel *self); -void gabble_base_call_channel_set_state (GabbleBaseCallChannel *self, - TpCallState state); - -void gabble_base_call_channel_update_flags (GabbleBaseCallChannel *self, - TpCallFlags set_flags, - TpCallFlags clear_flags); - -gboolean gabble_base_call_channel_update_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - TpCallMemberFlags set_flags, - TpCallMemberFlags clear_flags, - ...) G_GNUC_NULL_TERMINATED; -gboolean gabble_base_call_channel_remove_members ( - GabbleBaseCallChannel *self, - TpHandle contact, - ...) G_GNUC_NULL_TERMINATED; - -void gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, - GabbleBaseCallContent *content); + RING_TYPE_BASE_CALL_CHANNEL, RingBaseCallChannelClass)) + +RingCallMember *ring_base_call_channel_ensure_member ( + RingBaseCallChannel *self, + const gchar *jid); + +void ring_base_call_channel_remove_member (RingBaseCallChannel *self, + RingCallMember *member); + +RingCallMember *ring_base_call_channel_ensure_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle); + +RingCallMember * ring_base_call_channel_get_member_from_handle ( + RingBaseCallChannel *self, + TpHandle handle); + +RingCallContent * ring_base_call_channel_add_content ( + RingBaseCallChannel *self, + const gchar *name, + TpCallContentDisposition disposition); + +void ring_base_call_channel_remove_content (RingBaseCallChannel *self, + RingCallContent *content); + +GHashTable *ring_base_call_channel_get_members (RingBaseCallChannel *self); G_END_DECLS -#endif /* #ifndef __GABBLE_BASE_CALL_CHANNEL_H__*/ +#endif /* #ifndef __RING_BASE_CALL_CHANNEL_H__*/ diff --git a/src/base-call-content.c b/src/base-call-content.c deleted file mode 100644 index 44fb532..0000000 --- a/src/base-call-content.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * base-call-content.c - Source for GabbleBaseCallContent - * Copyright © 2009–2010 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * @author Will Thompson <will.thompson@collabora.co.uk> - * - * 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 "base-call-content.h" - -#include "base-call-stream.h" - -#define DEBUG_FLAG RING_DEBUG_MEDIA -#include "ring-debug.h" - -G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallContent, gabble_base_call_content, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - /* The base class doesn't implement Remove(), which is pretty - * protocol-specific. It just implements the properties. - */ - G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_CONTENT, - NULL); - ); - -struct _GabbleBaseCallContentPrivate -{ - RingConnection *conn; - TpDBusDaemon *dbus_daemon; - - gchar *object_path; - - gchar *name; - TpMediaStreamType media_type; - TpHandle creator; - TpCallContentDisposition disposition; - - GList *streams; - - gboolean dispose_has_run; - gboolean deinit_has_run; -}; - -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CONNECTION, - - PROP_INTERFACES, - PROP_NAME, - PROP_MEDIA_TYPE, - PROP_CREATOR, - PROP_DISPOSITION, - PROP_STREAMS -}; - -static void base_call_content_deinit_real (GabbleBaseCallContent *self); - -static void -gabble_base_call_content_init (GabbleBaseCallContent *self) -{ - GabbleBaseCallContentPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentPrivate); - - self->priv = priv; -} - -static void -gabble_base_call_content_constructed (GObject *obj) -{ - GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (obj); - GabbleBaseCallContentPrivate *priv = self->priv; - - if (G_OBJECT_CLASS (gabble_base_call_content_parent_class)->constructed != NULL) - G_OBJECT_CLASS (gabble_base_call_content_parent_class)->constructed (obj); - - DEBUG ("Registering %s", priv->object_path); - priv->dbus_daemon = g_object_ref ( - tp_base_connection_get_dbus_daemon ((TpBaseConnection *) priv->conn)); - tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); -} - -static void -gabble_base_call_content_dispose (GObject *object) -{ - GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (object); - GabbleBaseCallContentPrivate *priv = self->priv; - GList *l; - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - for (l = priv->streams; l != NULL; l = g_list_next (l)) - g_object_unref (l->data); - - tp_clear_pointer (&priv->streams, g_list_free); - tp_clear_object (&priv->conn); - - if (G_OBJECT_CLASS (gabble_base_call_content_parent_class)->dispose != NULL) - G_OBJECT_CLASS (gabble_base_call_content_parent_class)->dispose (object); -} - -static void -gabble_base_call_content_finalize (GObject *object) -{ - GabbleBaseCallContent *self = GABBLE_BASE_CALL_CONTENT (object); - GabbleBaseCallContentPrivate *priv = self->priv; - - /* free any data held directly by the object here */ - g_free (priv->object_path); - g_free (priv->name); - - G_OBJECT_CLASS (gabble_base_call_content_parent_class)->finalize (object); -} - -static void -gabble_base_call_content_get_property ( - GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleBaseCallContent *content = GABBLE_BASE_CALL_CONTENT (object); - GabbleBaseCallContentPrivate *priv = content->priv; - - switch (property_id) - { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_INTERFACES: - { - GabbleBaseCallContentClass *klass = - GABBLE_BASE_CALL_CONTENT_GET_CLASS (content); - - if (klass->extra_interfaces != NULL) - { - g_value_set_boxed (value, klass->extra_interfaces); - } - else - { - static gchar *empty[] = { NULL }; - - g_value_set_boxed (value, empty); - } - break; - } - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_CREATOR: - g_value_set_uint (value, priv->creator); - break; - case PROP_DISPOSITION: - g_value_set_uint (value, priv->disposition); - break; - case PROP_STREAMS: - { - GPtrArray *arr = g_ptr_array_sized_new (2); - GList *l; - - for (l = priv->streams; l != NULL; l = g_list_next (l)) - { - GabbleBaseCallStream *s = GABBLE_BASE_CALL_STREAM (l->data); - g_ptr_array_add (arr, - g_strdup (gabble_base_call_stream_get_object_path (s))); - } - - g_value_take_boxed (value, arr); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_base_call_content_set_property ( - GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleBaseCallContent *content = GABBLE_BASE_CALL_CONTENT (object); - GabbleBaseCallContentPrivate *priv = content->priv; - - switch (property_id) - { - case PROP_OBJECT_PATH: - priv->object_path = g_value_dup_string (value); - g_assert (priv->object_path != NULL); - break; - case PROP_CONNECTION: - priv->conn = g_value_dup_object (value); - break; - case PROP_NAME: - priv->name = g_value_dup_string (value); - break; - case PROP_MEDIA_TYPE: - priv->media_type = g_value_get_uint (value); - break; - case PROP_CREATOR: - priv->creator = g_value_get_uint (value); - break; - case PROP_DISPOSITION: - priv->disposition = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_base_call_content_class_init ( - GabbleBaseCallContentClass *bcc_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (bcc_class); - GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl content_props[] = { - { "Interfaces", "interfaces", NULL }, - { "Name", "name", NULL }, - { "Type", "media-type", NULL }, - { "Creator", "creator", NULL }, - { "Disposition", "disposition", NULL }, - { "Streams", "streams", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { RING_IFACE_CALL_CONTENT, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - content_props, - }, - { NULL } - }; - - g_type_class_add_private (bcc_class, sizeof (GabbleBaseCallContentPrivate)); - - object_class->constructed = gabble_base_call_content_constructed; - object_class->dispose = gabble_base_call_content_dispose; - object_class->finalize = gabble_base_call_content_finalize; - object_class->get_property = gabble_base_call_content_get_property; - object_class->set_property = gabble_base_call_content_set_property; - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_object ("connection", "RingConnection object", - "Gabble connection object that owns this call content", - RING_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional interfaces implemented by this content", - 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 ("name", "Name", - "The name of this content, if any", - "", - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_uint ("media-type", "Media Type", - "The media type of this content", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - param_spec = g_param_spec_uint ("creator", "Creator", - "The creator of this content", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATOR, param_spec); - - param_spec = g_param_spec_uint ("disposition", "Disposition", - "The disposition of this content", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec); - - param_spec = g_param_spec_boxed ("streams", "Stream", - "The streams of this content", - TP_ARRAY_TYPE_OBJECT_PATH_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STREAMS, - param_spec); - - bcc_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleBaseCallContentClass, dbus_props_class)); - - bcc_class->deinit = base_call_content_deinit_real; -} - -RingConnection * -gabble_base_call_content_get_connection (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); - - return self->priv->conn; -} - -const gchar * -gabble_base_call_content_get_object_path (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); - - return self->priv->object_path; -} - -const gchar * -gabble_base_call_content_get_name (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); - - return self->priv->name; -} - -TpMediaStreamType -gabble_base_call_content_get_media_type (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), - TP_MEDIA_STREAM_TYPE_AUDIO); - - return self->priv->media_type; -} - -TpCallContentDisposition -gabble_base_call_content_get_disposition (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), - TP_CALL_CONTENT_DISPOSITION_NONE); - - return self->priv->disposition; -} - -GList * -gabble_base_call_content_get_streams (GabbleBaseCallContent *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self), NULL); - - return self->priv->streams; -} - -void -gabble_base_call_content_add_stream (GabbleBaseCallContent *self, - GabbleBaseCallStream *stream) -{ - g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); - - self->priv->streams = g_list_prepend (self->priv->streams, - g_object_ref (stream)); - ring_svc_call_content_emit_stream_added (self, - gabble_base_call_stream_get_object_path (stream)); -} - -void -gabble_base_call_content_remove_stream (GabbleBaseCallContent *self, - GabbleBaseCallStream *stream) -{ - GabbleBaseCallContentPrivate *priv; - GList *l; - - g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); - - priv = self->priv; - - l = g_list_find (priv->streams, stream); - g_return_if_fail (l != NULL); - - priv->streams = g_list_remove_link (priv->streams, l); - ring_svc_call_content_emit_stream_removed (self, - gabble_base_call_stream_get_object_path (stream)); - g_object_unref (stream); -} - -static void -base_call_content_deinit_real (GabbleBaseCallContent *self) -{ - GabbleBaseCallContentPrivate *priv = self->priv; - - if (priv->deinit_has_run) - return; - - priv->deinit_has_run = TRUE; - - tp_dbus_daemon_unregister_object (priv->dbus_daemon, G_OBJECT (self)); - tp_clear_object (&priv->dbus_daemon); - - g_list_foreach (priv->streams, (GFunc) g_object_unref, NULL); - tp_clear_pointer (&priv->streams, g_list_free); -} - -void -gabble_base_call_content_deinit (GabbleBaseCallContent *self) -{ - GabbleBaseCallContentClass *klass; - - g_return_if_fail (GABBLE_IS_BASE_CALL_CONTENT (self)); - - klass = GABBLE_BASE_CALL_CONTENT_GET_CLASS (self); - g_return_if_fail (klass->deinit != NULL); - klass->deinit (self); -} diff --git a/src/base-call-content.h b/src/base-call-content.h deleted file mode 100644 index 705f7b1..0000000 --- a/src/base-call-content.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * base-call-content.h - Header for GabbleBaseBaseCallContent - * Copyright © 2009–2010 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * @author Will Thompson <will.thompson@collabora.co.uk> - * - * 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 - */ - -#ifndef GABBLE_BASE_CALL_CONTENT_H -#define GABBLE_BASE_CALL_CONTENT_H - -#include <glib-object.h> - -#include <telepathy-glib/telepathy-glib.h> - -#include <ring-extensions/ring-extensions.h> - -#include "ring-connection.h" -#include "base-call-stream.h" - -G_BEGIN_DECLS - -typedef struct _GabbleBaseCallContent GabbleBaseCallContent; -typedef struct _GabbleBaseCallContentPrivate GabbleBaseCallContentPrivate; -typedef struct _GabbleBaseCallContentClass GabbleBaseCallContentClass; - -typedef void (*GabbleBaseCallContentFunc) (GabbleBaseCallContent *); - -struct _GabbleBaseCallContentClass { - GObjectClass parent_class; - - TpDBusPropertiesMixinClass dbus_props_class; - - const gchar * const *extra_interfaces; - GabbleBaseCallContentFunc deinit; -}; - -struct _GabbleBaseCallContent { - GObject parent; - - GabbleBaseCallContentPrivate *priv; -}; - -GType gabble_base_call_content_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_BASE_CALL_CONTENT \ - (gabble_base_call_content_get_type ()) -#define GABBLE_BASE_CALL_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContent)) -#define GABBLE_BASE_CALL_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), \ - GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentClass)) -#define GABBLE_IS_BASE_CALL_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_CONTENT)) -#define GABBLE_IS_BASE_CALL_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_CONTENT)) -#define GABBLE_BASE_CALL_CONTENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), \ - GABBLE_TYPE_BASE_CALL_CONTENT, GabbleBaseCallContentClass)) - -RingConnection *gabble_base_call_content_get_connection ( - GabbleBaseCallContent *self); -const gchar *gabble_base_call_content_get_object_path ( - GabbleBaseCallContent *self); - -const gchar *gabble_base_call_content_get_name (GabbleBaseCallContent *self); -TpMediaStreamType gabble_base_call_content_get_media_type ( - GabbleBaseCallContent *self); -TpCallContentDisposition gabble_base_call_content_get_disposition ( - GabbleBaseCallContent *self); - -GList *gabble_base_call_content_get_streams (GabbleBaseCallContent *self); -void gabble_base_call_content_add_stream (GabbleBaseCallContent *self, - GabbleBaseCallStream *stream); -void gabble_base_call_content_remove_stream (GabbleBaseCallContent *self, - GabbleBaseCallStream *stream); - -void gabble_base_call_content_deinit (GabbleBaseCallContent *self); - -G_END_DECLS - -#endif /* #ifndef __GABBLE_BASE_CALL_CONTENT_H__*/ diff --git a/src/base-call-stream.c b/src/base-call-stream.c deleted file mode 100644 index e8449aa..0000000 --- a/src/base-call-stream.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * base-call-stream.c - Source for GabbleBaseCallStream - * Copyright © 2009–2010 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * @author Will Thompson <will.thompson@collabora.co.uk> - * - * 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 "base-call-stream.h" - -#define DEBUG_FLAG RING_DEBUG_MEDIA -#include "ring-debug.h" - -#include "ring-connection.h" - -G_DEFINE_TYPE_WITH_CODE(GabbleBaseCallStream, gabble_base_call_stream, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - /* The base class doesn't implement SetSending or RequestReceiving, because - * they're pretty protocol-specific. It just implements the properties. */ - G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_STREAM, NULL); - ) - -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CONNECTION, - - /* Call interface properties */ - PROP_INTERFACES, - PROP_SENDERS, -}; - -struct _GabbleBaseCallStreamPrivate -{ - gboolean dispose_has_run; - - gchar *object_path; - RingConnection *conn; - - GHashTable *senders; -}; - -static void -gabble_base_call_stream_init (GabbleBaseCallStream *self) -{ - GabbleBaseCallStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_BASE_CALL_STREAM, GabbleBaseCallStreamPrivate); - - self->priv = priv; - priv->senders = g_hash_table_new (g_direct_hash, g_direct_equal); -} - -static void -gabble_base_call_stream_constructed (GObject *obj) -{ - GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (obj); - GabbleBaseCallStreamPrivate *priv = self->priv; - TpDBusDaemon *bus = tp_base_connection_get_dbus_daemon ( - (TpBaseConnection *) priv->conn); - - if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->constructed - != NULL) - G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->constructed (obj); - - DEBUG ("Registering %s", priv->object_path); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); -} - -static void -gabble_base_call_stream_dispose (GObject *object) -{ - GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); - GabbleBaseCallStreamPrivate *priv = self->priv; - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->conn); - - if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->dispose != NULL) - G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->dispose (object); -} - -static void -gabble_base_call_stream_finalize (GObject *object) -{ - GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); - GabbleBaseCallStreamPrivate *priv = self->priv; - - /* free any data held directly by the object here */ - g_free (priv->object_path); - g_hash_table_destroy (priv->senders); - - if (G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->finalize != NULL) - G_OBJECT_CLASS (gabble_base_call_stream_parent_class)->finalize (object); -} - -static void -gabble_base_call_stream_get_property ( - GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); - GabbleBaseCallStreamPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_INTERFACES: - { - GabbleBaseCallStreamClass *klass = - GABBLE_BASE_CALL_STREAM_GET_CLASS (self); - - if (klass->extra_interfaces != NULL) - { - g_value_set_boxed (value, klass->extra_interfaces); - } - else - { - gchar *empty[] = { NULL }; - - g_value_set_boxed (value, empty); - } - break; - } - case PROP_SENDERS: - g_value_set_boxed (value, priv->senders); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_base_call_stream_set_property ( - GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleBaseCallStream *self = GABBLE_BASE_CALL_STREAM (object); - GabbleBaseCallStreamPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_CONNECTION: - priv->conn = g_value_dup_object (value); - g_assert (priv->conn != NULL); - break; - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_base_call_stream_class_init (GabbleBaseCallStreamClass *bsc_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (bsc_class); - GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl stream_props[] = { - { "Interfaces", "interfaces", NULL }, - { "Senders", "senders", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { RING_IFACE_CALL_STREAM, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - stream_props, - }, - { NULL } - }; - - g_type_class_add_private (bsc_class, sizeof (GabbleBaseCallStreamPrivate)); - - object_class->constructed = gabble_base_call_stream_constructed; - object_class->dispose = gabble_base_call_stream_dispose; - object_class->finalize = gabble_base_call_stream_finalize; - object_class->set_property = gabble_base_call_stream_set_property; - object_class->get_property = gabble_base_call_stream_get_property; - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional interfaces implemented by this stream", - 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 ("senders", "Senders", - "Sender map", - RING_HASH_TYPE_CONTACT_SENDING_STATE_MAP, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SENDERS, param_spec); - - param_spec = g_param_spec_object ("connection", "RingConnection object", - "Gabble connection object that owns this call stream", - RING_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - bsc_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleBaseCallStreamClass, dbus_props_class)); -} - -RingConnection * -gabble_base_call_stream_get_connection (GabbleBaseCallStream *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), NULL); - - return self->priv->conn; -} - -const gchar * -gabble_base_call_stream_get_object_path (GabbleBaseCallStream *self) -{ - g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), NULL); - - return self->priv->object_path; -} - -static gboolean -base_call_stream_sender_update_state (GabbleBaseCallStream *self, - TpHandle contact, - TpSendingState state) -{ - GabbleBaseCallStreamPrivate *priv = self->priv; - gpointer state_p = 0; - gboolean exists; - - exists = g_hash_table_lookup_extended (priv->senders, - GUINT_TO_POINTER (contact), - NULL, - &state_p); - - if (exists && GPOINTER_TO_UINT (state_p) == state) - return FALSE; - - DEBUG ("Updating sender %d state: %d => %d", contact, - GPOINTER_TO_UINT (state_p), state); - - g_hash_table_insert (priv->senders, - GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (state)); - - return TRUE; -} - -gboolean -gabble_base_call_stream_update_senders ( - GabbleBaseCallStream *self, - TpHandle contact, - TpSendingState state, - ...) -{ - GHashTable *updates = g_hash_table_new (g_direct_hash, g_direct_equal); - gboolean updated = FALSE; - va_list args; - - va_start (args, state); - - do - { - if (base_call_stream_sender_update_state (self, contact, state)) - { - g_hash_table_insert (updates, - GUINT_TO_POINTER (contact), - GUINT_TO_POINTER (state)); - updated = TRUE; - } - - contact = va_arg (args, TpHandle); - if (contact != 0) - state = va_arg (args, TpSendingState); - } - while (contact != 0); - - if (updated) - { - GArray *empty = g_array_new (FALSE, TRUE, sizeof (TpHandle)); - - ring_svc_call_stream_emit_senders_changed (self, updates, empty); - g_array_unref (empty); - } - - g_hash_table_unref (updates); - return updated; -} - -TpSendingState -gabble_base_call_stream_get_sender_state ( - GabbleBaseCallStream *self, - TpHandle sender, - gboolean *existed) -{ - gpointer state; - - g_return_val_if_fail (GABBLE_IS_BASE_CALL_STREAM (self), - TP_SENDING_STATE_NONE); - - if (g_hash_table_lookup_extended (self->priv->senders, - GUINT_TO_POINTER (sender), NULL, &state)) - { - if (existed != NULL) - *existed = TRUE; - - return GPOINTER_TO_UINT (state); - } - else - { - if (existed != NULL) - *existed = FALSE; - - return TP_SENDING_STATE_NONE; - } -} diff --git a/src/base-call-stream.h b/src/base-call-stream.h deleted file mode 100644 index b33ef7c..0000000 --- a/src/base-call-stream.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * base-call-stream.h - Header for GabbleBaseCallStream - * Copyright © 2009–2010 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * @author Will Thompson <will.thompson@collabora.co.uk> - * - * 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 - */ - -#ifndef GABBLE_BASE_CALL_STREAM_H -#define GABBLE_BASE_CALL_STREAM_H - -#include <glib-object.h> - -#include <telepathy-glib/telepathy-glib.h> -#include <ring-extensions/ring-extensions.h> - -#include "ring-connection.h" - -G_BEGIN_DECLS - -typedef struct _GabbleBaseCallStream GabbleBaseCallStream; -typedef struct _GabbleBaseCallStreamPrivate GabbleBaseCallStreamPrivate; -typedef struct _GabbleBaseCallStreamClass GabbleBaseCallStreamClass; - -struct _GabbleBaseCallStreamClass { - GObjectClass parent_class; - - TpDBusPropertiesMixinClass dbus_props_class; - - const gchar * const *extra_interfaces; -}; - -struct _GabbleBaseCallStream { - GObject parent; - - GabbleBaseCallStreamPrivate *priv; -}; - -GType gabble_base_call_stream_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_BASE_CALL_STREAM \ - (gabble_base_call_stream_get_type ()) -#define GABBLE_BASE_CALL_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_BASE_CALL_STREAM, GabbleBaseCallStream)) -#define GABBLE_BASE_CALL_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_BASE_CALL_STREAM, \ - GabbleBaseCallStreamClass)) -#define GABBLE_IS_BASE_CALL_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_BASE_CALL_STREAM)) -#define GABBLE_IS_BASE_CALL_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_BASE_CALL_STREAM)) -#define GABBLE_BASE_CALL_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_BASE_CALL_STREAM, \ - GabbleBaseCallStreamClass)) - -RingConnection *gabble_base_call_stream_get_connection ( - GabbleBaseCallStream *self); -const gchar *gabble_base_call_stream_get_object_path ( - GabbleBaseCallStream *self); - -TpSendingState gabble_base_call_stream_get_sender_state ( - GabbleBaseCallStream *self, - TpHandle sender, - gboolean *existed); -gboolean gabble_base_call_stream_update_senders ( - GabbleBaseCallStream *self, - TpHandle contact, - TpSendingState state, - ...) G_GNUC_NULL_TERMINATED; - -G_END_DECLS - -#endif diff --git a/src/ring-call-channel.h b/src/ring-call-channel.h index 8813a97..f2e1067 100644 --- a/src/ring-call-channel.h +++ b/src/ring-call-channel.h @@ -3,6 +3,7 @@ * * Copyright (C) 2007-2009 Nokia Corporation * @author Pekka Pessi <first.surname@nokia.com> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This work is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/ring-call-content.c b/src/ring-call-content.c index 30cc802..3837eb9 100644 --- a/src/ring-call-content.c +++ b/src/ring-call-content.c @@ -3,6 +3,7 @@ * Copyright ©2010 Collabora Ltd. * Copyright ©2010 Nokia Corporation * @author Will Thompson <will.thompson@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,10 +36,8 @@ struct _RingCallContentPrivate { static void implement_call_content (gpointer klass, gpointer unused G_GNUC_UNUSED); -G_DEFINE_TYPE_WITH_CODE (RingCallContent, ring_call_content, - GABBLE_TYPE_BASE_CALL_CONTENT, - G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_CONTENT, implement_call_content); -) +G_DEFINE_TYPE (RingCallContent, ring_call_content, + TP_TYPE_BASE_MEDIA_CALL_CONTENT); static void ring_call_content_init (RingCallContent *self) @@ -52,18 +51,18 @@ ring_call_content_constructed (GObject *object) { RingCallContent *self = RING_CALL_CONTENT (object); RingCallContentPrivate *priv = self->priv; - GabbleBaseCallContent *base = GABBLE_BASE_CALL_CONTENT (self); + TpBaseCallContent *base = TP_BASE_CALL_CONTENT (self); gchar *stream_path; if (G_OBJECT_CLASS (ring_call_content_parent_class)->constructed != NULL) G_OBJECT_CLASS (ring_call_content_parent_class)->constructed (object); stream_path = g_strdup_printf ("%s/%s", - gabble_base_call_content_get_object_path (base), "stream"); + tp_base_call_content_get_object_path (base), "stream"); priv->stream = ring_call_stream_new ( - gabble_base_call_content_get_connection (base), stream_path); - gabble_base_call_content_add_stream (base, - GABBLE_BASE_CALL_STREAM (priv->stream)); + RING_CONNECTION(tp_base_call_content_get_connection (base)), stream_path); + tp_base_call_content_add_stream (base, + TP_BASE_CALL_STREAM (priv->stream)); g_free (stream_path); } @@ -83,6 +82,7 @@ static void ring_call_content_class_init (RingCallContentClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + TpBaseCallContentClass *base_class = TP_BASE_CALL_CONTENT_CLASS(klass); object_class->constructed = ring_call_content_constructed; object_class->dispose = ring_call_content_dispose; @@ -115,7 +115,7 @@ ring_call_content_get_stream (RingCallContent *self) static void ring_call_content_remove ( - RingSvcCallContent *self, + RingCallContent *self, DBusGMethodInvocation *context) { /* We could just leave all this out — the base class leaves Remove() diff --git a/src/ring-call-content.h b/src/ring-call-content.h index a33a4be..f6cc737 100644 --- a/src/ring-call-content.h +++ b/src/ring-call-content.h @@ -3,6 +3,7 @@ * Copyright ©2010 Collabora Ltd. * Copyright ©2010 Nokia Corporation * @author Will Thompson <will.thompson@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,7 +25,9 @@ #include <glib-object.h> -#include "base-call-content.h" +#include <telepathy-glib/telepathy-glib.h> + +#include "ring-connection.h" #include "ring-call-stream.h" typedef struct _RingCallContent RingCallContent; @@ -32,11 +35,11 @@ typedef struct _RingCallContentClass RingCallContentClass; typedef struct _RingCallContentPrivate RingCallContentPrivate; struct _RingCallContentClass { - GabbleBaseCallContentClass parent_class; + TpBaseMediaCallContentClass parent_class; }; struct _RingCallContent { - GabbleBaseCallContent parent; + TpBaseMediaCallContent parent; RingCallContentPrivate *priv; }; @@ -49,6 +52,8 @@ RingCallContent *ring_call_content_new (RingConnection *connection, RingCallStream *ring_call_content_get_stream (RingCallContent *self); +static void ring_call_content_remove(RingCallContent *self, DBusGMethodInvocation *context); + /* TYPE MACROS */ #define RING_TYPE_CALL_CONTENT \ (ring_call_content_get_type ()) diff --git a/src/ring-call-member.c b/src/ring-call-member.c new file mode 100644 index 0000000..8a3bb39 --- /dev/null +++ b/src/ring-call-member.c @@ -0,0 +1,597 @@ +/* + * ring-call-member.c - Source for CallMember + * Copyright (C) 2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> + * + * 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 <stdio.h> +#include <stdlib.h> + +#include "util.h" + +#include "base-call-channel.h" + +#include "ring-connection.h" +#include "ring-call-member.h" + +G_DEFINE_TYPE(RingCallMember, ring_call_member, G_TYPE_OBJECT) + +/* signal enum */ +enum +{ + FLAGS_CHANGED, + CONTENT_ADDED, + CONTENT_REMOVED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/* properties */ +enum +{ + PROP_CALL = 1, + PROP_TARGET +}; + +/* private structure */ +struct _RingCallMemberPrivate +{ + TpHandle target; + + RingBaseCallChannel *call; + TpCallMemberFlags flags; + + GList *contents; + gchar *transport_ns; + gboolean accepted; + + gboolean dispose_has_run; +}; + +#define RING_CALL_MEMBER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), RING_TYPE_CALL_MEMBER, \ + RingCallMemberPrivate)) + +static void +ring_call_member_init (RingCallMember *self) +{ + RingCallMemberPrivate *priv = + RING_CALL_MEMBER_GET_PRIVATE (self); + + self->priv = priv; + priv->accepted = FALSE; +} + +static void +ring_call_member_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + RingCallMember *self = RING_CALL_MEMBER (object); + RingCallMemberPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_CALL: + g_value_set_object (value, ring_call_member_get_connection (self)); + break; + case PROP_TARGET: + g_value_set_uint (value, priv->target); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +ring_call_member_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + RingCallMember *self = RING_CALL_MEMBER (object); + RingCallMemberPrivate *priv = self->priv; + + switch (property_id) + { + case PROP_CALL: + priv->call = g_value_get_object (value); + g_assert (priv->call != NULL); + break; + case PROP_TARGET: + priv->target = g_value_get_uint (value); + g_assert (priv->target != 0); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void ring_call_member_dispose (GObject *object); +static void ring_call_member_finalize (GObject *object); + +static void +ring_call_member_class_init ( + RingCallMemberClass *ring_call_member_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (ring_call_member_class); + GParamSpec *param_spec; + + g_type_class_add_private (ring_call_member_class, + sizeof (RingCallMemberPrivate)); + + object_class->dispose = ring_call_member_dispose; + object_class->finalize = ring_call_member_finalize; + + object_class->get_property = ring_call_member_get_property; + object_class->set_property = ring_call_member_set_property; + + param_spec = g_param_spec_object ("call", "Call", + "The base call object that contains this member", + RING_TYPE_BASE_CALL_CHANNEL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_CALL, param_spec); + + param_spec = g_param_spec_uint ("target", "Target", + "the target handle of member", + 0, + G_MAXUINT, + 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_TARGET, param_spec); + + signals[FLAGS_CHANGED] = + g_signal_new ("flags-changed", + G_OBJECT_CLASS_TYPE (ring_call_member_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); + + signals[CONTENT_ADDED] = + g_signal_new ("content-added", + G_OBJECT_CLASS_TYPE (ring_call_member_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[CONTENT_REMOVED] = + g_signal_new ("content-removed", + G_OBJECT_CLASS_TYPE (ring_call_member_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); +} + +void +ring_call_member_dispose (GObject *object) +{ + RingCallMember *self = RING_CALL_MEMBER (object); + RingCallMemberPrivate *priv = self->priv; + GList *l; + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + for (l = priv->contents ; l != NULL; l = g_list_next (l)) + g_object_unref (l->data); + + tp_clear_pointer (&priv->contents, g_list_free); + + /* release any references held by the object here */ + + if (G_OBJECT_CLASS (ring_call_member_parent_class)->dispose) + G_OBJECT_CLASS (ring_call_member_parent_class)->dispose (object); +} + +void +ring_call_member_finalize (GObject *object) +{ + RingCallMember *self = RING_CALL_MEMBER (object); + RingCallMemberPrivate *priv = self->priv; + + g_free (priv->transport_ns); + priv->transport_ns = NULL; + + G_OBJECT_CLASS (ring_call_member_parent_class)->finalize (object); +} + +/* +static void +remote_state_changed_cb (WockyJingleSession *session, gpointer user_data) +{ + RingCallMember *self = RING_CALL_MEMBER (user_data); + RingCallMemberPrivate *priv = self->priv; + TpCallMemberFlags newflags = 0; + + if (wocky_jingle_session_get_remote_ringing (session)) + newflags |= TP_CALL_MEMBER_FLAG_RINGING; + + if (wocky_jingle_session_get_remote_hold (session)) + newflags |= TP_CALL_MEMBER_FLAG_HELD; + + if (priv->flags == newflags) + return; + + priv->flags = newflags; + + DEBUG ("Call members flags changed to: %d", priv->flags); + + g_signal_emit (self, signals[FLAGS_CHANGED], 0, priv->flags); +} +*/ + +/* +static void +member_content_removed_cb (RingCallMemberContent *mcontent, + gpointer user_data) +{ + RingCallMember *self = RING_CALL_MEMBER (user_data); + RingCallMemberPrivate *priv = self->priv; + + priv->contents = g_list_remove (priv->contents, mcontent); + g_signal_emit (self, signals[CONTENT_REMOVED], 0, mcontent); + g_object_unref (mcontent); +} + +static void +ring_call_member_add_member_content (RingCallMember *self, + RingCallMemberContent *content) +{ + RingCallMemberPrivate *priv = self->priv; + + priv->contents = g_list_prepend (priv->contents, content); + + ring_signal_connect_weak (content, "removed", + G_CALLBACK (member_content_removed_cb), G_OBJECT (self)); + + g_signal_emit (self, signals[CONTENT_ADDED], 0, content); +} +*/ + +/* This function handles additional contents added by the remote side */ +/* +static void +new_content_cb (WockyJingleSession *session, + WockyJingleContent *c, + gpointer user_data) +{ + RingCallMember *self = RING_CALL_MEMBER (user_data); + RingCallMemberContent *content = NULL; + + if (wocky_jingle_content_is_created_by_us (c)) + return; + + content = ring_call_member_content_from_jingle_content (c, self); + + ring_call_member_add_member_content (self, content); +} + +static gboolean +call_member_update_existing_content (RingCallMember *self, + WockyJingleContent *content) +{ + GList *l; + + for (l = self->priv->contents; l != NULL ; l = g_list_next (l)) + { + RingCallMemberContent *mcontent = RING_CALL_MEMBER_CONTENT (l->data); + + if (ring_call_member_content_has_jingle_content (mcontent)) + continue; + + if (!tp_strdiff (ring_call_member_content_get_name (mcontent), + wocky_jingle_content_get_name (content))) + { + ring_call_member_content_set_jingle_content (mcontent, content); + return TRUE; + } + } + + return FALSE; +} + +void +ring_call_member_set_session (RingCallMember *self, + WockyJingleSession *session) +{ + RingCallMemberPrivate *priv = self->priv; + GList *c, *contents; + + g_assert (priv->session == NULL); + g_assert (session != NULL); + + DEBUG ("Setting session: %p -> %p\n", self, session); + priv->session = g_object_ref (session); + + contents = wocky_jingle_session_get_contents (session); + for (c = contents ; c != NULL; c = g_list_next (c)) + { + WockyJingleContent *content = WOCKY_JINGLE_CONTENT (c->data); + + if (priv->transport_ns == NULL) + { + g_object_get (content, "transport-ns", + &priv->transport_ns, + NULL); + } + + if (!call_member_update_existing_content (self, content)) + { + RingCallMemberContent *mcontent = + ring_call_member_content_from_jingle_content (content, + self); + + ring_call_member_add_member_content (self, mcontent); + } + } + + g_object_notify (G_OBJECT (self), "session"); + + ring_signal_connect_weak (priv->session, "remote-state-changed", + G_CALLBACK (remote_state_changed_cb), G_OBJECT (self)); + ring_signal_connect_weak (priv->session, "new-content", + G_CALLBACK (new_content_cb), G_OBJECT (self)); + + if (priv->accepted) + ring_call_member_accept (self); + + g_list_free (contents); +} + +WockyJingleSession * +ring_call_member_get_session (RingCallMember *self) +{ + return self->priv->session; +} +*/ + +TpCallMemberFlags +ring_call_member_get_flags (RingCallMember *self) +{ + return self->priv->flags; +} + +TpHandle ring_call_member_get_handle ( + RingCallMember *self) +{ + return self->priv->target; +} + +GList * +ring_call_member_get_contents (RingCallMember *self) +{ + RingCallMemberPrivate *priv = self->priv; + + return priv->contents; +} + +/* +RingCallMemberContent * +ring_call_member_ensure_content (RingCallMember *self, + const gchar *name, + WockyJingleMediaType mtype) +{ + RingCallMemberPrivate *priv = self->priv; + GList *l; + RingCallMemberContent *content = NULL; + + for (l = priv->contents ; l != NULL; l = g_list_next (l)) + { + RingCallMemberContent *c = RING_CALL_MEMBER_CONTENT (l->data); + + if (ring_call_member_content_get_media_type (c) == mtype && + !tp_strdiff (ring_call_member_content_get_name (c), name)) + { + content = c; + break; + } + } + + if (content == NULL) + { + content = ring_call_member_content_new (name, mtype, self); + ring_call_member_add_member_content (self, content); + } + + return content; +} + +RingCallMemberContent * +ring_call_member_create_content (RingCallMember *self, + const gchar *name, + WockyJingleMediaType mtype, + WockyJingleContentSenders senders, + GError **error) +{ + RingCallMemberPrivate *priv = self->priv; + const gchar *content_ns; + WockyJingleContent *c; + RingCallMemberContent *content; + const gchar *peer_resource; + + g_assert (priv->session != NULL); + + peer_resource = wocky_jingle_session_get_peer_resource (priv->session); + + DEBUG ("Creating new content %s, type %d", name, mtype); + + if (peer_resource != NULL) + DEBUG ("existing call, using peer resource %s", peer_resource); + else + DEBUG ("existing call, using bare JID"); + + content_ns = jingle_pick_best_content_type (ring_call_member_get_connection (self), + priv->target, + peer_resource, mtype); + + if (content_ns == NULL) + { + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, + "Content type %d not available for this resource", mtype); + return NULL; + } + + DEBUG ("Creating new jingle content with ns %s : %s", + content_ns, priv->transport_ns); + + c = wocky_jingle_session_add_content (priv->session, + mtype, senders, name, content_ns, priv->transport_ns); + + g_assert (c != NULL); + + content = ring_call_member_content_from_jingle_content (c, self); + + ring_call_member_add_member_content (self, content); + + return content; +} + +void +ring_call_member_accept (RingCallMember *self) +{ + self->priv->accepted = TRUE; + + if (self->priv->session != NULL) + wocky_jingle_session_accept (self->priv->session); +} +*/ + +/** + * Start a new session using the existing contents for this member. For now + * assumes we're using the latest jingle dialect and ice-udp + * FIXME: make dialect and transport selection more dynamic? + */ +/* +gboolean +ring_call_member_open_session (RingCallMember *self, + GError **error) +{ + RingCallMemberPrivate *priv = self->priv; + RingConnection *conn = ring_call_member_get_connection (self); + WockyJingleFactory *jf; + WockyJingleSession *session; + gchar *jid; + + jid = ring_peer_to_jid (conn, priv->target, NULL); + + jf = ring_jingle_mint_get_factory (conn->jingle_mint); + g_return_val_if_fail (jf != NULL, FALSE); + + session = wocky_jingle_factory_create_session (jf, jid, WOCKY_JINGLE_DIALECT_V032, + FALSE); + DEBUG ("Created a jingle session: %p", session); + + priv->transport_ns = g_strdup (NS_JINGLE_TRANSPORT_ICEUDP); + + ring_call_member_set_session (self, session); + + g_free (jid); + + return TRUE; +} + +gboolean +ring_call_member_start_session (RingCallMember *self, + const gchar *audio_name, + const gchar *video_name, + GError **error) +{ + RingCallMemberPrivate *priv = self->priv; + TpBaseChannel *base_channel = TP_BASE_CHANNEL (priv->call); + TpHandle target = tp_base_channel_get_target_handle (base_channel); + const gchar *resource; + WockyJingleDialect dialect; + gchar *jid; + const gchar *transport; + WockyJingleFactory *jf; + WockyJingleSession *session; + + // FIXME might need to wait on capabilities, also don't need transport + // and dialect already + if (!jingle_pick_best_resource (ring_call_member_get_connection (self), + target, audio_name != NULL, video_name != NULL, + &transport, &dialect, &resource)) + { + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, + "member does not have the desired audio/video capabilities"); + return FALSE; + } + + jid = ring_peer_to_jid (ring_call_member_get_connection (self), target, resource); + + jf = ring_jingle_mint_get_factory ( + ring_call_member_get_connection (self)->jingle_mint); + g_return_val_if_fail (jf != NULL, FALSE); + + session = wocky_jingle_factory_create_session (jf, jid, dialect, FALSE); + g_free (jid); + + ring_call_member_set_session (self, session); + + priv->transport_ns = g_strdup (transport); + + if (audio_name != NULL) + ring_call_member_create_content (self, audio_name, + WOCKY_JINGLE_MEDIA_TYPE_AUDIO, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NULL); + + if (video_name != NULL) + ring_call_member_create_content (self, video_name, + WOCKY_JINGLE_MEDIA_TYPE_VIDEO, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NULL); + + return TRUE; +} +*/ + +RingConnection * +ring_call_member_get_connection (RingCallMember *self) +{ + TpBaseChannel *base_chan = TP_BASE_CHANNEL (self->priv->call); + + return RING_CONNECTION (tp_base_channel_get_connection (base_chan)); +} + +const gchar * +ring_call_member_get_transport_ns (RingCallMember *self) +{ + return self->priv->transport_ns; +} + +void +ring_call_member_shutdown (RingCallMember *self) +{ + RingCallMemberPrivate *priv = self->priv; + + /* removing the content will remove it from our list */ + while (priv->contents != NULL) + ring_call_member_content_remove ( + RING_CALL_MEMBER_CONTENT (priv->contents->data)); +} diff --git a/src/ring-call-member.h b/src/ring-call-member.h new file mode 100644 index 0000000..d80e26b --- /dev/null +++ b/src/ring-call-member.h @@ -0,0 +1,73 @@ +/* + * ring-call-member.h - Header for CallMember + * Copyright (C) 2010 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> + * + * 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 + */ + +#ifndef __RING_CALL_MEMBER_H__ +#define __RING_CALL_MEMBER_H__ + +#include <glib-object.h> + +#include <telepathy-glib/telepathy-glib.h> + +G_BEGIN_DECLS + +typedef struct _RingCallMember RingCallMember; +typedef struct _RingCallMemberPrivate RingCallMemberPrivate; +typedef struct _RingCallMemberClass RingCallMemberClass; + +struct _RingCallMemberClass { + GObjectClass parent_class; +}; + +struct _RingCallMember { + GObject parent; + RingCallMemberPrivate *priv; +}; + +GType ring_call_member_get_type (void); + +/* TYPE MACROS */ +#define RING_TYPE_CALL_MEMBER \ + (ring_call_member_get_type ()) +#define RING_CALL_MEMBER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), RING_TYPE_CALL_MEMBER, \ + RingCallMember)) +#define RING_CALL_MEMBER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), RING_TYPE_CALL_MEMBER, \ + RingCallMemberClass)) +#define RING_IS_CALL_MEMBER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), RING_TYPE_CALL_MEMBER)) +#define RING_IS_CALL_MEMBER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), RING_TYPE_CALL_MEMBER)) +#define RING_CALL_MEMBER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), RING_TYPE_CALL_MEMBER, \ + RingCallMemberClass)) + +TpHandle ring_call_member_get_handle(RingCallMember *self); + +TpCallMemberFlags ring_call_member_get_flags(RingCallMember *self); + +RingConnection * ring_call_member_get_connection(RingCallMember *self); + +void ring_call_member_shutdown(RingCallMember *self); + +G_END_DECLS + +#endif /* #ifndef __RING_CALL_MEMBER_H__*/ diff --git a/src/ring-call-stream.c b/src/ring-call-stream.c index d79e83f..f8ddd23 100644 --- a/src/ring-call-stream.c +++ b/src/ring-call-stream.c @@ -3,6 +3,7 @@ * Copyright ©2010 Collabora Ltd. * Copyright ©2010 Nokia Corporation * @author Will Thompson <will.thompson@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,10 +27,8 @@ static void implement_call_stream (gpointer klass, gpointer unused); -G_DEFINE_TYPE_WITH_CODE (RingCallStream, ring_call_stream, - GABBLE_TYPE_BASE_CALL_STREAM, - G_IMPLEMENT_INTERFACE (RING_TYPE_SVC_CALL_STREAM, implement_call_stream) -) +G_DEFINE_TYPE(RingCallStream, ring_call_stream, + TP_TYPE_BASE_MEDIA_CALL_STREAM); static void ring_call_stream_init (RingCallStream *self) @@ -53,7 +52,7 @@ ring_call_stream_new (RingConnection *connection, static void ring_call_stream_set_sending ( - RingSvcCallStream *self, + RingCallStream *self, gboolean send, DBusGMethodInvocation *context) { @@ -67,7 +66,7 @@ ring_call_stream_set_sending ( static void ring_call_stream_request_receiving ( - RingSvcCallStream *self, + RingCallStream *self, TpHandle contact, gboolean receive, DBusGMethodInvocation *context) diff --git a/src/ring-call-stream.h b/src/ring-call-stream.h index d0930d6..67ee728 100644 --- a/src/ring-call-stream.h +++ b/src/ring-call-stream.h @@ -3,6 +3,7 @@ * Copyright ©2010 Collabora Ltd. * Copyright ©2010 Nokia Corporation * @author Will Thompson <will.thompson@collabora.co.uk> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,17 +25,24 @@ #include <glib-object.h> -#include "base-call-stream.h" +#include <telepathy-glib/telepathy-glib.h> + +#include "ring-connection.h" + +G_BEGIN_DECLS typedef struct _RingCallStream RingCallStream; +typedef struct _RingCallStreamPrivate RingCallStreamPrivate; typedef struct _RingCallStreamClass RingCallStreamClass; struct _RingCallStreamClass { - GabbleBaseCallStreamClass parent_class; + TpBaseMediaCallStreamClass parent_class; }; struct _RingCallStream { - GabbleBaseCallStream parent; + TpBaseMediaCallStream parent; + + RingCallStreamPrivate *priv; }; GType ring_call_stream_get_type (void); @@ -58,4 +66,8 @@ RingCallStream *ring_call_stream_new (RingConnection *connection, (G_TYPE_INSTANCE_GET_CLASS ((obj), RING_TYPE_CALL_STREAM, \ RingCallStreamClass)) +void ring_call_stream_update_member_states(RingCallStream *self); + +G_END_DECLS + #endif /* RING_CALL_STREAM_H */ diff --git a/src/ring-connection.c b/src/ring-connection.c index c985795..35c6b3e 100644 --- a/src/ring-connection.c +++ b/src/ring-connection.c @@ -4,6 +4,7 @@ * Copyright (C) 2007-2010 Nokia Corporation * @author Pekka Pessi <first.surname@nokia.com> * @author Lassi Syrjala <first.surname@nokia.com> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This work is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/ring-connection.h b/src/ring-connection.h index 0981860..23b51b1 100644 --- a/src/ring-connection.h +++ b/src/ring-connection.h @@ -3,6 +3,7 @@ * * Copyright (C) 2007-2010 Nokia Corporation * @author Pekka Pessi <first.surname@nokia.com> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This work is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,10 +24,12 @@ #define RING_CONNECTION_H #include <glib-object.h> + #include <telepathy-glib/base-connection.h> #include <telepathy-glib/base-connection-manager.h> #include <telepathy-glib/contacts-mixin.h> -#include <ring-util.h> + +#include "ring-util.h" G_BEGIN_DECLS diff --git a/src/ring-util.c b/src/ring-util.c index e332fd3..384afdf 100644 --- a/src/ring-util.c +++ b/src/ring-util.c @@ -3,6 +3,7 @@ * * Copyright (C) 2007-2010 Nokia Corporation * @author Pekka Pessi <first.surname@nokia.com> + * @author Tom Swindell <t.swindell@rubyx.co.uk> * * This work is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/ring-util.h b/src/ring-util.h index df5c65c..a7445b9 100644 --- a/src/ring-util.h +++ b/src/ring-util.h @@ -3,7 +3,7 @@ * * Copyright (C) 2007-2010 Nokia Corporation * @author Pekka Pessi <first.surname@nokia.com> - * + * @author Tom Swindell <t.swindell@rubyx.co.uk> * This work 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 diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..a7f5b61 --- /dev/null +++ b/src/util.c @@ -0,0 +1,525 @@ +/* + * util.c - Source for Ring utility functions + * Copyright (C) 2006-2007 Collabora Ltd. + * Copyright (C) 2006-2007 Nokia Corporation + * @author Robert McQueen <robert.mcqueen@collabora.co.uk> + * @author Simon McVittie <simon.mcvittie@collabora.co.uk> + * + * 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 "util.h" + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gobject/gvaluecollector.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> + +#define DEBUG_FLAG RING_DEBUG_JID + +#include "ring-connection.h" + +gchar * +sha1_hex (const gchar *bytes, + guint len) +{ + gchar *hex = g_compute_checksum_for_string (G_CHECKSUM_SHA1, bytes, len); + guint i; + + for (i = 0; i < SHA1_HASH_SIZE * 2; i++) + { + g_assert (hex[i] != '\0'); + hex[i] = g_ascii_tolower (hex[i]); + } + + g_assert (hex[SHA1_HASH_SIZE * 2] == '\0'); + + return hex; +} + +void +sha1_bin (const gchar *bytes, + guint len, + guchar out[SHA1_HASH_SIZE]) +{ + GChecksum *checksum = g_checksum_new (G_CHECKSUM_SHA1); + gsize out_len = SHA1_HASH_SIZE; + + g_assert (g_checksum_type_get_length (G_CHECKSUM_SHA1) == SHA1_HASH_SIZE); + g_checksum_update (checksum, (const guchar *) bytes, len); + g_checksum_get_digest (checksum, out, &out_len); + g_assert (out_len == SHA1_HASH_SIZE); + g_checksum_free (checksum); +} + + +/** ring_generate_id: + * + * RFC4122 version 4 compliant random UUIDs generator. + * + * Returns: A string with RFC41122 version 4 random UUID, must be freed with + * g_free(). + */ +gchar * +ring_generate_id (void) +{ + GRand *grand; + gchar *str; + struct { + guint32 time_low; + guint16 time_mid; + guint16 time_hi_and_version; + guint8 clock_seq_hi_and_rsv; + guint8 clock_seq_low; + guint16 node_hi; + guint32 node_low; + } uuid; + + /* Fill with random. Every new GRand are seede with 128 bit read from + * /dev/urandom (or the current time on non-unix systems). This makes the + * random source good enough for our usage, but may not be suitable for all + * situation outside Ring. */ + grand = g_rand_new (); + uuid.time_low = g_rand_int (grand); + uuid.time_mid = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16); + uuid.time_hi_and_version = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16); + uuid.clock_seq_hi_and_rsv = (guint8) g_rand_int_range (grand, 0, G_MAXUINT8); + uuid.clock_seq_low = (guint8) g_rand_int_range (grand, 0, G_MAXUINT8); + uuid.node_hi = (guint16) g_rand_int_range (grand, 0, G_MAXUINT16); + uuid.node_low = g_rand_int (grand); + g_rand_free (grand); + + /* Set the two most significant bits (bits 6 and 7) of the + * clock_seq_hi_and_rsv to zero and one, respectively. */ + uuid.clock_seq_hi_and_rsv = (uuid.clock_seq_hi_and_rsv & 0x3F) | 0x80; + + /* Set the four most significant bits (bits 12 through 15) of the + * time_hi_and_version field to 4 */ + uuid.time_hi_and_version = (uuid.time_hi_and_version & 0x0fff) | 0x4000; + + str = g_strdup_printf ("%08x-%04x-%04x-%02x%02x-%04x%08x", + uuid.time_low, + uuid.time_mid, + uuid.time_hi_and_version, + uuid.clock_seq_hi_and_rsv, + uuid.clock_seq_low, + uuid.node_hi, + uuid.node_low); + + return str; +} + +/** + * ring_get_room_handle_from_jid: + * @room_repo: The %TP_HANDLE_TYPE_ROOM handle repository + * @jid: A JID + * + * Given a JID seen in the from="" attribute on a stanza, work out whether + * it's something to do with a MUC, and if so, return its handle. + * + * Returns: The handle of the MUC, if the JID refers to either a MUC + * we're in, or a contact's channel-specific JID inside a MUC. + * Returns 0 if the JID is either invalid, or nothing to do with a + * known MUC (typically this will mean it's the global JID of a contact). + */ +TpHandle +ring_get_room_handle_from_jid (TpHandleRepoIface *room_repo, + const gchar *jid) +{ + TpHandle handle; + gchar *room; + + room = ring_remove_resource (jid); + if (room == NULL) + return 0; + + handle = tp_handle_lookup (room_repo, room, NULL, NULL); + g_free (room); + return handle; +} + +#define INVALID_HANDLE(e, f, ...) \ + G_STMT_START { \ + DEBUG (f, ##__VA_ARGS__); \ + g_set_error (e, TP_ERROR, TP_ERROR_INVALID_HANDLE, f, ##__VA_ARGS__);\ + } G_STMT_END + +gchar * +ring_remove_resource (const gchar *jid) +{ + char *slash = strchr (jid, '/'); + gchar *buf; + + if (slash == NULL) + return g_strdup (jid); + + /* The user and domain parts can't contain '/', assuming it's valid */ + buf = g_malloc (slash - jid + 1); + strncpy (buf, jid, slash - jid); + buf[slash - jid] = '\0'; + + return buf; +} + +gchar * +ring_encode_jid ( + const gchar *node, + const gchar *domain, + const gchar *resource) +{ + gchar *tmp, *ret; + + g_return_val_if_fail (domain != NULL, NULL); + + if (node != NULL && resource != NULL) + tmp = g_strdup_printf ("%s@%s/%s", node, domain, resource); + else if (node != NULL) + tmp = g_strdup_printf ("%s@%s", node, domain); + else if (resource != NULL) + tmp = g_strdup_printf ("%s/%s", domain, resource); + else + tmp = g_strdup (domain); + + ret = g_utf8_normalize (tmp, -1, G_NORMALIZE_NFKC); + g_free (tmp); + return ret; +} + +typedef struct { + GObject *instance; + GObject *user_data; + gulong handler_id; +} WeakHandlerCtx; + +static WeakHandlerCtx * +whc_new (GObject *instance, + GObject *user_data) +{ + WeakHandlerCtx *ctx = g_slice_new0 (WeakHandlerCtx); + + ctx->instance = instance; + ctx->user_data = user_data; + + return ctx; +} + +static void +whc_free (WeakHandlerCtx *ctx) +{ + g_slice_free (WeakHandlerCtx, ctx); +} + +static void user_data_destroyed_cb (gpointer, GObject *); + +static void +instance_destroyed_cb (gpointer ctx_, + GObject *where_the_instance_was) +{ + WeakHandlerCtx *ctx = ctx_; + + /* No need to disconnect the signal here, the instance has gone away. */ + g_object_weak_unref (ctx->user_data, user_data_destroyed_cb, ctx); + whc_free (ctx); +} + +static void +user_data_destroyed_cb (gpointer ctx_, + GObject *where_the_user_data_was) +{ + WeakHandlerCtx *ctx = ctx_; + + g_signal_handler_disconnect (ctx->instance, ctx->handler_id); + g_object_weak_unref (ctx->instance, instance_destroyed_cb, ctx); + whc_free (ctx); +} + +/** + * ring_signal_connect_weak: + * @instance: the instance to connect to. + * @detailed_signal: a string of the form "signal-name::detail". + * @c_handler: the GCallback to connect. + * @user_data: an object to pass as data to c_handler calls. + * + * Connects a #GCallback function to a signal for a particular object, as if + * with g_signal_connect(). Additionally, arranges for the signal handler to be + * disconnected if @user_data is destroyed. + * + * This is intended to be a convenient way for objects to use themselves as + * user_data for callbacks without having to explicitly disconnect all the + * handlers in their finalizers. + */ +void +ring_signal_connect_weak (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + GObject *user_data) +{ + GObject *instance_obj = G_OBJECT (instance); + WeakHandlerCtx *ctx = whc_new (instance_obj, user_data); + + ctx->handler_id = g_signal_connect (instance, detailed_signal, c_handler, + user_data); + + g_object_weak_ref (instance_obj, instance_destroyed_cb, ctx); + g_object_weak_ref (user_data, user_data_destroyed_cb, ctx); +} + +typedef struct { + GSourceFunc function; + GObject *object; + guint source_id; +} WeakIdleCtx; + +static void +idle_weak_ref_notify (gpointer data, + GObject *dead_object) +{ + g_source_remove (GPOINTER_TO_UINT (data)); +} + +static void +idle_removed (gpointer data) +{ + WeakIdleCtx *ctx = (WeakIdleCtx *) data; + + g_slice_free (WeakIdleCtx, ctx); +} + +static gboolean +idle_callback (gpointer data) +{ + WeakIdleCtx *ctx = (WeakIdleCtx *) data; + + if (ctx->function ((gpointer) ctx->object)) + { + return TRUE; + } + else + { + g_object_weak_unref ( + ctx->object, idle_weak_ref_notify, GUINT_TO_POINTER (ctx->source_id)); + return FALSE; + } +} + +/* Like g_idle_add(), but cancel the callback if the provided object is + * finalized. + */ +guint +ring_idle_add_weak (GSourceFunc function, + GObject *object) +{ + WeakIdleCtx *ctx; + + ctx = g_slice_new0 (WeakIdleCtx); + ctx->function = function; + ctx->object = object; + ctx->source_id = g_idle_add_full ( + G_PRIORITY_DEFAULT_IDLE, idle_callback, ctx, idle_removed); + + g_object_weak_ref ( + object, idle_weak_ref_notify, GUINT_TO_POINTER (ctx->source_id)); + return ctx->source_id; +} + +GPtrArray * +ring_g_ptr_array_copy (GPtrArray *source) +{ + GPtrArray *ret = g_ptr_array_sized_new (source->len); + guint i; + + for (i = 0; i < source->len; i++) + g_ptr_array_add (ret, g_ptr_array_index (source, i)); + + return ret; +} + +gchar * +ring_peer_to_jid (RingConnection *conn, + TpHandle peer, + const gchar *resource) +{ + TpHandleRepoIface *repo = tp_base_connection_get_handles ( + TP_BASE_CONNECTION (conn), TP_HANDLE_TYPE_CONTACT); + const gchar *target = tp_handle_inspect (repo, peer); + + if (resource == NULL) + return g_strdup (target); + + return g_strdup_printf ("%s/%s", target, resource); +} + +/* Like wocky_enum_from_nick, but for GFlagsValues instead. */ +gboolean +ring_flag_from_nick (GType flag_type, + const gchar *nick, + guint *value) +{ + GFlagsClass *klass = g_type_class_ref (flag_type); + GFlagsValue *flag_value; + + g_return_val_if_fail (klass != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + flag_value = g_flags_get_value_by_nick (klass, nick); + g_type_class_unref (klass); + + if (flag_value != NULL) + { + *value = flag_value->value; + return TRUE; + } + else + { + return FALSE; + } +} + +/** + * ring_simple_async_succeed_or_fail_in_idle: + * @self: the source object for an asynchronous function + * @callback: a callback to call when @todo things have been done + * @user_data: user data for the callback + * @source_tag: the source tag for a #GSimpleAsyncResult + * @error: (allow-none): %NULL to indicate success, or an error on failure + * + * Create a new #GSimpleAsyncResult and schedule it to call its callback + * in an idle. If @error is %NULL, report success with + * tp_simple_async_report_success_in_idle(); if @error is non-%NULL, + * use g_simple_async_report_gerror_in_idle(). + */ +void +ring_simple_async_succeed_or_fail_in_idle (gpointer self, + GAsyncReadyCallback callback, + gpointer user_data, + gpointer source_tag, + const GError *error) +{ + if (error == NULL) + { + tp_simple_async_report_success_in_idle (self, callback, user_data, + source_tag); + } + else + { + /* not const-correct yet: GNOME #622004 */ + g_simple_async_report_gerror_in_idle (self, callback, user_data, + (GError *) error); + } +} + +/** + * ring_simple_async_countdown_new: + * @self: the source object for an asynchronous function + * @callback: a callback to call when @todo things have been done + * @user_data: user data for the callback + * @source_tag: the source tag for a #GSimpleAsyncResult + * @todo: number of things to do before calling @callback (at least 1) + * + * Create a new #GSimpleAsyncResult that will call its callback when a number + * of asynchronous operations have happened. + * + * An internal counter is initialized to @todo, incremented with + * ring_simple_async_countdown_inc() or decremented with + * ring_simple_async_countdown_dec(). + * + * When that counter reaches zero, if an error has been set with + * g_simple_async_result_set_from_error() or similar, the operation fails; + * otherwise, it succeeds. + * + * The caller must not use the operation result functions, such as + * g_simple_async_result_get_op_res_gssize() - this async result is only + * suitable for "void" async methods which return either success or a #GError, + * i.e. the same signature as g_async_initable_init_async(). + * + * Returns: (transfer full): a counter + */ +GSimpleAsyncResult * +ring_simple_async_countdown_new (gpointer self, + GAsyncReadyCallback callback, + gpointer user_data, + gpointer source_tag, + gssize todo) +{ + GSimpleAsyncResult *simple; + + g_return_val_if_fail (todo >= 1, NULL); + + simple = g_simple_async_result_new (self, callback, user_data, source_tag); + /* We (ab)use the op_res member as a count of things to do. When + * it reaches zero, the operation completes with any error that has been + * set, or with success. */ + g_simple_async_result_set_op_res_gssize (simple, todo); + + /* we keep one extra reference as long as the counter is nonzero */ + g_object_ref (simple); + + return simple; +} + +/** + * ring_simple_async_countdown_inc: + * @simple: a result created by ring_simple_async_countdown_new() + * + * Increment the counter in @simple, indicating that an additional async + * operation has been started. An additional call to + * ring_simple_async_countdown_dec() will be needed to make @simple + * call its callback. + */ +void +ring_simple_async_countdown_inc (GSimpleAsyncResult *simple) +{ + gssize todo = g_simple_async_result_get_op_res_gssize (simple); + + g_return_if_fail (todo >= 1); + g_simple_async_result_set_op_res_gssize (simple, todo + 1); +} + +/** + * ring_simple_async_countdown_dec: + * @simple: a result created by ring_simple_async_countdown_new() + * + * Decrement the counter in @simple. If the number of things to do has + * reached zero, schedule @simple to call its callback in an idle, then + * unref it. + * + * When one of the asynchronous operations needed for @simple succeeds, + * this should be signalled by a call to this function. + * + * When one of the asynchronous operations needed for @simple fails, + * this should be signalled by a call to g_simple_async_result_set_from_error() + * (or one of the similar functions), followed by a call to this function. + * If more than one async operation fails in this way, the #GError from the + * last failure will be used. + */ +void +ring_simple_async_countdown_dec (GSimpleAsyncResult *simple) +{ + gssize todo = g_simple_async_result_get_op_res_gssize (simple); + + g_simple_async_result_set_op_res_gssize (simple, --todo); + + if (todo <= 0) + { + g_simple_async_result_complete_in_idle (simple); + g_object_unref (simple); + } +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..a3fa43c --- /dev/null +++ b/src/util.h @@ -0,0 +1,110 @@ +/* + * util.h - Headers for Ring utility functions + * Copyright (C) 2006 Collabora Ltd. + * Copyright (C) 2006 Nokia Corporation + * @author Robert McQueen <robert.mcqueen@collabora.co.uk> + * + * 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 + */ + +#ifndef __GABBLE_UTIL_H__ +#define __GABBLE_UTIL_H__ + +#include <config.h> + +#include <glib.h> +#include <telepathy-glib/telepathy-glib.h> + +#include "ring-connection.h" + +/* Guarantees that the resulting hash is in lower-case */ +gchar *sha1_hex (const gchar *bytes, guint len); + +/* A SHA1 digest is 20 bytes long */ +#define SHA1_HASH_SIZE 20 +void sha1_bin (const gchar *bytes, guint len, guchar out[SHA1_HASH_SIZE]); + +gchar *ring_generate_id (void); + +G_GNUC_WARN_UNUSED_RESULT +gchar *ring_encode_jid (const gchar *node, const gchar *domain, + const gchar *resource); + +gchar *ring_remove_resource (const gchar *jid); +gchar *ring_normalize_room (TpHandleRepoIface *repo, const gchar *jid, + gpointer context, GError **error); +TpHandle ring_get_room_handle_from_jid (TpHandleRepoIface *room_repo, + const gchar *jid); + +void ring_signal_connect_weak (gpointer instance, const gchar *detailed_signal, + GCallback c_handler, GObject *user_data); +guint ring_idle_add_weak (GSourceFunc function, GObject *object); + +GPtrArray *ring_g_ptr_array_copy (GPtrArray *source); + +gchar * ring_peer_to_jid (RingConnection *conn, + TpHandle peer, + const gchar *resource); + +gboolean +ring_flag_from_nick (GType flag_type, const gchar *nick, + guint *value); + +void ring_simple_async_succeed_or_fail_in_idle (gpointer self, + GAsyncReadyCallback callback, + gpointer user_data, + gpointer source_tag, + const GError *error); + +GSimpleAsyncResult *ring_simple_async_countdown_new (gpointer self, + GAsyncReadyCallback callback, + gpointer user_data, + gpointer source_tag, + gssize todo); +void ring_simple_async_countdown_inc (GSimpleAsyncResult *simple); +void ring_simple_async_countdown_dec (GSimpleAsyncResult *simple); + +/* Boilerplate for telling servers which implement XEP-0079 not to store these + * messages for delivery later. Include it in your call to wocky_stanza_build() + * like so: + * + * wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, + * NULL, jid, + * '(', "close", + * ':', NS_TUBES, + * '@', "tube", id_str, + * ')', + * RING_AMP_DO_NOT_STORE_SPEC, + * NULL); + * + * Every 1000th user will win a Marshall amplifier! + */ +#define RING_AMP_DO_NOT_STORE_SPEC \ + '(', "amp", \ + ':', NS_AMP, \ + '(', "rule", \ + '@', "condition", "deliver-at", \ + '@', "value", "stored", \ + '@', "action", "error", \ + ')', \ + '(', "rule", \ + '@', "condition", "match-resource", \ + '@', "value", "exact", \ + '@', "action", "error", \ + ')', \ + ')' + + +#endif /* __GABBLE_UTIL_H__ */ |