static void
on_connection_future_ensure_sidecar_returned (GObject *source_object,
    GAsyncResult *result,
    gpointer user_data)
{
  GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
  gchar *object_path;
  GError *error = NULL;

  g_return_if_fail (TP_IS_CONNECTION (source_object));

  object_path = _tp_yts_connection_future_ensure_sidecar_finish (
      TP_CONNECTION (source_object), result, NULL, &error);

  if (error != NULL)
    {
      g_simple_async_result_set_from_error (res, error);
      g_clear_error (&error);
      g_simple_async_result_complete_in_idle (res);
      g_object_unref (res);
      return;
    }

  g_async_initable_new_async (TP_TYPE_YTS_STATUS, G_PRIORITY_DEFAULT, NULL,
      on_status_new_returned, res,
      "dbus-daemon", tp_proxy_get_dbus_daemon (source_object),
      "dbus-connection", tp_proxy_get_dbus_connection (source_object),
      "bus-name", tp_proxy_get_bus_name (source_object),
      "object-path", object_path,
      NULL);

  g_free (object_path);
}
static void
on_content_added_cb (TpProxy *proxy,
    const gchar *content_path,
    gpointer user_data,
    GObject *weak_object)
{
  TpyCallChannel *self = TPY_CALL_CHANNEL (proxy);
  TpyCallContent *content;

  DEBUG ("Content added: %s", content_path);

  content = g_object_new (TPY_TYPE_CALL_CONTENT,
          "bus-name", tp_proxy_get_bus_name (self),
          "dbus-daemon", tp_proxy_get_dbus_daemon (self),
          "dbus-connection", tp_proxy_get_dbus_connection (self),
          "object-path", content_path,
          NULL);

  if (content == NULL)
    {
      g_warning ("Could not create a CallContent for path %s", content_path);
      return;
    }

  g_ptr_array_add (self->priv->contents, content);
  tp_g_signal_connect_object (content, "notify::ready",
    G_CALLBACK (on_content_ready_cb), self, 0);

  g_signal_emit (self, _signals[CONTENT_ADDED], 0, content);
}
static void
mcd_client_registry_ready_cb (McdClientProxy *client,
    McdClientRegistry *self)
{
  DEBUG ("%s", tp_proxy_get_bus_name (client));

  g_signal_handlers_disconnect_by_func (client,
      mcd_client_registry_ready_cb, self);

  /* paired with the one in _mcd_client_registry_found_name */
  _mcd_client_registry_dec_startup_lock (self);
}
static void
connection_requested_handles (TpConnection *self,
                              const GArray *handles,
                              const GError *error,
                              gpointer user_data,
                              GObject *weak_object)
{
  RequestHandlesContext *context = user_data;

  g_object_ref (self);

  if (error == NULL)
    {
      if (G_UNLIKELY (g_strv_length (context->ids) != handles->len))
        {
          const gchar *cm = tp_proxy_get_bus_name ((TpProxy *) self);
          GError *e = g_error_new (TP_DBUS_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
              "Connection manager %s is broken: we asked for %u "
              "handles but RequestHandles returned %u",
              cm, g_strv_length (context->ids), handles->len);

          /* This CM is bad and wrong. We can't trust it to get anything
           * right. */
          WARNING ("%s", e->message);

          context->callback (self, context->handle_type, 0, NULL, NULL,
              e, context->user_data, weak_object);
          g_error_free (e);
          return;
        }

      DEBUG ("%u handles of type %u", handles->len,
          context->handle_type);
      /* On the Telepathy side, we have held these handles (at least once).
       * That's all we need. */

      context->callback (self, context->handle_type, handles->len,
          (const TpHandle *) handles->data,
          (const gchar * const *) context->ids,
          NULL, context->user_data, weak_object);
    }
  else
    {
      DEBUG ("%u handles of type %u failed: %s %u: %s",
          g_strv_length (context->ids), context->handle_type,
          g_quark_to_string (error->domain), error->code, error->message);
      context->callback (self, context->handle_type, 0, NULL, NULL, error,
          context->user_data, weak_object);
    }

  g_object_unref (self);
}
static void
mcd_client_registry_disconnect_client_signals (gpointer k G_GNUC_UNUSED,
    gpointer v,
    gpointer data)
{
  g_signal_handlers_disconnect_by_func (v, mcd_client_registry_ready_cb, data);
  g_signal_handlers_disconnect_by_func (v, mcd_client_registry_gone_cb, data);

  if (!_mcd_client_proxy_is_ready (v))
    {
      /* we'll never receive the ready signal now, so release the lock that
       * it would otherwise have released */
      DEBUG ("client %s disappeared before it became ready - treating it "
             "as ready for our purposes", tp_proxy_get_bus_name (v));
      mcd_client_registry_ready_cb (v, data);
    }
}
static void
tls_handler_init_async (GAsyncInitable *initable,
                        gint io_priority,
                        GCancellable *cancellable,
                        GAsyncReadyCallback callback,
                        gpointer user_data)
{
    GVariant *properties;
    const gchar *cert_object_path;
    const gchar *bus_name;
    GError *error = NULL;
    GQuark features[] = { TP_TLS_CERTIFICATE_FEATURE_CORE, 0 };
    /*
     * Used when channel doesn't implement ReferenceIdentities. A GStrv
     * with [0] the hostname, and [1] a NULL terminator.
     */
    gchar *default_identities[2];
    EmpathyServerTLSHandler *self = EMPATHY_SERVER_TLS_HANDLER (initable);
    EmpathyServerTLSHandlerPriv *priv = GET_PRIV (self);

    g_assert (priv->channel != NULL);

    priv->async_init_res = g_simple_async_result_new (G_OBJECT (self),
                           callback, user_data, empathy_server_tls_handler_new_async);
    properties = tp_channel_dup_immutable_properties (priv->channel);

    g_variant_lookup (properties,
                      TP_PROP_CHANNEL_TYPE_SERVER_TLS_CONNECTION_HOSTNAME,
                      "s", &priv->hostname);

    DEBUG ("Received hostname: %s", priv->hostname);

    g_variant_lookup (properties,
                      TP_PROP_CHANNEL_TYPE_SERVER_TLS_CONNECTION_REFERENCE_IDENTITIES,
                      "^as", &priv->reference_identities);

    /*
     * If the channel doesn't implement the ReferenceIdentities parameter
     * then fallback to the hostname.
     */
    if (priv->reference_identities == NULL)
    {
        default_identities[0] = (gchar *) priv->hostname;
        default_identities[1] = NULL;
        priv->reference_identities = g_strdupv (default_identities);
    }
    else
    {
#ifdef ENABLE_DEBUG
        gchar *output = g_strjoinv (", ", (gchar **) priv->reference_identities);
        DEBUG ("Received reference identities: %s", output);
        g_free (output);
#endif /* ENABLE_DEBUG */
    }

    g_variant_lookup (properties,
                      TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION ".ServerCertificate",
                      "&o", &cert_object_path);
    bus_name = tp_proxy_get_bus_name (TP_PROXY (priv->channel));

    DEBUG ("Creating an TpTLSCertificate for path %s, bus name %s",
           cert_object_path, bus_name);

    priv->certificate = tp_tls_certificate_new (TP_PROXY (priv->channel),
                        cert_object_path, &error);

    g_variant_unref (properties);

    if (error != NULL)
    {
        DEBUG ("Unable to create the TpTLSCertificate: error %s",
               error->message);

        g_simple_async_result_set_from_error (priv->async_init_res, error);
        g_simple_async_result_complete_in_idle (priv->async_init_res);

        g_error_free (error);
        tp_clear_object (&priv->async_init_res);

        return;
    }

    tp_proxy_prepare_async (priv->certificate, features,
                            tls_certificate_prepared_cb, self);
}
static void
mcd_client_registry_gone_cb (McdClientProxy *client,
    McdClientRegistry *self)
{
  _mcd_client_registry_remove (self, tp_proxy_get_bus_name (client));
}
static void
on_call_channel_get_all_properties_cb (TpProxy *proxy,
    GHashTable *properties,
    const GError *error,
    gpointer user_data,
    GObject *weak_object)
{
  TpyCallChannel *self = TPY_CALL_CHANNEL (proxy);
  GSimpleAsyncResult *result = user_data;
  GHashTable *hash_table;
  GPtrArray *contents;
  guint i;

  if (error != NULL)
    {
      g_warning ("Could not get the channel properties: %s", error->message);
      g_simple_async_result_set_from_error (result, error);
      goto out;
    }

  self->priv->state = tp_asv_get_uint32 (properties,
      "CallState", NULL);
  self->priv->flags = tp_asv_get_uint32 (properties,
      "CallFlags", NULL);
  self->priv->initial_audio = tp_asv_get_boolean (properties,
      "InitialAudio", NULL);
  self->priv->initial_video = tp_asv_get_boolean (properties,
      "InitialVideo", NULL);

  hash_table = tp_asv_get_boxed (properties,
      "CallStateDetails", TP_HASH_TYPE_STRING_VARIANT_MAP);
  if (hash_table != NULL)
    self->priv->details = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP,
        hash_table);

  hash_table = tp_asv_get_boxed (properties,
      "CallMembers", TPY_HASH_TYPE_CALL_MEMBER_MAP);
  update_call_members (self, hash_table, NULL);

  contents = tp_asv_get_boxed (properties,
      "Contents", TP_ARRAY_TYPE_OBJECT_PATH_LIST);

  for (i = 0; i < contents->len; i++)
    {
      const gchar *content_path = g_ptr_array_index (contents, i);
      TpyCallContent *content;

      DEBUG ("Content added: %s", content_path);

      content = g_object_new (TPY_TYPE_CALL_CONTENT,
              "bus-name", tp_proxy_get_bus_name (self),
              "dbus-daemon", tp_proxy_get_dbus_daemon (self),
              "dbus-connection", tp_proxy_get_dbus_connection (self),
              "object-path", content_path,
              NULL);

      if (content == NULL)
        {
          g_warning ("Could not create a CallContent for path %s", content_path);

          g_simple_async_result_set_error (result, TP_ERRORS, TP_ERROR_CONFUSED,
              "Could not create a CallContent for path %s", content_path);
          goto out;
        }

      g_ptr_array_add (self->priv->contents, content);

      tp_g_signal_connect_object (content, "notify::ready",
        G_CALLBACK (on_content_ready_cb), self, 0);
    }

  g_signal_emit (self, _signals[MEMBERS_CHANGED], 0, self->priv->members);

  self->priv->properties_retrieved = TRUE;

  maybe_go_to_ready (self);

out:
  /* TODO; ideally we should get rid of the ready property and complete once
   * all the contents have been prepared. Or maybe that should be another
   * feature? */
  g_simple_async_result_complete (result);
}