]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-contact.c
Make sure to not ref a NULL object
[empathy.git] / libempathy / empathy-contact.c
index 7a73b2bbb2f5a9c58243f18c519bca321cae9a6d..d248b2dd7b71d7c46cd7293142274ee391c7094f 100644 (file)
@@ -1,56 +1,56 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /*
- * Copyright (C) 2004 Imendio AB
- * Copyright (C) 2007-2008 Collabora Ltd.
+ * Copyright (C) 2007-2009 Collabora Ltd.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+ * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
- * Authors: Mikael Hallendal <micke@imendio.com>
- *          Martyn Russell <martyn@imendio.com>
- *          Xavier Claessens <xclaesse@gmail.com>
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ *          Sjoerd Simons <sjoerd.simons@collabora.co.uk>
  */
 
 #include "config.h"
 
 #include <string.h>
 
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 
 #include <telepathy-glib/util.h>
+#include <libmissioncontrol/mc-enum-types.h>
 
 #include "empathy-contact.h"
+#include "empathy-account-manager.h"
 #include "empathy-utils.h"
 #include "empathy-enum-types.h"
+#include "empathy-marshal.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
 #include "empathy-debug.h"
 
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact)
 typedef struct {
+  TpContact *tp_contact;
+  McAccount *account;
   gchar *id;
   gchar *name;
   EmpathyAvatar *avatar;
-  McAccount *account;
   McPresence presence;
   gchar *presence_message;
   guint handle;
   EmpathyCapabilities capabilities;
   gboolean is_user;
   guint hash;
-  EmpathyContactReady ready;
 } EmpathyContactPriv;
 
 static void contact_finalize (GObject *object);
@@ -64,18 +64,71 @@ G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT);
 enum
 {
   PROP_0,
+  PROP_TP_CONTACT,
+  PROP_ACCOUNT,
   PROP_ID,
   PROP_NAME,
   PROP_AVATAR,
-  PROP_ACCOUNT,
   PROP_PRESENCE,
   PROP_PRESENCE_MESSAGE,
   PROP_HANDLE,
   PROP_CAPABILITIES,
   PROP_IS_USER,
-  PROP_READY
 };
 
