]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-chat.c
Merge branch 'sasl'
[empathy.git] / libempathy / empathy-tp-chat.c
index 858cfae27d0468dbbc46d6b0653972b469658704..f1351049aedf8809d421fce0834a63eeb8514ba9 100644 (file)
@@ -30,7 +30,6 @@
 #include "empathy-tp-chat.h"
 #include "empathy-tp-contact-factory.h"
 #include "empathy-contact-list.h"
-#include "empathy-dispatcher.h"
 #include "empathy-marshal.h"
 #include "empathy-time.h"
 #include "empathy-utils.h"
@@ -41,6 +40,7 @@
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpChat)
 typedef struct {
        gboolean               dispose_has_run;
+       TpAccount             *account;
        TpConnection          *connection;
        EmpathyContact        *user;
        EmpathyContact        *remote_contact;
@@ -65,6 +65,7 @@ static void tp_chat_iface_init         (EmpathyContactListIface *iface);
 
 enum {
        PROP_0,
+       PROP_ACCOUNT,
        PROP_CHANNEL,
        PROP_REMOTE_CONTACT,
        PROP_PASSWORD_NEEDED,
@@ -110,6 +111,20 @@ tp_chat_async_cb (TpChannel *proxy,
        }
 }
 
+static void
+create_conference_cb (GObject *source,
+                     GAsyncResult *result,
+                     gpointer user_data)
+{
+       GError *error = NULL;
+
+       if (!tp_account_channel_request_create_channel_finish (
+                       TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error)) {
+               DEBUG ("Failed to create conference channel: %s", error->message);
+               g_error_free (error);
+       }
+}
+
 static void
 tp_chat_add (EmpathyContactList *list,
             EmpathyContact     *contact,
@@ -129,36 +144,37 @@ tp_chat_add (EmpathyContactList *list,
                tp_cli_channel_interface_group_call_add_members (priv->channel,
                        -1, &handles, NULL, NULL, NULL, NULL, NULL);
        } else if (priv->can_upgrade_to_muc) {
-               EmpathyDispatcher *dispatcher;
+               TpAccountChannelRequest *req;
                GHashTable        *props;
                const char        *object_path;
                GPtrArray          channels = { (gpointer *) &object_path, 1 };
                const char        *invitees[2] = { NULL, };
 
-               dispatcher = empathy_dispatcher_dup_singleton ();
-
                invitees[0] = empathy_contact_get_id (contact);
                object_path = tp_proxy_get_object_path (priv->channel);
 
                props = tp_asv_new (
-                   TP_IFACE_CHANNEL ".ChannelType", G_TYPE_STRING,
+                   TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
                        TP_IFACE_CHANNEL_TYPE_TEXT,
-                   TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT,
+                   TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
                        TP_HANDLE_TYPE_NONE,
-                   EMP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels",
+                   TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS,
                        TP_ARRAY_TYPE_OBJECT_PATH_LIST, &channels,
-                   EMP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeIDs",
+                   TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS,
                        G_TYPE_STRV, invitees,
                    /* FIXME: InvitationMessage ? */
                    NULL);
 
+               req = tp_account_channel_request_new (priv->account, props,
+                       TP_USER_ACTION_TIME_NOT_USER_ACTION);
+
                /* Although this is a MUC, it's anonymous, so CreateChannel is
-                * valid.
-                * props now belongs to EmpathyDispatcher, don't free it */
-               empathy_dispatcher_create_channel (dispatcher, priv->connection,
-                               props, EMPATHY_DISPATCHER_NON_USER_ACTION, NULL, NULL);
+                * valid. */
+               tp_account_channel_request_create_channel_async (req, NULL, NULL,
+                       create_conference_cb, NULL);
 
-               g_object_unref (dispatcher);
+               g_object_unref (req);
+               g_hash_table_unref (props);
        } else {
                g_warning ("Cannot add to this channel");
        }
@@ -203,6 +219,23 @@ tp_chat_get_members (EmpathyContactList *list)
        return members;
 }
 
+static void
+check_ready (EmpathyTpChat *chat)
+{
+       EmpathyTpChatPriv *priv = GET_PRIV (chat);
+
+       if (priv->ready)
+               return;
+
+       if (g_queue_get_length (priv->messages_queue) > 0)
+               return;
+
+       DEBUG ("Ready");
+
+       priv->ready = TRUE;
+       g_object_notify (G_OBJECT (chat), "ready");
+}
+
 static void
 tp_chat_emit_queued_messages (EmpathyTpChat *chat)
 {
@@ -220,6 +253,8 @@ tp_chat_emit_queued_messages (EmpathyTpChat *chat)
                g_queue_push_tail (priv->pending_messages_queue, message);
                g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
        }
+
+       check_ready (chat);
 }
 
 static void
