changeset 11454:201617d49573

[gaim-migrate @ 13693] This commit includes a number of changes: 1. Aliases are now used consistently in chats. If the prpl uses unique screen names for chats (e.g. Jabber), then aliases are not used at all. 2. The chat list is now colorized to match the colors used in the chat itself. 3. Buddies are bolded in the chat user list. 4. Buddies are sorted above non-buddies in the chat user list. 5. The chat user list is ellipsized when possible (i.e. on GTK+ 2.6.0 or above). 6. I've accepted patch #1178248, by Matt Amato to add "buddy-added" and "buddy-removed" signals. These were used in my implementation of #3 and #4, to update the GUI when users are added or removed from the buddy list. 7. I've added a "blist-node-aliased" signal that is emitted when a buddy, contact, or chat is aliased. 8. Since it was hard to separate and I need it at some point, I'm letting it slip in... I've changed GaimConversation.log to be a GList named logs. This way, we can have multiple logs for a single conversation. This will be necessary to implement unnamed chat logging in some reasonable fasion (see my notes in the TODO file). committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Tue, 06 Sep 2005 03:04:07 +0000
parents d446fcc2c63b
children bf76cec68ea7
files COPYRIGHT doc/blist-signals.dox plugins/ChangeLog.API plugins/signals-test.c src/blist.c src/conversation.c src/conversation.h src/gtkconv.c src/gtkconv.h src/protocols/irc/irc.c src/protocols/irc/msgs.c src/protocols/silc/chat.c src/protocols/yahoo/yahoochat.c src/prpl.h
diffstat 14 files changed, 723 insertions(+), 277 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Tue Sep 06 02:35:26 2005 +0000
+++ b/COPYRIGHT	Tue Sep 06 03:04:07 2005 +0000
@@ -6,6 +6,7 @@
 
 Dave Ahlswede
 Manuel Amador
+Matt Amato
 Daniel Atallah
 Paul Aurich
 Patrick Aussems
--- a/doc/blist-signals.dox	Tue Sep 06 02:35:26 2005 +0000
+++ b/doc/blist-signals.dox	Tue Sep 06 03:04:07 2005 +0000
@@ -9,6 +9,9 @@
   @signal buddy-signed-off
   @signal update-idle
   @signal blist-node-extended-menu
+  @signal buddy-added
+  @signal buddy-removed
+  @signal blist-node-aliased
  @endsignals
 
  <hr>
@@ -94,5 +97,29 @@
    a GList of GaimBlistNodeAction's allowing a plugin to add menu items
  @endsignaldef
 
+ @signaldef buddy-added
+  @signalproto
+void (*buddy_added)(GaimBuddy *buddy)
+  @endsignalproto
+  @signaldesc
+   Emitted when a new buddy is added to the buddy list.
+  @endsignaldef
+
+ @signaldef buddy-removed
+  @signalproto
+void (*buddy_removed)(GaimBuddy *buddy)
+  @endsignalproto
+  @signaldesc
+   Emitted when a buddy is removed from the buddy list.
+  @endsignaldef
+
+ @signaldef blist-node-aliased
+  @signalproto
+void (*blist_node_aliased)(GaimBlistNode *node, const char *old_alias)
+  @endsignalproto
+  @signaldesc
+   Emitted when a blist node (buddy, chat, or contact) is aliased.
+  @endsignaldef
+
  */
 // vim: syntax=c tw=75 et
--- a/plugins/ChangeLog.API	Tue Sep 06 02:35:26 2005 +0000
+++ b/plugins/ChangeLog.API	Tue Sep 06 03:04:07 2005 +0000
@@ -86,6 +86,21 @@
 	* Changed: GAIM_CONV_CHAT to GAIM_CONV_TYPE_CHAT.
 	* Changed: GAIM_CONV_MISC to GAIM_CONV_TYPE_MISC.
 	* Changed: GAIM_CONV_ANY to GAIM_CONV_TYPE_ANY.
+	* Changed: GaimConversationUiOps.write_conv, Replaced const char *who
+	           with const char *name, const char *alias
+	* Changed: gaim_conv_chat_add_users(), added extra_msgs and
+	           new_arrivals (pass NULL and FALSE respectively, to get the
+	           same behavior as before)
+	* Changed: chat_add_users in GaimConversationUiOps, added aliases list
+	* Removed: chat_add_user from GaimConversationUiOps
+	* Changed: GaimConversation.log became GList * GaimConversation.logs,
+	           so that a conversation can have multiple logs at once
+	* Changed: gaim_conv_chat_add_user, added extra_msgs list
+	* Added:   CHAT_USERS_ALIAS_COLUMN, CHAT_USERS_COLOR_COLUMN,
+	           CHAT_USERS_BUDDY_COLUMN to the list of columns for the chat
+	           user list
+	* Added:   OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS, see the prpl.h
+	           documentation if you're writing a prpl
 
 	Signals:
 	* Changed: "received-im-msg" and "received-chat-msg" to match, both
@@ -108,6 +123,9 @@
 	* Changed: Renamed "conversation-drag-end" to "conversation-dragging"
 	           and emit before the conv. window swap happens. This prevents
 	           the old conv window from being freed before the signal emits.
+	* Added:   "buddy-added" and "buddy-removed", which are self-explanatory
+	* Added:   "blist-node-aliased", an alias was set for a buddy, chat or
+	           contact.  See the Doxygen documentation for the details.
 
 version 1.0.0 (09/17/2004):
 	* Added: get_chat_name to the GaimPluginProtocolInfo struct
--- a/plugins/signals-test.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/plugins/signals-test.c	Tue Sep 06 03:04:07 2005 +0000
@@ -123,6 +123,39 @@
 }
 
 static void
+buddy_added_cb(GaimBuddy *buddy, void *data)
+{
+	gaim_debug_misc("signals test", "buddy_added_cb (%s)\n", gaim_buddy_get_name(buddy));
+}
+
+static void
+buddy_removed_cb(GaimBuddy *buddy, void *data)
+{
+	gaim_debug_misc("signals test", "buddy_removed_cb (%s)\n", gaim_buddy_get_name(buddy));
+}
+
+static void
+blist_node_aliased(GaimBlistNode *node, const char *old_alias)
+{
+	GaimContact *p = (GaimContact *)node;
+	GaimBuddy *b = (GaimBuddy *)node;
+	GaimChat *c = (GaimChat *)node;
+	GaimGroup *g = (GaimGroup *)node;
+
+	if (GAIM_BLIST_NODE_IS_CONTACT(node))
+		gaim_debug_misc("signals test", "blist-node-extended-menu (Contact: %s, %s)\n", p->alias, old_alias);
+	else if (GAIM_BLIST_NODE_IS_BUDDY(node))
+		gaim_debug_misc("signals test", "blist-node-extended-menu (Buddy: %s, %s)\n", b->name, old_alias);
+	else if (GAIM_BLIST_NODE_IS_CHAT(node))
+		gaim_debug_misc("signals test", "blist-node-extended-menu (Chat: %s, %s)\n", c->alias, old_alias);
+	else if (GAIM_BLIST_NODE_IS_GROUP(node))
+		gaim_debug_misc("signals test", "blist-node-extended-menu (Group: %s, %s)\n", g->name, old_alias);
+	else
+		gaim_debug_misc("signals test", "blist-node-extended-menu (UNKNOWN: %d, %s)\n", node->type, old_alias);
+
+}
+
+static void
 blist_node_extended_menu_cb(GaimBlistNode *node, void *data)
 {
 	GaimContact *p = (GaimContact *)node;
@@ -564,6 +597,12 @@
 						plugin, GAIM_CALLBACK(buddy_signed_on_cb), NULL);
 	gaim_signal_connect(blist_handle, "buddy-signed-off",
 						plugin, GAIM_CALLBACK(buddy_signed_off_cb), NULL);
+	gaim_signal_connect(blist_handle, "buddy-added",
+						plugin, GAIM_CALLBACK(buddy_added_cb), NULL);
+	gaim_signal_connect(blist_handle, "blist-removed",
+						plugin, GAIM_CALLBACK(buddy_removed_cb), NULL);
+	gaim_signal_connect(blist_handle, "blist-node-aliased",
+						plugin, GAIM_CALLBACK(blist_node_aliased), NULL);
 	gaim_signal_connect(blist_handle, "blist-node-extended-menu",
 						plugin, GAIM_CALLBACK(blist_node_extended_menu_cb), NULL);
 
