Beispiel #1
0
/**
 * 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 */
}
Beispiel #2
0
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;
}
Beispiel #4
0
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;
}
Beispiel #6
0
/**
 * 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);
    }
}
Beispiel #7
0
/**
 * 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);
    }
}
Beispiel #8
0
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);
        }
    }
}