]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-chat.c
Don't send unknown commands. Fixes bug #577026
[empathy.git] / libempathy-gtk / empathy-chat.c
index 22b6f46bb8897dae624dfe521a9182f512251358..d11f331610670887e24a875e44bc85733acd60f5 100644 (file)
 #include <stdlib.h>
 
 #include <gdk/gdkkeysyms.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
 
-#include <libmissioncontrol/mission-control.h>
 #include <telepathy-glib/util.h>
 
+#include <libempathy/empathy-account-manager.h>
 #include <libempathy/empathy-log-manager.h>
 #include <libempathy/empathy-contact-list.h>
-#include <libempathy/empathy-debug.h>
 #include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-dispatcher.h>
 
 #include "empathy-chat.h"
 #include "empathy-conf.h"
 #include "empathy-contact-list-store.h"
 #include "empathy-contact-list-view.h"
 #include "empathy-contact-menu.h"
+#include "empathy-theme-manager.h"
+#include "empathy-smiley-manager.h"
 #include "empathy-ui-utils.h"
 
-#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT, EmpathyChatPriv))
-
-#define DEBUG_DOMAIN "Chat"
+#define DEBUG_FLAG EMPATHY_DEBUG_CHAT
+#include <libempathy/empathy-debug.h>
 
 #define CHAT_DIR_CREATE_MODE  (S_IRUSR | S_IWUSR | S_IXUSR)
 #define CHAT_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
 #define MAX_INPUT_HEIGHT 150
 #define COMPOSING_STOP_TIMEOUT 5
 
