static void hev_impathy_tls_verifier_finalize(GObject * obj)
{
	HevImpathyTLSVerifier * self = HEV_IMPATHY_TLS_VERIFIER(obj);
	HevImpathyTLSVerifierPrivate * priv = HEV_IMPATHY_TLS_VERIFIER_GET_PRIVATE(self);

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

	if(priv->cert_chain)
	{
		tp_clear_pointer(&priv->cert_chain, g_ptr_array_unref);
		priv->cert_chain = NULL;
	}

	if(priv->trusted_ca_list)
	{
		tp_clear_pointer(&priv->trusted_ca_list, g_ptr_array_unref);
		priv->trusted_ca_list = NULL;
	}

	if(priv->details)
	{
		tp_clear_boxed(G_TYPE_HASH_TABLE, &priv->details);
		priv->details = NULL;
	}

	if(priv->hostname)
	{
		g_free(priv->hostname);
		priv->hostname = NULL;
	}

	G_OBJECT_CLASS(hev_impathy_tls_verifier_parent_class)->finalize(obj);
}
static void
salut_presence_cache_dispose (GObject *object)
{
  SalutPresenceCache *self = SALUT_PRESENCE_CACHE (object);
  SalutPresenceCachePrivate *priv = SALUT_PRESENCE_CACHE_PRIV (self);

  if (priv->dispose_has_run)
    return;

  DEBUG ("dispose called");

  priv->dispose_has_run = TRUE;

  g_hash_table_unref (priv->capabilities);
  priv->capabilities = NULL;

  g_hash_table_unref (priv->disco_pending);
  priv->disco_pending = NULL;

  tp_clear_pointer (&(priv->not_xep_capabilities.caps),
      gabble_capability_set_free);
  tp_clear_pointer (&(priv->not_xep_capabilities.data_forms),
      g_ptr_array_unref);

  if (G_OBJECT_CLASS (salut_presence_cache_parent_class)->dispose)
    G_OBJECT_CLASS (salut_presence_cache_parent_class)->dispose (object);
}
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
capability_info_free (CapabilityInfo *info)
{
  tp_clear_pointer (&info->caps, gabble_capability_set_free);
  tp_clear_pointer (&info->data_forms, g_ptr_array_unref);

  g_slice_free (CapabilityInfo, info);
}
static void
tpy_call_channel_dispose (GObject *obj)
{
  TpyCallChannel *self = (TpyCallChannel *) obj;

  tp_clear_pointer (&self->priv->contents, g_ptr_array_unref);
  tp_clear_pointer (&self->priv->details, g_hash_table_unref);
  tp_clear_pointer (&self->priv->members, g_hash_table_unref);

  G_OBJECT_CLASS (tpy_call_channel_parent_class)->dispose (obj);
}
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);
}
static void
gabble_im_factory_close_all (GabbleImFactory *self)
{
  /* Use a temporary variable (the macro does this) because we don't want
   * im_channel_closed_cb to remove the channel from the hash table a
   * second time */
  tp_clear_pointer (&self->priv->channels, g_hash_table_unref);

  if (self->priv->status_changed_id != 0)
    {
      g_signal_handler_disconnect (self->priv->conn,
          self->priv->status_changed_id);
      self->priv->status_changed_id = 0;
    }

  if (self->priv->message_cb_id != 0)
    {
      WockyPorter *porter = gabble_connection_dup_porter (self->priv->conn);

      wocky_porter_unregister_handler (porter, self->priv->message_cb_id);
      self->priv->message_cb_id = 0;

      wocky_porter_unregister_handler (porter, self->priv->delivery_report_cb_id);
      self->priv->delivery_report_cb_id = 0;

      g_object_unref (porter);
    }
}
static void
tp_base_media_call_stream_set_credentials (TpSvcCallStreamInterfaceMedia *iface,
    const gchar *username,
    const gchar *password,
    DBusGMethodInvocation *context)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (iface);

  g_free (self->priv->username);
  g_free (self->priv->password);
  self->priv->username = g_strdup (username);
  self->priv->password = g_strdup (password);

  tp_clear_pointer (&self->priv->local_candidates, g_ptr_array_unref);
  self->priv->local_candidates = g_ptr_array_new_with_free_func (
      (GDestroyNotify) tp_value_array_free);

  g_object_notify (G_OBJECT (self), "local-candidates");
  g_object_notify (G_OBJECT (self), "local-credentials");

  tp_svc_call_stream_interface_media_emit_local_credentials_changed (self,
      username, password);

  tp_svc_call_stream_interface_media_return_from_set_credentials (context);
}
static void
tpaw_calendar_button_finalize (GObject *object)
{
  TpawCalendarButton *self = (TpawCalendarButton *) object;

  tp_clear_pointer (&self->priv->date, g_date_free);

  G_OBJECT_CLASS (tpaw_calendar_button_parent_class)->finalize (object);
}
static void
empathy_sound_manager_dispose (GObject *object)
{
  EmpathySoundManager *self = (EmpathySoundManager *) object;

  tp_clear_pointer (&self->priv->repeating_sounds, g_hash_table_unref);
  tp_clear_object (&self->priv->gsettings_sound);

  G_OBJECT_CLASS (empathy_sound_manager_parent_class)->dispose (object);
}
static void
tp_base_media_call_stream_dispose (GObject *object)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (object);

  tp_clear_pointer (&self->priv->endpoints, _tp_object_list_free);

  if (G_OBJECT_CLASS (tp_base_media_call_stream_parent_class)->dispose)
    G_OBJECT_CLASS (tp_base_media_call_stream_parent_class)->dispose (object);
}
static void
tpl_call_event_dispose (GObject *object)
{
  TplCallEventPriv *priv = TPL_CALL_EVENT (object)->priv;

  tp_clear_object (&priv->end_actor);
  tp_clear_pointer (&priv->detailed_end_reason, g_free);

  G_OBJECT_CLASS (tpl_call_event_parent_class)->dispose (object);
}
static void
tp_call_stream_dispose (GObject *object)
{
  TpCallStream *self = (TpCallStream *) object;

  g_clear_object (&self->priv->content);
  g_clear_object (&self->priv->connection);
  tp_clear_pointer (&self->priv->remote_members, g_hash_table_unref);

  G_OBJECT_CLASS (tp_call_stream_parent_class)->dispose (object);
}
static void
empathy_server_sasl_handler_finalize (GObject *object)
{
  EmpathyServerSASLHandlerPriv *priv = EMPATHY_SERVER_SASL_HANDLER (object)->priv;

  DEBUG ("%p", object);

  tp_clear_pointer (&priv->password, g_free);

  G_OBJECT_CLASS (empathy_server_sasl_handler_parent_class)->finalize (object);
}
Exemple #15
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
auth_context_free (AuthContext *ctx)
{
  g_clear_object (&ctx->channel);
  g_clear_object (&ctx->service);
  tp_clear_pointer (&ctx->auth_data, ag_auth_data_unref);
  g_clear_object (&ctx->session);
  g_clear_object (&ctx->identity);
  g_free (ctx->username);

  g_slice_free (AuthContext, ctx);
}
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);
}
/**
 * tp_base_media_call_stream_set_relay_info:
 * @self: a #TpBaseMediaCallStream
 * @relays: the new relays info
 *
 * Set the relays info. The #GPtrArray should have a free_func defined such as
 * g_ptr_array_ref() is enough to keep the data and g_ptr_array_unref() is
 * enough to release it later.
 *
 * Note that this replaces the previously set relays, it is not an addition.
 *
 * Since: 0.17.5
 */