--- a/src/blist.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/blist.c	Tue Sep 06 03:04:07 2005 +0000
@@ -850,10 +850,10 @@
 void gaim_blist_alias_chat(GaimChat *chat, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+	char *old_alias = chat->alias;
 
 	g_return_if_fail(chat != NULL);
 
-	g_free(chat->alias);
 	if ((alias != NULL) && (*alias != '\0'))
 		chat->alias = g_strdup(alias);
 	else
@@ -863,16 +863,20 @@
 
 	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode *)chat);
+
+	gaim_signal_emit(gaim_blist_get_handle(), "blist-node-aliased",
+					 chat, old_alias);
+	g_free(old_alias);
 }
 
 void gaim_blist_alias_buddy(GaimBuddy *buddy, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
+	char *old_alias = buddy->alias;
 
 	g_return_if_fail(buddy != NULL);
 
-	g_free(buddy->alias);
 	if ((alias != NULL) && (*alias != '\0'))
 		buddy->alias = g_strdup(alias);
 	else
@@ -887,16 +891,20 @@
 											   buddy->account);
 	if (conv)
 		gaim_conversation_autoset_title(conv);
+
+	gaim_signal_emit(gaim_blist_get_handle(), "blist-node-aliased",
+					 buddy, old_alias);
+	g_free(old_alias);
 }
 
 void gaim_blist_server_alias_buddy(GaimBuddy *buddy, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
 	GaimConversation *conv;
+	char *old_alias = buddy->server_alias;
 
 	g_return_if_fail(buddy != NULL);
 
-	g_free(buddy->server_alias);
 	if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
 		buddy->server_alias = g_strdup(alias);
 	else
@@ -911,6 +919,10 @@
 											   buddy->account);
 	if (conv)
 		gaim_conversation_autoset_title(conv);
+
+	gaim_signal_emit(gaim_blist_get_handle(), "blist-node-aliased",
+					 buddy, old_alias);
+	g_free(old_alias);
 }
 
 /*
@@ -1338,6 +1350,9 @@
 
 	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)buddy);
+
+	/* Signal that the buddy has been added */
+	gaim_signal_emit(gaim_blist_get_handle(), "buddy-added", buddy);
 }
 
 GaimContact *gaim_contact_new()
@@ -1361,12 +1376,10 @@
 void gaim_contact_set_alias(GaimContact *contact, const char *alias)
 {
 	GaimBlistUiOps *ops = gaimbuddylist->ui_ops;
+	char *old_alias = contact->alias;
 
 	g_return_if_fail(contact != NULL);
 
-	if (contact->alias != NULL)
-		g_free(contact->alias);
-
 	if ((alias != NULL) && (*alias != '\0'))
 		contact->alias = g_strdup(alias);
 	else
@@ -1376,6 +1389,10 @@
 
 	if (ops && ops->update)
 		ops->update(gaimbuddylist, (GaimBlistNode*)contact);
+
+	gaim_signal_emit(gaim_blist_get_handle(), "blist-node-aliased",
+					 contact, old_alias);
+	g_free(old_alias);
 }
 
 const char *gaim_contact_get_alias(GaimContact* contact)
@@ -1670,7 +1687,7 @@
 		}
 		/*
 		 * Remove the last buddy and trigger the deletion of the contact.
-		 * It would probably be cleaner if contact-deletion was done after 
+		 * It would probably be cleaner if contact-deletion was done after
 		 * a timeout?  Or if it had to be done manually, like below?
 		 */
 		gaim_blist_remove_buddy((GaimBuddy*)node->child);
@@ -1756,6 +1773,9 @@
 	if (ops && ops->remove)
 		ops->remove(gaimbuddylist, node);
 
+	/* Signal that the buddy has been removed before freeing the memory for it */
+	gaim_signal_emit(gaim_blist_get_handle(), "buddy-removed", buddy);
+
 	/* Delete the node */
 	if (buddy->timer > 0)
 		gaim_timeout_remove(buddy->timer);
@@ -1839,7 +1859,7 @@
 		buf = g_strdup_printf(ngettext("%d buddy from group %s was not removed "
 									   "because its account was not logged in."
 									   "  This buddy and the group were not "
-									   "removed.\n", 
+									   "removed.\n",
 									   "%d buddies from group %s were not "
 									   "removed because their accounts were "
 									   "not logged in.  These buddies and "
@@ -2601,6 +2621,16 @@
 						 gaim_value_new(GAIM_TYPE_SUBTYPE,
 										GAIM_SUBTYPE_BLIST_BUDDY));
 
+	gaim_signal_register(handle, "buddy-added",
+						 gaim_marshal_VOID__POINTER, NULL, 1,
+						 gaim_value_new(GAIM_TYPE_SUBTYPE,
+										GAIM_SUBTYPE_BLIST_BUDDY));
+
+	gaim_signal_register(handle, "buddy-removed",
+						 gaim_marshal_VOID__POINTER, NULL, 1,
+						 gaim_value_new(GAIM_TYPE_SUBTYPE,
+										GAIM_SUBTYPE_BLIST_BUDDY));
+
 	gaim_signal_register(handle, "update-idle", gaim_marshal_VOID, NULL, 0);
 
 	gaim_signal_register(handle, "blist-node-extended-menu",
@@ -2608,6 +2638,12 @@
 			     gaim_value_new(GAIM_TYPE_SUBTYPE,
 					    GAIM_SUBTYPE_BLIST_NODE),
 			     gaim_value_new(GAIM_TYPE_BOXED, "GList **"));
+
+	gaim_signal_register(handle, "blist-node-aliased",
+						 gaim_marshal_VOID__POINTER_POINTER, NULL, 2,
+						 gaim_value_new(GAIM_TYPE_SUBTYPE,
+										GAIM_SUBTYPE_BLIST_NODE),
+						 gaim_value_new(GAIM_TYPE_STRING));
 }
 
 void
--- a/src/conversation.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/conversation.c	Tue Sep 06 03:04:07 2005 +0000
@@ -626,9 +626,10 @@
 
 	account = gaim_conversation_get_account(conv);
 
-	gaim_log_free(conv->log);
-	conv->log = gaim_log_new(GAIM_LOG_CHAT, gaim_conversation_get_name(conv),
-							 account, conv, time(NULL));
+	g_list_foreach(conv->logs, (GFunc)gaim_log_free, NULL);
+	g_list_free(conv->logs);
+	conv->logs = g_list_append(NULL, gaim_log_new(GAIM_LOG_CHAT, gaim_conversation_get_name(conv),
+							 account, conv, time(NULL)));
 
 	gc = gaim_account_get_connection(account);
 
@@ -684,9 +685,9 @@
 	conv->send_history = g_list_append(NULL, NULL);
 	conv->data         = g_hash_table_new_full(g_str_hash, g_str_equal,
 											   g_free, NULL);
-	conv->log          = gaim_log_new(type == GAIM_CONV_TYPE_CHAT ? GAIM_LOG_CHAT :
+	conv->logs         = g_list_append(NULL, gaim_log_new(type == GAIM_CONV_TYPE_CHAT ? GAIM_LOG_CHAT :
 									  GAIM_LOG_IM, conv->name, account,
-									  conv, time(NULL));
+									  conv, time(NULL)));
 	/* copy features from the connection. */
 	conv->features = gc->flags;
 	
@@ -929,7 +930,9 @@
 	if (ops != NULL && ops->destroy_conversation != NULL)
 		ops->destroy_conversation(conv);
 
-	gaim_log_free(conv->log);
+	g_list_foreach(conv->logs, (GFunc)gaim_log_free, NULL);
+	g_list_free(conv->logs);
+
 	GAIM_DBUS_UNREGISTER_POINTER(conv);
 	g_free(conv);
 	conv = NULL;
@@ -1273,6 +1276,7 @@
 	GaimConnection *gc = NULL;
 	GaimAccount *account;
 	GaimConversationUiOps *ops;
+	const char *alias = NULL;
 	GaimConvWindow *win;
 	GaimBuddy *b;
 	GaimUnseenState unseen;
@@ -1305,45 +1309,42 @@
 		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM ||
 			!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 