-struct _EmpathyChatPriv {
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat)
+typedef struct {
        EmpathyTpChat     *tp_chat;
+       gulong            tp_chat_destroy_handler;
        McAccount         *account;
        gchar             *id;
        gchar             *name;
@@ -70,16 +73,14 @@ struct _EmpathyChatPriv {
        EmpathyContact    *remote_contact;
 
        EmpathyLogManager *log_manager;
-       MissionControl    *mc;
+       EmpathyAccountManager *account_manager;
        GSList            *sent_messages;
        gint               sent_messages_index;
        GList             *compositors;
-       GList             *backlog_messages;
        GCompletion       *completion;
        guint              composing_stop_timeout_id;
        guint              block_events_timeout_id;
        TpHandleType       handle_type;
-       gpointer           token;
        gint               contacts_width;
        gboolean           has_input_vscroll;
 
@@ -92,10 +93,7 @@ struct _EmpathyChatPriv {
        GtkWidget         *hbox_topic;
        GtkWidget         *label_topic;
        GtkWidget         *contact_list_view;
-};
-
-static void empathy_chat_class_init (EmpathyChatClass *klass);
-static void empathy_chat_init       (EmpathyChat      *chat);
+} EmpathyChatPriv;
 
 enum {
        COMPOSING,
@@ -123,6 +121,7 @@ chat_get_property (GObject    *object,
                   GValue     *value,
                   GParamSpec *pspec)
 {
+       EmpathyChat *chat = EMPATHY_CHAT (object);
        EmpathyChatPriv *priv = GET_PRIV (object);
 
        switch (param_id) {
@@ -133,7 +132,7 @@ chat_get_property (GObject    *object,
                g_value_set_object (value, priv->account);
                break;
        case PROP_NAME:
-               g_value_set_string (value, priv->name);
+               g_value_set_string (value, empathy_chat_get_name (chat));
                break;
        case PROP_ID:
                g_value_set_string (value, priv->id);
@@ -169,32 +168,35 @@ chat_set_property (GObject      *object,
 }
 
 static void
-chat_status_changed_cb (MissionControl           *mc,
-                       TpConnectionStatus        status,
-                       McPresence                presence,
-                       TpConnectionStatusReason  reason,
-                       const gchar              *unique_name,
-                       EmpathyChat              *chat)
+chat_connection_changed_cb (EmpathyAccountManager *manager,
+                           McAccount *account,
+                           TpConnectionStatusReason reason,
+                           TpConnectionStatus current,
+                           TpConnectionStatus previous,
+                           EmpathyChat *chat)
 {
        EmpathyChatPriv *priv = GET_PRIV (chat);
-       McAccount       *account;
 
-       account = mc_account_lookup (unique_name);
-
-       if (status == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat &&
+       if (current == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat &&
            empathy_account_equal (account, priv->account) &&
-           priv->handle_type != TP_HANDLE_TYPE_NONE) {
-               empathy_debug (DEBUG_DOMAIN,
-                              "Account reconnected, request a new Text channel");
-               mission_control_request_channel_with_string_handle (mc,
-                                                                   priv->account,
-                                                                   TP_IFACE_CHANNEL_TYPE_TEXT,
-                                                                   priv->id,
-                                                                   priv->handle_type,
-                                                                   NULL, NULL);
+           priv->handle_type != TP_HANDLE_TYPE_NONE &&
+           !EMP_STR_EMPTY (priv->id)) {
+               
+               DEBUG ("Account reconnected, request a new Text channel");
+
+               switch (priv->handle_type) {
+                       case TP_HANDLE_TYPE_CONTACT:
+                               empathy_dispatcher_chat_with_contact_id (account, priv->id,
+                                       NULL, NULL);
+                               break;
+                       case TP_HANDLE_TYPE_ROOM:
+                               empathy_dispatcher_join_muc (account, priv->id, NULL, NULL);
+                               break;
+                       default:
+                               g_assert_not_reached ();
+                               break;
+               }
        }
-
-       g_object_unref (account);
 }
 
 static void
@@ -257,24 +259,6 @@ chat_composing_stop (EmpathyChat *chat)
                                   TP_CHANNEL_CHAT_STATE_ACTIVE);
 }
 
-static void
-chat_destroy_cb (EmpathyTpChat *tp_chat,
-                EmpathyChat    *chat)
-{
-       EmpathyChatPriv *priv;
-
-       priv = GET_PRIV (chat);
-
-       if (priv->tp_chat) {
-               g_object_unref (priv->tp_chat);
-               priv->tp_chat = NULL;
-               g_object_notify (G_OBJECT (chat), "tp-chat");
-       }
-
-       empathy_chat_view_append_event (chat->view, _("Disconnected"));
-       gtk_widget_set_sensitive (chat->input_text_view, FALSE);
-}
-
 static void 
 chat_sent_message_add (EmpathyChat  *chat,
                       const gchar *str)
@@ -322,8 +306,7 @@ chat_sent_message_get_next (EmpathyChat *chat)
        priv = GET_PRIV (chat);
 
        if (!priv->sent_messages) {
-               empathy_debug (DEBUG_DOMAIN, 
-                             "No sent messages, next message is NULL");
+               DEBUG ("No sent messages, next message is NULL");
                return NULL;
        }
 
@@ -333,9 +316,7 @@ chat_sent_message_get_next (EmpathyChat *chat)
                priv->sent_messages_index++;
        }
        
-       empathy_debug (DEBUG_DOMAIN, 
-                     "Returning next message index:%d",
-                     priv->sent_messages_index);
+       DEBUG ("Returning next message index:%d", priv->sent_messages_index);
 
        return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
 }
@@ -350,8 +331,7 @@ chat_sent_message_get_last (EmpathyChat *chat)
        priv = GET_PRIV (chat);
        
        if (!priv->sent_messages) {
-               empathy_debug (DEBUG_DOMAIN, 
-                             "No sent messages, last message is NULL");
+               DEBUG ("No sent messages, last message is NULL");
                return NULL;
        }
 
@@ -359,9 +339,7 @@ chat_sent_message_get_last (EmpathyChat *chat)
                priv->sent_messages_index--;
        }
 
-       empathy_debug (DEBUG_DOMAIN, 
-                     "Returning last message index:%d",
-                     priv->sent_messages_index);
+       DEBUG ("Returning last message index:%d", priv->sent_messages_index);
 
        return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
 }
