void
empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
					    TpHandle                 handle,
					    EmpathyTpContactFactoryContactCb callback,
					    gpointer                 user_data,
					    GDestroyNotify           destroy,
					    GObject                 *weak_object)
{
	EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
	GetContactsData *data;

	g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));

	data = g_slice_new (GetContactsData);
	data->callback.contact_cb = callback;
	data->user_data = user_data;
	data->destroy = destroy;
	data->tp_factory = g_object_ref (tp_factory);
	tp_connection_get_contacts_by_handle (priv->connection,
					      1, &handle,
					      G_N_ELEMENTS (contact_features),
					      contact_features,
					      get_contact_by_handle_cb,
					      data,
					      (GDestroyNotify) get_contacts_data_free,
					      weak_object);
}
void
empathy_tp_contact_factory_get_from_handle (TpConnection            *connection,
					    TpHandle                 handle,
					    EmpathyTpContactFactoryContactCb callback,
					    gpointer                 user_data,
					    GDestroyNotify           destroy,
					    GObject                 *weak_object)
{
	GetContactsData *data;

	g_return_if_fail (TP_IS_CONNECTION (connection));

	data = g_slice_new (GetContactsData);
	data->callback.contact_cb = callback;
	data->user_data = user_data;
	data->destroy = destroy;
	data->connection = g_object_ref (connection);
	tp_connection_get_contacts_by_handle (connection,
					      1, &handle,
					      G_N_ELEMENTS (contact_features),
					      contact_features,
					      get_contact_by_handle_cb,
					      data,
					      (GDestroyNotify) get_contacts_data_free,
					      weak_object);
}
/* The callback is NOT given a reference to the EmpathyContact objects */
void
empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
					     guint n_handles,
					     const TpHandle *handles,
					     EmpathyTpContactFactoryContactsByHandleCb callback,
					     gpointer                 user_data,
					     GDestroyNotify           destroy,
					     GObject                 *weak_object)
{
	EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
	GetContactsData *data;

	if (n_handles == 0) {
		callback (tp_factory, 0, NULL, 0, NULL, NULL, user_data, weak_object);
		return;
	}

	g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
	g_return_if_fail (handles != NULL);

	data = g_slice_new (GetContactsData);
	data->callback.handles_cb = callback;
	data->user_data = user_data;
	data->destroy = destroy;
	data->tp_factory = g_object_ref (tp_factory);
	tp_connection_get_contacts_by_handle (priv->connection,
					      n_handles, handles,
					      G_N_ELEMENTS (contact_features),
					      contact_features,
					      get_contacts_by_handle_cb,
					      data,
					      (GDestroyNotify) get_contacts_data_free,
					      weak_object);
}
/* The callback is NOT given a reference to the EmpathyContact objects */
void
empathy_tp_contact_factory_get_from_handles (TpConnection *connection,
					     guint n_handles,
					     const TpHandle *handles,
					     EmpathyTpContactFactoryContactsByHandleCb callback,
					     gpointer                 user_data,
					     GDestroyNotify           destroy,
					     GObject                 *weak_object)
{
	GetContactsData *data;

	if (n_handles == 0) {
		callback (connection, 0, NULL, 0, NULL, NULL, user_data, weak_object);
		return;
	}

	g_return_if_fail (TP_IS_CONNECTION (connection));
	g_return_if_fail (handles != NULL);

	data = g_slice_new (GetContactsData);
	data->callback.handles_cb = callback;
	data->user_data = user_data;
	data->destroy = destroy;
	data->connection = g_object_ref (connection);
	tp_connection_get_contacts_by_handle (connection,
					      n_handles, handles,
					      G_N_ELEMENTS (contact_features),
					      contact_features,
					      get_contacts_by_handle_cb,
					      data,
					      (GDestroyNotify) get_contacts_data_free,
					      weak_object);
}
static void remmina_tp_channel_handler_channel_ready(TpChannel *channel, const GError *channel_error, gpointer user_data)
{
	RemminaTpChannelHandler *chandler = (RemminaTpChannelHandler *) user_data;
	TpHandle handle;
	GError *error = NULL;
	TpContactFeature features[] =
	{ TP_CONTACT_FEATURE_ALIAS, TP_CONTACT_FEATURE_AVATAR_TOKEN };

	if (channel_error != NULL)
	{
		g_print("remmina_tp_channel_handler_channel_ready: %s\n", channel_error->message);
		remmina_tp_channel_handler_free(chandler);
		return;
	}

	if (tp_cli_channel_connect_to_closed(channel, remmina_tp_channel_handler_channel_closed, chandler, NULL, NULL, &error)
			== NULL)
	{
		g_print("tp_cli_channel_connect_to_closed: %s\n", channel_error->message);
		remmina_tp_channel_handler_free(chandler);
		return;
	}
	g_print("remmina_tp_channel_handler_channel_ready: %s\n", chandler->channel_path);

	handle = tp_channel_get_handle(channel, NULL);
	tp_connection_get_contacts_by_handle(chandler->connection, 1, &handle, G_N_ELEMENTS(features), features,
			remmina_tp_channel_handler_get_contacts, chandler, NULL, NULL);
}
/**
 * shell_get_tp_contacts:
 * @self: A connection, which must be ready
 * @n_handles: Number of handles in handles
 * @handles: (array length=n_handles) (element-type uint): Array of handles
 * @n_features: Number of features in features
 * @features: (array length=n_features) (allow-none) (element-type uint):
 *  Array of features
 * @callback: (scope async): User callback to run when the contacts are ready
 *
 * Wrap tp_connection_get_contacts_by_handle so we can transform the array
 * into a null-terminated one, which gjs can handle.
 * We send the original callback to tp_connection_get_contacts_by_handle as
 * user_data, and we have our own function as callback, which does the
 * transforming.
 */
