/** * tp_properties_context_return * @ctx: the properties context representing a SetProperties call * @error: If %NULL, return successfully; otherwise return this error * * Commit the property changes and return from the pending D-Bus call. */ void tp_properties_context_return (TpPropertiesContext *ctx, GError *error) { GObject *obj = ctx->mixin->priv->object; TpIntSet *changed_props_val, *changed_props_flags; guint i; DEBUG ("%s", (error) ? "failure" : "success"); changed_props_val = tp_intset_sized_new (ctx->mixin_cls->num_props); changed_props_flags = tp_intset_sized_new (ctx->mixin_cls->num_props); for (i = 0; i < ctx->mixin_cls->num_props; i++) { if (ctx->values[i]) { if (!error) { tp_properties_mixin_change_value (obj, i, ctx->values[i], changed_props_val); tp_properties_mixin_change_flags (obj, i, TP_PROPERTY_FLAG_READ, 0, changed_props_flags); } g_value_unset (ctx->values[i]); ctx->values[i] = NULL; } } if (!error) { tp_properties_mixin_emit_changed (obj, changed_props_val); tp_properties_mixin_emit_flags (obj, changed_props_flags); tp_intset_destroy (changed_props_val); tp_intset_destroy (changed_props_flags); dbus_g_method_return (ctx->dbus_ctx); } else { dbus_g_method_return_error (ctx->dbus_ctx, error); g_error_free (error); } ctx->dbus_ctx = NULL; tp_intset_destroy (ctx->remaining); ctx->remaining = NULL; /* The context itself is not freed - it's a static part of the mixin */ }
static gboolean add_member (GObject *object, TpHandle member, const gchar *message, GError **error) { ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); /* In connection managers that supported the RequestChannel method for * streamed media channels, it would be necessary to support adding the * called contact to the members of an outgoing call. However, in this * legacy-free example, we don't support that usage, so the only use for * AddMembers is to accept an incoming call. */ if (member == self->group.self_handle && tp_handle_set_is_member (self->group.local_pending, member)) { /* We're in local-pending, move to members to accept. */ TpIntSet *set = tp_intset_new_containing (member); GHashTableIter iter; gpointer v; g_assert (self->priv->progress == PROGRESS_CALLING); g_message ("SIGNALLING: send: Accepting incoming call from %s", tp_handle_inspect (contact_repo, self->priv->handle)); self->priv->progress = PROGRESS_ACTIVE; tp_group_mixin_change_members (object, "", set /* added */, NULL /* nobody removed */, NULL /* nobody added to local pending */, NULL /* nobody added to remote pending */, member /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (set); g_hash_table_iter_init (&iter, self->priv->streams); while (g_hash_table_iter_next (&iter, NULL, &v)) { /* we accept the proposed stream direction... */ example_callable_media_stream_accept_proposed_direction (v); /* ... and the stream tries to connect */ example_callable_media_stream_connect (v); } return TRUE; } /* Otherwise it's a meaningless request, so reject it. */ g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, "Cannot add handle %u to channel", member); return FALSE; }
static TpBaseConnection * _tp_legacy_protocol_new_connection (TpBaseProtocol *protocol, GHashTable *asv, GError **error) { _TpLegacyProtocol *self = (_TpLegacyProtocol *) protocol; const TpCMProtocolSpec *protospec = self->protocol_spec; TpBaseConnectionManagerClass *cls; TpBaseConnection *conn = NULL; void *params = NULL; TpIntset *params_present = NULL; TpCMParamSetter set_param; if (self->cm == NULL) { g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Connection manager no longer available"); return NULL; } g_object_ref (self->cm); g_assert (protospec->parameters != NULL); g_assert (protospec->params_new != NULL); g_assert (protospec->params_free != NULL); cls = TP_BASE_CONNECTION_MANAGER_GET_CLASS (self->cm); params_present = tp_intset_new (); params = protospec->params_new (); set_param = protospec->set_param; if (set_param == NULL) set_param = tp_cm_param_setter_offset; if (!parse_parameters (protospec->parameters, (GHashTable *) asv, params_present, set_param, params, error)) { goto finally; } conn = (cls->new_connection) (self->cm, protospec->name, params_present, params, error); finally: if (params_present != NULL) tp_intset_destroy (params_present); if (params != NULL) protospec->params_free (params); g_object_unref (self->cm); return conn; }
static void example_callable_media_channel_close (ExampleCallableMediaChannel *self, TpHandle actor, TpChannelGroupChangeReason reason) { if (self->priv->progress != PROGRESS_ENDED) { TpIntSet *everyone; self->priv->progress = PROGRESS_ENDED; if (actor == self->group.self_handle) { const gchar *send_reason; /* In a real protocol these would be some sort of real protocol * construct, like an XMPP error stanza or a SIP error code */ switch (reason) { case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: send_reason = "<user-is-busy/>"; break; case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: send_reason = "<no-answer/>"; break; default: send_reason = "<call-terminated/>"; } g_message ("SIGNALLING: send: Terminating call: %s", send_reason); } everyone = tp_intset_new_containing (self->priv->handle); tp_intset_add (everyone, self->group.self_handle); tp_group_mixin_change_members ((GObject *) self, "", NULL /* nobody added */, everyone /* removed */, NULL /* nobody locally pending */, NULL /* nobody remotely pending */, actor, reason); tp_intset_destroy (everyone); g_signal_emit (self, signals[SIGNAL_CALL_TERMINATED], 0); tp_svc_channel_emit_closed (self); } }
static gboolean add_member (GObject *obj, TpHandle handle, const gchar *message, GError **error) { TpTestsTextChannelGroup *self = TP_TESTS_TEXT_CHANNEL_GROUP (obj); TpIntSet *add = tp_intset_new (); tp_intset_add (add, handle); tp_group_mixin_change_members (obj, message, add, NULL, NULL, NULL, self->conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (add); return TRUE; }
/** * tp_properties_mixin_change_value: * @obj: An object with the properties mixin * @prop_id: A property ID on which to act * @new_value: Property value * @props: either %NULL, or a pointer to a TpIntSet * * Change the value of the given property ID in response to a server state * change. * * If the old and new values match, nothing happens; no signal is emitted and * @props is ignored. Otherwise, the following applies: * * If @props is %NULL the PropertiesChanged signal is emitted for this one * property. * * Otherwise, the property ID is added to the set; the caller is responsible * for passing the set to tp_properties_mixin_emit_changed() once a batch of * properties have been changed. */ void tp_properties_mixin_change_value (GObject *obj, guint prop_id, const GValue *new_value, TpIntSet *props) { TpPropertiesMixin *mixin = TP_PROPERTIES_MIXIN (obj); TpPropertiesMixinClass *mixin_cls = TP_PROPERTIES_MIXIN_CLASS ( G_OBJECT_GET_CLASS (obj)); TpProperty *prop; g_assert (prop_id < mixin_cls->num_props); prop = &mixin->properties[prop_id]; if (prop->value) { if (values_are_equal (prop->value, new_value)) return; } else { prop->value = tp_g_value_slice_new (mixin_cls->signatures[prop_id].type); } g_value_copy (new_value, prop->value); if (props) { tp_intset_add (props, prop_id); } else { TpIntSet *changed_props = tp_intset_sized_new (prop_id + 1); tp_intset_add (changed_props, prop_id); tp_properties_mixin_emit_changed (obj, changed_props); tp_intset_destroy (changed_props); } }
/** * tp_properties_mixin_change_flags: * @obj: An object with the properties mixin * @prop_id: A property ID on which to act * @add: Property flags to be added via bitwise OR * @del: Property flags to be removed via bitwise AND * @props: either %NULL, or a pointer to a TpIntSet * * Change the flags for the given property ID in response to a server state * change. * * Flags removed by @del override flags added by @add. This should not be * relied upon. * * If @props is %NULL the PropertyFlagsChanged signal is emitted for this * single property. * * Otherwise, the property ID is added to the set; the caller is responsible * for passing the set to tp_properties_mixin_emit_flags() once a batch of * properties have been changed. */ void tp_properties_mixin_change_flags (GObject *obj, guint prop_id, TpPropertyFlags add, TpPropertyFlags del, TpIntSet *props) { TpPropertiesMixin *mixin = TP_PROPERTIES_MIXIN (obj); TpPropertiesMixinClass *mixin_cls = TP_PROPERTIES_MIXIN_CLASS ( G_OBJECT_GET_CLASS (obj)); TpProperty *prop; guint prev_flags; g_assert (prop_id < mixin_cls->num_props); prop = &mixin->properties[prop_id]; prev_flags = prop->flags; prop->flags |= add; prop->flags &= ~del; if (prop->flags == prev_flags) return; if (props) { tp_intset_add (props, prop_id); } else { TpIntSet *changed_props = tp_intset_sized_new (prop_id + 1); tp_intset_add (changed_props, prop_id); tp_properties_mixin_emit_flags (obj, changed_props); tp_intset_destroy (changed_props); } }
static void constructed (GObject *object) { void (*chain_up) (GObject *) = ((GObjectClass *) example_callable_media_channel_parent_class)->constructed; ExampleCallableMediaChannel *self = EXAMPLE_CALLABLE_MEDIA_CHANNEL (object); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpIntSet *members; TpIntSet *local_pending; if (chain_up != NULL) chain_up (object); tp_handle_ref (contact_repo, self->priv->handle); tp_handle_ref (contact_repo, self->priv->initiator); tp_dbus_daemon_register_object ( tp_base_connection_get_dbus_daemon (self->priv->conn), self->priv->object_path, self); tp_group_mixin_init (object, G_STRUCT_OFFSET (ExampleCallableMediaChannel, group), contact_repo, self->priv->conn->self_handle); /* Initially, the channel contains the initiator as a member; they are also * the actor for the change that adds any initial members. */ members = tp_intset_new_containing (self->priv->initiator); if (self->priv->locally_requested) { /* Nobody is locally pending. The remote peer will turn up in * remote-pending state when we actually contact them, which is done * in RequestStreams */ self->priv->progress = PROGRESS_NONE; local_pending = NULL; } else { /* This is an incoming call, so the self-handle is locally * pending, to indicate that we need to answer. */ self->priv->progress = PROGRESS_CALLING; local_pending = tp_intset_new_containing (self->priv->conn->self_handle); } tp_group_mixin_change_members (object, "", members /* added */, NULL /* nobody removed */, local_pending, /* added to local-pending */ NULL /* nobody added to remote-pending */, self->priv->initiator /* actor */, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); tp_intset_destroy (members); if (local_pending != NULL) tp_intset_destroy (local_pending); /* We don't need to allow adding or removing members to this Group in ways * that need flags set, so the only flag we set is to say we support the * Properties interface to the Group. * * It doesn't make sense to add anyone to the Group, since we already know * who we're going to call (or were called by). The only call to AddMembers * we need to support is to move ourselves from local-pending to member in * the incoming call case, and that's always allowed anyway. * * (Connection managers that support the various backwards-compatible * ways to make an outgoing StreamedMedia channel have to support adding the * peer to remote-pending, but that has no actual effect other than to * obscure what's going on; in this one, there's no need to support that * usage.) * * Similarly, it doesn't make sense to remove anyone from this Group apart * from ourselves (to hang up), and removing the SelfHandle is always * allowed anyway. */ tp_group_mixin_change_flags (object, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); /* Future versions of telepathy-spec will allow a channel request to * say "initially include an audio stream" and/or "initially include a video * stream", which would be represented like this; we don't support this * usage yet, though, so ExampleCallableMediaManager will never invoke * our constructor in this way. */ g_assert (!(self->priv->locally_requested && self->priv->initial_audio)); g_assert (!(self->priv->locally_requested && self->priv->initial_video)); if (!self->priv->locally_requested) { /* the caller has almost certainly asked us for some streams - there's * not much point in having a call otherwise */ if (self->priv->initial_audio) { g_message ("Channel initially has an audio stream"); example_callable_media_channel_add_stream (self, TP_MEDIA_STREAM_TYPE_AUDIO, FALSE); } if (self->priv->initial_video) { g_message ("Channel initially has a video stream"); example_callable_media_channel_add_stream (self, TP_MEDIA_STREAM_TYPE_VIDEO, FALSE); } } }