-			if (who == NULL) {
-				if (flags & GAIM_MESSAGE_SEND) {
-					b = gaim_find_buddy(account,
-							    gaim_account_get_username(account));
-					if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) {
-						if (gaim_account_get_alias(account) != NULL)
-							who = account->alias;
-						else if (b != NULL && strcmp(b->name, gaim_buddy_get_contact_alias(b)))
-							who = gaim_buddy_get_contact_alias(b);
-						else if (gaim_connection_get_display_name(gc) != NULL)
-							who = gaim_connection_get_display_name(gc);
-						else
-							who = gaim_account_get_username(account);
-					}
-					else
-						who = gaim_account_get_username(account);
-				}
-				else {
-					b = gaim_find_buddy(account,
-							    gaim_conversation_get_name(conv));
-
-					if (b != NULL && gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT)
-						who = gaim_buddy_get_contact_alias(b);
-					else
-						who = gaim_conversation_get_name(conv);
-				}
+			if (flags & GAIM_MESSAGE_SEND) {
+				b = gaim_find_buddy(account,
+							gaim_account_get_username(account));
+
+				if (gaim_account_get_alias(account) != NULL)
+					alias = account->alias;
+				else if (b != NULL && strcmp(b->name, gaim_buddy_get_contact_alias(b)))
+					alias = gaim_buddy_get_contact_alias(b);
+				else if (gaim_connection_get_display_name(gc) != NULL)
+					alias = gaim_connection_get_display_name(gc);
+				else
+					alias = gaim_account_get_username(account);
 			}
-			else if ((who != NULL) && (*who != '\0') && gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) {
+			else
+			{
+				if (who == NULL || *who == '\0')
+					who = gaim_conversation_get_name(conv);
+
 				b = gaim_find_buddy(account, who);
 
 				if (b != NULL)
-					who = gaim_buddy_get_contact_alias(b);
+					alias = gaim_buddy_get_contact_alias(b);
+				else
+					alias = who;
 			}
 		}
 	}
 
-	if (gaim_conversation_is_logging(conv))
-		gaim_log_write(conv->log, flags, who, mtime, message);
-	ops->write_conv(conv, who, message, flags, mtime);
+	if (gaim_conversation_is_logging(conv)) {
+		GList *log = conv->logs;
+		while (log != NULL) {
+			gaim_log_write((GaimLog *)log->data, flags, alias, mtime, message);
+			log = log->next;
+		}
+	}
+	ops->write_conv(conv, who, alias, message, flags, mtime);
 
 	win = gaim_conversation_get_window(conv);
 
@@ -1881,14 +1882,16 @@
 	GaimAccount *account;
 	GaimConversation *conv;
 	GaimConnection *gc;
+	GaimPluginProtocolInfo *prpl_info;
 
 	g_return_if_fail(chat != NULL);
 	g_return_if_fail(who != NULL);
 	g_return_if_fail(message != NULL);
 
-	conv    = gaim_conv_chat_get_conversation(chat);
-	gc      = gaim_conversation_get_gc(conv);
-	account = gaim_connection_get_account(gc);
+	conv      = gaim_conv_chat_get_conversation(chat);
+	gc        = gaim_conversation_get_gc(conv);
+	account   = gaim_connection_get_account(gc);
+	prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
 
 	/* Don't display this if the person who wrote it is ignored. */
 	if (gaim_conv_chat_is_user_ignored(chat, who))
@@ -1899,7 +1902,11 @@
 		const char *nick;
 
 		str = g_strdup(gaim_normalize(account, who));
-		nick = gaim_conv_chat_get_nick(chat);
+
+		if (prpl_info->options & OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS)
+			nick = account->gc->display_name;
+		else
+			nick = account->username;
 
 		if (!g_utf8_collate(str, gaim_normalize(account, nick))) {
 			flags |= GAIM_MESSAGE_SEND;
@@ -1930,55 +1937,32 @@
 }
 
 void
-gaim_conv_chat_add_user(GaimConvChat *chat, const char *user, const char *extra_msg,
-						GaimConvChatBuddyFlags flags, gboolean new_arrival)
+gaim_conv_chat_add_user(GaimConvChat *chat, const char *user,
+						const char *extra_msg, GaimConvChatBuddyFlags flags,
+						gboolean new_arrival)
+{
+	GList *users = g_list_append(NULL, (char *)user);
+	GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
+	GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
+	
+	gaim_conv_chat_add_users(chat, users, extra_msgs, flags2, new_arrival);
+
+	g_list_free(users);
+	g_list_free(extra_msgs);
+	g_list_free(flags2);
+}
+
+void
+gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *extra_msgs,
+						 GList *flags, gboolean new_arrivals)
 {
 	GaimConversation *conv;
 	GaimConversationUiOps *ops;
 	GaimConvChatBuddy *cb;
-	char tmp[BUF_LONG];
-	gboolean quiet;
-
-	g_return_if_fail(chat != NULL);
-	g_return_if_fail(user != NULL);
-
-	conv = gaim_conv_chat_get_conversation(chat);
-	ops  = gaim_conversation_get_ui_ops(conv);
-
-	quiet = GPOINTER_TO_INT(gaim_signal_emit_return_1(gaim_conversations_get_handle(),
-					 "chat-buddy-joining", conv, user, flags)) |
-			gaim_conv_chat_is_user_ignored(chat, user);
-
-	cb = gaim_conv_chat_cb_new(user, flags);
-
-	gaim_conv_chat_set_users(chat,
-		g_list_append(gaim_conv_chat_get_users(chat), cb));
-
-	if (ops != NULL && ops->chat_add_user != NULL)
-		ops->chat_add_user(conv, user, new_arrival);
-
-	if (!quiet && new_arrival) {
-		if (extra_msg == NULL)
-			g_snprintf(tmp, sizeof(tmp), _("%s entered the room."), user);
-		else
-			g_snprintf(tmp, sizeof(tmp),
-					   _("%s [<I>%s</I>] entered the room."),
-					   user, extra_msg);
-
-		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
-	}
-
-	gaim_signal_emit(gaim_conversations_get_handle(),
-					 "chat-buddy-joined", conv, user, flags);
-}
-
-void
-gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *flags)
-{
-	GaimConversation *conv;
-	GaimConversationUiOps *ops;
-	GaimConvChatBuddy *cb;
+	GaimConnection *gc;
+	GaimPluginProtocolInfo *prpl_info;
 	GList *ul, *fl;
+	GList *aliases = NULL;
 
 	g_return_if_fail(chat  != NULL);
 	g_return_if_fail(users != NULL);
@@ -1986,32 +1970,78 @@
 	conv = gaim_conv_chat_get_conversation(chat);
 	ops  = gaim_conversation_get_ui_ops(conv);
 
+	gc = gaim_conversation_get_gc(conv);
+	if (!gc || !(prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)))
+		return;
+
 	ul = users;
 	fl = flags;
 	while ((ul != NULL) && (fl != NULL)) {
 		const char *user = (const char *)ul->data;
-		GaimConvChatBuddyFlags f = GPOINTER_TO_INT(fl->data);
+		const char *alias = user;
+		gboolean quiet;
+		GaimConvChatBuddyFlags flags = GPOINTER_TO_INT(fl->data);
+		const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
+
+		if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+			char *tmp;
+			GaimBuddy *buddy;
+
+			if (prpl_info->options & OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS)
+				tmp = g_strdup(gaim_normalize(conv->account, gc->display_name));
+			else
+				tmp = g_strdup(gaim_normalize(conv->account, conv->account->username));
+
+			if (!strcmp(tmp, gaim_normalize(conv->account, user))) {
+				alias = gaim_account_get_alias(conv->account);
+				if (alias == NULL)
+					alias = gaim_connection_get_display_name(gc);
+			} else {
+				if ((buddy = gaim_find_buddy(gc->account, user)) != NULL)
+					alias = gaim_buddy_get_contact_alias(buddy);
+			}
+			g_free(tmp);
+		}
+
+		quiet = GPOINTER_TO_INT(gaim_signal_emit_return_1(gaim_conversations_get_handle(),
+						 "chat-buddy-joining", conv, user, flags)) |
+				gaim_conv_chat_is_user_ignored(chat, user);
+
+		cb = gaim_conv_chat_cb_new(user, flags);
+		gaim_conv_chat_set_users(chat,
+				g_list_prepend(gaim_conv_chat_get_users(chat), cb));
+		aliases = g_list_append(aliases, (char *)alias);
+
+		if (!quiet && new_arrivals) {
+			char *tmp;
+
+			if (extra_msg == NULL)
+				tmp = g_strdup_printf(_("%s entered the room."), alias);
+			else
+				tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
+									  alias, extra_msg);
+
+			gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
+			g_free(tmp);
+		}
 
 		gaim_signal_emit(gaim_conversations_get_handle(),
-						 "chat-buddy-joining", conv, user, f);
-
-		cb = gaim_conv_chat_cb_new(user, f);
-		gaim_conv_chat_set_users(chat,
-				g_list_append(gaim_conv_chat_get_users(chat), cb));
-
-		gaim_signal_emit(gaim_conversations_get_handle(),
-						 "chat-buddy-joined", conv, user, f);
+						 "chat-buddy-joined", conv, user, flags);
 		ul = ul->next;
 		fl = fl->next;