@@ -265,6 +300,9 @@ tp_chat_build_message (EmpathyTpChat *chat,
        empathy_message_set_incoming (message, incoming);
        empathy_message_set_flags (message, flags);
 
+       if (flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK)
+               empathy_message_set_is_backlog (message, TRUE);
+
        g_queue_push_tail (priv->messages_queue, message);
 
        if (from_handle == 0) {
@@ -407,7 +445,7 @@ tp_chat_state_changed_got_contact_cb (TpConnection            *connection,
 
        state = GPOINTER_TO_UINT (user_data);
        DEBUG ("Chat state changed for %s (%d): %d",
-               empathy_contact_get_name (contact),
+               empathy_contact_get_alias (contact),
                empathy_contact_get_handle (contact), state);
 
        g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
@@ -495,6 +533,8 @@ tp_chat_list_pending_messages_cb (TpChannel       *channel,
                acknowledge_messages (chat, empty_non_text_content_ids);
                g_array_free (empty_non_text_content_ids, TRUE);
        }
+
+       check_ready (chat);
 }
 
 static void
@@ -738,6 +778,8 @@ tp_chat_dispose (GObject *object)
 
        priv->dispose_has_run = TRUE;
 
+       tp_clear_object (&priv->account);
+
        if (priv->connection != NULL)
                g_object_unref (priv->connection);
        priv->connection = NULL;
@@ -797,7 +839,7 @@ tp_chat_finalize (GObject *object)
 }
 
 static void
-tp_chat_check_if_ready (EmpathyTpChat *chat)
+check_almost_ready (EmpathyTpChat *chat)
 {
        EmpathyTpChatPriv *priv = GET_PRIV (chat);
 
@@ -817,13 +859,14 @@ tp_chat_check_if_ready (EmpathyTpChat *chat)
            priv->remote_contact == NULL)
                return;
 
-       DEBUG ("Ready!");
-
        tp_cli_channel_type_text_connect_to_received (priv->channel,
                                                      tp_chat_received_cb,
                                                      NULL, NULL,
                                                      G_OBJECT (chat), NULL);
        priv->listing_pending_messages = TRUE;
+
+       /* TpChat will be ready once ListPendingMessages returned and all the messages
+        * have been added to the pending messages queue. */
        tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1,
                                                             FALSE,
                                                             tp_chat_list_pending_messages_cb,
@@ -842,8 +885,6 @@ tp_chat_check_if_ready (EmpathyTpChat *chat)
                                                                           tp_chat_state_changed_cb,
                                                                           NULL, NULL,
                                                                           G_OBJECT (chat), NULL);
-       priv->ready = TRUE;
-       g_object_notify (G_OBJECT (chat), "ready");
 }
 
 static void
@@ -865,7 +906,7 @@ tp_chat_update_remote_contact (EmpathyTpChat *chat)
         * have the group interface. If it has the conference interface, then
         * it is indeed a MUC. */
        if (tp_proxy_has_interface_by_id (priv->channel,
-                                         EMP_IFACE_QUARK_CHANNEL_INTERFACE_CONFERENCE)) {
+                                         TP_IFACE_QUARK_CHANNEL_INTERFACE_CONFERENCE)) {
                return;
        }
 
@@ -942,7 +983,7 @@ tp_chat_got_added_contacts_cb (TpConnection            *connection,
        }
 
        tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat));
-       tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat));
+       check_almost_ready (EMPATHY_TP_CHAT (chat));
 }
 
 static EmpathyContact *
