]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-chat.c
Updated.
[empathy.git] / libempathy / empathy-tp-chat.c
index a2852e1d877bd7a65c418a6753d6878b47cc35da..b11725f48e1eb23b77754896f45d596f30881ff3 100644 (file)
@@ -2,20 +2,19 @@
 /*
  * Copyright (C) 2007 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: Xavier Claessens <xclaesse@gmail.com>
  */
 #include <libtelepathy/tp-props-iface.h>
 
 #include "empathy-tp-chat.h"
-#include "empathy-contact-manager.h"
-#include "empathy-tp-contact-list.h"
+#include "empathy-contact-factory.h"
 #include "empathy-marshal.h"
-#include "gossip-debug.h"
-#include "gossip-time.h"
-#include "gossip-utils.h"
+#include "empathy-debug.h"
+#include "empathy-time.h"
+#include "empathy-utils.h"
 
 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
                       EMPATHY_TYPE_TP_CHAT, EmpathyTpChatPriv))
 #define DEBUG_DOMAIN "TpChat"
 
 struct _EmpathyTpChatPriv {
-       EmpathyTpContactList  *list;
-       EmpathyContactManager *manager;
+       EmpathyContactFactory *factory;
+       EmpathyContact        *user;
        McAccount             *account;
        gchar                 *id;
        MissionControl        *mc;
+       gboolean               acknowledge;
 
        TpChan                *tp_chan;
        DBusGProxy            *props_iface;
@@ -56,56 +55,63 @@ struct _EmpathyTpChatPriv {
        DBusGProxy            *chat_state_iface;
 };
 
-static void      empathy_tp_chat_class_init    (EmpathyTpChatClass        *klass);
-static void      empathy_tp_chat_init          (EmpathyTpChat             *chat);
-static void      tp_chat_finalize              (GObject                   *object);
-static GObject * tp_chat_constructor           (GType                      type,
-                                               guint                      n_props,
-                                               GObjectConstructParam     *props);
-static void      tp_chat_get_property          (GObject                   *object,
-                                               guint                      param_id,
-                                               GValue                    *value,
-                                               GParamSpec                *pspec);
-static void      tp_chat_set_property          (GObject                   *object,
-                                               guint                      param_id,
-                                               const GValue              *value,
-                                               GParamSpec                *pspec);
-static void      tp_chat_destroy_cb            (TpChan                    *text_chan,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_closed_cb             (TpChan                    *text_chan,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_received_cb           (DBusGProxy                *text_iface,
-                                               guint                      message_id,
-                                               guint                      timestamp,
-                                               guint                      from_handle,
-                                               guint                      message_type,
-                                               guint                      message_flags,
-                                               gchar                     *message_body,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_sent_cb               (DBusGProxy                *text_iface,
-                                               guint                      timestamp,
-                                               guint                      message_type,
-                                               gchar                     *message_body,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_state_changed_cb      (DBusGProxy                *chat_state_iface,
-                                               guint                      handle,
-                                               TelepathyChannelChatState  state,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_emit_message          (EmpathyTpChat             *chat,
-                                               guint                      type,
-                                               guint                      timestamp,
-                                               guint                      from_handle,
-                                               const gchar               *message_body);
-static void      tp_chat_properties_ready_cb   (TpPropsIface              *props_iface,
-                                               EmpathyTpChat             *chat);
-static void      tp_chat_properties_changed_cb (TpPropsIface              *props_iface,
-                                               guint                      prop_id,
-                                               TpPropsChanged             flag,
-                                               EmpathyTpChat             *chat);
+static void             empathy_tp_chat_class_init    (EmpathyTpChatClass        *klass);
+static void             empathy_tp_chat_init          (EmpathyTpChat             *chat);
+static void             tp_chat_finalize              (GObject                   *object);
+static GObject *        tp_chat_constructor           (GType                      type,
+                                                      guint                      n_props,
+                                                      GObjectConstructParam     *props);
+static void             tp_chat_get_property          (GObject                   *object,
+                                                      guint                      param_id,
+                                                      GValue                    *value,
+                                                      GParamSpec                *pspec);
+static void             tp_chat_set_property          (GObject                   *object,
+                                                      guint                      param_id,
+                                                      const GValue              *value,
+                                                      GParamSpec                *pspec);
+static void             tp_chat_destroy_cb            (TpChan                    *text_chan,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_closed_cb             (TpChan                    *text_chan,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_received_cb           (DBusGProxy                *text_iface,
+                                                      guint                      message_id,
+                                                      guint                      timestamp,
+                                                      guint                      from_handle,
+                                                      guint                      message_type,
+                                                      guint                      message_flags,
+                                                      gchar                     *message_body,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_sent_cb               (DBusGProxy                *text_iface,
+                                                      guint                      timestamp,
+                                                      guint                      message_type,
+                                                      gchar                     *message_body,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_send_error_cb         (DBusGProxy                *text_iface,
+                                                      guint                      error_code,
+                                                      guint                      timestamp,
+                                                      guint                      message_type,
+                                                      gchar                     *message_body,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_state_changed_cb      (DBusGProxy                *chat_state_iface,
+                                                      guint                      handle,
+                                                      TelepathyChannelChatState  state,
+                                                      EmpathyTpChat             *chat);
+static EmpathyMessage * tp_chat_build_message         (EmpathyTpChat             *chat,
+                                                      guint                      type,
+                                                      guint                      timestamp,
+                                                      guint                      from_handle,
+                                                      const gchar               *message_body);
+static void             tp_chat_properties_ready_cb   (TpPropsIface              *props_iface,
+                                                      EmpathyTpChat             *chat);
+static void             tp_chat_properties_changed_cb (TpPropsIface              *props_iface,
+                                                      guint                      prop_id,
+                                                      TpPropsChanged             flag,
+                                                      EmpathyTpChat             *chat);
 enum {
        PROP_0,
        PROP_ACCOUNT,
        PROP_TP_CHAN,
+       PROP_ACKNOWLEDGE,
 
        PROP_ANONYMOUS,
        PROP_INVITE_ONLY,
@@ -125,6 +131,7 @@ enum {
 
 enum {
        MESSAGE_RECEIVED,
+       SEND_ERROR,
        CHAT_STATE_CHANGED,
        DESTROY,
        LAST_SIGNAL
@@ -162,6 +169,15 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                                                              G_PARAM_READWRITE |
                                                              G_PARAM_CONSTRUCT_ONLY));
 
+       /* Normal properties */
+       g_object_class_install_property (object_class,
+                                        PROP_ACKNOWLEDGE,
+                                        g_param_spec_boolean ("acknowledge",
+                                                              "acknowledge",
+                                                              "acknowledge",
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+
        /* Properties of Text Channel */
        g_object_class_install_property (object_class,
                                         PROP_ANONYMOUS,
@@ -278,7 +294,17 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                              NULL, NULL,
                              g_cclosure_marshal_VOID__OBJECT,
                              G_TYPE_NONE,
-                             1, GOSSIP_TYPE_MESSAGE);
+                             1, EMPATHY_TYPE_MESSAGE);
+
+       signals[SEND_ERROR] =
+               g_signal_new ("send-error",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0,
+                             NULL, NULL,
+                             empathy_marshal_VOID__OBJECT_UINT,
+                             G_TYPE_NONE,
+                             2, EMPATHY_TYPE_MESSAGE, G_TYPE_UINT);
 
        signals[CHAT_STATE_CHANGED] =
                g_signal_new ("chat-state-changed",
@@ -288,7 +314,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                              NULL, NULL,
                              empathy_marshal_VOID__OBJECT_UINT,
                              G_TYPE_NONE,
-                             2, GOSSIP_TYPE_CONTACT, G_TYPE_UINT);
+                             2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
 
        signals[DESTROY] =
                g_signal_new ("destroy",
@@ -319,27 +345,48 @@ tp_chat_finalize (GObject *object)
        chat = EMPATHY_TP_CHAT (object);
        priv = GET_PRIV (chat);
 
-       if (priv->tp_chan) {
-               gossip_debug (DEBUG_DOMAIN, "Closing channel...");
+       if (priv->text_iface) {
+               dbus_g_proxy_disconnect_signal (priv->text_iface, "Received",
+                                               G_CALLBACK (tp_chat_received_cb),
+                                               chat);
+               dbus_g_proxy_disconnect_signal (priv->text_iface, "Sent",
+                                               G_CALLBACK (tp_chat_sent_cb),
+                                               chat);
+               dbus_g_proxy_disconnect_signal (priv->text_iface, "SendError",
+                                               G_CALLBACK (tp_chat_send_error_cb),
+                                               chat);
+       }
+
+       if (priv->chat_state_iface) {
+               dbus_g_proxy_disconnect_signal (priv->chat_state_iface, "ChatStateChanged",
+                                               G_CALLBACK (tp_chat_state_changed_cb),
+                                               chat);
+       }
 
+       if (priv->tp_chan) {
                g_signal_handlers_disconnect_by_func (priv->tp_chan,
                                                      tp_chat_destroy_cb,
                                                      object);
-
-               if (!tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error)) {
-                       gossip_debug (DEBUG_DOMAIN, 
-                                     "Error closing text channel: %s",
-                                     error ? error->message : "No error given");
-                       g_clear_error (&error);
+               dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed",
+                                               G_CALLBACK (tp_chat_closed_cb),
+                                               chat);
+               if (priv->acknowledge) {
+                       empathy_debug (DEBUG_DOMAIN, "Closing channel...");
+                       if (!tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error)) {
+                               empathy_debug (DEBUG_DOMAIN, 
+                                             "Error closing text channel: %s",
+                                             error ? error->message : "No error given");
+                               g_clear_error (&error);
+                       }
                }
                g_object_unref (priv->tp_chan);
        }
 
-       if (priv->manager) {
-               g_object_unref (priv->manager);
+       if (priv->factory) {
+               g_object_unref (priv->factory);
        }
-       if (priv->list) {
-               g_object_unref (priv->list);
+       if (priv->user) {
+               g_object_unref (priv->user);
        }
        if (priv->account) {
                g_object_unref (priv->account);
@@ -364,10 +411,9 @@ tp_chat_constructor (GType                  type,
 
        priv = GET_PRIV (chat);
 
-       priv->manager = empathy_contact_manager_new ();
-       priv->list = empathy_contact_manager_get_list (priv->manager, priv->account);
-       priv->mc = gossip_mission_control_new ();
-       g_object_ref (priv->list);
+       priv->factory = empathy_contact_factory_new ();
+       priv->user = empathy_contact_factory_get_user (priv->factory, priv->account);
+       priv->mc = empathy_mission_control_new ();
 
        priv->text_iface = tp_chan_get_interface (priv->tp_chan,
                                                  TELEPATHY_CHAN_IFACE_TEXT_QUARK);
@@ -388,6 +434,9 @@ tp_chat_constructor (GType                  type,
        dbus_g_proxy_connect_signal (priv->text_iface, "Sent",
                                     G_CALLBACK (tp_chat_sent_cb),
                                     chat, NULL);
+       dbus_g_proxy_connect_signal (priv->text_iface, "SendError",
+                                    G_CALLBACK (tp_chat_send_error_cb),
+                                    chat, NULL);
 
        if (priv->chat_state_iface != NULL) {
                dbus_g_proxy_connect_signal (priv->chat_state_iface,
@@ -453,6 +502,9 @@ tp_chat_get_property (GObject    *object,
        case PROP_TP_CHAN:
                g_value_set_object (value, priv->tp_chan);
                break;
+       case PROP_ACKNOWLEDGE:
+               g_value_set_boolean (value, priv->acknowledge);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                break;
@@ -489,6 +541,10 @@ tp_chat_set_property (GObject      *object,
        case PROP_TP_CHAN:
                priv->tp_chan = g_object_ref (g_value_get_object (value));
                break;
+       case PROP_ACKNOWLEDGE:
+               empathy_tp_chat_set_acknowledge (EMPATHY_TP_CHAT (object),
+                                                g_value_get_boolean (value));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                break;
@@ -506,7 +562,7 @@ empathy_tp_chat_new (McAccount *account,
 }
 
 EmpathyTpChat *
-empathy_tp_chat_new_with_contact (GossipContact *contact)
+empathy_tp_chat_new_with_contact (EmpathyContact *contact)
 {
        EmpathyTpChat  *chat;
        MissionControl *mc;
@@ -516,10 +572,10 @@ empathy_tp_chat_new_with_contact (GossipContact *contact)
        const gchar    *bus_name;
        guint           handle;
 
-       g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
+       g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
 
-       mc = gossip_mission_control_new ();
-       account = gossip_contact_get_account (contact);
+       mc = empathy_mission_control_new ();
+       account = empathy_contact_get_account (contact);
 
        if (mission_control_get_connection_status (mc, account, NULL) != 0) {
                /* The account is not connected, nothing to do. */
@@ -529,7 +585,7 @@ empathy_tp_chat_new_with_contact (GossipContact *contact)
        tp_conn = mission_control_get_connection (mc, account, NULL);
        g_return_val_if_fail (tp_conn != NULL, NULL);
        bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn));
-       handle = gossip_contact_get_handle (contact);
+       handle = empathy_contact_get_handle (contact);
 
        text_chan = tp_conn_new_channel (tp_get_bus (),
                                         tp_conn,
@@ -548,39 +604,79 @@ empathy_tp_chat_new_with_contact (GossipContact *contact)
        return chat;
 }
 
+gboolean
+empathy_tp_chat_get_acknowledge (EmpathyTpChat *chat)
+{
+       EmpathyTpChatPriv *priv;
+
+       g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE);
+
+       priv = GET_PRIV (chat);
+
+       return priv->acknowledge;
+}
+
 void
-empathy_tp_chat_request_pending (EmpathyTpChat *chat)
+empathy_tp_chat_set_acknowledge (EmpathyTpChat *chat,
+                                gboolean       acknowledge)
+{
+       EmpathyTpChatPriv *priv;
+
+       g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
+
+       priv = GET_PRIV (chat);
+
+       priv->acknowledge = acknowledge;
+       g_object_notify (G_OBJECT (chat), "acknowledge");
+}
+
+TpChan *
+empathy_tp_chat_get_channel (EmpathyTpChat *chat)
+{
+       EmpathyTpChatPriv *priv;
+
+       g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
+
+       priv = GET_PRIV (chat);
+
+       return priv->tp_chan;
+}
+
+GList *
+empathy_tp_chat_get_pendings (EmpathyTpChat *chat)
 {
        EmpathyTpChatPriv *priv;
        GPtrArray         *messages_list;
        guint              i;
+       GList             *messages = NULL;
        GError            *error = NULL;
 
-       g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
+       g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
 
        priv = GET_PRIV (chat);
 
        /* If we do this call async, don't forget to ignore Received signal
         * until we get the answer */
        if (!tp_chan_type_text_list_pending_messages (priv->text_iface,
-                                                     TRUE,
+                                                     priv->acknowledge,
                                                      &messages_list,
                                                      &error)) {
-               gossip_debug (DEBUG_DOMAIN, 
+               empathy_debug (DEBUG_DOMAIN, 
                              "Error retrieving pending messages: %s",
                              error ? error->message : "No error given");
                g_clear_error (&error);
-               return;
+               return NULL;
        }
 
        for (i = 0; i < messages_list->len; i++) {
-               GValueArray *message_struct;
-               const gchar *message_body;
-               guint        message_id;
-               guint        timestamp;
-               guint        from_handle;
-               guint        message_type;
-               guint        message_flags;
+               EmpathyMessage *message;
+               GValueArray    *message_struct;
+               const gchar    *message_body;
+               guint           message_id;
+               guint           timestamp;
+               guint           from_handle;
+               guint           message_type;
+               guint           message_flags;
 
                message_struct = g_ptr_array_index (messages_list, i);
 
@@ -591,43 +687,48 @@ empathy_tp_chat_request_pending (EmpathyTpChat *chat)
                message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4));
                message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5));
 
-               gossip_debug (DEBUG_DOMAIN, "Message pending: %s", message_body);
+               empathy_debug (DEBUG_DOMAIN, "Message pending: %s", message_body);
+
+               message = tp_chat_build_message (chat,
+                                                message_type,
+                                                timestamp,
+                                                from_handle,
+                                                message_body);
 
-               tp_chat_emit_message (chat,
-                                     message_type,
-                                     timestamp,
-                                     from_handle,
-                                     message_body);
+               messages = g_list_prepend (messages, message);
 
                g_value_array_free (message_struct);
        }
+       messages = g_list_reverse (messages);
 
        g_ptr_array_free (messages_list, TRUE);
+
+       return messages;
 }
 
 void
 empathy_tp_chat_send (EmpathyTpChat *chat,
-                     GossipMessage *message)
+                     EmpathyMessage *message)
 {
        EmpathyTpChatPriv *priv;
        const gchar       *message_body;
-       GossipMessageType  message_type;
+       EmpathyMessageType  message_type;
        GError            *error = NULL;
 
        g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
-       g_return_if_fail (GOSSIP_IS_MESSAGE (message));
+       g_return_if_fail (EMPATHY_IS_MESSAGE (message));
 
        priv = GET_PRIV (chat);
 
-       message_body = gossip_message_get_body (message);
-       message_type = gossip_message_get_type (message);
+       message_body = empathy_message_get_body (message);
+       message_type = empathy_message_get_type (message);
 
-       gossip_debug (DEBUG_DOMAIN, "Sending message: %s", message_body);
+       empathy_debug (DEBUG_DOMAIN, "Sending message: %s", message_body);
        if (!tp_chan_type_text_send (priv->text_iface,
                                     message_type,
                                     message_body,
                                     &error)) {
-               gossip_debug (DEBUG_DOMAIN, 
+               empathy_debug (DEBUG_DOMAIN, 
                              "Send Error: %s", 
                              error ? error->message : "No error given");
                g_clear_error (&error);
@@ -646,11 +747,11 @@ empathy_tp_chat_set_state (EmpathyTpChat             *chat,
        priv = GET_PRIV (chat);
 
        if (priv->chat_state_iface) {
-               gossip_debug (DEBUG_DOMAIN, "Set state: %d", state);
+               empathy_debug (DEBUG_DOMAIN, "Set state: %d", state);
                if (!tp_chan_iface_chat_state_set_chat_state (priv->chat_state_iface,
                                                              state,
                                                              &error)) {
-                       gossip_debug (DEBUG_DOMAIN,
+                       empathy_debug (DEBUG_DOMAIN,
                                      "Set Chat State Error: %s",
                                      error ? error->message : "No error given");
                        g_clear_error (&error);
@@ -667,12 +768,10 @@ empathy_tp_chat_get_id (EmpathyTpChat *chat)
 
        priv = GET_PRIV (chat);
 
-       if (priv->id) {
-               return priv->id;
+       if (!priv->id) {
+               priv->id = empathy_inspect_channel (priv->account, priv->tp_chan);
        }
 
-       priv->id = gossip_get_channel_id (priv->account, priv->tp_chan);
-
        return priv->id;
 }
 
@@ -684,7 +783,7 @@ tp_chat_destroy_cb (TpChan        *text_chan,
 
        priv = GET_PRIV (chat);
 
-       gossip_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
+       empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
 
        g_object_unref  (priv->tp_chan);
        priv->tp_chan = NULL;
@@ -708,7 +807,6 @@ tp_chat_closed_cb (TpChan        *text_chan,
                                              tp_chat_destroy_cb,
                                              chat);
        tp_chat_destroy_cb (text_chan, chat);
-
 }
 
 static void
@@ -722,23 +820,30 @@ tp_chat_received_cb (DBusGProxy    *text_iface,
                     EmpathyTpChat *chat)
 {
        EmpathyTpChatPriv *priv;
-       GArray            *message_ids;
+       EmpathyMessage    *message;
 
        priv = GET_PRIV (chat);
 
-       gossip_debug (DEBUG_DOMAIN, "Message received: %s", message_body);
+       empathy_debug (DEBUG_DOMAIN, "Message received: %s", message_body);
+
+       message = tp_chat_build_message (chat,
+                                        message_type,
+                                        timestamp,
+                                        from_handle,
+                                        message_body);
+
+       g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
+       g_object_unref (message);
 
-       tp_chat_emit_message (chat,
-                             message_type,
-                             timestamp,
-                             from_handle,
-                             message_body);
+       if (priv->acknowledge) {
+               GArray *message_ids;
 
-       message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
-       g_array_append_val (message_ids, message_id);
-       tp_chan_type_text_acknowledge_pending_messages (priv->text_iface,
-                                                       message_ids, NULL);
-       g_array_free (message_ids, TRUE);
+               message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
+               g_array_append_val (message_ids, message_id);
+               tp_chan_type_text_acknowledge_pending_messages (priv->text_iface,
+                                                               message_ids, NULL);
+               g_array_free (message_ids, TRUE);
+       }
 }
 
 static void
@@ -748,13 +853,41 @@ tp_chat_sent_cb (DBusGProxy    *text_iface,
                 gchar         *message_body,
                 EmpathyTpChat *chat)
 {
-       gossip_debug (DEBUG_DOMAIN, "Message sent: %s", message_body);
+       EmpathyMessage *message;
 
-       tp_chat_emit_message (chat,
-                             message_type,
-                             timestamp,
-                             0,
-                             message_body);
+       empathy_debug (DEBUG_DOMAIN, "Message sent: %s", message_body);
+
+       message = tp_chat_build_message (chat,
+                                        message_type,
+                                        timestamp,
+                                        0,
+                                        message_body);
+
+       g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
+       g_object_unref (message);
+}
+
+static void
+tp_chat_send_error_cb (DBusGProxy    *text_iface,
+                      guint          error_code,
+                      guint          timestamp,
+                      guint          message_type,
+                      gchar         *message_body,
+                      EmpathyTpChat *chat)
+{
+       EmpathyMessage *message;
+
+       empathy_debug (DEBUG_DOMAIN, "Message sent error: %s (%d)",
+                      message_body, error_code);
+
+       message = tp_chat_build_message (chat,
+                                        message_type,
+                                        timestamp,
+                                        0,
+                                        message_body);
+
+       g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code);
+       g_object_unref (message);
 }
 
 static void
@@ -764,54 +897,53 @@ tp_chat_state_changed_cb (DBusGProxy                *chat_state_iface,
                          EmpathyTpChat             *chat)
 {
        EmpathyTpChatPriv *priv;
-       GossipContact     *contact;
+       EmpathyContact     *contact;
 
        priv = GET_PRIV (chat);
 
-       contact = empathy_tp_contact_list_get_from_handle (priv->list, handle);
+       contact = empathy_contact_factory_get_from_handle (priv->factory,
+                                                          priv->account,
+                                                          handle);
 
-       gossip_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d",
-                     gossip_contact_get_name (contact),
+       empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d",
+                     empathy_contact_get_name (contact),
                      handle,
                      state);
 
        g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
-
        g_object_unref (contact);
 }
 
-static void
-tp_chat_emit_message (EmpathyTpChat *chat,
-                     guint          type,
-                     guint          timestamp,
-                     guint          from_handle,
-                     const gchar   *message_body)
+static EmpathyMessage *
+tp_chat_build_message (EmpathyTpChat *chat,
+                      guint          type,
+                      guint          timestamp,
+                      guint          from_handle,
+                      const gchar   *message_body)
 {
        EmpathyTpChatPriv *priv;
-       GossipMessage     *message;
-       GossipContact     *sender;
-       GossipContact     *receiver;
+       EmpathyMessage    *message;
+       EmpathyContact    *sender;
 
        priv = GET_PRIV (chat);
 
-       receiver = empathy_tp_contact_list_get_user (priv->list);
        if (from_handle == 0) {
-               sender = g_object_ref (receiver);
+               sender = g_object_ref (priv->user);
        } else {
-               sender = empathy_tp_contact_list_get_from_handle (priv->list,
+               sender = empathy_contact_factory_get_from_handle (priv->factory,
+                                                                 priv->account,
                                                                  from_handle);
        }
 
-       message = gossip_message_new (message_body);
-       gossip_message_set_type (message, type);
-       gossip_message_set_sender (message, sender);
-       gossip_message_set_receiver (message, receiver);
-       gossip_message_set_timestamp (message, (GossipTime) timestamp);
-
-       g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
+       message = empathy_message_new (message_body);
+       empathy_message_set_type (message, type);
+       empathy_message_set_sender (message, sender);
+       empathy_message_set_receiver (message, priv->user);
+       empathy_message_set_timestamp (message, timestamp);
 
-       g_object_unref (message);
        g_object_unref (sender);
+
+       return message;
 }
 
 static void