Ejemplo n.º 1
0
static void
on_call_state_changed_cb (TpCallChannel *call,
  TpCallState state,
  TpCallFlags flags,
  TpCallStateReason *reason,
  GHashTable *details,
  EmpathyCallHandler *handler)
{
  EmpathyCallHandlerPriv *priv = handler->priv;

  /* Clean up the TfChannel before bubbling the state-change signal
   * further up. This ensures that the conference-removed signal is
   * emitted before state-changed so that the client gets a chance
   * to remove the conference from the pipeline before resetting the
   * pipeline itself.
   */
  if (state == TP_CALL_STATE_ENDED)
    {
      tp_channel_close_async (TP_CHANNEL (call), NULL, NULL);
      priv->accept_when_initialised = FALSE;
      tp_clear_object (&priv->call);
      tp_clear_object (&priv->tfchannel);
    }

  g_signal_emit (handler, signals[STATE_CHANGED], 0, state,
      reason->dbus_reason);

  if (state == TP_CALL_STATE_INITIALISED &&
      priv->accept_when_initialised)
    {
      tp_call_channel_accept_async (priv->call, on_call_accepted_cb, NULL);
      priv->accept_when_initialised = FALSE;
    }
}
static void tls_certificate_got_all_handler(TpProxy *proxy,
			GHashTable *properties, const GError *error,
			gpointer user_data, GObject *weak_object)
{
	HevImpathyTLSCertificate *self = HEV_IMPATHY_TLS_CERTIFICATE(weak_object);
	HevImpathyTLSCertificatePrivate *priv =
		HEV_IMPATHY_TLS_CERTIFICATE_GET_PRIVATE(self);
	GPtrArray *cert_data = NULL;

	g_debug("%s:%d[%s]", __FILE__, __LINE__, __FUNCTION__);

	if(NULL != error)
	{
		g_simple_async_result_set_from_error(priv->async_prepare_res, error);
		g_simple_async_result_complete(priv->async_prepare_res);
		tp_clear_object(&priv->async_prepare_res);

		return;
	}

	priv->cert_type = g_strdup(tp_asv_get_string(properties,
					"CertificateType"));
	priv->state = tp_asv_get_uint32(properties, "State", NULL);

	cert_data = tp_asv_get_boxed(properties, "CertificateChainData",
				TP_ARRAY_TYPE_UCHAR_ARRAY_LIST);
	g_assert(NULL != cert_data);
	priv->cert_data = g_boxed_copy(TP_ARRAY_TYPE_UCHAR_ARRAY_LIST,
				cert_data);

	priv->is_prepared = TRUE;

	g_simple_async_result_complete(priv->async_prepare_res);
	tp_clear_object(&priv->async_prepare_res);
}
Ejemplo n.º 3
0
static gint
name_sort_func (GtkTreeModel *model,
    GtkTreeIter *iter_a,
    GtkTreeIter *iter_b,
    gpointer user_data)
{
  gchar *name_a, *name_b;
  FolksPersona *persona_a, *persona_b;
  gint ret_val;

  gtk_tree_model_get (model, iter_a,
          EMPATHY_PERSONA_STORE_COL_NAME, &name_a,
          EMPATHY_PERSONA_STORE_COL_PERSONA, &persona_a,
          -1);
  gtk_tree_model_get (model, iter_b,
          EMPATHY_PERSONA_STORE_COL_NAME, &name_b,
          EMPATHY_PERSONA_STORE_COL_PERSONA, &persona_b,
          -1);

  if (persona_a == NULL || persona_b == NULL)
    ret_val = 0;
  else
    ret_val = sort_personas (persona_a, persona_b);

  tp_clear_object (&persona_a);
  tp_clear_object (&persona_b);

  return ret_val;
}
static void
create_tube_data_free (CreateTubeData *data)
{
  tp_clear_object (&data->connection);
  tp_clear_object (&data->channel);

  g_slice_free (CreateTubeData, data);
}
static void
observer_dispose (GObject *object)
{
  EmpathyCallObserver *self = EMPATHY_CALL_OBSERVER (object);

  tp_clear_object (&self->priv->notify_mgr);
  tp_clear_object (&self->priv->observer);
  g_list_free_full (self->priv->channels, g_object_unref);
  self->priv->channels = NULL;
}
Ejemplo n.º 6
0
static void
empathy_call_handler_dispose (GObject *object)
{
  EmpathyCallHandlerPriv *priv = GET_PRIV (object);

  tp_clear_object (&priv->tfchannel);
  tp_clear_object (&priv->call);
  tp_clear_object (&priv->contact);

  G_OBJECT_CLASS (empathy_call_handler_parent_class)->dispose (object);
}
Ejemplo n.º 7
0
static void
create_tube_data_free (CreateTubeData *data)
{
  tp_clear_object (&data->connection);
  tp_clear_object (&data->channel);

  tp_clear_object (&data->global_cancellable);
  tp_clear_object (&data->op_cancellable);
  tp_clear_pointer (&data->unix_path, unix_path_destroy);

  g_slice_free (CreateTubeData, data);
}
static void
empathy_server_sasl_handler_dispose (GObject *object)
{
  EmpathyServerSASLHandlerPriv *priv = EMPATHY_SERVER_SASL_HANDLER (object)->priv;

  DEBUG ("%p", object);

  tp_clear_object (&priv->channel);
  tp_clear_object (&priv->account);

  G_OBJECT_CLASS (empathy_server_sasl_handler_parent_class)->dispose (object);
}
Ejemplo n.º 9
0
static void
dispose (GObject *object)
{
  EmpathyIndividualLinkerPriv *priv = GET_PRIV (object);

  tp_clear_object (&priv->individual_store);
  tp_clear_object (&priv->persona_store);
  tp_clear_object (&priv->start_individual);
  tp_clear_object (&priv->new_individual);

  G_OBJECT_CLASS (empathy_individual_linker_parent_class)->dispose (object);
}
static void
chatroom_manager_dispose (GObject *object)
{
  EmpathyChatroomManagerPriv *priv;

  priv = GET_PRIV (object);

  tp_clear_object (&priv->observer);
  tp_clear_object (&priv->monitor);

  (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->dispose) (object);
}
static void
empathy_irc_network_chooser_dispose (GObject *object)
{
  EmpathyIrcNetworkManager *self = (EmpathyIrcNetworkManager *) object;
  EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);

  tp_clear_object (&priv->settings);
  tp_clear_object (&priv->network_manager);
  tp_clear_object (&priv->network);

  if (G_OBJECT_CLASS (empathy_irc_network_chooser_parent_class)->dispose)
    G_OBJECT_CLASS (empathy_irc_network_chooser_parent_class)->dispose (object);
}
Ejemplo n.º 12
0
void
empathy_launch_program (const gchar *dir,
    const gchar *name,
    const gchar *args)
{
  GdkDisplay *display;
  GError *error = NULL;
  gchar *path, *cmd;
  GAppInfo *app_info;
  GdkAppLaunchContext *context = NULL;

  /* Try to run from source directory if possible */
  path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "src",
      name, NULL);

  if (!g_file_test (path, G_FILE_TEST_EXISTS))
    {
      g_free (path);
      path = g_build_filename (dir, name, NULL);
    }

  if (args != NULL)
    cmd = g_strconcat (path, " ", args, NULL);
  else
    cmd = g_strdup (path);

  app_info = g_app_info_create_from_commandline (cmd, NULL, 0, &error);
  if (app_info == NULL)
    {
      DEBUG ("Failed to create app info: %s", error->message);
      g_error_free (error);
      goto out;
    }

  display = gdk_display_get_default ();
  context = gdk_display_get_app_launch_context (display);

  if (!g_app_info_launch (app_info, NULL, (GAppLaunchContext *) context,
      &error))
    {
      g_warning ("Failed to launch %s: %s", name, error->message);
      g_error_free (error);
      goto out;
    }