@@ -371,26 +349,33 @@ chat_send (EmpathyChat  *chat,
           const gchar *msg)
 {
        EmpathyChatPriv *priv;
-       EmpathyMessage  *message;
-
-       priv = GET_PRIV (chat);
 
-       if (G_STR_EMPTY (msg)) {
+       if (EMP_STR_EMPTY (msg)) {
                return;
        }
 
+       priv = GET_PRIV (chat);
+
        chat_sent_message_add (chat, msg);
 
+       /* If this is not a command, send the message */
+       if (msg[0] != '/') {
+               EmpathyMessage  *message;
+
+               message = empathy_message_new (msg);
+               empathy_tp_chat_send (priv->tp_chat, message);
+               g_object_unref (message);
+               return;
+       }
+
+       /* Check for all supported commands */
        if (g_str_has_prefix (msg, "/clear")) {
                empathy_chat_view_clear (chat->view);
                return;
        }
 
-       message = empathy_message_new (msg);
-
-       empathy_tp_chat_send (priv->tp_chat, message);
-
-       g_object_unref (message);
+       /* This is an unknown command, display a message to the user */
+       empathy_chat_view_append_event (chat->view, _("Unsupported command"));
 }
 
 static void
@@ -464,9 +449,9 @@ chat_state_changed_cb (EmpathyTpChat      *tp_chat,
                g_assert_not_reached ();
        }
 
-       empathy_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s",
-                     was_composing ? "yes" : "no",
-                     priv->compositors ? "yes" : "no");
+       DEBUG ("Was composing: %s now composing: %s",
+               was_composing ? "yes" : "no",
+               priv->compositors ? "yes" : "no");
 
        if ((was_composing && !priv->compositors) ||
            (!was_composing && priv->compositors)) {
@@ -477,67 +462,36 @@ chat_state_changed_cb (EmpathyTpChat      *tp_chat,
 }
 
 static void
-chat_message_received_cb (EmpathyTpChat  *tp_chat,
-                         EmpathyMessage *message,
-                         EmpathyChat    *chat)
+chat_message_received (EmpathyChat *chat, EmpathyMessage *message)
 {
-       EmpathyChatPriv *priv;
+       EmpathyChatPriv *priv = GET_PRIV (chat);
        EmpathyContact  *sender;
-       const gchar     *body;
-
-       priv = GET_PRIV (chat);
 
        sender = empathy_message_get_sender (message);
-       body = empathy_message_get_body (message);
-       while (priv->backlog_messages) {
-               EmpathyMessage *log_message;
-               EmpathyContact *log_sender;
-               const gchar    *log_body;
-
-               log_message = priv->backlog_messages->data;
-               log_sender = empathy_message_get_sender (log_message);
-               log_body = empathy_message_get_body (log_message);
-
-               priv->backlog_messages = g_list_remove (priv->backlog_messages,
-                                                       log_message);
-
-               if (empathy_contact_equal (sender, log_sender) &&
-                   !tp_strdiff (body, log_body)) {
-                       /* The message we received is already displayed because
-                        * some jabber chatrooms sends us back logs and we
-                        * already displayed it from localy logged messages. */
-                       empathy_debug (DEBUG_DOMAIN, "Skipping message because "
-                                      "it is already displayed from logged "
-                                      "messages");
-                       g_object_unref (log_message);
-                       return;
-               }
-               g_object_unref (log_message);
-       }
-
-       empathy_debug (DEBUG_DOMAIN, "Appending new message from %s (%d)",
-                      empathy_contact_get_name (sender),
-                      empathy_contact_get_handle (sender));
 
-       if (priv->id) {
-               gboolean is_chatroom;
-
-               is_chatroom = priv->handle_type == TP_HANDLE_TYPE_ROOM;
-               empathy_log_manager_add_message (priv->log_manager,
-                                                priv->id, is_chatroom,
-                                                message);
-       }
+       DEBUG ("Appending new message from %s (%d)",
+               empathy_contact_get_name (sender),
+               empathy_contact_get_handle (sender));
 
        empathy_chat_view_append_message (chat->view, message);
 
-       /* We received a message so the contact is no more composing */
-       chat_state_changed_cb (tp_chat, sender,
+       /* We received a message so the contact is no longer composing */
+       chat_state_changed_cb (priv->tp_chat, sender,
                               TP_CHANNEL_CHAT_STATE_ACTIVE,
                               chat);
 
        g_signal_emit (chat, signals[NEW_MESSAGE], 0, message);
 }
 
+static void
+chat_message_received_cb (EmpathyTpChat  *tp_chat,
+                         EmpathyMessage *message,
+                         EmpathyChat    *chat)
+{
+       chat_message_received (chat, message);
+       empathy_tp_chat_acknowledge_message (tp_chat, message);
+}
+
 static void
 chat_send_error_cb (EmpathyTpChat          *tp_chat,
                    EmpathyMessage         *message,
@@ -588,7 +542,7 @@ chat_property_changed_cb (EmpathyTpChat *tp_chat,
                priv->subject = g_value_dup_string (value);
                g_object_notify (G_OBJECT (chat), "subject");
 
-               if (G_STR_EMPTY (priv->subject)) {
+               if (EMP_STR_EMPTY (priv->subject)) {
                        gtk_widget_hide (priv->hbox_topic);
                } else {
                        gtk_label_set_text (GTK_LABEL (priv->label_topic), priv->subject);
@@ -597,7 +551,7 @@ chat_property_changed_cb (EmpathyTpChat *tp_chat,
                if (priv->block_events_timeout_id == 0) {
                        gchar *str;
 
-                       if (!G_STR_EMPTY (priv->subject)) {
+                       if (!EMP_STR_EMPTY (priv->subject)) {
                                str = g_strdup_printf (_("Topic set to: %s"), priv->subject);
                        } else {
                                str = g_strdup (_("No topic defined"));
@@ -916,24 +870,23 @@ static void
 chat_input_realize_cb (GtkWidget   *widget,
                       EmpathyChat *chat)
 {
-       empathy_debug (DEBUG_DOMAIN, "Setting focus to the input text view");
+       DEBUG ("Setting focus to the input text view");
        gtk_widget_grab_focus (widget);
 }
 
 static void
-chat_insert_smiley_activate_cb (GtkWidget   *menuitem,
-                               EmpathyChat *chat)
+chat_insert_smiley_activate_cb (EmpathySmileyManager *manager,
+                               EmpathySmiley        *smiley,
+                               gpointer              user_data)
 {
+       EmpathyChat   *chat = EMPATHY_CHAT (user_data);
        GtkTextBuffer *buffer;
        GtkTextIter    iter;
-       const gchar   *smiley;
-
-       smiley = g_object_get_data (G_OBJECT (menuitem), "smiley_text");
 
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
 
        gtk_text_buffer_get_end_iter (buffer, &iter);
-       gtk_text_buffer_insert (buffer, &iter, smiley, -1);
+       gtk_text_buffer_insert (buffer, &iter, smiley->str, -1);
 
        gtk_text_buffer_get_end_iter (buffer, &iter);
        gtk_text_buffer_insert (buffer, &iter, " ", -1);
@@ -978,88 +931,126 @@ chat_text_check_word_spelling_cb (GtkMenuItem     *menuitem,
                                  EmpathyChatSpell *chat_spell)
 {
        empathy_spell_dialog_show (chat_spell->chat,
-                                 chat_spell->start,
-                                 chat_spell->end,
+                                 &chat_spell->start,
+                                 &chat_spell->end,
                                  chat_spell->word);
 }
 
+static void
+chat_text_send_cb (GtkMenuItem *menuitem,
+                  EmpathyChat *chat)
+{
+       chat_input_text_view_send (chat);
+}
+
 static void
 chat_input_populate_popup_cb (GtkTextView *view,
                              GtkMenu     *menu,
                              EmpathyChat *chat)
 {
-       EmpathyChatPriv  *priv;
-       GtkTextBuffer   *buffer;
-       GtkTextTagTable *table;
-       GtkTextTag      *tag;
-       gint             x, y;
-       GtkTextIter      iter, start, end;
-       GtkWidget       *item;
-       gchar           *str = NULL;
-       EmpathyChatSpell *chat_spell;
-       GtkWidget       *smiley_menu;
+       EmpathyChatPriv      *priv;
+       GtkTextBuffer        *buffer;
+       GtkTextTagTable      *table;
+       GtkTextTag           *tag;
+       gint                  x, y;
+       GtkTextIter           iter, start, end;
+       GtkWidget            *item;
+       gchar                *str = NULL;
+       EmpathyChatSpell      *chat_spell;
+       EmpathySmileyManager *smiley_manager;
+       GtkWidget            *smiley_menu;
+       GtkWidget            *image;
 
        priv = GET_PRIV (chat);
+       buffer = gtk_text_view_get_buffer (view);
 
        /* Add the emoticon menu. */
        item = gtk_separator_menu_item_new ();
        gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
        gtk_widget_show (item);
 
-       item = gtk_menu_item_new_with_mnemonic (_("Insert Smiley"));
+       item = gtk_image_menu_item_new_with_mnemonic (_("Insert Smiley"));
+       image = gtk_image_new_from_icon_name ("face-smile",
+                                             GTK_ICON_SIZE_MENU);
+       gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
        gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
        gtk_widget_show (item);
 
-       smiley_menu = empathy_chat_view_get_smiley_menu (
-               G_CALLBACK (chat_insert_smiley_activate_cb),
-               chat);
+       smiley_manager = empathy_smiley_manager_dup_singleton ();
+       smiley_menu = empathy_smiley_menu_new (smiley_manager,
+                                              chat_insert_smiley_activate_cb,
+                                              chat);
        gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smiley_menu);
+       g_object_unref (smiley_manager);
+
+       /* Add the Send menu item. */
+       gtk_text_buffer_get_bounds (buffer, &start, &end);
+       str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+       if (!EMP_STR_EMPTY (str)) {
+               item = gtk_menu_item_new_with_mnemonic (_("_Send"));
+               g_signal_connect (G_OBJECT (item), "activate",
+                                 G_CALLBACK (chat_text_send_cb), chat);
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+               gtk_widget_show (item);
+       }
+       str = NULL;
 
        /* Add the spell check menu item. */
-       buffer = gtk_text_view_get_buffer (view);
        table = gtk_text_buffer_get_tag_table (buffer);
-
        tag = gtk_text_tag_table_lookup (table, "misspelled");
-
        gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
-
        gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
                                               GTK_TEXT_WINDOW_WIDGET,
                                               x, y,
                                               &x, &y);
-
        gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y);
-
        start = end = iter;
-
        if (gtk_text_iter_backward_to_tag_toggle (&start, tag) &&
            gtk_text_iter_forward_to_tag_toggle (&end, tag)) {
 
                str = gtk_text_buffer_get_text (buffer,
                                                &start, &end, FALSE);
        }
-
-       if (G_STR_EMPTY (str)) {
-               return;
+       if (!EMP_STR_EMPTY (str)) {
+               chat_spell = chat_spell_new (chat, str, start, end);
+               g_object_set_data_full (G_OBJECT (menu),
+                                       "chat_spell", chat_spell,
+                                       (GDestroyNotify) chat_spell_free);
+
+               item = gtk_separator_menu_item_new ();
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+               gtk_widget_show (item);
+
+               item = gtk_image_menu_item_new_with_mnemonic (_("_Check Word Spelling..."));
+               image = gtk_image_new_from_icon_name (GTK_STOCK_SPELL_CHECK,
+                                                     GTK_ICON_SIZE_MENU);
+               gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+               g_signal_connect (item,
+                                 "activate",
+                                 G_CALLBACK (chat_text_check_word_spelling_cb),
+                                 chat_spell);
+               gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+               gtk_widget_show (item);
        }
+}
 
-       chat_spell = chat_spell_new (chat, str, start, end);
+static gboolean
+chat_log_filter (EmpathyMessage *message,
+                gpointer user_data)
+{
+       EmpathyChat *chat = (EmpathyChat *) user_data;
+       EmpathyChatPriv *priv = GET_PRIV (chat);
+       const GList *pending;
 
-       g_object_set_data_full (G_OBJECT (menu),
-                               "chat_spell", chat_spell,
-                               (GDestroyNotify) chat_spell_free);
+       pending = empathy_tp_chat_get_pending_messages (priv->tp_chat);
 
-       item = gtk_separator_menu_item_new ();
-       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
-       gtk_widget_show (item);
+       for (; pending; pending = g_list_next (pending)) {
+               if (empathy_message_equal (message, pending->data)) {
+                       return FALSE;
+               }
+       }
 
-       item = gtk_menu_item_new_with_mnemonic (_("_Check Word Spelling..."));
-       g_signal_connect (item,
-                         "activate",
-                         G_CALLBACK (chat_text_check_word_spelling_cb),
-                         chat_spell);
-       gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
-       gtk_widget_show (item);
+       return TRUE;
 }
 
 static void
@@ -1068,8 +1059,6 @@ chat_add_logs (EmpathyChat *chat)
        EmpathyChatPriv *priv = GET_PRIV (chat);
        gboolean         is_chatroom;
        GList           *messages, *l;
-       guint            num_messages;
-       guint            i;
 
        if (!priv->id) {
                return;
@@ -1080,25 +1069,21 @@ chat_add_logs (EmpathyChat *chat)
 
        /* Add messages from last conversation */
        is_chatroom = priv->handle_type == TP_HANDLE_TYPE_ROOM;
-       messages = empathy_log_manager_get_last_messages (priv->log_manager,
-                                                         priv->account,
-                                                         priv->id,
-                                                         is_chatroom);
-       num_messages  = g_list_length (messages);
-
-       /* Only keep the 10 last messages */
-       for (i = 0; num_messages - i > 10; i++) {
-               EmpathyMessage *message;
-
-               message = messages->data;
-               messages = g_list_remove (messages, message);
-               g_object_unref (message);
-       }
 
-       for (l = messages; l; l = l->next) {
+       messages = empathy_log_manager_get_filtered_messages (priv->log_manager,
+                                                             priv->account,
+                                                             priv->id,
+                                                             is_chatroom,
+                                                             5,
+                                                             chat_log_filter,
+                                                             chat);
+
+       for (l = messages; l; l = g_list_next (l)) {
                empathy_chat_view_append_message (chat->view, l->data);
+               g_object_unref (l->data);
        }
-       priv->backlog_messages = messages;
+
+       g_list_free (messages);
 
        /* Turn back on scrolling */
        empathy_chat_view_scroll (chat->view, TRUE);
@@ -1255,6 +1240,45 @@ chat_remote_contact_changed_cb (EmpathyChat *chat)
        g_object_notify (G_OBJECT (chat), "id");
 }
 
+static void
+chat_destroy_cb (EmpathyTpChat *tp_chat,
+                EmpathyChat   *chat)
+{
+       EmpathyChatPriv *priv;
+
+       priv = GET_PRIV (chat);
+
+       if (!priv->tp_chat) {
+               return;
+       }
+
+       chat_composing_remove_timeout (chat);
+       g_object_unref (priv->tp_chat);
+       priv->tp_chat = NULL;
+       g_object_notify (G_OBJECT (chat), "tp-chat");
+
+       empathy_chat_view_append_event (chat->view, _("Disconnected"));
+       gtk_widget_set_sensitive (chat->input_text_view, FALSE);
+       chat_set_show_contacts (chat, FALSE);
+}
+
+static void
+show_pending_messages (EmpathyChat *chat) {
+       EmpathyChatPriv *priv = GET_PRIV (chat);
+       const GList *messages, *l;
+
+       if (chat->view == NULL || priv->tp_chat == NULL)
+               return;
+
+       messages = empathy_tp_chat_get_pending_messages (priv->tp_chat);
+
+       for (l = messages; l != NULL ; l = g_list_next (l)) {
+               EmpathyMessage *message = EMPATHY_MESSAGE (l->data);
+               chat_message_received (chat, message);
+       }
+       empathy_tp_chat_acknowledge_messages (priv->tp_chat, messages);
+}
+
 static void
 chat_create_ui (EmpathyChat *chat)
 {
@@ -1281,8 +1305,8 @@ chat_create_ui (EmpathyChat *chat)
        g_free (filename);
        g_object_unref (glade);
 
-       /* Add message GtkTextView. */
-       chat->view = empathy_chat_view_new ();
+       /* Add message view. */
+       chat->view = empathy_theme_manager_create_view (empathy_theme_manager_get ());
        g_signal_connect (chat->view, "focus_in_event",
                          G_CALLBACK (chat_text_view_focus_in_event_cb),
                          chat);
@@ -1396,7 +1420,7 @@ chat_finalize (GObject *object)
        chat = EMPATHY_CHAT (object);
        priv = GET_PRIV (chat);
 
-       empathy_debug (DEBUG_DOMAIN, "Finalized: %p", object);
+       DEBUG ("Finalized: %p", object);
 
        g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL);
        g_slist_free (priv->sent_messages);
@@ -1404,16 +1428,17 @@ chat_finalize (GObject *object)
        g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL);
        g_list_free (priv->compositors);
 
-       g_list_foreach (priv->backlog_messages, (GFunc) g_object_unref, NULL);
-       g_list_free (priv->backlog_messages);
-
        chat_composing_remove_timeout (chat);
 
-       empathy_disconnect_account_status_changed (priv->token);
-       g_object_unref (priv->mc);
+       g_signal_handlers_disconnect_by_func (priv->account_manager,
+                                             chat_connection_changed_cb, object);
+
+       g_object_unref (priv->account_manager);
        g_object_unref (priv->log_manager);
 
        if (priv->tp_chat) {
+               g_signal_handler_disconnect (priv->tp_chat, priv->tp_chat_destroy_handler);
+               empathy_tp_chat_close (priv->tp_chat);
                g_object_unref (priv->tp_chat);
        }
        if (priv->account) {
@@ -1430,6 +1455,7 @@ chat_finalize (GObject *object)
        g_free (priv->id);
        g_free (priv->name);
        g_free (priv->subject);
+       g_completion_free (priv->completion);
 
        G_OBJECT_CLASS (empathy_chat_parent_class)->finalize (object);
 }
@@ -1441,6 +1467,7 @@ chat_constructed (GObject *object)
 
        chat_create_ui (chat);
        chat_add_logs (chat);
+       show_pending_messages (chat);
 }
 
 static void
@@ -1537,17 +1564,20 @@ chat_block_events_timeout_cb (gpointer data)
 static void
 empathy_chat_init (EmpathyChat *chat)
 {
-       EmpathyChatPriv *priv = GET_PRIV (chat);
+       EmpathyChatPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chat,
+               EMPATHY_TYPE_CHAT, EmpathyChatPriv);
 
-       priv->log_manager = empathy_log_manager_new ();
+       chat->priv = priv;
+       priv->log_manager = empathy_log_manager_dup_singleton ();
        priv->contacts_width = -1;
        priv->sent_messages = NULL;
        priv->sent_messages_index = -1;
-       priv->mc = empathy_mission_control_new ();
+       priv->account_manager = empathy_account_manager_dup_singleton ();
 
-       priv->token = empathy_connect_to_account_status_changed (priv->mc,
-                                                  G_CALLBACK (chat_status_changed_cb),
-                                                  chat, NULL);
+       g_signal_connect (priv->account_manager,
+                         "account-connection-changed",
+                         G_CALLBACK (chat_connection_changed_cb),
+                         chat);
 
        /* Block events for some time to avoid having "has come online" or
         * "joined" messages. */
@@ -1614,7 +1644,8 @@ empathy_chat_set_tp_chat (EmpathyChat   *chat,
        g_signal_connect_swapped (tp_chat, "notify::remote-contact",
                                  G_CALLBACK (chat_remote_contact_changed_cb),
                                  chat);
-       g_signal_connect (tp_chat, "destroy",
+       priv->tp_chat_destroy_handler =
+               g_signal_connect (tp_chat, "destroy",
                          G_CALLBACK (chat_destroy_cb),
                          chat);
 
@@ -1627,12 +1658,14 @@ empathy_chat_set_tp_chat (EmpathyChat   *chat,
                }
        }
 
-       empathy_tp_chat_set_acknowledge (priv->tp_chat, TRUE);
-       empathy_tp_chat_emit_pendings (priv->tp_chat);
-
        g_object_notify (G_OBJECT (chat), "tp-chat");
        g_object_notify (G_OBJECT (chat), "id");
        g_object_notify (G_OBJECT (chat), "account");
+
+       /* This is a noop when tp-chat is set at object construction time and causes
+        * the pending messages to be show when it's set on the object after it has
+        * been created */
+       show_pending_messages (chat);
 }
 
 McAccount *
@@ -1659,10 +1692,19 @@ const gchar *
 empathy_chat_get_name (EmpathyChat *chat)
 {
        EmpathyChatPriv *priv = GET_PRIV (chat);
+       const gchar *ret;
 
        g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL);
 
-       return priv->name;
+       ret = priv->name;
+       if (!ret && priv->remote_contact) {
+               ret = empathy_contact_get_name (priv->remote_contact);
+       }
+
+       if (!ret)
+               ret = priv->id;
+
+       return ret ? ret : _("Conversation");
 }
 
 const gchar *
@@ -1747,7 +1789,7 @@ empathy_chat_cut (EmpathyChat *chat)
        g_return_if_fail (EMPATHY_IS_CHAT (chat));
 
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
-       if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) {
+       if (gtk_text_buffer_get_has_selection (buffer)) {
                GtkClipboard *clipboard;
 
                clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
@@ -1763,13 +1805,13 @@ empathy_chat_copy (EmpathyChat *chat)
 
        g_return_if_fail (EMPATHY_IS_CHAT (chat));
 
-       if (empathy_chat_view_get_selection_bounds (chat->view, NULL, NULL)) {
+       if (empathy_chat_view_get_has_selection (chat->view)) {
                empathy_chat_view_copy_clipboard (chat->view);
                return;
        }
 
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
-       if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL)) {
+       if (gtk_text_buffer_get_has_selection (buffer)) {
                GtkClipboard *clipboard;
 
                clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
@@ -1794,8 +1836,8 @@ empathy_chat_paste (EmpathyChat *chat)
 
 void
 empathy_chat_correct_word (EmpathyChat  *chat,
-                         GtkTextIter  start,
-                         GtkTextIter  end,
+                         GtkTextIter *start,
+                         GtkTextIter *end,
                          const gchar *new_word)
 {
        GtkTextBuffer *buffer;
@@ -1805,9 +1847,19 @@ empathy_chat_correct_word (EmpathyChat  *chat,
 
        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
 
-       gtk_text_buffer_delete (buffer, &start, &end);
-       gtk_text_buffer_insert (buffer, &start,
+       gtk_text_buffer_delete (buffer, start, end);
+       gtk_text_buffer_insert (buffer, start,
                                new_word,
                                -1);
 }
 
+gboolean
+empathy_chat_is_room (EmpathyChat *chat)
+{
+       EmpathyChatPriv *priv = GET_PRIV (chat);
+
+       g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE);
+
+       return (priv->handle_type == TP_HANDLE_TYPE_ROOM);
+}
+