void
shell_get_tp_contacts (TpConnection *self,
                       guint n_handles,
                       const TpHandle *handles,
                       guint n_features,
                       const TpContactFeature *features,
                       ShellGetTpContactCb callback)
{
  tp_connection_get_contacts_by_handle(self, n_handles, handles,
                                       n_features, features,
                                       shell_global_get_tp_contacts_cb,
                                       callback, NULL, NULL);
}
static void
display_reject_notification (EmpathyCallObserver *self,
    TpChannel *channel)
{
  TpHandle handle;
  TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS,
      TP_CONTACT_FEATURE_AVATAR_DATA };

  handle = tp_channel_get_handle (channel, NULL);

  tp_connection_get_contacts_by_handle (tp_channel_borrow_connection (channel),
      1, &handle, G_N_ELEMENTS (features), features, get_contact_cb,
      g_object_ref (channel), g_object_unref, G_OBJECT (self));
}
static void
connection_identified (TpStreamTubeChannel *self,
    GSocketConnection *conn,
    TpHandle handle,
    guint connection_id)
{
  TpStreamTubeConnection *tube_conn;

  tube_conn = _tp_stream_tube_connection_new (conn, self);

  g_hash_table_insert (self->priv->tube_connections,
      GUINT_TO_POINTER (connection_id), tube_conn);

  g_object_weak_ref (G_OBJECT (tube_conn), remote_connection_destroyed_cb,
      self);

  if (can_identify_contact (self))
    {
      TpConnection *connection;
      GArray *features;

      connection = tp_channel_get_connection (TP_CHANNEL (self));
      features = tp_simple_client_factory_dup_contact_features (
          tp_proxy_get_factory (connection), connection);

      /* Spec does not give the id with the handle */
      G_GNUC_BEGIN_IGNORE_DEPRECATIONS
      /* Pass the ref on tube_conn to the function */
      tp_connection_get_contacts_by_handle (connection,
          1, &handle,
          features->len, (TpContactFeature *) features->data,
          _new_remote_connection_with_contact,
          tube_conn, g_object_unref, G_OBJECT (self));
       G_GNUC_END_IGNORE_DEPRECATIONS

      g_array_unref (features);
    }
  else
    {
      g_signal_emit (self, _signals[INCOMING], 0, tube_conn);

      g_object_unref (tube_conn);
    }
}
static void
new_local_connection_identified (TpStreamTubeChannel *self,
    GSocketConnection *conn,
    guint connection_id)
{
  TpHandle initiator_handle;
  TpStreamTubeConnection *tube_conn;
  TpConnection *connection;
  GArray *features;

  tube_conn = _tp_stream_tube_connection_new (conn, self);

  g_hash_table_insert (self->priv->tube_connections,
      GUINT_TO_POINTER (connection_id), tube_conn);

  g_object_weak_ref (G_OBJECT (tube_conn), remote_connection_destroyed_cb,
      self);

  /* We are accepting a tube so the contact of the connection is the
   * initiator of the tube */
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  initiator_handle = tp_channel_get_initiator_handle (TP_CHANNEL (self));

  connection = tp_channel_get_connection (TP_CHANNEL (self));
  features = tp_simple_client_factory_dup_contact_features (
      tp_proxy_get_factory (connection), connection);

  /* Pass ownership of tube_conn to the function */
  tp_connection_get_contacts_by_handle (connection,
      1, &initiator_handle,
      features->len, (TpContactFeature *) features->data,
      new_local_connection_with_contact,
      tube_conn, g_object_unref, G_OBJECT (self));
  G_GNUC_END_IGNORE_DEPRECATIONS

  g_array_unref (features);
}
static void
tp_connection_get_contact_list_attributes_cb(TpConnection* connection,
						GHashTable *out_Attributes,
						const GError* error,
						gpointer user_data,
						GObject* /*weak_object*/)
{
	UT_DEBUGMSG(("tp_connection_get_contact_list_attributes\n"));
	if (error)
		UT_DEBUGMSG(("%s\n", error->message));
	UT_return_if_fail(!error);

	std::vector<TpHandle> handles;

	// get the list of contact handles
	gpointer key;
	GHashTableIter iter;
	g_hash_table_iter_init(&iter, out_Attributes);
	while (g_hash_table_iter_next(&iter, &key, NULL))
	{
		TpHandle contact_handle = GPOINTER_TO_UINT(key);
		handles.push_back(contact_handle);
	}

	// fetch the contacts belonging to the handles
	static TpContactFeature features[] = {
		TP_CONTACT_FEATURE_ALIAS,
		TP_CONTACT_FEATURE_PRESENCE
	};

	tp_connection_get_contacts_by_handle (connection,
			handles.size(), &handles[0],
			G_N_ELEMENTS (features), features,
			list_contacts_for_connection_cb,
			user_data, NULL, NULL);
}
static void
mex_telepathy_channel_initialize_channel (MexTelepathyChannel *self)
{
  MexTelepathyChannelPrivate *priv = self->priv;

  GstBus *bus;
  GstElement *pipeline;
  GstStateChangeReturn ret;
  gboolean ready;

  TpHandle contactHandle = tp_channel_get_handle (priv->channel, NULL);
  TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS,
                                  TP_CONTACT_FEATURE_AVATAR_DATA,
                                  TP_CONTACT_FEATURE_AVATAR_TOKEN};

  MEX_INFO ("New channel");

  if (contactHandle)
    tp_connection_get_contacts_by_handle (
      priv->connection, 1, &contactHandle, 1,
      features,
      mex_telepathy_channel_on_contact_fetched,
      self, NULL, NULL);

  pipeline = gst_pipeline_new (NULL);

  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);

  if (ret == GST_STATE_CHANGE_FAILURE)
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      g_object_unref (pipeline);
      MEX_WARNING ("Failed to start an empty pipeline !?");
      return;
    }

  priv->pipeline = pipeline;

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  priv->buswatch = gst_bus_add_watch (bus, mex_telepathy_channel_on_bus_watch,
                                      self);
  g_object_unref (bus);

  tf_channel_new_async (priv->channel, mex_telepathy_channel_new_tf_channel,
                        self);

  tpy_cli_channel_type_call_call_accept (TP_PROXY (priv->channel), -1,
                                         NULL, NULL, NULL, NULL);

  priv->channel = g_object_ref (priv->channel);
  g_signal_connect (priv->channel, "notify::ready",
                    G_CALLBACK (mex_telepathy_channel_on_ready),
                    self);
  g_signal_connect (priv->channel, "invalidated",
                    G_CALLBACK (mex_telepathy_channel_on_proxy_invalidated),
                    self);

  g_signal_connect (TPY_CALL_CHANNEL (priv->channel), "state-changed",
                    G_CALLBACK (mex_telepathy_channel_on_call_state_changed),
                    self);

  g_object_get (priv->channel, "ready", &ready, NULL);
  if (ready)
    mex_telepathy_channel_on_ready (TPY_CALL_CHANNEL (priv->channel), NULL, self);
}