+		if (extra_msgs != NULL)
+			extra_msgs = extra_msgs->next;
 	}
 
 	if (ops != NULL && ops->chat_add_users != NULL)
-		ops->chat_add_users(conv, users);
+		ops->chat_add_users(conv, users, aliases);
+
+	g_list_free(aliases);
 }
 
 void
 gaim_conv_chat_rename_user(GaimConvChat *chat, const char *old_user,
-					  const char *new_user)
+						   const char *new_user)
 {
 	GaimConversation *conv;
 	GaimConversationUiOps *ops;
@@ -2030,7 +2060,7 @@
 	flags = gaim_conv_chat_user_get_flags(chat, old_user);
 	cb = gaim_conv_chat_cb_new(new_user, flags);
 	gaim_conv_chat_set_users(chat,
-		g_list_append(gaim_conv_chat_get_users(chat), cb));
+		g_list_prepend(gaim_conv_chat_get_users(chat), cb));
 
 	if (ops != NULL && ops->chat_rename_user != NULL)
 		ops->chat_rename_user(conv, old_user, new_user);
@@ -2061,8 +2091,25 @@
 			g_snprintf(tmp, sizeof(tmp),
 					_("You are now known as %s"), new_user);
 		} else {
+			GaimConnection *gc = gaim_conversation_get_gc(conv);
+			GaimPluginProtocolInfo *prpl_info;
+			const char *old_alias = old_user;
+			const char *new_alias = new_user;
+	
+			if (!gc || !(prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)))
+				return;
+		
+			if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+				GaimBuddy *buddy;
+	
+				if ((buddy = gaim_find_buddy(gc->account, old_user)) != NULL)
+					old_alias = gaim_buddy_get_contact_alias(buddy);
+				if ((buddy = gaim_find_buddy(gc->account, new_user)) != NULL)
+					new_alias = gaim_buddy_get_contact_alias(buddy);
+			}
+
 			g_snprintf(tmp, sizeof(tmp),
-					_("%s is now known as %s"), old_user, new_user);
+					_("%s is now known as %s"), old_alias, new_alias);
 		}
 
 		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
@@ -2077,6 +2124,7 @@
 	GaimConvChatBuddy *cb;
 	char tmp[BUF_LONG];
 	gboolean quiet;
+	const char *alias = user;
 
 	g_return_if_fail(chat != NULL);
 	g_return_if_fail(user != NULL);
@@ -2102,11 +2150,24 @@
 	/* NOTE: Don't remove them from ignored in case they re-enter. */
 
 	if (!quiet) {
+		GaimConnection *gc = gaim_conversation_get_gc(conv);
+		GaimPluginProtocolInfo *prpl_info;
+
+		if (!gc || !(prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)))
+			return;
+
+		if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+			GaimBuddy *buddy;
+
+			if ((buddy = gaim_find_buddy(gc->account, user)) != NULL)
+				alias = gaim_buddy_get_contact_alias(buddy);
+		}
+
 		if (reason != NULL && *reason != '\0')
 			g_snprintf(tmp, sizeof(tmp),
-					   _("%s left the room (%s)."), user, reason);
+					   _("%s left the room (%s)."), alias, reason);
 		else
-			g_snprintf(tmp, sizeof(tmp), _("%s left the room."), user);
+			g_snprintf(tmp, sizeof(tmp), _("%s left the room."), alias);
 
 		gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
 	}
--- a/src/conversation.h	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/conversation.h	Tue Sep 06 03:04:07 2005 +0000
@@ -184,12 +184,11 @@
 	void (*write_im)(GaimConversation *conv, const char *who,
 	                 const char *message, GaimMessageFlags flags,
 	                 time_t mtime);
-	void (*write_conv)(GaimConversation *conv, const char *who,
+	void (*write_conv)(GaimConversation *conv, const char *name, const char *alias,
 	                   const char *message, GaimMessageFlags flags,
 	                   time_t mtime);
 
-	void (*chat_add_user)(GaimConversation *conv, const char *user, gboolean new_arrival);
-	void (*chat_add_users)(GaimConversation *conv, GList *users);
+	void (*chat_add_users)(GaimConversation *conv, GList *users, GList *aliases);
 	void (*chat_rename_user)(GaimConversation *conv,
 	                         const char *old_name, const char *new_name);
 	void (*chat_remove_user)(GaimConversation *conv, const char *user);
@@ -206,8 +205,6 @@
 	                            const guchar *data, gsize size);
 	void (*custom_smiley_close)(GaimConversation *conv, const char *smile);
 
-
-
 	/* Events */
 	void (*updated)(GaimConversation *conv, GaimConvUpdateType type);
 
@@ -287,7 +284,7 @@
 
 	gboolean logging;           /**< The status of logging.             */
 
-	GaimLog *log;               /**< This conversation's log            */
+	GList *logs;                /**< This conversation's logs           */
 
 	GList *send_history;        /**< The send history.                  */
 
@@ -1208,14 +1205,22 @@
 /**
  * Adds a list of users to a chat.
  *
- * The data is copied from @a users, so it is up to the developer to
- * free this list after calling this function.
+ * The data is copied from @a users, @a extra_msgs, and @a flags, so it is up to
+ * the caller to free this list after calling this function.
  *
- * @param chat      The chat.
- * @param users     The list of users to add.
- * @param flags     The list of flags for each user.
+ * @param chat         The chat.
+ * @param users        The list of users to add.
+ * @param extra_msgs   An extra message to display with the join message for each
+ *                     user.  This list may be shorter than @a users, in which
+ *                     case, the users after the end of extra_msgs will not have
+ *                     an extra message.  By extension, this means that extra_msgs
+ *                     can simply be @c NULL and none of the users will have an
+ *                     extra message.
+ * @param flags        The list of flags for each user.
+ * @param new_arrivals Decides whether or not to show join notices.
  */
-void gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *flags);
+void gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *extra_msgs,
+							  GList *flags, gboolean new_arrivals);
 
 /**
  * Renames a user in a chat.
--- a/src/gtkconv.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/gtkconv.c	Tue Sep 06 03:04:07 2005 +0000
@@ -116,13 +116,31 @@
 /* Prototypes. <-- because Paco-Paco hates this comment. */
 static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first);
 static GList *generate_invite_user_names(GaimConnection *gc);
-static void add_chat_buddy_common(GaimConversation *conv,
-								  const char *name);
+static void add_chat_buddy_common(GaimConversation *conv, const char *name,
+								  const char *alias);
 static gboolean tab_complete(GaimConversation *conv);
 static void update_typing_icon(GaimGtkConversation *gtkconv);
 static gboolean update_send_as_selection(GaimConvWindow *win);
 static char *item_factory_translate_func (const char *path, gpointer func_data);
 
+static GdkColor *get_nick_color(GaimGtkConversation *gtkconv, const char *name) {
+	static GdkColor col;
+	GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml);
+	float scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) *
+			   (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green)));
+
+	col = nick_colors[g_str_hash(name) % NUM_NICK_COLORS];
+
+	/* The colors are chosen to look fine on white; we should never have to darken */
+	if (scale > 1) {
+		col.red   *= scale;
+		col.green *= scale;
+		col.blue  *= scale;
+	}
+
+	return &col;
+}
+
 static void
 do_close(GtkWidget *w, int resp, GaimConvWindow *win)
 {
@@ -255,7 +273,6 @@
 size_allocate_cb(GtkWidget *w, GtkAllocation *allocation, GaimGtkConversation *gtkconv)
 {
 	GaimConversation *conv = gtkconv->active_conv;
-	GaimConvWindow *win = gaim_conversation_get_window(conv);
 	
 	if (!GTK_WIDGET_VISIBLE(w))
 		return FALSE;
@@ -1429,6 +1446,7 @@
 	GtkTreeModel *model;
 	GtkTreeSelection *sel;
 	char *name;
+	char *alias;
 
 	chat    = GAIM_CONV_CHAT(conv);
 	gtkchat = gtkconv->u.chat;
@@ -1437,7 +1455,10 @@
 	sel   = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list));
 
 	if (gtk_tree_selection_get_selected(sel, NULL, &iter)) {
-		gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &name, -1);
+		gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
+						   CHAT_USERS_NAME_COLUMN, &name,
+						   CHAT_USERS_ALIAS_COLUMN, &alias,
+						   -1);
 		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 	}
 	else
@@ -1448,8 +1469,9 @@
 	else
 		gaim_conv_chat_ignore(chat, name);
 