+enum {
+  PRESENCE_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+tp_contact_notify_cb (TpContact *tp_contact,
+                      GParamSpec *param,
+                      GObject *contact)
+{
+  EmpathyContactPriv *priv = GET_PRIV (contact);
+
+  /* Forward property notifications */
+  if (!tp_strdiff (param->name, "alias"))
+    g_object_notify (contact, "name");
+  else if (!tp_strdiff (param->name, "presence-type")) {
+    McPresence presence;
+
+    presence = empathy_contact_get_presence (EMPATHY_CONTACT (contact));
+    g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, priv->presence);
+    priv->presence = presence;
+    g_object_notify (contact, "presence");
+  }
+  else if (!tp_strdiff (param->name, "presence-message"))
+    g_object_notify (contact, "presence-message");
+  else if (!tp_strdiff (param->name, "identifier"))
+    g_object_notify (contact, "id");
+  else if (!tp_strdiff (param->name, "handle"))
+    g_object_notify (contact, "handle");
+}
+
+static void
+contact_dispose (GObject *object)
+{
+  EmpathyContactPriv *priv = GET_PRIV (object);
+
+  if (priv->tp_contact)
+    {
+      g_signal_handlers_disconnect_by_func (priv->tp_contact,
+          tp_contact_notify_cb, object);
+      g_object_unref (priv->tp_contact);
+    }
+  priv->tp_contact = NULL;
+
+  if (priv->account)
+    g_object_unref (priv->account);
+  priv->account = NULL;
+
+  G_OBJECT_CLASS (empathy_contact_parent_class)->dispose (object);
+}
+
 static void
 empathy_contact_class_init (EmpathyContactClass *class)
 {
@@ -84,9 +137,26 @@ empathy_contact_class_init (EmpathyContactClass *class)
   object_class = G_OBJECT_CLASS (class);
 
   object_class->finalize = contact_finalize;
+  object_class->dispose = contact_dispose;
   object_class->get_property = contact_get_property;
   object_class->set_property = contact_set_property;
 
+  g_object_class_install_property (object_class,
+      PROP_TP_CONTACT,
+      g_param_spec_object ("tp-contact",
+        "TpContact",
+        "The TpContact associated with the contact",
+        TP_TYPE_CONTACT,
+        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+      PROP_ACCOUNT,
+      g_param_spec_object ("account",
+        "The account",
+        "The account associated with the contact",
+        MC_TYPE_ACCOUNT,
+        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
   g_object_class_install_property (object_class,
       PROP_ID,
       g_param_spec_string ("id",
@@ -111,14 +181,6 @@ empathy_contact_class_init (EmpathyContactClass *class)
         EMPATHY_TYPE_AVATAR,
         G_PARAM_READWRITE));
 
-  g_object_class_install_property (object_class,
-      PROP_ACCOUNT,
-      g_param_spec_object ("account",
-        "Contact Account",
-        "The account associated with the contact",
-        MC_TYPE_ACCOUNT,
-        G_PARAM_READWRITE));
-
   g_object_class_install_property (object_class,
       PROP_PRESENCE,
       g_param_spec_uint ("presence",
@@ -164,14 +226,16 @@ empathy_contact_class_init (EmpathyContactClass *class)
         FALSE,
         G_PARAM_READWRITE));
 
-  g_object_class_install_property (object_class,
-      PROP_READY,
-      g_param_spec_flags ("ready",
-        "Contact ready flags",
-        "Flags for ready properties",
-        EMPATHY_TYPE_CONTACT_READY,
-        EMPATHY_CONTACT_READY_NONE,
-        G_PARAM_READABLE));
+  signals[PRESENCE_CHANGED] =
+    g_signal_new ("presence-changed",
+                  G_TYPE_FROM_CLASS (class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  _empathy_marshal_VOID__ENUM_ENUM,
+                  G_TYPE_NONE,
+                  2, MC_TYPE_PRESENCE,
+                  MC_TYPE_PRESENCE);
 
   g_type_class_add_private (object_class, sizeof (EmpathyContactPriv));
 }
@@ -199,150 +263,142 @@ contact_finalize (GObject *object)
   g_free (priv->presence_message);
 
   if (priv->avatar)
-    {
       empathy_avatar_unref (priv->avatar);
-    }
-
-  if (priv->account)
-    {
-      g_object_unref (priv->account);
-    }
 
   G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object);
 }
 
 static void
-contact_get_property (GObject *object,
-                      guint param_id,
-                      GValue *value,
-                      GParamSpec *pspec)
+set_tp_contact (EmpathyContact *contact,
+                TpContact *tp_contact)
 {
-  EmpathyContactPriv *priv;
+  EmpathyContactPriv *priv = GET_PRIV (contact);
 
-  priv = GET_PRIV (object);
+  if (tp_contact == NULL)
+    return;
+
+  g_assert (priv->tp_contact == NULL);
+  priv->tp_contact = g_object_ref (tp_contact);
+  priv->presence = empathy_contact_get_presence (contact);
 
-  switch (param_id) {
-  case PROP_ID:
-    g_value_set_string (value, priv->id);
-    break;
-  case PROP_NAME:
-    g_value_set_string (value,
-        empathy_contact_get_name (EMPATHY_CONTACT (object)));
-    break;
-  case PROP_AVATAR:
-    g_value_set_boxed (value, priv->avatar);
-    break;
-  case PROP_ACCOUNT:
-    g_value_set_object (value, priv->account);
-    break;
-  case PROP_PRESENCE:
-    g_value_set_uint (value, priv->presence);
-    break;
-  case PROP_PRESENCE_MESSAGE:
-    g_value_set_string (value, priv->presence_message);
-    break;
-  case PROP_HANDLE:
-    g_value_set_uint (value, priv->handle);
-    break;
-  case PROP_CAPABILITIES:
-    g_value_set_flags (value, priv->capabilities);
-    break;
-  case PROP_IS_USER:
-    g_value_set_boolean (value, priv->is_user);
-    break;
-  case PROP_READY:
-    g_value_set_flags (value, priv->ready);
-    break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-    break;
-  };
+  g_signal_connect (priv->tp_contact, "notify",
+    G_CALLBACK (tp_contact_notify_cb), contact);
 }
 
 static void
-contact_set_property (GObject *object,
+contact_get_property (GObject *object,
                       guint param_id,
-                      const GValue *value,
+                      GValue *value,
                       GParamSpec *pspec)
 {
-  EmpathyContactPriv *priv;
+  EmpathyContact *contact = EMPATHY_CONTACT (object);
 
-  priv = GET_PRIV (object);
-
-  switch (param_id) {
-  case PROP_ID:
-    empathy_contact_set_id (EMPATHY_CONTACT (object),
-        g_value_get_string (value));
-    break;
-  case PROP_NAME:
-    empathy_contact_set_name (EMPATHY_CONTACT (object),
-        g_value_get_string (value));
-    break;
-  case PROP_AVATAR:
-    empathy_contact_set_avatar (EMPATHY_CONTACT (object),
-        g_value_get_boxed (value));
-    break;
-  case PROP_ACCOUNT:
-    empathy_contact_set_account (EMPATHY_CONTACT (object),
-        MC_ACCOUNT (g_value_get_object (value)));
-    break;
-  case PROP_PRESENCE:
-    empathy_contact_set_presence (EMPATHY_CONTACT (object),
-        g_value_get_uint (value));
-    break;
-  case PROP_PRESENCE_MESSAGE:
-    empathy_contact_set_presence_message (EMPATHY_CONTACT (object),
-        g_value_get_string (value));
-    break;
-  case PROP_HANDLE:
-    empathy_contact_set_handle (EMPATHY_CONTACT (object),
-        g_value_get_uint (value));
-    break;
-  case PROP_CAPABILITIES:
-    empathy_contact_set_capabilities (EMPATHY_CONTACT (object),
-        g_value_get_flags (value));
-    break;
-  case PROP_IS_USER:
-    empathy_contact_set_is_user (EMPATHY_CONTACT (object),
-        g_value_get_boolean (value));
-    break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-    break;
-  };
+  switch (param_id)
+    {
+      case PROP_TP_CONTACT:
+        g_value_set_object (value, empathy_contact_get_tp_contact (contact));
+        break;
+      case PROP_ACCOUNT:
+        g_value_set_object (value, empathy_contact_get_account (contact));
+        break;
+      case PROP_ID:
+        g_value_set_string (value, empathy_contact_get_id (contact));
+        break;
+      case PROP_NAME:
+        g_value_set_string (value, empathy_contact_get_name (contact));
+        break;
+      case PROP_AVATAR:
+        g_value_set_boxed (value, empathy_contact_get_avatar (contact));
+        break;
+      case PROP_PRESENCE:
+        g_value_set_uint (value, empathy_contact_get_presence (contact));
+        break;
+      case PROP_PRESENCE_MESSAGE:
+        g_value_set_string (value, empathy_contact_get_presence_message (contact));
+        break;
+      case PROP_HANDLE:
+        g_value_set_uint (value, empathy_contact_get_handle (contact));
+        break;
+      case PROP_CAPABILITIES:
+        g_value_set_flags (value, empathy_contact_get_capabilities (contact));
+        break;
+      case PROP_IS_USER:
+        g_value_set_boolean (value, empathy_contact_is_user (contact));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    };
 }
 
 static void
-contact_set_ready_flag (EmpathyContact *contact,
-                        EmpathyContactReady flag)
+contact_set_property (GObject *object,
+                      guint param_id,
+                      const GValue *value,
+                      GParamSpec *pspec)
 {
-  EmpathyContactPriv *priv = GET_PRIV (contact);
+  EmpathyContact *contact = EMPATHY_CONTACT (object);
+  EmpathyContactPriv *priv = GET_PRIV (object);
 
-  if (!(priv->ready & flag))
+  switch (param_id)
     {
-      priv->ready |= flag;
-      g_object_notify (G_OBJECT (contact), "ready");
-    }
+      case PROP_TP_CONTACT:
+        set_tp_contact (contact, g_value_get_object (value));
+        break;
+      case PROP_ACCOUNT:
+        g_assert (priv->account == NULL);
+        priv->account = g_value_dup_object (value);
+        break;
+      case PROP_ID:
+        empathy_contact_set_id (contact, g_value_get_string (value));
+        break;
+      case PROP_NAME:
+        empathy_contact_set_name (contact, g_value_get_string (value));
+        break;
+      case PROP_AVATAR:
+        empathy_contact_set_avatar (contact, g_value_get_boxed (value));
+        break;
+      case PROP_PRESENCE:
+        empathy_contact_set_presence (contact, g_value_get_uint (value));
+        break;
+      case PROP_PRESENCE_MESSAGE:
+        empathy_contact_set_presence_message (contact, g_value_get_string (value));
+        break;
+      case PROP_HANDLE:
+        empathy_contact_set_handle (contact, g_value_get_uint (value));
+        break;
+      case PROP_CAPABILITIES:
+        empathy_contact_set_capabilities (contact, g_value_get_flags (value));
+        break;
+      case PROP_IS_USER:
+        empathy_contact_set_is_user (contact, g_value_get_boolean (value));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    };
 }
 
 EmpathyContact *
-empathy_contact_new (McAccount *account)
+empathy_contact_new (TpContact *tp_contact)
 {
+  g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL);
+
   return g_object_new (EMPATHY_TYPE_CONTACT,
-      "account", account,
+      "tp-contact", tp_contact,
       NULL);
 }
 
-EmpathyContact *
-empathy_contact_new_full (McAccount  *account,
-                          const gchar *id,
-                          const gchar *name)
+TpContact *
+empathy_contact_get_tp_contact (EmpathyContact *contact)
 {
-  return g_object_new (EMPATHY_TYPE_CONTACT,
-      "account", account,
-       "name", name,
-       "id", id,
-       NULL);
+  EmpathyContactPriv *priv;
+
+  g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
+
+  priv = GET_PRIV (contact);
+
+  return priv->tp_contact;
 }
 
 const gchar *
@@ -354,6 +410,9 @@ empathy_contact_get_id (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
+  if (priv->tp_contact != NULL)
+    return tp_contact_get_identifier (priv->tp_contact);
+
   return priv->id;
 }
 
@@ -377,12 +436,9 @@ empathy_contact_set_id (EmpathyContact *contact,
       priv->id = g_strdup (id);
 
       g_object_notify (G_OBJECT (contact), "id");
-      if (G_STR_EMPTY (priv->name))
-        {
+      if (EMP_STR_EMPTY (priv->name))
           g_object_notify (G_OBJECT (contact), "name");
-        }
     }
-  contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID);
 
   g_object_unref (contact);
 }