out:
  tp_clear_object (&app_info);
  tp_clear_object (&context);
  g_free (path);
  g_free (cmd);
}
static void
location_manager_dispose (GObject *object)
{
  EmpathyLocationManager *self = (EmpathyLocationManager *) object;
  void (*dispose) (GObject *) =
    G_OBJECT_CLASS (empathy_location_manager_parent_class)->dispose;

  tp_clear_object (&self->priv->account_manager);
  tp_clear_object (&self->priv->gsettings_loc);
  tp_clear_pointer (&self->priv->location, g_hash_table_unref);

  if (dispose != NULL)
    dispose (object);
}
static void
empathy_server_tls_handler_finalize (GObject *object)
{
    EmpathyServerTLSHandlerPriv *priv = GET_PRIV (object);

    DEBUG ("%p", object);

    tp_clear_object (&priv->channel);
    tp_clear_object (&priv->certificate);
    g_strfreev (priv->reference_identities);
    g_free (priv->hostname);

    G_OBJECT_CLASS (empathy_server_tls_handler_parent_class)->finalize (object);
}
static void
presence_manager_dispose (GObject *object)
{
  EmpathyPresenceManager *self = (EmpathyPresenceManager *) object;

  tp_clear_object (&self->priv->gs_proxy);
  tp_clear_object (&self->priv->manager);

  tp_clear_object (&self->priv->connectivity);
  tp_clear_pointer (&self->priv->connect_times, g_hash_table_unref);

  next_away_stop (EMPATHY_PRESENCE_MANAGER (object));

  G_OBJECT_CLASS (empathy_presence_manager_parent_class)->dispose (object);
}
Ejemplo n.º 16
0
static void
contact_toggle_cell_data_func (GtkTreeViewColumn *tree_column,
    GtkCellRenderer *cell,
    GtkTreeModel *tree_model,
    GtkTreeIter *iter,
    EmpathyIndividualLinker *self)
{
  EmpathyIndividualLinkerPriv *priv;
  FolksIndividual *individual;
  gboolean is_group, individual_added;

  priv = GET_PRIV (self);

  gtk_tree_model_get (tree_model, iter,
      EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group,
      EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
      -1);

  individual_added = GPOINTER_TO_UINT (g_hash_table_lookup (
      priv->changed_individuals, individual));

  /* We don't want to show checkboxes next to the group rows.
   * All checkboxes should be sensitive except the checkbox for the start
   * individual, which should be permanently active and insensitive */
  g_object_set (cell,
      "visible", !is_group,
      "sensitive", individual != priv->start_individual,
      "activatable", individual != priv->start_individual,
      "active", individual_added || individual == priv->start_individual,
      NULL);

  tp_clear_object (&individual);
}
static void
tp_streamed_media_dispose (GObject *object)
{
  EmpathyTpStreamedMediaPriv *priv = GET_PRIV (object);

  DEBUG ("Disposing: %p, %d", object, priv->dispose_has_run);

  if (priv->dispose_has_run)
    return;

  priv->dispose_has_run = TRUE;

  if (priv->channel != NULL)
    {
      g_signal_handlers_disconnect_by_func (priv->channel,
        tp_streamed_media_channel_invalidated_cb, object);

      g_object_unref (priv->channel);
      priv->channel = NULL;
    }

  if (priv->contact != NULL)
      g_object_unref (priv->contact);

  tp_clear_object (&priv->account);

  if (G_OBJECT_CLASS (empathy_tp_streamed_media_parent_class)->dispose)
    G_OBJECT_CLASS (empathy_tp_streamed_media_parent_class)->dispose (object);
}
static void
on_abort (gpointer unused G_GNUC_UNUSED)
{
    g_debug ("McdService aborted, unreffing it");
    mcd_debug_print_tree (mcd);
    tp_clear_object (&mcd);
}
static void hev_impathy_server_sasl_handler_get_password_async_handler(GObject *source,
			GAsyncResult *res, gpointer user_data)
{
	HevImpathyServerSASLHandler *self = HEV_IMPATHY_SERVER_SASL_HANDLER(user_data);
	HevImpathyServerSASLHandlerPrivate *priv =
		HEV_IMPATHY_SERVER_SASL_HANDLER_GET_PRIVATE(self);
	const gchar *password = NULL;
	GError *error = NULL;

	g_debug("%s:%d[%s]", __FILE__, __LINE__, __FUNCTION__);

	password = hev_impathy_keyring_get_account_password_finish(TP_ACCOUNT(source),
				res, &error);
	if(NULL != password)
	{
		priv->password = g_strdup(password);

		/* Do this in an idle so the async result will get there
		 * first. */
		g_idle_add(hev_impathy_server_sasl_handler_give_password, user_data);
	}

	g_simple_async_result_complete(priv->async_init_res);
	tp_clear_object(&priv->async_init_res);
}
Ejemplo n.º 20
0
void
empathy_new_individual_dialog_show_with_individual (GtkWindow *parent,
    FolksIndividual *individual)
{
  GtkWidget *dialog;
  GtkWidget *button;
  EmpathyContact *contact = NULL;
  GtkWidget *contact_widget;

  g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual));

  if (new_individual_dialog)
    {
      gtk_window_present (GTK_WINDOW (new_individual_dialog));
      return;
    }

  /* Create dialog */
  dialog = gtk_dialog_new ();
  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
  gtk_window_set_title (GTK_WINDOW (dialog), _("New Contact"));

  /* Cancel button */
  button = gtk_button_new_with_label (GTK_STOCK_CANCEL);
  gtk_button_set_use_stock (GTK_BUTTON (button), TRUE);
  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button,
      GTK_RESPONSE_CANCEL);
  gtk_widget_show (button);

  /* Add button */
  button = gtk_button_new_with_label (GTK_STOCK_ADD);
  gtk_button_set_use_stock (GTK_BUTTON (button), TRUE);
  gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK);
  gtk_widget_show (button);

  /* Contact info widget */
  if (individual != NULL)
    contact = empathy_contact_dup_from_folks_individual (individual);

  contact_widget = empathy_contact_widget_new (contact);
  gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8);
  gtk_box_pack_start (
      GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
      contact_widget, TRUE, TRUE, 0);
  empathy_contact_widget_set_account_filter (contact_widget,
      can_add_contact_to_account, NULL);
  gtk_widget_show (contact_widget);

  new_individual_dialog = dialog;

  g_signal_connect (dialog, "response", G_CALLBACK (new_individual_response_cb),
      contact_widget);

  if (parent != NULL)
    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);

  gtk_widget_show (dialog);

  tp_clear_object (&contact);
}
static void
dialog_response_cb (GtkDialog *dialog,
    gint response,
    EmpathyIrcNetworkChooser *self)
{
  EmpathyIrcNetworkChooserPriv *priv = GET_PRIV (self);
  EmpathyIrcNetworkChooserDialog *chooser =
    EMPATHY_IRC_NETWORK_CHOOSER_DIALOG (priv->dialog);

  if (response != GTK_RESPONSE_CLOSE &&
      response != GTK_RESPONSE_DELETE_EVENT)
    return;

  if (empathy_irc_network_chooser_dialog_get_changed (chooser))
    {
      tp_clear_object (&priv->network);

      priv->network = g_object_ref (
          empathy_irc_network_chooser_dialog_get_network (chooser));

      update_server_params (self);
      set_label (self);

      g_signal_emit (self, signals[SIG_CHANGED], 0);
    }

  gtk_widget_destroy (priv->dialog);
  priv->dialog = NULL;
}
Ejemplo n.º 22
0
/**
 * empathy_groups_widget_set_group_details:
 * @self: an #EmpathyGroupsWidget
 * @group_details: the #FolksGroupDetails whose membership is to be edited, or
 * %NULL
 *
 * Change the #FolksGroupDetails whose group membership is to be edited by the
 * #EmpathyGroupsWidget.
 */