-	add_chat_buddy_common(conv, name);
+	add_chat_buddy_common(conv, name, alias);
 	g_free(name);
+	g_free(alias);
 }
 
 static void
@@ -1531,6 +1553,7 @@
 				 GaimPluginProtocolInfo *prpl_info, GaimConnection *gc)
 {
 	static GtkWidget *menu = NULL;
+	gboolean is_me = FALSE;
 	GtkWidget *button;
 
 	/*
@@ -1540,43 +1563,56 @@
 	if (menu)
 		gtk_widget_destroy(menu);
 
+	if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+		char *tmp;
+
+		if (prpl_info->options & OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS)
+			tmp = g_strdup(gaim_normalize(conv->account, gc->display_name));
+		else
+			tmp = g_strdup(gaim_normalize(conv->account, conv->account->username));
+
+		if (!strcmp(tmp, gaim_normalize(conv->account, who)))
+			is_me = TRUE;
+		g_free(tmp);
+	}
+
 	menu = gtk_menu_new();
 
-	button = gaim_new_item_from_stock(menu, _("IM"), GAIM_STOCK_IM,
-				G_CALLBACK(menu_chat_im_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
-	g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
-
-	if (gc && prpl_info && prpl_info->send_file
-			&& (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who))) {
-		button = gaim_new_item_from_stock(menu, _("Send File"), 
-			GAIM_STOCK_FILE_TRANSFER, G_CALLBACK(menu_chat_send_file_cb),
-			GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
+	if (!is_me) {
+		button = gaim_new_item_from_stock(menu, _("IM"), GAIM_STOCK_IM,
+					G_CALLBACK(menu_chat_im_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
+		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+
+		if (prpl_info && prpl_info->send_file
+				&& (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who))) {
+			button = gaim_new_item_from_stock(menu, _("Send File"), 
+				GAIM_STOCK_FILE_TRANSFER, G_CALLBACK(menu_chat_send_file_cb),
+				GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
+			g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
+		}
+
+		if (gaim_conv_chat_is_user_ignored(GAIM_CONV_CHAT(conv), who))
+			button = gaim_new_item_from_stock(menu, _("Un-Ignore"), GAIM_STOCK_IGNORE,
+							G_CALLBACK(ignore_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
+		else
+			button = gaim_new_item_from_stock(menu, _("Ignore"), GAIM_STOCK_IGNORE,
+							G_CALLBACK(ignore_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
 		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
-	if (gaim_conv_chat_is_user_ignored(GAIM_CONV_CHAT(conv), who))
-		button = gaim_new_item_from_stock(menu, _("Un-Ignore"), GAIM_STOCK_IGNORE,
-						G_CALLBACK(ignore_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
-	else
-		button = gaim_new_item_from_stock(menu, _("Ignore"), GAIM_STOCK_IGNORE,
-						G_CALLBACK(ignore_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
-	g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
-
-	if (gc && (prpl_info->get_info || prpl_info->get_cb_info)) {
+	if (prpl_info->get_info || prpl_info->get_cb_info) {
 		button = gaim_new_item_from_stock(menu, _("Info"), GAIM_STOCK_INFO,
 						G_CALLBACK(menu_chat_info_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
 		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
-	if (gc && prpl_info->get_cb_away) {
+	if (prpl_info->get_cb_away) {
 		button = gaim_new_item_from_stock(menu, _("Get Away Message"), GAIM_STOCK_AWAY,
 					G_CALLBACK(menu_chat_get_away_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
 		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
 
-	/* XXX: jabber can only add buddies from here in certain circumstances */
-	/* Added by Jonas <jonas@birme.se> */
-	if (gc) {
+	if (!is_me && !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
 		if (gaim_find_buddy(gc->account, who))
 			button = gaim_new_item_from_stock(menu, _("Remove"), GTK_STOCK_REMOVE,
 						G_CALLBACK(menu_chat_add_remove_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
@@ -1585,7 +1621,6 @@
 						G_CALLBACK(menu_chat_add_remove_cb), GAIM_GTK_CONVERSATION(conv), 0, 0, NULL);
 		g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
 	}
-	/* End Jonas */
 
 	return menu;
 }
@@ -3388,39 +3423,106 @@
 }
 
 static void
-add_chat_buddy_common(GaimConversation *conv, const char *name)
+add_chat_buddy_common(GaimConversation *conv, const char *name, const char *alias)
 {
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GaimConvChat *chat;
+	GaimConnection *gc;
+	GaimPluginProtocolInfo *prpl_info;
 	GaimConvChatBuddyFlags flags;
-	GtkTreeIter iter;
 	GtkListStore *ls;
 	GdkPixbuf *pixbuf;
+	GtkTreeIter iter;
+	gboolean is_me = FALSE;
+	gboolean is_buddy;
+	GdkColor send_color;
+ 
+	gdk_color_parse(SEND_COLOR, &send_color);
 
 	chat    = GAIM_CONV_CHAT(conv);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gtkchat = gtkconv->u.chat;
+	gc      = gaim_conversation_get_gc(conv);
+
+	if (!gc || !(prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)))
+		return;
 
 	ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)));
 
 	flags = gaim_conv_chat_user_get_flags(chat, name);
 	pixbuf = get_chat_buddy_status_icon(chat, name, flags);
 
+	if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
+		char *tmp;
+		
+		if (prpl_info->options & OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS)
+			tmp = g_strdup(gaim_normalize(conv->account, gc->display_name));
+		else
+			tmp = g_strdup(gaim_normalize(conv->account, conv->account->username));
+		
+		if (!strcmp(tmp, gaim_normalize(conv->account, name)))
+			is_me = TRUE;
+		g_free(tmp);
+	}
+
+	is_buddy = (gaim_find_buddy(conv->account, name) != NULL);
+
 	gtk_list_store_append(ls, &iter);
-	gtk_list_store_set(ls, &iter, CHAT_USERS_ICON_COLUMN, pixbuf,
-					   CHAT_USERS_NAME_COLUMN, name, CHAT_USERS_FLAGS_COLUMN, flags, -1);
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), CHAT_USERS_NAME_COLUMN,
-										 GTK_SORT_ASCENDING);
+	gtk_list_store_set(ls, &iter,
+						CHAT_USERS_ICON_COLUMN,  pixbuf,
+						CHAT_USERS_ALIAS_COLUMN, alias,
+						CHAT_USERS_NAME_COLUMN,  name,
+						CHAT_USERS_FLAGS_COLUMN, flags,
+						CHAT_USERS_COLOR_COLUMN, is_me ? &send_color : get_nick_color(gtkconv, alias),
+						CHAT_USERS_BUDDY_COLUMN, is_buddy,
+						-1);
+
 	if (pixbuf)
 		g_object_unref(pixbuf);
 }
 
+static void
+tab_complete_process_item(int *most_matched, char *entered, char **partial, char *nick_partial,
+				  GList **matches, gboolean command, char *name)
+{
+	strncpy(nick_partial, name, strlen(entered));
+	nick_partial[strlen(entered)] = '\0';
+	if (gaim_utf8_strcasecmp(nick_partial, entered))
+		return;
+
+	/* if we're here, it's a possible completion */
+
+	if (*most_matched == -1) {
+		/*
+		 * this will only get called once, since from now
+		 * on *most_matched is >= 0
+		 */
+		*most_matched = strlen(name);
+		*partial = g_strdup(name);
+	}
+	else if (*most_matched) {
+		char *tmp = g_strdup(name);
+
+		while (gaim_utf8_strcasecmp(tmp, *partial)) {
+			(*partial)[*most_matched] = '\0';
+			if (*most_matched < strlen(tmp))
+				tmp[*most_matched] = '\0';
+			(*most_matched)--;
+		}
+		(*most_matched)++;
+
+		g_free(tmp);
+	}
+
+	*matches = g_list_insert_sorted(*matches, g_strdup(name),
+								   (GCompareFunc)gaim_utf8_strcasecmp);
+}
+
 static gboolean
 tab_complete(GaimConversation *conv)
 {
 	GaimGtkConversation *gtkconv;
-	GaimConvChat *chat;
 	GtkTextIter cursor, word_start, start_buffer;
 	int start;
 	int most_matched = -1;
@@ -3429,8 +3531,6 @@
 	char *nick_partial;
 	const char *prefix;
 	GList *matches = NULL;
-	GList *list = NULL;
-	GList *l = NULL;
 	gboolean command = FALSE;
 
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
@@ -3481,59 +3581,49 @@
 	nick_partial = g_malloc(strlen(entered)+1);
 
 	if (command) {
-		list = gaim_cmd_list(conv);
+		GList *list = gaim_cmd_list(conv);
+		GList *l;
+
+		/* Commands */
+		for (l = list; l != NULL; l = l->next) {
+			tab_complete_process_item(&most_matched, entered, &partial, nick_partial,
+									  &matches, TRUE, l->data);
+		}
+		g_list_free(list);
 	} else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
-		chat = GAIM_CONV_CHAT(conv);
-		list = gaim_conv_chat_get_users(chat);
+		GaimConvChat *chat = GAIM_CONV_CHAT(conv);
+		GList *l = gaim_conv_chat_get_users(chat);
+		GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(GAIM_GTK_CONVERSATION(conv)->u.chat->list));
+		GtkTreeIter iter;
+		int f;
+
+		/* Users */
+		for (; l != NULL; l = l->next) {
+			tab_complete_process_item(&most_matched, entered, &partial, nick_partial,
+									  &matches, TRUE, ((GaimConvChatBuddy *)l->data)->name);
+		}
+
+
+		/* Aliases */
+		if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
+		{
+			do {
+				char *alias;
+
+				gtk_tree_model_get(model, &iter, CHAT_USERS_ALIAS_COLUMN, &alias, -1);
+				tab_complete_process_item(&most_matched, entered, &partial, nick_partial,
+										  &matches, FALSE, alias);
+				g_free(alias);
+
+				f = gtk_tree_model_iter_next(model, &iter);
+			} while (f != 0);
+		}
 	} else {
 		g_free(nick_partial);
 		g_free(entered);
 		return FALSE;
 	}
 