@@ -396,10 +452,11 @@ empathy_contact_get_name (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
-  if (G_STR_EMPTY (priv->name))
-    {
+  if (priv->tp_contact != NULL)
+    return tp_contact_get_alias (priv->tp_contact);
+
+  if (EMP_STR_EMPTY (priv->name))
       return empathy_contact_get_id (contact);
-    }
 
   return priv->name;
 }
@@ -421,7 +478,6 @@ empathy_contact_set_name (EmpathyContact *contact,
       priv->name = g_strdup (name);
       g_object_notify (G_OBJECT (contact), "name");
     }
-  contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME);
   g_object_unref (contact);
 }
 
@@ -457,9 +513,7 @@ empathy_contact_set_avatar (EmpathyContact *contact,
     }
 
   if (avatar)
-    {
       priv->avatar = empathy_avatar_ref (avatar);
-    }
 
   g_object_notify (G_OBJECT (contact), "avatar");
 }
@@ -473,30 +527,65 @@ empathy_contact_get_account (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
-  return priv->account;
+  if (priv->account != NULL)
+    return priv->account;
+
+  if (priv->tp_contact != NULL)
+    {
+      EmpathyAccountManager *manager;
+      TpConnection *connection;
+
+      /* FIXME: This assume the account manager already exists */
+      manager = empathy_account_manager_dup_singleton ();
+      connection = tp_contact_get_connection (priv->tp_contact);
+      priv->account = empathy_account_manager_get_account (manager, connection);
+      g_object_unref (manager);
+
+      return g_object_ref (priv->account);
+    }
+
+  return NULL;
 }
 
