diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c
index 2a009b3..5587677 100644
--- a/libempathy/empathy-dispatcher.c
+++ b/libempathy/empathy-dispatcher.c
@@ -59,7 +59,6 @@ typedef struct
   GHashTable *connections;
   GHashTable *outstanding_classes_requests;
 
-  GHashTable *request_channel_class_async_ids;
   /* reffed (TpAccount *) => gulong
    * Signal handler ID of the "status-changed" signal */
   GHashTable *status_changed_handlers;
@@ -262,17 +261,6 @@ dispatcher_status_changed_cb (TpAccount *account,
     dispatcher_init_connection_if_needed (self, conn);
 }
 
-static void
-remove_idle_handlers (gpointer key,
-                      gpointer value,
-                      gpointer user_data)
-{
-  guint source_id;
-
-  source_id = GPOINTER_TO_UINT (value);
-  g_source_remove (source_id);
-}
-
 static GObject *
 dispatcher_constructor (GType type,
                         guint n_construct_params,
@@ -329,13 +317,6 @@ dispatcher_finalize (GObject *object)
   GList *list;
   gpointer account, id;
 
-  if (priv->request_channel_class_async_ids != NULL)
-    {
-      g_hash_table_foreach (priv->request_channel_class_async_ids,
-        remove_idle_handlers, NULL);
-      g_hash_table_destroy (priv->request_channel_class_async_ids);
-    }
-
   g_hash_table_iter_init (&iter, priv->outstanding_classes_requests);
   while (g_hash_table_iter_next (&iter, &connection, (gpointer *) &list))
     {
@@ -473,8 +454,6 @@ empathy_dispatcher_init (EmpathyDispatcher *self)
       "account-validity-changed", G_CALLBACK (account_validity_changed_cb),
       self, 0);
 
-  priv->request_channel_class_async_ids = g_hash_table_new (g_direct_hash,
-    g_direct_equal);
   priv->status_changed_handlers = g_hash_table_new_full (NULL, NULL,
       (GDestroyNotify) g_object_unref, NULL);
 }
@@ -679,48 +658,6 @@ empathy_dispatcher_find_channel_classes (EmpathyDispatcher *self,
   return matching_classes;
 }
 
-static gboolean
-find_channel_class_idle_cb (gpointer user_data)
-{
-  GList *retval;
-  GList *requests;
-  FindChannelRequest *request = user_data;
-  ConnectionData *cd;
-  gboolean is_ready = TRUE;
-  EmpathyDispatcherPriv *priv = GET_PRIV (request->dispatcher);
-
-  g_hash_table_remove (priv->request_channel_class_async_ids, request);
-
-  cd = g_hash_table_lookup (priv->connections, request->connection);
-
-  if (cd == NULL)
-    is_ready = FALSE;
-  else if (cd->requestable_channels == NULL)
-    is_ready = FALSE;
-
-  if (is_ready)
-    {
-      retval = empathy_dispatcher_find_channel_classes (request->dispatcher,
-          request->connection, request->channel_type, request->handle_type,
-          request->properties);
-
-      request->callback (retval, request->user_data);
-      free_find_channel_request (request);
-      g_list_free (retval);
-
-      return FALSE;
-    }
-
-  requests = g_hash_table_lookup (priv->outstanding_classes_requests,
-      request->connection);
-  requests = g_list_prepend (requests, request);
-
-  g_hash_table_insert (priv->outstanding_classes_requests,
-      request->connection, requests);
-
-  return FALSE;
-}
-
 static GArray *
 setup_varargs (va_list var_args,
                const char *channel_namespace,
@@ -822,64 +759,3 @@ empathy_dispatcher_find_requestable_channel_classes
 
   return retval;
 }
-
-/**
- * empathy_dispatcher_find_requestable_channel_classes_async:
- * @dispatcher: an #EmpathyDispatcher
- * @connection: a #TpConnection
- * @channel_type: a string identifying the type of the channel to lookup
- * @handle_type: the handle type for the channel
- * @callback: the callback to call when @connection is ready
- * @user_data: the user data to pass to @callback
- * @first_property_name: %NULL, or the name of the first fixed property,
- * followed optionally by more names, followed by %NULL.
- *
- * Please see the documentation of
- * empathy_dispatcher_find_requestable_channel_classes() for a detailed
- * description of this function.
- */
-void
-empathy_dispatcher_find_requestable_channel_classes_async
-                                 (EmpathyDispatcher *self,
-                                  TpConnection *connection,
-                                  const gchar *channel_type,
-                                  guint handle_type,
-                                  EmpathyDispatcherFindChannelClassCb callback,
-                                  gpointer user_data,
-                                  const char *first_property_name,
-                                  ...)
-{
-  va_list var_args;
-  GArray *properties;
-  FindChannelRequest *request;
-  EmpathyDispatcherPriv *priv;
-  guint source_id;
-
-  g_return_if_fail (EMPATHY_IS_DISPATCHER (self));
-  g_return_if_fail (TP_IS_CONNECTION (connection));
-  g_return_if_fail (channel_type != NULL);
-  g_return_if_fail (handle_type != 0);
-
-  priv = GET_PRIV (self);
-
-  va_start (var_args, first_property_name);
-
-  properties = setup_varargs (var_args, channel_type, first_property_name);
-
-  va_end (var_args);
-
-  /* append another request for this connection */
-  request = g_slice_new0 (FindChannelRequest);
-  request->dispatcher = g_object_ref (self);
-  request->channel_type = g_strdup (channel_type);
-  request->handle_type = handle_type;
-  request->connection = connection;
-  request->callback = callback;
-  request->user_data = user_data;
-  request->properties = properties;
-
-  source_id = g_idle_add (find_channel_class_idle_cb, request);
-
-  g_hash_table_insert (priv->request_channel_class_async_ids,
-    request, GUINT_TO_POINTER (source_id));
-}
diff --git a/libempathy/empathy-dispatcher.h b/libempathy/empathy-dispatcher.h
index cd54fa5..2f786db 100644
--- a/libempathy/empathy-dispatcher.h
+++ b/libempathy/empathy-dispatcher.h
@@ -70,12 +70,6 @@ void empathy_dispatcher_join_muc (TpAccount *account,
   const gchar *roomname,
   gint64 timestamp);
 
