]> git.0d.be Git - empathy.git/commitdiff
Handle the case where a user's id changes in a chatroom
authorJonathon Jongsma <jjongsma@gnome.org>
Wed, 7 Jan 2009 21:49:08 +0000 (15:49 -0600)
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Wed, 18 Nov 2009 19:09:34 +0000 (19:09 +0000)
Telepathy-glib has a enum value for the MembersChanged signal to signify that a
user's ID has changed.  Previously, empathy was simply interpreting this as if a
user with the old name had left the chat and a different user with the new name
had entered the chat.  This change handles this case more gracefully by updating
the contact's id (and name) when this change reason is present

One thing that does not yet work with this patch is if you are engaged in a
private chat with a person and they change their nick in the middle of the chat.
Then the EmpathyContact* that you are chatting with is no longer the
EmpathyContact* representing the remote user, so messages won't be delivered
properly.  When we detect that a user has been 'renamed', we probably need to
somehow go through all of the private chats with that person and swap out the
old (invalid) EmpathyContact* and replace it with the new one so that the chat
can continue without interruption.

libempathy-gtk/empathy-chat.c
libempathy-gtk/empathy-contact-list-store.c
libempathy/empathy-contact-list.c
libempathy/empathy-tp-chat.c

index 07bd35711086d27c087a5848cd704ea143116a7d..cc946b1e1678e280898bcad72fe960caf001354a 100644 (file)
@@ -1791,6 +1791,8 @@ chat_members_changed_cb (EmpathyTpChat  *tp_chat,
                         gboolean        is_member,
                         EmpathyChat    *chat)
 {
+       g_return_if_fail (TP_CHANNEL_GROUP_CHANGE_REASON_RENAMED != reason);
+
        EmpathyChatPriv *priv = GET_PRIV (chat);
        const gchar *name = empathy_contact_get_name (contact);
        gchar *str;
@@ -1809,6 +1811,30 @@ chat_members_changed_cb (EmpathyTpChat  *tp_chat,
        g_free (str);
 }
 
+static void
+chat_member_renamed_cb (EmpathyTpChat  *tp_chat,
+                        EmpathyContact *old_contact,
+                        EmpathyContact *new_contact,
+                        guint           reason,
+                        gchar          *message,
+                        EmpathyChat    *chat)
+{
+       g_return_if_fail (TP_CHANNEL_GROUP_CHANGE_REASON_RENAMED == reason);
+
+       EmpathyChatPriv *priv = GET_PRIV (chat);
+
+       if (priv->block_events_timeout_id == 0) {
+               gchar *str;
+
+               str = g_strdup_printf (_("%s is now known as %s"),
+                                      empathy_contact_get_name (old_contact),
+                                      empathy_contact_get_name (new_contact));
+               empathy_chat_view_append_event (chat->view, str);
+               g_free (str);
+       }
+
+}
+
 static gboolean
 chat_reset_size_request (gpointer widget)
 {
@@ -2536,6 +2562,9 @@ empathy_chat_set_tp_chat (EmpathyChat   *chat,
        g_signal_connect (tp_chat, "members-changed",
                          G_CALLBACK (chat_members_changed_cb),
                          chat);
+       g_signal_connect (tp_chat, "member-renamed",
+                         G_CALLBACK (chat_member_renamed_cb),
+                         chat);
        g_signal_connect_swapped (tp_chat, "notify::remote-contact",
                                  G_CALLBACK (chat_remote_contact_changed_cb),
                                  chat);
index 6572b4c908a0e4bd8b683467992441d2d1a6453a..417250fcd7fa879cfa9f49110fdcb044858f7b05 100644 (file)
@@ -103,6 +103,12 @@ static void             contact_list_store_members_changed_cb        (EmpathyCon
                                                                      gchar                         *message,
                                                                      gboolean                       is_member,
                                                                      EmpathyContactListStore       *store);
+static void             contact_list_store_member_renamed_cb         (EmpathyContactList            *list_iface,
+                                                                     EmpathyContact                *old_contact,
+                                                                     EmpathyContact                *new_contact,
+                                                                     guint                          reason,
+                                                                     gchar                         *message,
+                                                                     EmpathyContactListStore       *store);
 static void             contact_list_store_groups_changed_cb         (EmpathyContactList            *list_iface,
                                                                      EmpathyContact                *contact,
                                                                      gchar                         *group,
@@ -174,6 +180,10 @@ contact_list_store_iface_setup (gpointer user_data)
        GList                       *contacts, *l;
 
        /* Signal connection. */
+       g_signal_connect (priv->list,
+                         "member-renamed",
+                         G_CALLBACK (contact_list_store_member_renamed_cb),
+                         store);
        g_signal_connect (priv->list,
                          "members-changed",
                          G_CALLBACK (contact_list_store_members_changed_cb),
@@ -308,6 +318,9 @@ contact_list_store_dispose (GObject *object)
        }
        g_list_free (contacts);
 
+       g_signal_handlers_disconnect_by_func (priv->list,
+                                             G_CALLBACK (contact_list_store_member_renamed_cb),
+                                             object);
        g_signal_handlers_disconnect_by_func (priv->list,
                                              G_CALLBACK (contact_list_store_members_changed_cb),
                                              object);
@@ -834,6 +847,49 @@ contact_list_store_members_changed_cb (EmpathyContactList      *list_iface,
        }
 }
 
+static void
+contact_list_store_member_renamed_cb (EmpathyContactList      *list_iface,
+                                     EmpathyContact          *old_contact,
+                                     EmpathyContact          *new_contact,
+                                     guint                    reason,
+                                     gchar                   *message,
+                                     EmpathyContactListStore *store)
+{
+       EmpathyContactListStorePriv *priv;
+
+       priv = GET_PRIV (store);
+
+       DEBUG ("Contact %s (%d) renamed to %s (%d)",
+               empathy_contact_get_id (old_contact),
+               empathy_contact_get_handle (old_contact),
+               empathy_contact_get_id (new_contact),
+               empathy_contact_get_handle (new_contact));
+
+       /* connect to signals of new contact */
+       g_signal_connect (new_contact, "notify::presence",
+                         G_CALLBACK (contact_list_store_contact_updated_cb),
+                         store);
+       g_signal_connect (new_contact, "notify::presence-message",
+                         G_CALLBACK (contact_list_store_contact_updated_cb),
+                         store);
+       g_signal_connect (new_contact, "notify::name",
+                         G_CALLBACK (contact_list_store_contact_updated_cb),
+                         store);
+       g_signal_connect (new_contact, "notify::avatar",
+                         G_CALLBACK (contact_list_store_contact_updated_cb),
+                         store);
+       g_signal_connect (new_contact, "notify::capabilities",
+                         G_CALLBACK (contact_list_store_contact_updated_cb),
+                         store);
+       contact_list_store_add_contact (store, new_contact);
+
+       /* disconnect from old contact */
+       g_signal_handlers_disconnect_by_func (old_contact,
+                                             G_CALLBACK (contact_list_store_contact_updated_cb),
+                                             store);
+       contact_list_store_remove_contact (store, old_contact);
+}
+
 static void
 contact_list_store_groups_changed_cb (EmpathyContactList      *list_iface,
                                      EmpathyContact          *contact,
index d9493af1e8091307d7bf05fc4ef96ee06872f15a..d4859210a6508e3dab49d40d9bf55d710a8a5167 100644 (file)
@@ -54,6 +54,15 @@ contact_list_base_init (gpointer klass)
        static gboolean initialized = FALSE;
 
        if (!initialized) {
+               g_signal_new ("member-renamed",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             0,
+                             NULL, NULL,
+                             _empathy_marshal_VOID__OBJECT_OBJECT_UINT_STRING,
+                             G_TYPE_NONE,
+                             4, EMPATHY_TYPE_CONTACT, EMPATHY_TYPE_CONTACT, G_TYPE_UINT, G_TYPE_STRING);
+
                g_signal_new ("members-changed",
                              G_TYPE_FROM_CLASS (klass),
                              G_SIGNAL_RUN_LAST,
index aa8c1a1c5592447a285d9d9d5bc6223f2a1a60b8..aebeb6670321ac2fb6e30c175f2f7421eb78686d 100644 (file)
@@ -946,6 +946,83 @@ chat_lookup_contact (EmpathyTpChat *chat,
        return NULL;
 }
 
+typedef struct
+{
+    TpHandle old_handle;
+    guint reason;
+    const gchar *message;
+} ContactRenameData;
+
+static ContactRenameData*
+contact_rename_data_new (TpHandle handle,
+                        guint reason,
+                        const gchar* message)
+{
+       ContactRenameData *data = g_new (ContactRenameData, 1);
+       data->old_handle = handle;
+       data->reason = reason;
+       data->message = message;
+
+       return data;
+}
+
+static void
+contact_rename_data_free (ContactRenameData* data)
+{
+    g_free (data);
+}
+
+static void
+tp_chat_got_renamed_contacts_cb (EmpathyTpContactFactory *factory,
+                                 guint                    n_contacts,
+                                 EmpathyContact * const * contacts,
+                                 guint                    n_failed,
+                                 const TpHandle          *failed,
+                                 const GError            *error,
+                                 gpointer                 user_data,
+                                 GObject                 *chat)
+{
+       EmpathyTpChatPriv *priv = GET_PRIV (chat);
+       const TpIntSet *members;
+       TpHandle handle;
+       EmpathyContact *old = NULL, *new = NULL;
+
+       if (error) {
+               DEBUG ("Error: %s", error->message);
+               return;
+       }
+
+       /* renamed members can only be delivered one at a time */
+       g_warn_if_fail (n_contacts == 1);
+
+       ContactRenameData *rename_data = (ContactRenameData*) user_data;
+
+       new = contacts[0];
+
+       members = tp_channel_group_get_members (priv->channel);
+       handle = empathy_contact_get_handle (new);
+
+       old = chat_lookup_contact (EMPATHY_TP_CHAT (chat),
+                                  rename_data->old_handle, TRUE);
+
+       /* Make sure the contact is still member */
+       if (tp_intset_is_member (members, handle)) {
+               priv->members = g_list_prepend (priv->members,
+                       g_object_ref (new));
+
+               if (old != NULL) {
+                       g_signal_emit_by_name (chat, "member-renamed",
+                                              old, new, rename_data->reason,
+                                              rename_data->message);
+                       g_object_unref (old);
+               }
+       }
+
+       tp_chat_update_remote_contact (EMPATHY_TP_CHAT (chat));
+       tp_chat_check_if_ready (EMPATHY_TP_CHAT (chat));
+}
+
+
 static void
 tp_chat_group_members_changed_cb (TpChannel     *self,
                                  gchar         *message,
@@ -961,6 +1038,24 @@ tp_chat_group_members_changed_cb (TpChannel     *self,
        EmpathyContact *contact;
        EmpathyContact *actor_contact = NULL;
        guint i;
+       ContactRenameData *rename_data;
+
+       /* 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);
+
+               TpHandle old_handle = g_array_index (removed, guint, 0);
+
+               rename_data = contact_rename_data_new (old_handle, reason, message);
+               empathy_tp_contact_factory_get_from_handles (priv->factory,
+                       added->len, (TpHandle *) added->data,
+                       tp_chat_got_renamed_contacts_cb,
+                       rename_data, (GDestroyNotify) contact_rename_data_free,
+                       G_OBJECT (chat));
+               return;
+       }
 
        if (actor != 0) {
                actor_contact = chat_lookup_contact (chat, actor, FALSE);