void
tp_base_media_call_stream_set_relay_info (TpBaseMediaCallStream *self,
    GPtrArray *relays)
{
  g_return_if_fail (TP_IS_BASE_MEDIA_CALL_STREAM (self));
  g_return_if_fail (relays != NULL);

  tp_clear_pointer (&self->priv->relay_info, g_ptr_array_unref);
  self->priv->relay_info = g_ptr_array_ref (relays);

  tp_svc_call_stream_interface_media_emit_relay_info_changed (self,
      self->priv->relay_info);

  maybe_got_server_info (self);
}
static void hev_impathy_server_sasl_handler_finalize(GObject * obj)
{
	HevImpathyServerSASLHandler * self = HEV_IMPATHY_SERVER_SASL_HANDLER(obj);
	HevImpathyServerSASLHandlerPrivate * priv = HEV_IMPATHY_SERVER_SASL_HANDLER_GET_PRIVATE(self);

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

	if(priv->password)
	{
		tp_clear_pointer(&priv->password, g_free);
		priv->password = NULL;
	}

	G_OBJECT_CLASS(hev_impathy_server_sasl_handler_parent_class)->finalize(obj);
}
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);
}
static void
log_window_chats_set_selected (EmpathyLogWindow *window)
{
	GtkTreeView          *view;
	GtkTreeModel         *model;
	GtkTreeSelection     *selection;
	GtkTreeIter           iter;
	GtkTreePath          *path;
	gboolean              ok;

	view = GTK_TREE_VIEW (window->treeview_chats);
	model = gtk_tree_view_get_model (view);
	selection = gtk_tree_view_get_selection (view);

	if (!gtk_tree_model_get_iter_first (model, &iter)) {
		return;
	}

	for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) {
		TpAccount *this_account;
		gchar     *this_chat_id;
		gboolean   this_is_chatroom;

		gtk_tree_model_get (model, &iter,
				    COL_CHAT_ACCOUNT, &this_account,
				    COL_CHAT_ID, &this_chat_id,
				    COL_CHAT_IS_CHATROOM, &this_is_chatroom,
				    -1);

		if (this_account == window->selected_account &&
		    !tp_strdiff (this_chat_id, window->selected_chat_id) &&
		    this_is_chatroom == window->selected_is_chatroom) {
			gtk_tree_selection_select_iter (selection, &iter);
			path = gtk_tree_model_get_path (model, &iter);
			gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
			gtk_tree_path_free (path);
			g_object_unref (this_account);
			g_free (this_chat_id);
			break;
		}

		g_object_unref (this_account);
		g_free (this_chat_id);
	}

	tp_clear_object (&window->selected_account);
	tp_clear_pointer (&window->selected_chat_id, g_free);
}
static void
tp_base_media_call_stream_finalize (GObject *object)
{
  TpBaseMediaCallStream *self = TP_BASE_MEDIA_CALL_STREAM (object);

  tp_clear_pointer (&self->priv->local_candidates, g_ptr_array_unref);
  tp_clear_pointer (&self->priv->stun_servers, g_ptr_array_unref);
  tp_clear_pointer (&self->priv->relay_info, g_ptr_array_unref);
  tp_clear_pointer (&self->priv->username, g_free);
  tp_clear_pointer (&self->priv->password, g_free);
  tp_clear_pointer (&self->priv->receiving_requests, tp_intset_destroy);

  G_OBJECT_CLASS (tp_base_media_call_stream_parent_class)->finalize (object);
}
static void
preferences_theme_changed_cb (GtkComboBox        *combo,
			      EmpathyPreferences *preferences)
{
	EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
	GtkTreeIter   iter;

	if (gtk_combo_box_get_active_iter (combo, &iter)) {
		GtkTreeModel *model;
		gboolean      is_adium;
		gchar        *name;
		gchar        *path;
		GHashTable   *info;

		model = gtk_combo_box_get_model (combo);
		gtk_tree_model_get (model, &iter,
				    COL_THEME_IS_ADIUM, &is_adium,
				    COL_THEME_NAME, &name,
				    COL_THEME_ADIUM_PATH, &path,
				    COL_THEME_ADIUM_INFO, &info,
				    -1);

		g_settings_set_string (priv->gsettings_chat,
				       EMPATHY_PREFS_CHAT_THEME,
				       name);
		if (is_adium) {
			gboolean variant;

			g_settings_set_string (priv->gsettings_chat,
					       EMPATHY_PREFS_CHAT_ADIUM_PATH,
					       path);

			variant = preferences_theme_variants_fill (preferences, info);
			gtk_widget_set_visible (priv->hbox_chat_theme_variant, variant);
		} else {
			gtk_widget_hide (priv->hbox_chat_theme_variant);
		}
		g_free (name);
		g_free (path);
		tp_clear_pointer (&info, g_hash_table_unref);
	}
}
void
tpaw_calendar_button_set_date (TpawCalendarButton *self,
    GDate *date)
{
  if (date == self->priv->date)
    return;

  tp_clear_pointer (&self->priv->date, g_date_free);

  if (date != NULL)
    {
      /* There is no g_date_copy()... */
      self->priv->date = g_date_new_dmy (date->day, date->month, date->year);
    }

  update_label (self);
  update_calendar (self);

  g_signal_emit (self, signals[DATE_CHANGED], 0, self->priv->date);
}
static void
empathy_chat_manager_finalize (GObject *object)
{
  EmpathyChatManager *self = EMPATHY_CHAT_MANAGER (object);
  EmpathyChatManagerPriv *priv = GET_PRIV (self);

  if (priv->closed_queue != NULL)
    {
      g_queue_foreach (priv->closed_queue, (GFunc) chat_data_free, NULL);
      g_queue_free (priv->closed_queue);
      priv->closed_queue = NULL;
    }

  tp_clear_pointer (&priv->messages, g_hash_table_unref);

  tp_clear_object (&priv->handler);
  tp_clear_object (&priv->chatroom_mgr);
  tp_clear_object (&priv->individual_mgr);

  G_OBJECT_CLASS (empathy_chat_manager_parent_class)->finalize (object);
}
static void
on_call_state_changed_cb (TpProxy *proxy,
    guint call_state,
    guint call_flags,
    const GValueArray *call_state_reason,
    GHashTable *call_state_details,
    gpointer user_data,
    GObject *weak_object)
{
  TpyCallChannel *self = TPY_CALL_CHANNEL (proxy);

  DEBUG ("Call state changed");

  self->priv->state = call_state;
  self->priv->flags = call_flags;

  tp_clear_pointer (&self->priv->details, g_hash_table_unref);
  self->priv->details = g_hash_table_ref (call_state_details);

  g_signal_emit (self, _signals[STATE_CHANGED], 0,
      call_state, call_flags, call_state_reason, call_state_details);
}
static void
teardown (Test *test,
    gconstpointer data G_GNUC_UNUSED)
{
  TpConnection *conn;
  GError *error = NULL;

  g_clear_error (&test->error);
  tp_clear_pointer (&test->mainloop, g_main_loop_unref);
  tp_clear_object (&test->conn);

  /* disconnect the connection so we don't leak it */
  conn = tp_connection_new (test->dbus, test->conn_name, test->conn_path,
      &error);
  g_assert (conn != NULL);
  g_assert_no_error (error);

  tp_tests_connection_assert_disconnect_succeeds (conn);

  g_assert (!tp_connection_run_until_ready (conn, FALSE, &error, NULL));
  g_assert_error (error, TP_ERROR, TP_ERROR_CANCELLED);
  g_clear_error (&error);

  test->service_conn_as_base = NULL;
  g_object_unref (test->service_conn);
  g_free (test->conn_name);
  g_free (test->conn_path);

  g_object_unref (test->dbus);
  test->dbus = NULL;
  g_object_unref (test->client_bus);
  test->client_bus = NULL;

  dbus_g_connection_unref (test->client_dbusglib);
  dbus_connection_close (test->client_libdbus);
  dbus_connection_unref (test->client_libdbus);
}
void
gabble_call_member_dispose (GObject *object)
{
  GabbleCallMember *self = GABBLE_CALL_MEMBER (object);
  GabbleCallMemberPrivate *priv = self->priv;
  GList *l;

  if (priv->dispose_has_run)
    return;

  priv->dispose_has_run = TRUE;

  tp_clear_object (&priv->session);

  for (l = priv->contents ; l != NULL; l = g_list_next (l))
    g_object_unref (l->data);

  tp_clear_pointer (&priv->contents, g_list_free);

  /* release any references held by the object here */

  if (G_OBJECT_CLASS (gabble_call_member_parent_class)->dispose)
    G_OBJECT_CLASS (gabble_call_member_parent_class)->dispose (object);
}
static AgAccountService *
uoa_password_common (TpAccount *tp_account,
    GSimpleAsyncResult *result,
    AgAuthData **ret_auth_data)
{
  const GValue *storage_id;
  AgAccountId account_id;
  AgManager *manager = NULL;
  AgAccount *account = NULL;
  GList *l;
  AgAccountService *service = NULL;
  AgAuthData *auth_data = NULL;

  g_assert (ret_auth_data != NULL);
  *ret_auth_data = NULL;

  storage_id = tp_account_get_storage_identifier (tp_account);
  account_id = g_value_get_uint (storage_id);
  if (account_id == 0)
    {
      g_simple_async_result_set_error (result,
          TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "StorageId is invalid, cannot get the AgAccount for this TpAccount");
      g_simple_async_result_complete_in_idle (result);
      goto error;
    }

  manager = empathy_uoa_manager_dup ();
  account = ag_manager_get_account (manager, account_id);

  /* Assuming there is only one IM service */
  l = ag_account_list_services_by_type (account, EMPATHY_UOA_SERVICE_TYPE);
  if (l == NULL)
    {
      g_simple_async_result_set_error (result,
          TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "AgAccount has no IM service");
      g_simple_async_result_complete_in_idle (result);
      goto error;
    }
  service = ag_account_service_new (account, l->data);
  ag_service_list_free (l);

  auth_data = ag_account_service_get_auth_data (service);
  if (auth_data == NULL)
    {
      g_simple_async_result_set_error (result,
          TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "Service has no AgAuthData");
      g_simple_async_result_complete_in_idle (result);
      goto error;
    }

  if (tp_strdiff (ag_auth_data_get_mechanism (auth_data), "password") ||
      tp_strdiff (ag_auth_data_get_method (auth_data), "password"))
    {
      g_simple_async_result_set_error (result,
          TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
          "Service does not use password authentication");
      g_simple_async_result_complete_in_idle (result);
      goto error;
    }

  g_object_unref (manager);
  g_object_unref (account);

  *ret_auth_data = auth_data;
  return service;

error:
  g_clear_object (&manager);
  g_clear_object (&account);
  g_clear_object (&service);
  tp_clear_pointer (&auth_data, ag_auth_data_unref);
  return NULL;
}
static void
reload_contact_info (TpawUserInfo *self)
{
  TpConnection *connection;
  TpContact *contact = NULL;
  TpContactInfoFlags flags;

  /* Cancel previous RequestContactInfo, if any */
  if (self->priv->details_cancellable != NULL)
    g_cancellable_cancel (self->priv->details_cancellable);
  g_clear_object (&self->priv->details_cancellable);

  /* Remove current contact info widgets, if any */
  gtk_container_foreach (GTK_CONTAINER (self), grid_foreach_cb, NULL);
  gtk_widget_hide (self->priv->details_label);
  gtk_widget_hide (self->priv->details_spinner);

  tp_clear_pointer (&self->priv->details_to_set, tp_contact_info_list_free);
  self->priv->details_changed = FALSE;

  connection = tp_account_get_connection (self->priv->account);
  if (connection != NULL)
    {
      contact = tp_connection_get_self_contact (connection);

      /* FIXME: we should rely on the factory to do this, see bgo#706892 */
      if (!tp_proxy_is_prepared (connection,
            TP_CONNECTION_FEATURE_CONTACT_INFO) &&
          !self->priv->tried_preparing_contact_info)
        {
          GQuark features[] = { TP_CONNECTION_FEATURE_CONTACT_INFO, 0 };

          /* Prevent an infinite loop if the connection doesn't implement
           * ContactInfo, see bgo#709677 */
          self->priv->tried_preparing_contact_info = TRUE;

          tp_proxy_prepare_async (connection, features,
              connection_contact_info_prepared_cb, g_object_ref (self));
        }
    }

  /* Display infobar if we don't have a self contact (probably offline) */
  if (contact == NULL)
    {
      GtkWidget *infobar;
      GtkWidget *content;
      GtkWidget *label;

      infobar = gtk_info_bar_new ();
      gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_INFO);
      content = gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar));
      label = gtk_label_new (_("Go online to edit your personal information."));
      gtk_container_add (GTK_CONTAINER (content), label);
      gtk_widget_show (label);

      gtk_grid_attach_next_to ((GtkGrid *) self, infobar,
          NULL, GTK_POS_BOTTOM, 3, 1);
      gtk_widget_show (infobar);

      g_object_set_data (G_OBJECT (infobar),
          DATA_IS_CONTACT_INFO, (gpointer) TRUE);
      return;
    }

  if (!tp_proxy_has_interface_by_id (connection,
          TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO))
    return;

  flags = tp_connection_get_contact_info_flags (connection);
  if ((flags & TP_CONTACT_INFO_FLAG_CAN_SET) == 0)
    return;

  /* Request the contact's info */
  gtk_widget_show (self->priv->details_spinner);
  gtk_spinner_start (GTK_SPINNER (self->priv->details_spinner));

  g_assert (self->priv->details_cancellable == NULL);
  self->priv->details_cancellable = g_cancellable_new ();
  tp_contact_request_contact_info_async (contact,
      self->priv->details_cancellable, request_contact_info_cb,
      self);
}