@@ -1052,7 +1093,7 @@ tp_chat_got_renamed_contacts_cb (TpConnection            *connection,
        }
 
        tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat));
-       tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat));
+       check_almost_ready (EMPATHY_TP_CHAT (chat));
 }
 
 
@@ -1077,8 +1118,11 @@ tp_chat_group_members_changed_cb (TpChannel     *self,
        /* Contact renamed */
        if (reason == TP_CHANNEL_GROUP_CHANGE_REASON_RENAMED) {
                /* there can only be a single 'added' and a single 'removed' handle */
-               g_warn_if_fail (removed->len == 1);
-               g_warn_if_fail (added->len == 1);
+               if (removed->len != 1 || added->len != 1) {
+                       g_warning ("RENAMED with %u added, %u removed (expected 1, 1)",
+                               added->len, removed->len);
+                       return;
+               }
 
                old_handle = g_array_index (removed, guint, 0);
 
@@ -1148,7 +1192,7 @@ tp_chat_got_remote_contact_cb (TpConnection            *connection,
        priv->remote_contact = g_object_ref (contact);
        g_object_notify (chat, "remote-contact");
 
-       tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat));
+       check_almost_ready (EMPATHY_TP_CHAT (chat));
 }
 
 static void
@@ -1168,7 +1212,7 @@ tp_chat_got_self_contact_cb (TpConnection            *connection,
 
        priv->user = g_object_ref (contact);
        empathy_contact_set_is_user (priv->user, TRUE);
-       tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat));
+       check_almost_ready (EMPATHY_TP_CHAT (chat));
 }
 
 static void
@@ -1206,7 +1250,7 @@ got_password_flags_cb (TpChannel *proxy,
        priv->got_password_flags = TRUE;
        priv->password_flags = password_flags;
 
-       tp_chat_check_if_ready (EMPATHY_TP_CHAT (self));
+       check_almost_ready (EMPATHY_TP_CHAT (self));
 }
 
 static GObject *