-	for (l = list; l; l = l->next) {
-		char *name;
-
-		if (command)
-			name = l->data;
-		else {
-			GaimConvChatBuddy *cb = l->data;
-			name = cb->name;
-		}
-
-		strncpy(nick_partial, name, strlen(entered));
-		nick_partial[strlen(entered)] = '\0';
-		if(gaim_utf8_strcasecmp(nick_partial, entered))
-			continue;
-
-		/* if we're here, it's a possible completion */
-
-		if (most_matched == -1) {
-			/*
-			 * this will only get called once, since from now
-			 * on most_matched is >= 0
-			 */
-			most_matched = strlen(name);
-			partial = g_strdup(name);
-		}
-		else if (most_matched) {
-			char *tmp = g_strdup(name);
-
-			while (gaim_utf8_strcasecmp(tmp, partial)) {
-				partial[most_matched] = '\0';
-				if(most_matched < strlen(tmp))
-					tmp[most_matched] = '\0';
-				most_matched--;
-			}
-			most_matched++;
-
-			g_free(tmp);
-		}
-
-		matches = g_list_insert_sorted(matches, name,
-		                               (GCompareFunc)gaim_utf8_strcasecmp);
-	}
-
 	g_free(nick_partial);
 
 	/* we're only here if we're doing new style */
@@ -3542,8 +3632,6 @@
 	if (!matches) {
 		/* if matches isn't set partials won't be either */
 		g_free(entered);
-		if (command)
-			g_list_free(list);
 		return (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) ? TRUE : FALSE;
 	}
 
@@ -3564,6 +3652,7 @@
 			gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer,
 											 matches->data, -1);
 
+		g_free(matches->data);
 		matches = g_list_remove(matches, matches->data);
 	}
 	else {
@@ -3577,6 +3666,7 @@
 			char *tmp = addthis;
 			addthis = g_strconcat(tmp, matches->data, " ", NULL);
 			g_free(tmp);
+			g_free(matches->data);
 			matches = g_list_remove(matches, matches->data);
 		}
 
@@ -3586,8 +3676,6 @@
 		g_free(addthis);
 	}
 
-	if (command)
-		g_list_free(list);
 	g_free(entered);
 	g_free(partial);
 
@@ -3819,10 +3907,19 @@
 {
 	GaimConvChatBuddyFlags f1 = 0, f2 = 0;
 	char *user1 = NULL, *user2 = NULL;
+	gboolean buddy1 = FALSE, buddy2 = FALSE;
 	gint ret = 0;
 
-	gtk_tree_model_get(model, a, CHAT_USERS_NAME_COLUMN, &user1, CHAT_USERS_FLAGS_COLUMN, &f1, -1);
-	gtk_tree_model_get(model, b, CHAT_USERS_NAME_COLUMN, &user2, CHAT_USERS_FLAGS_COLUMN, &f2, -1);
+	gtk_tree_model_get(model, a,
+						CHAT_USERS_ALIAS_COLUMN, &user1,
+						CHAT_USERS_FLAGS_COLUMN, &f1,
+						CHAT_USERS_BUDDY_COLUMN, &buddy1,
+						-1);
+	gtk_tree_model_get(model, b,
+						CHAT_USERS_ALIAS_COLUMN, &user2,
+						CHAT_USERS_FLAGS_COLUMN, &f2,
+						CHAT_USERS_BUDDY_COLUMN, &buddy2,
+						-1);
 
 	if (user1 == NULL || user2 == NULL) {
 		if (!(user1 == NULL && user2 == NULL))
@@ -3830,6 +3927,8 @@
 	} else if (f1 != f2) {
 		/* sort more important users first */
 		ret = (f1 > f2) ? -1 : 1;
+	} else if (buddy1 != buddy2) {
+		ret = buddy1 ? -1 : 1;
 	} else {
 		ret = gaim_utf8_strcasecmp(user1, user2);
 	}
@@ -3840,6 +3939,155 @@
 	return ret;
 }
 
+static void
+update_chat_alias(GaimBuddy *buddy, GaimConversation *conv, GaimConnection *gc, GaimPluginProtocolInfo *prpl_info)
+{
+	GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
+	GtkTreeModel *model;
+	char *normalized_name;
+	GtkTreeIter iter;
+	int f;
+
+	g_return_if_fail(buddy != NULL);
+	g_return_if_fail(conv != NULL);
+
+	/* This is safe because this callback is only used in chats, not IMs. */
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkconv->u.chat->list));
+
+	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
+		return;
+
+	normalized_name = g_strdup(gaim_normalize(conv->account, buddy->name));
+
+	do {
+		char *name;
+
+		gtk_tree_model_get(model, &iter, CHAT_USERS_NAME_COLUMN, &name, -1);
+
+		if (!strcmp(normalized_name, gaim_normalize(conv->account, name))) {
+			const char *alias = name;
+			char *tmp;
+			GaimBuddy *buddy2;
+
+			if (prpl_info->options & OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS)
+				tmp = g_strdup(gaim_normalize(conv->account, gc->display_name));
+			else
+				tmp = g_strdup(gaim_normalize(conv->account, conv->account->username));
+
+			if (strcmp(tmp, gaim_normalize(conv->account, name))) {
+				/* This user is not me, so look into updating the alias. */
+
+				if ((buddy2 = gaim_find_buddy(conv->account, name)) != NULL)
+					alias = gaim_buddy_get_contact_alias(buddy2);
+
+				gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+								   CHAT_USERS_ALIAS_COLUMN, alias,
+								   CHAT_USERS_COLOR_COLUMN, get_nick_color(gtkconv, alias),
+								   -1);
+			}
+			g_free(tmp);
+			g_free(name);
+			break;
+		}
+
+		f = gtk_tree_model_iter_next(model, &iter);
+
+		g_free(name);
+	} while (f != 0);
+
+	g_free(normalized_name);
+
+}
+
+static void
+blist_node_aliased_cb(GaimBlistNode *node, const char *old_alias, GaimConversation *conv)
+{
+	GaimConnection *gc;
+	GaimPluginProtocolInfo *prpl_info;
+
+	g_return_if_fail(node != NULL);
+	g_return_if_fail(conv != NULL);
+
+	gc = gaim_conversation_get_gc(conv);
+	g_return_if_fail(gc != NULL);
+	g_return_if_fail(gc->prpl != NULL);
+	prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
+
+	if (prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)
+		return;
+
+	if (GAIM_BLIST_NODE_IS_CONTACT(node))
+	{
+		GaimBlistNode *bnode;
+
+		for(bnode = node->child; bnode; bnode = bnode->next) {
+
+			if(!GAIM_BLIST_NODE_IS_BUDDY(bnode))
+				continue;
+
+			update_chat_alias((GaimBuddy *)bnode, conv, gc, prpl_info);
+		}
+	}
+	else if (GAIM_BLIST_NODE_IS_BUDDY(node))
+		update_chat_alias((GaimBuddy *)node, conv, gc, prpl_info);
+}
+
+static void
+buddy_cb_common(GaimBuddy *buddy, GaimConversation *conv, gboolean is_buddy)
+{
+	GtkTreeModel *model;
+	char *normalized_name;
+	GtkTreeIter iter;
+	int f;
+
+	g_return_if_fail(buddy != NULL);
+	g_return_if_fail(conv != NULL);
+
+	/* This is safe because this callback is only used in chats, not IMs. */
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(GAIM_GTK_CONVERSATION(conv)->u.chat->list));
+
+	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
+		return;
+
+	normalized_name = g_strdup(gaim_normalize(conv->account, buddy->name));
+
+	do {
+		char *name;
+
+		gtk_tree_model_get(model, &iter, CHAT_USERS_NAME_COLUMN, &name, -1);
+
+		if (!strcmp(normalized_name, gaim_normalize(conv->account, name))) {
+			gtk_list_store_set(GTK_LIST_STORE(model), &iter, CHAT_USERS_BUDDY_COLUMN, is_buddy, -1);
+			g_free(name);
+			break;
+		}
+
+		f = gtk_tree_model_iter_next(model, &iter);
+
+		g_free(name);
+	} while (f != 0);
+
+	g_free(normalized_name);
+
+	blist_node_aliased_cb((GaimBlistNode *)buddy, NULL, conv);
+}
+
+static void
+buddy_added_cb(GaimBuddy *buddy, GaimConversation *conv)
+{
+	buddy_cb_common(buddy, conv, TRUE);
+}
+
+static void
+buddy_removed_cb(GaimBuddy *buddy, GaimConversation *conv)
+{
+	/* If there's another buddy for the same "dude" on the list, do nothing. */
+	if (gaim_find_buddy(buddy->account, buddy->name) != NULL)
+		return;
+
+	buddy_cb_common(buddy, conv, FALSE);
+}
+
 static GtkWidget *
 setup_chat_pane(GaimGtkConversation *gtkconv)
 {
@@ -3857,6 +4105,7 @@
 	GtkListStore *ls;
 	GtkCellRenderer *rend;
 	GtkTreeViewColumn *col;
+	void *blist_handle = gaim_blist_get_handle();
 	GList *focus_chain = NULL;
 
 	gtkchat = gtkconv->u.chat;
@@ -3941,10 +4190,10 @@
 	gtk_widget_show(sw);
 
 	ls = gtk_list_store_new(CHAT_USERS_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
-							G_TYPE_INT);
-	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(ls), CHAT_USERS_NAME_COLUMN,
+							G_TYPE_STRING, G_TYPE_INT, GDK_TYPE_COLOR, G_TYPE_BOOLEAN);
+	gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_COLUMN,
 									sort_chat_users, NULL, NULL);
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), CHAT_USERS_NAME_COLUMN,
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), CHAT_USERS_ALIAS_COLUMN,
 										 GTK_SORT_ASCENDING);
 
 	list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