-void
-empathy_contact_set_account (EmpathyContact *contact,
-                             McAccount *account)
+TpConnection *
+empathy_contact_get_connection (EmpathyContact *contact)
 {
   EmpathyContactPriv *priv;
 
-  g_return_if_fail (EMPATHY_IS_CONTACT (contact));
-  g_return_if_fail (MC_IS_ACCOUNT (account));
+  g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
 
   priv = GET_PRIV (contact);
 
-  if (account == priv->account)
-    return;
+  if (priv->tp_contact != NULL)
+    return tp_contact_get_connection (priv->tp_contact);
 
-  if (priv->account)
+  return NULL;
+}
+
+static McPresence
+presence_type_to_mc_presence (TpConnectionPresenceType type)
+{
+  switch (type)
     {
-      g_object_unref (priv->account);
+      case TP_CONNECTION_PRESENCE_TYPE_UNSET:
+      case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
+      case TP_CONNECTION_PRESENCE_TYPE_ERROR:
+        return MC_PRESENCE_UNSET;
+      case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
+        return MC_PRESENCE_OFFLINE;
+      case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE:
+        return MC_PRESENCE_AVAILABLE;
+      case TP_CONNECTION_PRESENCE_TYPE_AWAY:
+        return MC_PRESENCE_AWAY;
+      case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY:
+        return MC_PRESENCE_EXTENDED_AWAY;
+      case TP_CONNECTION_PRESENCE_TYPE_HIDDEN:
+        return MC_PRESENCE_HIDDEN;
+      case TP_CONNECTION_PRESENCE_TYPE_BUSY:
+        return MC_PRESENCE_DO_NOT_DISTURB;
     }
-  priv->account = g_object_ref (account);
 
-  g_object_notify (G_OBJECT (contact), "account");
+  return MC_PRESENCE_UNSET;
 }
 
 McPresence