@@ -1222,10 +1266,13 @@ tp_chat_constructor (GType                  type,
 
        priv = GET_PRIV (chat);
 
-       priv->connection = g_object_ref (tp_channel_borrow_connection (priv->channel));
-       g_signal_connect (priv->channel, "invalidated",
+       priv->connection = g_object_ref (tp_account_get_connection (priv->account));
+       tp_g_signal_connect_object (priv->channel, "invalidated",
                          G_CALLBACK (tp_chat_invalidated_cb),
-                         chat);
+                         chat, 0);
+
+       g_assert (tp_proxy_is_prepared (priv->connection,
+               TP_CONNECTION_FEATURE_CAPABILITIES));
 
        if (tp_proxy_has_interface_by_id (priv->channel,
                                          TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) {
@@ -1247,11 +1294,12 @@ tp_chat_constructor (GType                  type,
 
                priv->can_upgrade_to_muc = FALSE;
 
-               g_signal_connect (priv->channel, "group-members-changed",
-                       G_CALLBACK (tp_chat_group_members_changed_cb), chat);
+               tp_g_signal_connect_object (priv->channel, "group-members-changed",
+                       G_CALLBACK (tp_chat_group_members_changed_cb), chat, 0);
        } else {
-               EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton ();
-               GList *list, *ptr;
+               TpCapabilities *caps;
+               GPtrArray *classes;
+               guint i;
 
                /* Get the self contact from the connection's self handle */
                handle = tp_connection_get_self_handle (priv->connection);
@@ -1265,24 +1313,21 @@ tp_chat_constructor (GType                  type,
                        handle, tp_chat_got_remote_contact_cb,
                        NULL, NULL, chat);
 
-               list = empathy_dispatcher_find_requestable_channel_classes (
-                       dispatcher, priv->connection,
-                       tp_channel_get_channel_type (priv->channel),
-                       TP_UNKNOWN_HANDLE_TYPE, NULL);
+               caps = tp_connection_get_capabilities (priv->connection);
+               g_assert (caps != NULL);
+
+               classes = tp_capabilities_get_channel_classes (caps);
 
-               for (ptr = list; ptr; ptr = ptr->next) {
-                       GValueArray *array = ptr->data;
+               for (i = 0; i < classes->len; i++) {
+                       GValueArray *array = g_ptr_array_index (classes, i);
                        const char **oprops = g_value_get_boxed (
                                g_value_array_get_nth (array, 1));
 
-                       if (tp_strv_contains (oprops, EMP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels")) {
+                       if (tp_strv_contains (oprops, TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS)) {
                                priv->can_upgrade_to_muc = TRUE;
                                break;
                        }
                }
-
-               g_list_free (list);
-               g_object_unref (dispatcher);
        }
 
        if (tp_proxy_has_interface_by_id (priv->channel,
@@ -1330,6 +1375,9 @@ tp_chat_get_property (GObject    *object,
        EmpathyTpChatPriv *priv = GET_PRIV (object);
 
        switch (param_id) {
+       case PROP_ACCOUNT:
+               g_value_set_object (value, priv->account);
+               break;
        case PROP_CHANNEL:
                g_value_set_object (value, priv->channel);
                break;
@@ -1357,6 +1405,9 @@ tp_chat_set_property (GObject      *object,
        EmpathyTpChatPriv *priv = GET_PRIV (object);
 
        switch (param_id) {
+       case PROP_ACCOUNT:
+               priv->account = g_value_dup_object (value);
+               break;
        case PROP_CHANNEL:
                priv->channel = g_value_dup_object (value);
                break;
@@ -1377,6 +1428,16 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
        object_class->get_property = tp_chat_get_property;
        object_class->set_property = tp_chat_set_property;
 
+       g_object_class_install_property (object_class,
+                                        PROP_ACCOUNT,
+                                        g_param_spec_object ("account",
+                                                             "TpAccount",
+                                                             "the account associated with the chat",
+                                                             TP_TYPE_ACCOUNT,
+                                                             G_PARAM_READWRITE |
+                                                             G_PARAM_CONSTRUCT_ONLY |
+                                                             G_PARAM_STATIC_STRINGS));
+
        g_object_class_install_property (object_class,
                                         PROP_CHANNEL,
                                         g_param_spec_object ("channel",
@@ -1484,9 +1545,14 @@ tp_chat_iface_init (EmpathyContactListIface *iface)
 }
 
 EmpathyTpChat *
-empathy_tp_chat_new (TpChannel *channel)
+empathy_tp_chat_new (TpAccount *account,
+                    TpChannel *channel)
 {
+       g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+       g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
+
        return g_object_new (EMPATHY_TYPE_TP_CHAT,
+                            "account", account,
                             "channel", channel,
                             NULL);
 }
@@ -1541,6 +1607,16 @@ empathy_tp_chat_get_channel (EmpathyTpChat *chat)
        return priv->channel;
 }
 
+TpAccount *
+empathy_tp_chat_get_account (EmpathyTpChat *chat)
+{
+       EmpathyTpChatPriv *priv = GET_PRIV (chat);
+
+       g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
+
+       return priv->account;
+}
+
 TpConnection *
 empathy_tp_chat_get_connection (EmpathyTpChat *chat)
 {
@@ -1550,7 +1626,6 @@ empathy_tp_chat_get_connection (EmpathyTpChat *chat)
 
        return tp_channel_borrow_connection (priv->channel);
 }
-
 gboolean
 empathy_tp_chat_is_ready (EmpathyTpChat *chat)
 {
@@ -1868,7 +1943,8 @@ empathy_tp_chat_join (EmpathyTpChat *self)
 }
 
 gboolean
-empathy_tp_chat_is_invited (EmpathyTpChat *self)
+empathy_tp_chat_is_invited (EmpathyTpChat *self,
+                           TpHandle *inviter)
 {
        EmpathyTpChatPriv *priv = GET_PRIV (self);
        TpHandle self_handle;
@@ -1881,5 +1957,5 @@ empathy_tp_chat_is_invited (EmpathyTpChat *self)
                return FALSE;
 
        return tp_channel_group_get_local_pending_info (priv->channel, self_handle,
-               NULL, NULL, NULL);
+               inviter, NULL, NULL);
 }