@@ -3953,8 +4202,7 @@
 
 	col = gtk_tree_view_column_new_with_attributes(NULL, rend,
 												   "pixbuf", CHAT_USERS_ICON_COLUMN, NULL);
-	gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE);
-
+	gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
 
 	g_signal_connect(G_OBJECT(list), "button_press_event",
@@ -3964,9 +4212,27 @@
 
 	rend = gtk_cell_renderer_text_new();
 
+	g_object_set(rend,
+				 "foreground-set", TRUE,
+				 "weight", PANGO_WEIGHT_BOLD,
+				 NULL);
 	col = gtk_tree_view_column_new_with_attributes(NULL, rend,
-												   "text", CHAT_USERS_NAME_COLUMN, NULL);
-	gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE);
+												   "text", CHAT_USERS_ALIAS_COLUMN,
+												   "foreground-gdk", CHAT_USERS_COLOR_COLUMN,
+												   "weight-set", CHAT_USERS_BUDDY_COLUMN,
+												   NULL);
+
+	gaim_signal_connect(blist_handle, "buddy-added",
+						gtkchat, GAIM_CALLBACK(buddy_added_cb), conv);
+	gaim_signal_connect(blist_handle, "buddy-removed",
+						gtkchat, GAIM_CALLBACK(buddy_removed_cb), conv);
+	gaim_signal_connect(blist_handle, "blist-node-aliased",
+						gtkchat, GAIM_CALLBACK(blist_node_aliased_cb), conv);
+
+#if GTK_CHECK_VERSION(2,6,0)
+	gtk_tree_view_column_set_expand(col, TRUE);
+	g_object_set(rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+#endif
 
 	gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
 
@@ -4751,6 +5017,7 @@
 		g_free(gtkconv->u.im);
 	}
 	else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
+		gaim_signals_disconnect_by_handle(gtkconv->u.chat);
 		g_free(gtkconv->u.chat);
 	}
 
@@ -4918,7 +5185,7 @@
 }
 
 static void
-gaim_gtkconv_write_conv(GaimConversation *conv, const char *who,
+gaim_gtkconv_write_conv(GaimConversation *conv, const char *name, const char *alias,
 						const char *message, GaimMessageFlags flags,
 						time_t mtime)
 {
@@ -5009,10 +5276,10 @@
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, 0);
 	} else {
 		char *new_message = g_memdup(message, length);
-		char *who_escaped = (who ? g_markup_escape_text(who, strlen(who)) : g_strdup(""));
+		char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup(""));
 		/* The initial offset is to deal with
 		 * escaped entities making the string longer */
-		int tag_start_offset = (who ? (strlen(who_escaped) - strlen(who)) : 0);
+		int tag_start_offset = alias ? (strlen(alias_escaped) - strlen(alias)) : 0;
 		int tag_end_offset = 0;
 
 		if (flags & GAIM_MESSAGE_WHISPER) {
@@ -5020,12 +5287,12 @@
 
 			/* If we're whispering, it's not an autoresponse. */
 			if (gaim_message_meify(new_message, -1 )) {
-				g_snprintf(str, 1024, "***%s", who_escaped);
+				g_snprintf(str, 1024, "***%s", alias_escaped);
 				strcpy(color, "#6C2585");
 				tag_start_offset += 3;
 			}
 			else {
-				g_snprintf(str, 1024, "*%s*:", who_escaped);
+				g_snprintf(str, 1024, "*%s*:", alias_escaped);
 				tag_start_offset += 1;
 				tag_end_offset = 2;
 				strcpy(color, "#00FF00");
@@ -5036,11 +5303,11 @@
 				str = g_malloc(1024);
 
 				if (flags & GAIM_MESSAGE_AUTO_RESP) {
-					g_snprintf(str, 1024, "%s ***%s", AUTO_RESPONSE, who_escaped);
+					g_snprintf(str, 1024, "%s ***%s", AUTO_RESPONSE, alias_escaped);
 					tag_start_offset += 4
 						+ strlen(AUTO_RESPONSE);
 				} else {
-					g_snprintf(str, 1024, "***%s", who_escaped);
+					g_snprintf(str, 1024, "***%s", alias_escaped);
 					tag_start_offset += 3;
 				}
 
@@ -5052,29 +5319,21 @@
 			else {
 				str = g_malloc(1024);
 				if (flags & GAIM_MESSAGE_AUTO_RESP) {
-					g_snprintf(str, 1024, "%s %s", who_escaped, AUTO_RESPONSE);
+					g_snprintf(str, 1024, "%s %s", alias_escaped, AUTO_RESPONSE);
 					tag_start_offset += 1
 						+ strlen(AUTO_RESPONSE);
 				} else {
-					g_snprintf(str, 1024, "%s:", who_escaped);
+					g_snprintf(str, 1024, "%s:", alias_escaped);
 					tag_end_offset = 1;
 				}
 				if (flags & GAIM_MESSAGE_NICK)
 					strcpy(color, "#AF7F00");
 				else if (flags & GAIM_MESSAGE_RECV) {
 					if (flags & GAIM_MESSAGE_COLORIZE) {
-						GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml);
-						GdkColor col = nick_colors[g_str_hash(who) % NUM_NICK_COLORS];
-						float scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) *
-							       (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green)));
-						if (scale > 1) { /* The colors are chosen to look fine on white; we should never have to darken */
-							col.red = col.red * scale;
-							col.green = col.green * scale;
-							col.blue = col.blue * scale;
-						}
+						GdkColor *col = get_nick_color(gtkconv, alias);
 
 						g_snprintf(color, sizeof(color), "#%02X%02X%02X",
-							   col.red >> 8, col.green >> 8, col.blue >> 8);
+							   col->red >> 8, col->green >> 8, col->blue >> 8);
 					} else
 						strcpy(color, RECV_COLOR);
 				}