@@ -508,6 +597,10 @@ empathy_contact_get_presence (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
+  if (priv->tp_contact != NULL)
+    return presence_type_to_mc_presence (tp_contact_get_presence_type (
+        priv->tp_contact));
+
   return priv->presence;
 }
 
@@ -516,6 +609,7 @@ empathy_contact_set_presence (EmpathyContact *contact,
                               McPresence presence)
 {
   EmpathyContactPriv *priv;
+  McPresence old_presence;
 
   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
 
@@ -524,8 +618,11 @@ empathy_contact_set_presence (EmpathyContact *contact,
   if (presence == priv->presence)
     return;
 
+  old_presence = priv->presence;
   priv->presence = presence;
 
+  g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, old_presence);
+
   g_object_notify (G_OBJECT (contact), "presence");
 }
 
@@ -538,6 +635,9 @@ empathy_contact_get_presence_message (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
+  if (priv->tp_contact != NULL)
+    return tp_contact_get_presence_message (priv->tp_contact);
+
   return priv->presence_message;
 }
 
@@ -567,6 +667,9 @@ empathy_contact_get_handle (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
+  if (priv->tp_contact != NULL)
+    return tp_contact_get_handle (priv->tp_contact);
+
   return priv->handle;
 }
 
@@ -586,7 +689,6 @@ empathy_contact_set_handle (EmpathyContact *contact,
       priv->handle = handle;
       g_object_notify (G_OBJECT (contact), "handle");
     }
-  contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE);
   g_object_unref (contact);
 }
 
@@ -653,28 +755,24 @@ empathy_contact_set_is_user (EmpathyContact *contact,
 gboolean
 empathy_contact_is_online (EmpathyContact *contact)
 {
-  EmpathyContactPriv *priv;
-
   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
 
-  priv = GET_PRIV (contact);
-
-  return (priv->presence > MC_PRESENCE_OFFLINE);
+  return (empathy_contact_get_presence (contact) > MC_PRESENCE_OFFLINE);
 }
 
 const gchar *
 empathy_contact_get_status (EmpathyContact *contact)
 {
-  EmpathyContactPriv *priv;
+  const gchar *message;
 
   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
 
-  priv = GET_PRIV (contact);
-
-  if (priv->presence_message)
-    return priv->presence_message;
+  message = empathy_contact_get_presence_message (contact);
+  if (message)
+    return message;
 
-  return empathy_presence_get_default_message (priv->presence);
+  return empathy_presence_get_default_message (
+      empathy_contact_get_presence (contact));
 }
 
 gboolean
@@ -687,11 +785,11 @@ empathy_contact_can_voip (EmpathyContact *contact)
   priv = GET_PRIV (contact);
 
   return priv->capabilities & (EMPATHY_CAPABILITIES_AUDIO |
-             EMPATHY_CAPABILITIES_VIDEO);
+      EMPATHY_CAPABILITIES_VIDEO);
 }
 