-void empathy_dispatcher_find_requestable_channel_classes_async
-    (EmpathyDispatcher *dispatcher, TpConnection *connection,
-     const gchar *channel_type, guint handle_type,
-     EmpathyDispatcherFindChannelClassCb callback, gpointer user_data,
-     const char *first_property_name, ...);
-
 GList * empathy_dispatcher_find_requestable_channel_classes
     (EmpathyDispatcher *dispatcher, TpConnection *connection,
      const gchar *channel_type, guint handle_type,
diff --git a/libempathy/empathy-ft-handler.c b/libempathy/empathy-ft-handler.c
index f18278a..9d08911 100644
--- a/libempathy/empathy-ft-handler.c
+++ b/libempathy/empathy-ft-handler.c
@@ -1031,35 +1031,53 @@ callbacks_data_free (gpointer user_data)
   g_slice_free (CallbacksData, data);
 }
 
-static void
+static gboolean
 set_content_hash_type_from_classes (EmpathyFTHandler *handler,
-    GList *classes)
+    GPtrArray *classes)
 {
-  GValueArray *class;
-  GValue *v;
-  GList *l;
   GArray *possible_values;
   guint value;
-  GHashTable *fprops;
   gboolean valid;
   EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
+  gboolean support_ft = FALSE;
+  guint i;
 
   possible_values = g_array_new (TRUE, TRUE, sizeof (guint));
 
-  for (l = classes; l != NULL; l = l->next)
+  for (i = 0; i < classes->len; i++)
     {
-      class = l->data;
-      v = g_value_array_get_nth (class, 0);
-      fprops = g_value_get_boxed (v);
+      GHashTable *fixed;
+      GStrv allowed;
+      const gchar *chan_type;
+
+      tp_value_array_unpack (g_ptr_array_index (classes, i), 2,
+          &fixed, &allowed);
+
+      chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE);
+
+      if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER))
+        continue;
+
+      if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) !=
+          TP_HANDLE_TYPE_CONTACT)
+        continue;
+
+      support_ft = TRUE;
 
       value = tp_asv_get_uint32
-        (fprops, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType",
+        (fixed, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType",
          &valid);
 
       if (valid)
         g_array_append_val (possible_values, value);
     }
 
+  if (!support_ft)
+    {
+      g_array_free (possible_values, TRUE);
+      return FALSE;
+    }
+
   if (possible_values->len == 0)
     {
       /* there are no channel classes with hash support, disable it. */
@@ -1093,18 +1111,35 @@ out:
 
   DEBUG ("Hash enabled %s; setting content hash type as %u",
          priv->use_hash ? "True" : "False", priv->content_hash_type);
+
+  return TRUE;
 }
 
 static void