@@ -5087,8 +5346,8 @@
 			}
 		}
 
-		if(who_escaped)
-			g_free(who_escaped);
+		if(alias_escaped)
+			g_free(alias_escaped);
 		g_snprintf(buf2, BUF_LONG,
 			   "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>"
 			   "<B>%s</B></FONT> ",
@@ -5096,9 +5355,11 @@
 
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, 0);
 
-		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
+		if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT &&
+		    !(flags & GAIM_MESSAGE_SEND)) {
+
 			GtkTextIter start, end;
-			GtkTextTag *buddytag = get_buddy_tag(conv, who);
+			GtkTextTag *buddytag = get_buddy_tag(conv, name);
 
 			gtk_text_buffer_get_end_iter(
 					GTK_IMHTML(gtkconv->imhtml)->text_buffer,
@@ -5149,39 +5410,13 @@
 }
 
 static void
-gaim_gtkconv_chat_add_user(GaimConversation *conv, const char *user, gboolean new_arrival)
-{
-	GaimConvChat *chat;
-	GaimGtkConversation *gtkconv;
-	GaimGtkChatPane *gtkchat;
-	char tmp[BUF_LONG];
-	int num_users;
-
-	chat    = GAIM_CONV_CHAT(conv);
-	gtkconv = GAIM_GTK_CONVERSATION(conv);
-	gtkchat = gtkconv->u.chat;
-
-	num_users = g_list_length(gaim_conv_chat_get_users(chat));
-
-	g_snprintf(tmp, sizeof(tmp),
-			   ngettext("%d person in room", "%d people in room",
-						num_users), num_users);
-
-	gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp);
-
-	if (gtkconv->make_sound && new_arrival)
-		gaim_sound_play_event(GAIM_SOUND_CHAT_JOIN);
-
-	add_chat_buddy_common(conv, user);
-}
-
-static void
-gaim_gtkconv_chat_add_users(GaimConversation *conv, GList *users)
+gaim_gtkconv_chat_add_users(GaimConversation *conv, GList *users, GList *aliases)
 {
 	GaimConvChat *chat;
 	GaimGtkConversation *gtkconv;
 	GaimGtkChatPane *gtkchat;
 	GList *l;
+	GList *ll;
 	char tmp[BUF_LONG];
 	int num_users;
 
@@ -5198,8 +5433,12 @@
 
 	gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp);
 
-	for (l = users; l != NULL; l = l->next) {
-		add_chat_buddy_common(conv, (char *)l->data);
+	l = users;
+	ll = aliases;
+	while (l != NULL && ll != NULL) {
+		add_chat_buddy_common(conv, (const char *)l->data, (const char *)ll->data);
+		l = l->next;
+		ll = ll->next;
 	}
 }
 
@@ -5213,6 +5452,7 @@
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	int f = 1;
+	char *alias = NULL;
 
 	chat    = GAIM_CONV_CHAT(conv);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
@@ -5229,6 +5469,7 @@
 		gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &val, -1);
 
 		if (!gaim_utf8_strcasecmp(old_name, val)) {
+			gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_ALIAS_COLUMN, &alias, -1);
 			gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 			g_free(val);
 			break;
@@ -5242,7 +5483,10 @@
 	if (!gaim_conv_chat_find_user(chat, old_name))
 		return;
 
-	add_chat_buddy_common(conv, new_name);
+	g_return_if_fail(alias != NULL);
+
+	add_chat_buddy_common(conv, new_name, alias);
+	g_free(alias);
 }
 
 static void
@@ -5360,6 +5604,7 @@
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	int f = 1;
+	char *alias = NULL;
 
 	chat    = GAIM_CONV_CHAT(conv);
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
@@ -5376,6 +5621,7 @@
 		gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &val, -1);
 
 		if (!gaim_utf8_strcasecmp(user, val)) {
+			gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &alias, -1);
 			gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 			g_free(val);
 			break;
@@ -5389,7 +5635,10 @@
 	if (!gaim_conv_chat_find_user(chat, user))
 		return;
 
-	add_chat_buddy_common(conv, user);
+	g_return_if_fail(alias != NULL);
+
+	add_chat_buddy_common(conv, user, alias);
+	g_free(alias);
 }
 
 static gboolean
@@ -5651,7 +5900,6 @@
 	gaim_gtkconv_write_chat,         /* write_chat           */
 	gaim_gtkconv_write_im,           /* write_im             */
 	gaim_gtkconv_write_conv,         /* write_conv           */
-	gaim_gtkconv_chat_add_user,      /* chat_add_user        */
 	gaim_gtkconv_chat_add_users,     /* chat_add_users       */
 	gaim_gtkconv_chat_rename_user,   /* chat_rename_user     */
 	gaim_gtkconv_chat_remove_user,   /* chat_remove_user     */
--- a/src/gtkconv.h	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/gtkconv.h	Tue Sep 06 03:04:07 2005 +0000
@@ -32,8 +32,11 @@
 
 enum {
 	CHAT_USERS_ICON_COLUMN,
+	CHAT_USERS_ALIAS_COLUMN,
 	CHAT_USERS_NAME_COLUMN,
 	CHAT_USERS_FLAGS_COLUMN,
+	CHAT_USERS_COLOR_COLUMN,
+	CHAT_USERS_BUDDY_COLUMN,
 	CHAT_USERS_COLUMNS
 };
 
--- a/src/protocols/irc/irc.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/protocols/irc/irc.c	Tue Sep 06 03:04:07 2005 +0000
@@ -751,7 +751,7 @@
 
 static GaimPluginProtocolInfo prpl_info =
 {
-	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL,
+	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS,
 	NULL,					/* user_splits */
 	NULL,					/* protocol_options */
 	NO_BUDDY_ICONS,		/* icon_spec */
--- a/src/protocols/irc/msgs.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/protocols/irc/msgs.c	Tue Sep 06 03:04:07 2005 +0000
@@ -401,7 +401,7 @@
 			if (users != NULL) {
 				GList *l;
 
-				gaim_conv_chat_add_users(GAIM_CONV_CHAT(convo), users, flags);
+				gaim_conv_chat_add_users(GAIM_CONV_CHAT(convo), users, NULL, flags, FALSE);
 
 				for (l = users; l != NULL; l = l->next)
 					g_free(l->data);
--- a/src/protocols/silc/chat.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/protocols/silc/chat.c	Tue Sep 06 03:04:07 2005 +0000
@@ -1019,7 +1019,7 @@
 	}
 	silc_hash_table_list_reset(&htl);
 
-	gaim_conv_chat_add_users(GAIM_CONV_CHAT(convo), users, flags);
+	gaim_conv_chat_add_users(GAIM_CONV_CHAT(convo), users, NULL, flags, FALSE);
 	g_list_free(users);
 	g_list_free(flags);
 
--- a/src/protocols/yahoo/yahoochat.c	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/protocols/yahoo/yahoochat.c	Tue Sep 06 03:04:07 2005 +0000
@@ -433,7 +433,7 @@
 				gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), NULL, topic);
 			yd->in_chat = 1;
 			yd->chat_name = g_strdup(room);
-			gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, flags);
+			gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, NULL, flags, FALSE);
 
 			tmpmsg = g_strdup_printf(_("You are now chatting in %s."), room);
 			gaim_conv_chat_write(GAIM_CONV_CHAT(c), "", tmpmsg, GAIM_MESSAGE_SYSTEM, time(NULL));
@@ -444,7 +444,7 @@
 				gaim_conv_chat_set_topic(GAIM_CONV_CHAT(c), NULL, topic);
 			yd->in_chat = 1;
 			yd->chat_name = g_strdup(room);
-			gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, flags);
+			gaim_conv_chat_add_users(GAIM_CONV_CHAT(c), members, NULL, flags, FALSE);
 		}
 	} else if (c) {
 		yahoo_chat_add_users(GAIM_CONV_CHAT(c), members);
--- a/src/prpl.h	Tue Sep 06 02:35:26 2005 +0000
+++ b/src/prpl.h	Tue Sep 06 03:04:07 2005 +0000
@@ -162,6 +162,14 @@
 	 */
 	OPT_PROTO_REGISTER_NOSCREENNAME = 0x00000200,
 
+	/**
+	 * Chats use the display name for "my" nickname.
+	 *
+	 * IRC uses the user's current nickname in the chat list, not the
+	 * username that's been setup for the account.
+	 */
+	OPT_PROTO_USE_DISPLAY_NAME_FOR_ME_IN_CHATS = 0x00000200
+
 } GaimProtocolOptions;
 
 /**