-EmpathyContactReady
-empathy_contact_get_ready (EmpathyContact *contact)
+gboolean
+empathy_contact_can_send_files (EmpathyContact *contact)
 {
   EmpathyContactPriv *priv;
 
@@ -699,75 +797,7 @@ empathy_contact_get_ready (EmpathyContact *contact)
 
   priv = GET_PRIV (contact);
 
-  return priv->ready;
-}
-
-gboolean
-empathy_contact_equal (gconstpointer v1,
-                       gconstpointer v2)
-{
-  McAccount *account_a;
-  McAccount *account_b;
-  const gchar *id_a;
-  const gchar *id_b;
-
-  g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
-  g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
-
-  account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
-  account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
-
-  id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
-  id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
-
-  return empathy_account_equal (account_a, account_b) &&
-         !tp_strdiff (id_a, id_b);
-}
-
-guint
-empathy_contact_hash (gconstpointer key)
-{
-  EmpathyContactPriv *priv;
-
-  g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1);
-
-  priv = GET_PRIV (EMPATHY_CONTACT (key));
-
-  if (priv->hash == 0) {
-    priv->hash = empathy_account_hash (priv->account) ^
-           g_str_hash (priv->id);
-  }
-
-  return priv->hash;
-}
-
-static gboolean
-contact_is_ready_func (GObject *contact,
-                       gpointer user_data)
-{
-  EmpathyContactPriv *priv = GET_PRIV (contact);
-  EmpathyContactReady ready;
-
-  ready = GPOINTER_TO_UINT (user_data);
-
-  /* When the name is NULL, empathy_contact_get_name() fallback to the id.
-   * When the caller want to wait the name to be ready, it also want to wait
-   * the id to be ready in case of fallback. */
-  if ((ready & EMPATHY_CONTACT_READY_NAME) && G_STR_EMPTY (priv->name)) {
-    ready |= EMPATHY_CONTACT_READY_ID;
-  }
-
-  return (priv->ready & ready) == ready;
-}
-
-void
-empathy_contact_run_until_ready (EmpathyContact *contact,
-                                 EmpathyContactReady ready,
-                                 GMainLoop **loop)
-{
-  empathy_run_until_ready_full (contact, "notify::ready",
-      contact_is_ready_func, GUINT_TO_POINTER (ready),
-      loop);
+  return priv->capabilities & EMPATHY_CAPABILITIES_FT;
 }
 
 static gchar *
@@ -775,21 +805,24 @@ contact_get_avatar_filename (EmpathyContact *contact,
                              const gchar *token)
 {
   EmpathyContactPriv *priv = GET_PRIV (contact);
+  McAccount *account;
   gchar *avatar_path;
   gchar *avatar_file;
   gchar *token_escaped;
   gchar *contact_escaped;
 
-  if (G_STR_EMPTY (priv->id))
+  if (EMP_STR_EMPTY (priv->id))
     return NULL;
 
   contact_escaped = tp_escape_as_identifier (priv->id);
   token_escaped = tp_escape_as_identifier (token);
+  account = empathy_contact_get_account (contact);
 
+  /* FIXME: Do not use the account, but proto/cm instead */
   avatar_path = g_build_filename (g_get_user_cache_dir (),
       PACKAGE_NAME,
       "avatars",
-      mc_account_get_unique_name (priv->account),
+      mc_account_get_unique_name (account),
       contact_escaped,
       NULL);
   g_mkdir_with_parents (avatar_path, 0700);
@@ -818,7 +851,7 @@ empathy_contact_load_avatar_data (EmpathyContact *contact,
   g_return_if_fail (data != NULL);
   g_return_if_fail (len > 0);
   g_return_if_fail (format != NULL);
-  g_return_if_fail (!G_STR_EMPTY (token));
+  g_return_if_fail (!EMP_STR_EMPTY (token));
 
   /* Load and set the avatar */
   avatar = empathy_avatar_new (g_memdup (data, len), len, g_strdup (format),
@@ -837,9 +870,7 @@ empathy_contact_load_avatar_data (EmpathyContact *contact,
           g_clear_error (&error);
         }
       else
-        {
           DEBUG ("Avatar saved to %s", filename);
-        }
     }
   g_free (filename);
 }
@@ -855,7 +886,7 @@ empathy_contact_load_avatar_cache (EmpathyContact *contact,
   GError *error = NULL;
 
   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
-  g_return_val_if_fail (!G_STR_EMPTY (token), FALSE);
+  g_return_val_if_fail (!EMP_STR_EMPTY (token), FALSE);
 
   /* Load the avatar from file if it exists */
   filename = contact_get_avatar_filename (contact, token);