]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-chat.c
Merge remote-tracking branch 'jonny/ft'
[empathy.git] / libempathy / empathy-tp-chat.c
index 34e2d40b271b01975b3309704b791b90f5a2eba6..96eda77b847abeae591081cffd5574afd4bf5c18 100644 (file)
@@ -30,7 +30,6 @@
 #include "empathy-tp-chat.h"
 #include "empathy-tp-contact-factory.h"
 #include "empathy-contact-list.h"
-#include "empathy-marshal.h"
 #include "empathy-request-util.h"
 #include "empathy-time.h"
 #include "empathy-utils.h"
@@ -47,15 +46,17 @@ struct _EmpathyTpChatPrivate {
        GQueue                *messages_queue;
        /* Queue of messages signalled but not acked yet */
        GQueue                *pending_messages_queue;
-       gboolean               had_properties_list;
-       GPtrArray             *properties;
-       TpChannelPasswordFlags password_flags;
-       /* TRUE if we fetched the password flag of the channel or if it's not needed
-        * (channel doesn't implement the Password interface) */
-       gboolean               got_password_flags;
+
+       /* Subject */
+       gboolean               supports_subject;
+       gboolean               can_set_subject;
+       gchar                 *subject;
+
+       /* Room config (for now, we only track the title and don't support
+        * setting it) */
+       gchar                 *title;
+
        gboolean               can_upgrade_to_muc;
-       gboolean               got_sms_channel;
-       gboolean               sms_channel;
 
        GHashTable            *messages_being_sent;
 
@@ -69,16 +70,15 @@ enum {
        PROP_0,
        PROP_ACCOUNT,
        PROP_REMOTE_CONTACT,
-       PROP_PASSWORD_NEEDED,
-       PROP_SMS_CHANNEL,
        PROP_N_MESSAGES_SENDING,
+       PROP_TITLE,
+       PROP_SUBJECT,
 };
 
 enum {
        MESSAGE_RECEIVED,
        SEND_ERROR,
        CHAT_STATE_CHANGED,
-       PROPERTY_CHANGED,
        MESSAGE_ACKNOWLEDGED,
        LAST_SIGNAL
 };
@@ -365,7 +365,8 @@ handle_delivery_report (EmpathyTpChat *self,
                tp_chat_set_delivery_status (self, delivery_token,
                        EMPATHY_DELIVERY_STATUS_NONE);
                goto out;
-       } else if (delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED) {
+       } else if (delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED &&
+                  delivery_status != TP_DELIVERY_STATUS_TEMPORARILY_FAILED) {
                goto out;
        }
 
@@ -379,7 +380,7 @@ handle_delivery_report (EmpathyTpChat *self,
         * TpMessage. (fdo #35884) */
        echo = tp_asv_get_boxed (header, "delivery-echo",
                TP_ARRAY_TYPE_MESSAGE_PART_LIST);
-       if (echo != NULL && echo->len >= 1) {
+       if (echo != NULL && echo->len >= 2) {
                const GHashTable *echo_body;
 
                echo_body = g_ptr_array_index (echo, 1);
@@ -593,220 +594,142 @@ list_pending_messages (EmpathyTpChat *self)
 }
 
 static void
-tp_chat_property_flags_changed_cb (TpProxy         *proxy,
-                                  const GPtrArray *properties,
-                                  gpointer         user_data,
-                                  GObject         *chat)
+update_subject (EmpathyTpChat *self,
+               GHashTable *properties)
 {
-       EmpathyTpChat *self = (EmpathyTpChat *) chat;
-       guint              i, j;
+       EmpathyTpChatPrivate *priv = self->priv;
+       gboolean can_set, valid;
+       const gchar *subject;
 
-       if (!self->priv->had_properties_list || !properties) {
-               return;
+       can_set = tp_asv_get_boolean (properties, "CanSet", &valid);
+       if (valid) {
+               priv->can_set_subject = can_set;
        }
 
-       for (i = 0; i < properties->len; i++) {
-               GValueArray           *prop_struct;
-               EmpathyTpChatProperty *property;
-               guint                  id;
-               guint                  flags;
-
-               prop_struct = g_ptr_array_index (properties, i);
-               id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
-               flags = g_value_get_uint (g_value_array_get_nth (prop_struct, 1));
-
-               for (j = 0; j < self->priv->properties->len; j++) {
-                       property = g_ptr_array_index (self->priv->properties, j);
-                       if (property->id == id) {
-                               property->flags = flags;
-                               DEBUG ("property %s flags changed: %d",
-                                       property->name, property->flags);
-                               break;
-                       }
-               }
+       subject = tp_asv_get_string (properties, "Subject");
+       if (subject != NULL) {
+               g_free (priv->subject);
+               priv->subject = g_strdup (subject);
+               g_object_notify (G_OBJECT (self), "subject");
        }
+
+       /* TODO: track Actor and Timestamp. */
 }
 
 static void
-tp_chat_properties_changed_cb (TpProxy         *proxy,
-                              const GPtrArray *properties,
-                              gpointer         user_data,
-                              GObject         *chat)
+tp_chat_get_all_subject_cb (TpProxy      *proxy,
+                           GHashTable   *properties,
+                           const GError *error,
+                           gpointer      user_data G_GNUC_UNUSED,
+                           GObject      *chat)
 {
-       EmpathyTpChat *self = (EmpathyTpChat *) chat;
-       guint              i, j;
+       EmpathyTpChat *self = EMPATHY_TP_CHAT (chat);
+       EmpathyTpChatPrivate *priv = self->priv;
 
-       if (!self->priv->had_properties_list || !properties) {
+       if (error) {
+               DEBUG ("Error fetching subject: %s", error->message);
                return;
        }
 
-       for (i = 0; i < properties->len; i++) {
-               GValueArray           *prop_struct;
-               EmpathyTpChatProperty *property;
-               guint                  id;
-               GValue                *src_value;
-
-               prop_struct = g_ptr_array_index (properties, i);
-               id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
-               src_value = g_value_get_boxed (g_value_array_get_nth (prop_struct, 1));
-
-               for (j = 0; j < self->priv->properties->len; j++) {
-                       property = g_ptr_array_index (self->priv->properties, j);
-                       if (property->id == id) {
-                               if (property->value) {
-                                       g_value_copy (src_value, property->value);
-                               } else {
-                                       property->value = tp_g_value_slice_dup (src_value);
-                               }
-
-                               DEBUG ("property %s changed", property->name);
-                               g_signal_emit (chat, signals[PROPERTY_CHANGED], 0,
-                                              property->name, property->value);
-                               break;
-                       }
+       priv->supports_subject = TRUE;
+       update_subject (self, properties);
+}
+
+static void
+update_title (EmpathyTpChat *self,
+             GHashTable *properties)
+{
+       EmpathyTpChatPrivate *priv = self->priv;
+       const gchar *title = tp_asv_get_string (properties, "Title");
+
+       if (title != NULL) {
+               if (tp_str_empty (title)) {
+                       title = NULL;
                }
+
+               g_free (priv->title);
+               priv->title = g_strdup (title);
+               g_object_notify (G_OBJECT (self), "title");
        }
 }
 
 static void
-tp_chat_get_properties_cb (TpProxy         *proxy,
-                          const GPtrArray *properties,
-                          const GError    *error,
-                          gpointer         user_data,
-                          GObject         *chat)
+tp_chat_get_all_room_config_cb (TpProxy      *proxy,
+                               GHashTable   *properties,
+                               const GError *error,
+                               gpointer      user_data G_GNUC_UNUSED,
+                               GObject      *chat)
 {
+       EmpathyTpChat *self = EMPATHY_TP_CHAT (chat);
+
        if (error) {
-               DEBUG ("Error getting properties: %s", error->message);
+               DEBUG ("Error fetching room config: %s", error->message);
                return;
        }
 
-       tp_chat_properties_changed_cb (proxy, properties, user_data, chat);
+       update_title (self, properties);
 }
 
 static void
-tp_chat_list_properties_cb (TpProxy         *proxy,
-                           const GPtrArray *properties,
-                           const GError    *error,
-                           gpointer         user_data,
-                           GObject         *chat)
+tp_chat_dbus_properties_changed_cb (TpProxy *proxy,
+                                   const gchar *interface_name,
+                                   GHashTable *changed,
+                                   const gchar **invalidated,
+                                   gpointer user_data,
+                                   GObject *chat)
 {
-       EmpathyTpChat *self = (EmpathyTpChat *) chat;
-       GArray            *ids;
-       guint              i;
-
-       self->priv->had_properties_list = TRUE;
+       EmpathyTpChat *self = EMPATHY_TP_CHAT (chat);
 
-       if (error) {
-               DEBUG ("Error listing properties: %s", error->message);
-               return;
+       if (!tp_strdiff (interface_name, TP_IFACE_CHANNEL_INTERFACE_SUBJECT)) {
+               update_subject (self, changed);
        }
 
-       ids = g_array_sized_new (FALSE, FALSE, sizeof (guint), properties->len);
-       self->priv->properties = g_ptr_array_sized_new (properties->len);
-       for (i = 0; i < properties->len; i++) {
-               GValueArray           *prop_struct;
-               EmpathyTpChatProperty *property;
-
-               prop_struct = g_ptr_array_index (properties, i);
-               property = g_slice_new0 (EmpathyTpChatProperty);
-               property->id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
-               property->name = g_value_dup_string (g_value_array_get_nth (prop_struct, 1));
-               property->flags = g_value_get_uint (g_value_array_get_nth (prop_struct, 3));
-
-               DEBUG ("Adding property name=%s id=%d flags=%d",
-                       property->name, property->id, property->flags);
-               g_ptr_array_add (self->priv->properties, property);
-               if (property->flags & TP_PROPERTY_FLAG_READ) {
-                       g_array_append_val (ids, property->id);
-               }
+       if (!tp_strdiff (interface_name, TP_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG)) {
+               update_title (self, changed);
        }
-
-       tp_cli_properties_interface_call_get_properties (proxy, -1,
-                                                        ids,
-                                                        tp_chat_get_properties_cb,
-                                                        NULL, NULL,
-                                                        chat);
-
-       g_array_free (ids, TRUE);
 }
 
 void
-empathy_tp_chat_set_property (EmpathyTpChat *self,
-                             const gchar   *name,
-                             const GValue  *value)
+empathy_tp_chat_set_subject (EmpathyTpChat *self,
+                            const gchar   *subject)
 {
-       EmpathyTpChatProperty *property;
-       guint                  i;
-
-       if (!self->priv->had_properties_list) {
-               return;
-       }
-
-       for (i = 0; i < self->priv->properties->len; i++) {
-               property = g_ptr_array_index (self->priv->properties, i);
-               if (!tp_strdiff (property->name, name)) {
-                       GPtrArray   *properties;
-                       GValueArray *prop;
-                       GValue       id = {0, };
-                       GValue       dest_value = {0, };
-
-                       if (!(property->flags & TP_PROPERTY_FLAG_WRITE)) {
-                               break;
-                       }
-
-                       g_value_init (&id, G_TYPE_UINT);
-                       g_value_init (&dest_value, G_TYPE_VALUE);
-                       g_value_set_uint (&id, property->id);
-                       g_value_set_boxed (&dest_value, value);
-
-                       prop = g_value_array_new (2);
-                       g_value_array_append (prop, &id);
-                       g_value_array_append (prop, &dest_value);
-
-                       properties = g_ptr_array_sized_new (1);
-                       g_ptr_array_add (properties, prop);
-
-                       DEBUG ("Set property %s", name);
-                       tp_cli_properties_interface_call_set_properties (self, -1,
-                                                                        properties,
-                                                                        (tp_cli_properties_interface_callback_for_set_properties)
-                                                                        tp_chat_async_cb,
-                                                                        "Seting property", NULL,
-                                                                        G_OBJECT (self));
+       tp_cli_channel_interface_subject_call_set_subject (TP_CHANNEL (self), -1,
+                                                          subject,
+                                                          tp_chat_async_cb,
+                                                          "while setting subject", NULL,
+                                                          G_OBJECT (self));
+}
 
-                       g_ptr_array_free (properties, TRUE);
-                       g_value_array_free (prop);
+const gchar *
+empathy_tp_chat_get_title (EmpathyTpChat *self)
+{
+       EmpathyTpChatPrivate *priv = self->priv;
 
-                       break;
-               }
-       }
+       return priv->title;
 }
 
-EmpathyTpChatProperty *
-empathy_tp_chat_get_property (EmpathyTpChat *self,
-                             const gchar   *name)
+gboolean
+empathy_tp_chat_supports_subject (EmpathyTpChat *self)
 {
-       EmpathyTpChatProperty *property;
-       guint                  i;
+       EmpathyTpChatPrivate *priv = self->priv;
 
-       if (!self->priv->had_properties_list) {
-               return NULL;
-       }
+       return priv->supports_subject;
+}
 
-       for (i = 0; i < self->priv->properties->len; i++) {
-               property = g_ptr_array_index (self->priv->properties, i);
-               if (!tp_strdiff (property->name, name)) {
-                       return property;
-               }
-       }
+gboolean
+empathy_tp_chat_can_set_subject (EmpathyTpChat *self)
+{
+       EmpathyTpChatPrivate *priv = self->priv;
 
-       return NULL;
+       return priv->can_set_subject;
 }
 
-GPtrArray *
-empathy_tp_chat_get_properties (EmpathyTpChat *self)
+const gchar *
+empathy_tp_chat_get_subject (EmpathyTpChat *self)
 {
-       return self->priv->properties;
+       EmpathyTpChatPrivate *priv = self->priv;
+
+       return priv->subject;
 }
 
 static void
@@ -835,27 +758,15 @@ static void
 tp_chat_finalize (GObject *object)
 {
        EmpathyTpChat *self = (EmpathyTpChat *) object;
-       guint              i;
 
        DEBUG ("Finalize: %p", object);
 
-       if (self->priv->properties) {
-               for (i = 0; i < self->priv->properties->len; i++) {
-                       EmpathyTpChatProperty *property;
-
-                       property = g_ptr_array_index (self->priv->properties, i);
-                       g_free (property->name);
-                       if (property->value) {
-                               tp_g_value_slice_free (property->value);
-                       }
-                       g_slice_free (EmpathyTpChatProperty, property);
-               }
-               g_ptr_array_free (self->priv->properties, TRUE);
-       }
-
        g_queue_free (self->priv->messages_queue);
        g_queue_free (self->priv->pending_messages_queue);
-       g_hash_table_destroy (self->priv->messages_being_sent);
+       g_hash_table_unref (self->priv->messages_being_sent);
+
+       g_free (self->priv->title);
+       g_free (self->priv->subject);
 
        G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object);
 }
@@ -863,22 +774,18 @@ tp_chat_finalize (GObject *object)
 static void
 check_almost_ready (EmpathyTpChat *self)
 {
+       TpChannel *channel = (TpChannel *) self;
+
        if (self->priv->ready_result == NULL)
                return;
 
        if (self->priv->user == NULL)
                return;
 
-       if (!self->priv->got_password_flags)
-               return;
-
-       if (!self->priv->got_sms_channel)
-               return;
-
        /* We need either the members (room) or the remote contact (private chat).
         * If the chat is protected by a password we can't get these information so
         * consider the chat as ready so it can be presented to the user. */
-       if (!empathy_tp_chat_password_needed (self) && self->priv->members == NULL &&
+       if (!tp_channel_password_needed (channel) && self->priv->members == NULL &&
            self->priv->remote_contact == NULL)
                return;
 
@@ -901,66 +808,6 @@ check_almost_ready (EmpathyTpChat *self)
        check_ready (self);
 }
 
-static void
-tp_chat_update_remote_contact (EmpathyTpChat *self)
-{
-       TpChannel *channel = (TpChannel *) self;
-       EmpathyContact *contact = NULL;
-       TpHandle self_handle;
-       TpHandleType handle_type;
-       GList *l;
-
-       /* If this is a named chatroom, never pretend it is a private chat */
-       tp_channel_get_handle (channel, &handle_type);
-       if (handle_type == TP_HANDLE_TYPE_ROOM) {
-               return;
-       }
-
-       /* This is an MSN chat, but it's the new style where 1-1 chats don't
-        * have the group interface. If it has the conference interface, then
-        * it is indeed a MUC. */
-       if (tp_proxy_has_interface_by_id (self,
-                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_CONFERENCE)) {
-               return;
-       }
-
-       /* This is an MSN-like chat where anyone can join the chat at anytime.
-        * If there is only one non-self contact member, we are in a private
-        * chat and we set the "remote-contact" property to that contact. If
-        * there are more, set the "remote-contact" property to NULL and the
-        * UI will display a contact list. */
-       self_handle = tp_channel_group_get_self_handle (channel);
-       for (l = self->priv->members; l; l = l->next) {
-               /* Skip self contact if member */
-               if (empathy_contact_get_handle (l->data) == self_handle) {
-                       continue;
-               }
-
-               /* We have more than one remote contact, break */
-               if (contact != NULL) {
-                       contact = NULL;
-                       break;
-               }
-
-               /* If we didn't find yet a remote contact, keep this one */
-               contact = l->data;
-       }
-
-       if (self->priv->remote_contact == contact) {
-               return;
-       }
-
-       DEBUG ("Changing remote contact from %p to %p",
-               self->priv->remote_contact, contact);
-
-       if (self->priv->remote_contact) {
-               g_object_unref (self->priv->remote_contact);
-       }
-
-       self->priv->remote_contact = contact ? g_object_ref (contact) : NULL;
-       g_object_notify (G_OBJECT (self), "remote-contact");
-}
-
 static void
 tp_chat_got_added_contacts_cb (TpConnection            *connection,
                               guint                    n_contacts,
@@ -996,7 +843,6 @@ tp_chat_got_added_contacts_cb (TpConnection            *connection,
                }
        }
 
-       tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat));
        check_almost_ready (EMPATHY_TP_CHAT (chat));
 }
 
@@ -1104,7 +950,6 @@ tp_chat_got_renamed_contacts_cb (TpConnection            *connection,
                self->priv->user = g_object_ref (new);
        }
 
-       tp_chat_update_remote_contact (self);
        check_almost_ready (self);
 }
 
@@ -1180,8 +1025,6 @@ tp_chat_group_members_changed_cb (TpChannel     *channel,
                        G_OBJECT (self));
        }
 
-       tp_chat_update_remote_contact (self);
-
        if (actor_contact != NULL) {
                g_object_unref (actor_contact);
        }
@@ -1228,77 +1071,6 @@ tp_chat_got_self_contact_cb (TpConnection            *connection,
        check_almost_ready (self);
 }
 
-static void
-password_flags_changed_cb (TpChannel *channel,
-    guint added,
-    guint removed,
-    gpointer user_data,
-    GObject *weak_object)
-{
-       EmpathyTpChat *self = EMPATHY_TP_CHAT (weak_object);
-       gboolean was_needed, needed;
-
-       was_needed = empathy_tp_chat_password_needed (self);
-
-       self->priv->password_flags |= added;
-       self->priv->password_flags ^= removed;
-
-       needed = empathy_tp_chat_password_needed (self);
-
-       if (was_needed != needed)
-               g_object_notify (G_OBJECT (self), "password-needed");
-}
-
-static void
-got_password_flags_cb (TpChannel *proxy,
-                            guint password_flags,
-                            const GError *error,
-                            gpointer user_data,
-                            GObject *weak_object)
-{
-       EmpathyTpChat *self = EMPATHY_TP_CHAT (weak_object);
-
-       self->priv->got_password_flags = TRUE;
-       self->priv->password_flags = password_flags;
-
-       check_almost_ready (EMPATHY_TP_CHAT (self));
-}
-
-static void
-sms_channel_changed_cb (TpChannel *channel,
-                       gboolean   sms_channel,
-                       gpointer   user_data,
-                       GObject   *chat)
-{
-       EmpathyTpChat *self = (EmpathyTpChat *) chat;
-
-       self->priv->sms_channel = sms_channel;
-
-       g_object_notify (G_OBJECT (chat), "sms-channel");
-}
-
-static void
-get_sms_channel_cb (TpProxy      *channel,
-                   const GValue *value,
-                   const GError *in_error,
-                   gpointer      user_data,
-                   GObject      *chat)
-{
-       EmpathyTpChat *self = (EmpathyTpChat *) chat;
-
-       if (in_error != NULL) {
-               DEBUG ("Failed to get SMSChannel: %s", in_error->message);
-               return;
-       }
-
-       g_return_if_fail (G_VALUE_HOLDS_BOOLEAN (value));
-
-       self->priv->sms_channel = g_value_get_boolean (value);
-       self->priv->got_sms_channel = TRUE;
-
-       check_almost_ready (EMPATHY_TP_CHAT (chat));
-}
-
 static void
 tp_chat_get_property (GObject    *object,
                      guint       param_id,
@@ -1314,16 +1086,18 @@ tp_chat_get_property (GObject    *object,
        case PROP_REMOTE_CONTACT:
                g_value_set_object (value, self->priv->remote_contact);
                break;
-       case PROP_PASSWORD_NEEDED:
-               g_value_set_boolean (value, empathy_tp_chat_password_needed (self));
-               break;
-       case PROP_SMS_CHANNEL:
-               g_value_set_boolean (value, self->priv->sms_channel);
-               break;
        case PROP_N_MESSAGES_SENDING:
                g_value_set_uint (value,
                        g_hash_table_size (self->priv->messages_being_sent));
                break;
+       case PROP_TITLE:
+               g_value_set_string (value,
+                       empathy_tp_chat_get_title (self));
+               break;
+       case PROP_SUBJECT:
+               g_value_set_string (value,
+                       empathy_tp_chat_get_subject (self));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
                break;
@@ -1405,22 +1179,6 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                                                              EMPATHY_TYPE_CONTACT,
                                                              G_PARAM_READABLE));
 
-       g_object_class_install_property (object_class,
-                                        PROP_PASSWORD_NEEDED,
-                                        g_param_spec_boolean ("password-needed",
-                                                              "password needed",
-                                                              "TRUE if a password is needed to join the channel",
-                                                              FALSE,
-                                                              G_PARAM_READABLE));
-
-       g_object_class_install_property (object_class,
-                                        PROP_SMS_CHANNEL,
-                                        g_param_spec_boolean ("sms-channel",
-                                                              "SMS Channel",
-                                                              "TRUE if channel is for sending SMSes",
-                                                              FALSE,
-                                                              G_PARAM_READABLE));
-
        g_object_class_install_property (object_class,
                                         PROP_N_MESSAGES_SENDING,
                                         g_param_spec_uint ("n-messages-sending",
@@ -1429,6 +1187,24 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                                                            0, G_MAXUINT, 0,
                                                            G_PARAM_READABLE));
 
+       g_object_class_install_property (object_class,
+                                        PROP_TITLE,
+                                        g_param_spec_string ("title",
+                                                             "Title",
+                                                             "A human-readable name for the room, if any",
+                                                             NULL,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (object_class,
+                                        PROP_SUBJECT,
+                                        g_param_spec_string ("subject",
+                                                             "Subject",
+                                                             "The room's current subject, if any",
+                                                             NULL,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_STATIC_STRINGS));
+
        /* Signals */
        signals[MESSAGE_RECEIVED] =
                g_signal_new ("message-received-empathy",
@@ -1436,7 +1212,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__OBJECT,
+                             g_cclosure_marshal_generic,
                              G_TYPE_NONE,
                              1, EMPATHY_TYPE_MESSAGE);
 
@@ -1446,7 +1222,7 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL, NULL,
-                             _empathy_marshal_VOID__STRING_UINT_STRING,
+                             g_cclosure_marshal_generic,
                              G_TYPE_NONE,
                              3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
 
@@ -1456,27 +1232,17 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL, NULL,
-                             _empathy_marshal_VOID__OBJECT_UINT,
+                             g_cclosure_marshal_generic,
                              G_TYPE_NONE,
                              2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
 
-       signals[PROPERTY_CHANGED] =
-               g_signal_new ("property-changed",
-                             G_TYPE_FROM_CLASS (klass),
-                             G_SIGNAL_RUN_LAST,
-                             0,
-                             NULL, NULL,
-                             _empathy_marshal_VOID__STRING_BOXED,
-                             G_TYPE_NONE,
-                             2, G_TYPE_STRING, G_TYPE_VALUE);
-
        signals[MESSAGE_ACKNOWLEDGED] =
                g_signal_new ("message-acknowledged",
                              G_TYPE_FROM_CLASS (klass),
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__OBJECT,
+                             g_cclosure_marshal_generic,
                              G_TYPE_NONE,
                              1, EMPATHY_TYPE_MESSAGE);
 
@@ -1504,7 +1270,9 @@ tp_chat_iface_init (EmpathyContactListIface *iface)
 }
 
 EmpathyTpChat *
-empathy_tp_chat_new (TpAccount *account,
+empathy_tp_chat_new (
+                    TpSimpleClientFactory *factory,
+                    TpAccount *account,
                     TpConnection *conn,
                     const gchar *object_path,
                     const GHashTable *immutable_properties)
@@ -1516,6 +1284,7 @@ empathy_tp_chat_new (TpAccount *account,
        g_return_val_if_fail (immutable_properties != NULL, NULL);
 
        return g_object_new (EMPATHY_TYPE_TP_CHAT,
+                            "factory", factory,
                             "account", account,
                             "connection", conn,
                             "dbus-daemon", conn_proxy->dbus_daemon,
@@ -1578,25 +1347,6 @@ empathy_tp_chat_send (EmpathyTpChat *self,
        g_free (message_body);
 }
 
-void
-empathy_tp_chat_set_state (EmpathyTpChat *self,
-                          TpChannelChatState  state)
-{
-       g_return_if_fail (EMPATHY_IS_TP_CHAT (self));
-
-       if (tp_proxy_has_interface_by_id (self,
-                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE)) {
-               DEBUG ("Set state: %d", state);
-               tp_cli_channel_interface_chat_state_call_set_chat_state ((TpChannel *) self, -1,
-                                                                        state,
-                                                                        tp_chat_async_cb,
-                                                                        "setting chat state",
-                                                                        NULL,
-                                                                        G_OBJECT (self));
-       }
-}
-
-
 const GList *
 empathy_tp_chat_get_pending_messages (EmpathyTpChat *self)
 {
@@ -1620,102 +1370,6 @@ empathy_tp_chat_acknowledge_message (EmpathyTpChat *self,
                                           tp_msg, NULL, NULL);
 }
 
-void
-empathy_tp_chat_acknowledge_messages (EmpathyTpChat *self,
-                                     const GSList *messages) {
-       const GSList *l;
-       GList *messages_to_ack = NULL;
-
-       g_return_if_fail (EMPATHY_IS_TP_CHAT (self));
-
-       if (messages == NULL)
-               return;
-
-       for (l = messages; l != NULL; l = g_slist_next (l)) {
-               EmpathyMessage *message = EMPATHY_MESSAGE (l->data);
-
-               if (empathy_message_is_incoming (message)) {
-                       TpMessage *tp_msg = empathy_message_get_tp_message (message);
-                       messages_to_ack = g_list_append (messages_to_ack, tp_msg);
-               }
-       }
-
-       if (messages_to_ack != NULL) {
-               tp_text_channel_ack_messages_async (TP_TEXT_CHANNEL (self),
-                                                   messages_to_ack, NULL, NULL);
-       }
-
-       g_list_free (messages_to_ack);
-}
-
-void
-empathy_tp_chat_acknowledge_all_messages (EmpathyTpChat *self)
-{
-  empathy_tp_chat_acknowledge_messages (self,
-    (GSList *) empathy_tp_chat_get_pending_messages (self));
-}
-
-gboolean
-empathy_tp_chat_password_needed (EmpathyTpChat *self)
-{
-       return self->priv->password_flags & TP_CHANNEL_PASSWORD_FLAG_PROVIDE;
-}
-
-static void
-provide_password_cb (TpChannel *channel,
-                                     gboolean correct,
-                                     const GError *error,
-                                     gpointer user_data,
-                                     GObject *weak_object)
-{
-       GSimpleAsyncResult *result = user_data;
-
-       if (error != NULL) {
-               g_simple_async_result_set_from_error (result, error);
-       }
-       else if (!correct) {
-               /* The current D-Bus API is a bit weird so re-use the
-                * AuthenticationFailed error */
-               g_simple_async_result_set_error (result, TP_ERRORS,
-                                                TP_ERROR_AUTHENTICATION_FAILED, "Wrong password");
-       }
-
-       g_simple_async_result_complete (result);
-       g_object_unref (result);
-}
-
-void
-empathy_tp_chat_provide_password_async (EmpathyTpChat *self,
-                                                    const gchar *password,
-                                                    GAsyncReadyCallback callback,
-                                                    gpointer user_data)
-{
-       GSimpleAsyncResult *result;
-
-       result = g_simple_async_result_new (G_OBJECT (self),
-                                           callback, user_data,
-                                           empathy_tp_chat_provide_password_finish);
-
-       tp_cli_channel_interface_password_call_provide_password
-               ((TpChannel *) self, -1, password, provide_password_cb, result,
-                NULL, G_OBJECT (self));
-}
-
-gboolean
-empathy_tp_chat_provide_password_finish (EmpathyTpChat *self,
-                                                     GAsyncResult *result,
-                                                     GError **error)
-{
-       if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
-               error))
-               return FALSE;
-
-       g_return_val_if_fail (g_simple_async_result_is_valid (result,
-                                                             G_OBJECT (self), empathy_tp_chat_provide_password_finish), FALSE);
-
-       return TRUE;
-}
-
 /**
  * empathy_tp_chat_can_add_contact:
  *
@@ -1788,7 +1442,7 @@ empathy_tp_chat_join (EmpathyTpChat *self)
        tp_cli_channel_interface_group_call_add_members ((TpChannel *) self, -1, members,
                "", add_members_cb, NULL, NULL, G_OBJECT (self));
 
-       g_array_free (members, TRUE);
+       g_array_unref (members);
 }
 
 gboolean
@@ -1824,15 +1478,6 @@ empathy_tp_chat_get_self_contact (EmpathyTpChat *self)
        return self->priv->user;
 }
 
-
-gboolean
-empathy_tp_chat_is_sms_channel (EmpathyTpChat *self)
-{
-       g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), FALSE);
-
-       return self->priv->sms_channel;
-}
-
 GQuark
 empathy_tp_chat_get_feature_ready (void)
 {
@@ -1840,28 +1485,27 @@ empathy_tp_chat_get_feature_ready (void)
 }
 
 static void
-conn_prepared_cb (GObject *source,
-       GAsyncResult *result,
+tp_chat_prepare_ready_async (TpProxy *proxy,
+       const TpProxyFeature *feature,
+       GAsyncReadyCallback callback,
        gpointer user_data)
 {
-       EmpathyTpChat *self = user_data;
-       TpChannel *channel = (TpChannel *) self;
-       GError *error = NULL;
-       TpHandle handle;
-       TpConnection *connection = (TpConnection *) source;
+       EmpathyTpChat *self = (EmpathyTpChat *) proxy;
+       TpChannel *channel = (TpChannel *) proxy;
+       TpConnection *connection;
+       gboolean listen_for_dbus_properties_changed = FALSE;
 
-       if (!tp_proxy_prepare_finish (source, result, &error)) {
-               g_simple_async_result_set_from_error (self->priv->ready_result, error);
-               g_error_free (error);
-               g_simple_async_result_complete (self->priv->ready_result);
-               tp_clear_object (&self->priv->ready_result);
-               return;
-       }
+       g_assert (self->priv->ready_result == NULL);
+       self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
+               callback, user_data, tp_chat_prepare_ready_async);
+
+       connection = tp_channel_borrow_connection (channel);
 
        if (tp_proxy_has_interface_by_id (self,
                                          TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) {
                const TpIntSet *members;
                GArray *handles;
+               TpHandle handle;
 
                /* Get self contact from the group's self handle */
                handle = tp_channel_group_get_self_handle (channel);
@@ -1884,6 +1528,7 @@ conn_prepared_cb (GObject *source,
                TpCapabilities *caps;
                GPtrArray *classes;
                guint i;
+               TpHandle handle;
 
                /* Get the self contact from the connection's self handle */
                handle = tp_connection_get_self_handle (connection);
@@ -1915,70 +1560,29 @@ conn_prepared_cb (GObject *source,
        }
 
        if (tp_proxy_has_interface_by_id (self,
-                                         TP_IFACE_QUARK_PROPERTIES_INTERFACE)) {
-               tp_cli_properties_interface_call_list_properties (channel, -1,
-                                                                 tp_chat_list_properties_cb,
-                                                                 NULL, NULL,
-                                                                 G_OBJECT (self));
-               tp_cli_properties_interface_connect_to_properties_changed (channel,
-                                                                          tp_chat_properties_changed_cb,
-                                                                          NULL, NULL,
-                                                                          G_OBJECT (self), NULL);
-               tp_cli_properties_interface_connect_to_property_flags_changed (channel,
-                                                                              tp_chat_property_flags_changed_cb,
-                                                                              NULL, NULL,
-                                                                              G_OBJECT (self), NULL);
+                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_SUBJECT)) {
+               tp_cli_dbus_properties_call_get_all (channel, -1,
+                                                    TP_IFACE_CHANNEL_INTERFACE_SUBJECT,
+                                                    tp_chat_get_all_subject_cb,
+                                                    NULL, NULL,
+                                                    G_OBJECT (self));
+               listen_for_dbus_properties_changed = TRUE;
        }
 
-       /* Check if the chat is password protected */
        if (tp_proxy_has_interface_by_id (self,
-                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_PASSWORD)) {
-               self->priv->got_password_flags = FALSE;
-
-               tp_cli_channel_interface_password_connect_to_password_flags_changed
-                       (channel, password_flags_changed_cb, self, NULL,
-                        G_OBJECT (self), NULL);
-
-               tp_cli_channel_interface_password_call_get_password_flags
-                       (channel, -1, got_password_flags_cb, self, NULL, G_OBJECT (self));
-       } else {
-               /* No Password interface, so no need to fetch the password flags */
-               self->priv->got_password_flags = TRUE;
+                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_ROOM_CONFIG)) {
+               tp_cli_dbus_properties_call_get_all (channel, -1,
+                                                    TP_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG,
+                                                    tp_chat_get_all_room_config_cb,
+                                                    NULL, NULL,
+                                                    G_OBJECT (self));
+               listen_for_dbus_properties_changed = TRUE;
        }
 
-       /* Check if the chat is for SMS */
-       if (tp_proxy_has_interface_by_id (channel,
-                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_SMS)) {
-               tp_cli_channel_interface_sms_connect_to_sms_channel_changed (
-                       channel,
-                       sms_channel_changed_cb, self, NULL, G_OBJECT (self), NULL);
-
-               tp_cli_dbus_properties_call_get (channel, -1,
-                       TP_IFACE_CHANNEL_INTERFACE_SMS, "SMSChannel",
-                       get_sms_channel_cb, self, NULL, G_OBJECT (self));
-       } else {
-               /* if there's no SMS support, then we're not waiting for it */
-               self->priv->got_sms_channel = TRUE;
+       if (listen_for_dbus_properties_changed) {
+               tp_cli_dbus_properties_connect_to_properties_changed (channel,
+                                                                     tp_chat_dbus_properties_changed_cb,
+                                                                     NULL, NULL,
+                                                                     G_OBJECT (self), NULL);
        }
 }
-
-static void
-tp_chat_prepare_ready_async (TpProxy *proxy,
-       const TpProxyFeature *feature,
-       GAsyncReadyCallback callback,
-       gpointer user_data)
-{
-       EmpathyTpChat *self = (EmpathyTpChat *) proxy;
-       TpChannel *channel = (TpChannel *) proxy;
-       TpConnection *connection;
-       GQuark conn_features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
-
-       g_assert (self->priv->ready_result == NULL);
-       self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
-               callback, user_data, tp_chat_prepare_ready_async);
-
-       connection = tp_channel_borrow_connection (channel);
-
-       tp_proxy_prepare_async (connection, conn_features,
-               conn_prepared_cb, self);
-}