void
empathy_groups_widget_set_group_details (EmpathyGroupsWidget *self,
    FolksGroupDetails *group_details)
{
  EmpathyGroupsWidgetPriv *priv;

  g_return_if_fail (EMPATHY_IS_GROUPS_WIDGET (self));
  g_return_if_fail (
      group_details == NULL || FOLKS_IS_GROUP_DETAILS (group_details));

  priv = GET_PRIV (self);

  if (group_details == priv->group_details)
    return;

  if (priv->group_details != NULL)
    {
      g_signal_handlers_disconnect_by_func (priv->group_details,
          group_details_group_changed_cb, self);
    }

  tp_clear_object (&priv->group_details);

  if (group_details != NULL)
    {
      priv->group_details = g_object_ref (group_details);

      g_signal_connect (priv->group_details, "group-changed",
          (GCallback) group_details_group_changed_cb, self);

      populate_data (self);
    }

  g_object_notify (G_OBJECT (self), "group-details");
}
static void
mcd_client_registry_dispose (GObject *object)
{
  McdClientRegistry *self = MCD_CLIENT_REGISTRY (object);
  void (*chain_up) (GObject *) =
    G_OBJECT_CLASS (_mcd_client_registry_parent_class)->dispose;

  if (self->priv->dbus_daemon != NULL)
    {
      DBusGConnection *gconn =
        tp_proxy_get_dbus_connection (self->priv->dbus_daemon);
      DBusConnection *dconn = dbus_g_connection_get_connection (gconn);

      dbus_connection_remove_filter (dconn,
          mcd_client_registry_name_owner_filter,
          self);
    }

  tp_clear_object (&self->priv->dbus_daemon);

  if (self->priv->clients != NULL)
    {
      g_hash_table_foreach (self->priv->clients,
          mcd_client_registry_disconnect_client_signals, self);

    }

  tp_clear_pointer (&self->priv->clients, g_hash_table_unref);

  if (chain_up != NULL)
    chain_up (object);
}
Ejemplo n.º 24
0
static gboolean
update_list_mode_foreach (GtkTreeModel *model,
    GtkTreePath *path,
    GtkTreeIter *iter,
    EmpathyPersonaStore *self)
{
  EmpathyPersonaStorePriv *priv;
  FolksPersona *persona;
  GdkPixbuf *pixbuf_status;

  priv = GET_PRIV (self);

  gtk_tree_model_get (model, iter,
      EMPATHY_PERSONA_STORE_COL_PERSONA, &persona,
      -1);

  if (persona == NULL)
    return FALSE;

  /* get icon from hash_table */
  pixbuf_status = get_persona_status_icon (self, persona);

  gtk_list_store_set (GTK_LIST_STORE (self), iter,
      EMPATHY_PERSONA_STORE_COL_ICON_STATUS, pixbuf_status,
      EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR_VISIBLE, priv->show_avatars,
      -1);

  tp_clear_object (&persona);

  return FALSE;
}
static void
empathy_server_sasl_handler_get_password_async_cb (GObject *source,
    GAsyncResult *result,
    gpointer user_data)
{
  EmpathyServerSASLHandlerPriv *priv;
  const gchar *password;
  GError *error = NULL;

  priv = EMPATHY_SERVER_SASL_HANDLER (user_data)->priv;

  password = empathy_keyring_get_account_password_finish (TP_ACCOUNT (source),
      result, &error);

  if (password != NULL)
    {
      priv->password = g_strdup (password);

      /* Do this in an idle so the async result will get there
       * first. */
      g_idle_add (empathy_server_sasl_handler_give_password, user_data);
    }

  g_simple_async_result_complete (priv->async_init_res);
  tp_clear_object (&priv->async_init_res);
}
Ejemplo n.º 26
0
static void
query_unread_mails_cb (GObject *source_object,
    GAsyncResult *res,
    gpointer user_data)
{
  GError *error = NULL;
  WockyPorter *porter = WOCKY_PORTER (source_object);
  WockyStanza *reply = wocky_porter_send_iq_finish (porter, res, &error);
  GabbleConnection *conn = GABBLE_CONNECTION (user_data);

  if (reply == NULL ||
      wocky_stanza_extract_errors (reply, NULL, &error, NULL, NULL))
    {
      DEBUG ("Failed retreive unread emails information: %s", error->message);
      g_error_free (error);
    }
  else if (conn->mail_priv->interested)
    {
      WockyNode *node = wocky_node_get_child (
          wocky_stanza_get_top_node (reply), "mailbox");

      DEBUG ("Got unread mail details");

      if (node != NULL)
        store_unread_mails (conn, node);
    }
  /* else we no longer care about unread mail, so ignore it */

  tp_clear_object (&reply);

  return_from_request_inbox_url (conn);
}
static void
individual_edit_dialog_set_individual (
    EmpathyIndividualEditDialog *dialog,
    FolksIndividual *individual)
{
  EmpathyIndividualEditDialogPriv *priv;

  g_return_if_fail (EMPATHY_INDIVIDUAL_EDIT_DIALOG (dialog));
  g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual));

  priv = GET_PRIV (dialog);

  /* Remove the old Individual */
  if (priv->individual != NULL)
    {
      g_signal_handlers_disconnect_by_func (priv->individual,
          (GCallback) individual_removed_cb, dialog);
    }

  tp_clear_object (&priv->individual);

  /* Add the new Individual */
  priv->individual = individual;

  if (individual != NULL)
    {
      g_object_ref (individual);
      g_signal_connect (individual, "removed",
          (GCallback) individual_removed_cb, dialog);

      /* Update the UI */
      empathy_individual_widget_set_individual (
          EMPATHY_INDIVIDUAL_WIDGET (priv->individual_widget), individual);
    }
}
Ejemplo n.º 28
0
static void
auth_channel_closed_cb (GabbleServerSaslChannel *channel,
    GabbleAuthManager *self)
{
  SavedError tmp = { NULL, NULL, 0 };

  tp_channel_manager_emit_channel_closed_for_object (self,
      TP_EXPORTABLE_CHANNEL (channel));

  g_assert (self->priv->channel == channel);

  /* this is our last chance to find out why it failed */
  if (gabble_server_sasl_channel_get_failure_details (channel,
      &tmp.name, &tmp.details, &tmp.reason))
    self->priv->error = g_slice_dup (SavedError, &tmp);

  g_signal_handler_disconnect (self->priv->channel, self->priv->closed_id);
  tp_clear_object (&self->priv->channel);

  /* discard info we were holding in case we wanted to fall back */
  g_slist_foreach (self->priv->mechanisms, (GFunc) g_free, NULL);
  tp_clear_pointer (&self->priv->mechanisms, g_slist_free);
  tp_clear_pointer (&self->priv->server, g_free);
  tp_clear_pointer (&self->priv->session_id, g_free);
  tp_clear_pointer (&self->priv->username, g_free);
}
static void
avatar_cell_data_func (GtkTreeViewColumn *tree_column,
    GtkCellRenderer *cell,
    GtkTreeModel *model,
    GtkTreeIter *iter,
    EmpathyPersonaView *self)
{
  GdkPixbuf *pixbuf;
  gboolean show_avatar, is_active;

  gtk_tree_model_get (model, iter,
      EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR, &pixbuf,
      EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR_VISIBLE, &show_avatar,
      EMPATHY_PERSONA_STORE_COL_IS_ACTIVE, &is_active,
      -1);

  g_object_set (cell,
      "visible", show_avatar,
      "pixbuf", pixbuf,
      NULL);

  tp_clear_object (&pixbuf);

  cell_set_background (self, cell, is_active);
}
Ejemplo n.º 30
0
static gint
state_sort_func (GtkTreeModel *model,
    GtkTreeIter *iter_a,
    GtkTreeIter *iter_b,
    gpointer user_data)
{
  gint ret_val;
  gchar *name_a, *name_b;
  FolksPersona *persona_a, *persona_b;

  gtk_tree_model_get (model, iter_a,
          EMPATHY_PERSONA_STORE_COL_NAME, &name_a,
          EMPATHY_PERSONA_STORE_COL_PERSONA, &persona_a,
          -1);
  gtk_tree_model_get (model, iter_b,
          EMPATHY_PERSONA_STORE_COL_NAME, &name_b,
          EMPATHY_PERSONA_STORE_COL_PERSONA, &persona_b,
          -1);

  if (persona_a == NULL || persona_b == NULL) {
    ret_val = 0;
    goto free_and_out;
  }

  /* If we managed to get this far, we can start looking at
   * the presences.
   */
  ret_val = -tp_connection_presence_type_cmp_availability (
      folks_presence_get_presence_type (FOLKS_PRESENCE (persona_a)),
      folks_presence_get_presence_type (FOLKS_PRESENCE (persona_b)));

  if (ret_val == 0) {
    /* Fallback: compare by name et al. */
    ret_val = sort_personas (persona_a, persona_b);
  }

free_and_out:
  g_free (name_a);
  g_free (name_b);

  tp_clear_object (&persona_a);
  tp_clear_object (&persona_b);

  return ret_val;
}