-find_ft_channel_classes_cb (GList *channel_classes,
+conn_prepared_cb (GObject *conn,
+    GAsyncResult *result,
     gpointer user_data)
 {
   CallbacksData *data = user_data;
   EmpathyFTHandler *handler = data->handler;
   EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
   GError *myerr = NULL;
+  TpCapabilities *caps;
+  GPtrArray *classes;
+
+  if (!tp_proxy_prepare_finish (conn, result, &myerr))
+    {
+      DEBUG ("Failed to prepare connection: %s", myerr->message);
+
+      data->callback (handler, myerr, data->user_data);
+      goto out;
+    }
+
+  caps = tp_connection_get_capabilities (TP_CONNECTION (conn));
+  classes = tp_capabilities_get_channel_classes (caps);
 
-  if (channel_classes == NULL)
+  /* set whether we support hash and the type of it */
+  if (!set_content_hash_type_from_classes (handler, classes))
     {
       g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK,
           EMPATHY_FT_ERROR_NOT_SUPPORTED,
@@ -1118,13 +1153,11 @@ find_ft_channel_classes_cb (GList *channel_classes,
     }
   else
     {
-      /* set whether we support hash and the type of it */
-      set_content_hash_type_from_classes (handler, channel_classes);
-
       /* get back to the caller now */
       data->callback (handler, NULL, data->user_data);
     }
 
+out:
   callbacks_data_free (data);
 }
 
@@ -1202,11 +1235,14 @@ out:
   else
     {
       /* see if FT/hashing are allowed */
-      empathy_dispatcher_find_requestable_channel_classes_async
-          (priv->dispatcher, empathy_contact_get_connection (priv->contact),
-           TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT,
-           find_ft_channel_classes_cb, cb_data,
-           TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType", NULL);
+      TpConnection *connection;
+      GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
+
+      connection = empathy_contact_get_connection (priv->contact);
+      g_assert (connection != NULL);
+
+      tp_proxy_prepare_async (connection, features,
+          conn_prepared_cb, cb_data);
     }
 }
 
diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c
index c1e911e..f135104 100644
--- a/libempathy/empathy-tp-chat.c
+++ b/libempathy/empathy-tp-chat.c
@@ -30,7 +30,6 @@
 #include "empathy-tp-chat.h"
 #include "empathy-tp-contact-factory.h"
 #include "empathy-contact-list.h"
-#include "empathy-dispatcher.h"
 #include "empathy-marshal.h"
 #include "empathy-time.h"
 #include "empathy-utils.h"
@@ -1272,6 +1271,9 @@ tp_chat_constructor (GType                  type,
 			  G_CALLBACK (tp_chat_invalidated_cb),
 			  chat, 0);
 
+	g_assert (tp_proxy_is_prepared (priv->connection,
+		TP_CONNECTION_FEATURE_CAPABILITIES));
+
 	if (tp_proxy_has_interface_by_id (priv->channel,
 					  TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) {
 		const TpIntSet *members;
@@ -1295,8 +1297,9 @@ tp_chat_constructor (GType                  type,
 		tp_g_signal_connect_object (priv->channel, "group-members-changed",
 			G_CALLBACK (tp_chat_group_members_changed_cb), chat, 0);
 	} else {
-		EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton ();
-		GList *list, *ptr;
+		TpCapabilities *caps;
+		GPtrArray *classes;
+		guint i;
 
 		/* Get the self contact from the connection's self handle */
 		handle = tp_connection_get_self_handle (priv->connection);
@@ -1310,13 +1313,13 @@ tp_chat_constructor (GType                  type,
 			handle, tp_chat_got_remote_contact_cb,
 			NULL, NULL, chat);
 
-		list = empathy_dispatcher_find_requestable_channel_classes (
-			dispatcher, priv->connection,
-			tp_channel_get_channel_type (priv->channel),
-			TP_UNKNOWN_HANDLE_TYPE, NULL);
+		caps = tp_connection_get_capabilities (priv->connection);
+		g_assert (caps != NULL);
+
+		classes = tp_capabilities_get_channel_classes (caps);
 
-		for (ptr = list; ptr; ptr = ptr->next) {
-			GValueArray *array = ptr->data;
+		for (i = 0; i < classes->len; i++) {
+			GValueArray *array = g_ptr_array_index (classes, i);
 			const char **oprops = g_value_get_boxed (
 				g_value_array_get_nth (array, 1));
 
@@ -1325,9 +1328,6 @@ tp_chat_constructor (GType                  type,
 				break;
 			}
 		}
-
-		g_list_free (list);
-		g_object_unref (dispatcher);
 	}
 
 	if (tp_proxy_has_interface_by_id (priv->channel,
diff --git a/src/empathy-chat-manager.c b/src/empathy-chat-manager.c
index cfa38ec..d16be29 100644
--- a/src/empathy-chat-manager.c
+++ b/src/empathy-chat-manager.c
@@ -255,8 +255,12 @@ empathy_chat_manager_init (EmpathyChatManager *self)
     }
 
   /* Text channels handler */
-  priv->handler = tp_simple_handler_new (dbus, FALSE, FALSE, "Empathy", FALSE,
-      handle_channels, self, NULL);
+  priv->handler = tp_simple_handler_new (dbus, FALSE, FALSE, "Empathy",
+      FALSE, handle_channels, self, NULL);
+
+  /* EmpathyTpChat relies on this feature being prepared */
+  tp_base_client_add_connection_features_varargs (priv->handler,
+    TP_CONNECTION_FEATURE_CAPABILITIES, 0);
 
   g_object_unref (dbus);
 
diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c
index fdd0672..0216eea 100644
--- a/src/empathy-event-manager.c
+++ b/src/empathy-event-manager.c
@@ -1206,6 +1206,10 @@ empathy_event_manager_init (EmpathyEventManager *manager)
   priv->approver = tp_simple_approver_new (dbus, "Empathy.EventManager", FALSE,
       approve_channels, manager, NULL);
 
+  /* EmpathyTpChat relies on this feature being prepared */
+  tp_base_client_add_connection_features_varargs (priv->approver,
+    TP_CONNECTION_FEATURE_CAPABILITIES, 0);
+
   /* Private text channels */
   tp_base_client_take_approver_filter (priv->approver,
       tp_asv_new (
