changeset 31686:167ea4b4765c

Patch from Zac West which performs periodic WHO updates on IRC channel participants in order to track 'away' status, userhost, and real name. Plucked from a series of im.pidgin.adium commits.
author Evan Schoenberg <evan.s@dreskin.net>
date Mon, 21 Feb 2011 01:25:28 +0000
parents 06791ebf7681
children bb15e3331bf8 90bff83c91cf
files libpurple/protocols/irc/irc.c libpurple/protocols/irc/irc.h libpurple/protocols/irc/msgs.c libpurple/protocols/irc/parse.c
diffstat 4 files changed, 104 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/irc/irc.c	Mon Feb 21 01:18:49 2011 +0000
+++ b/libpurple/protocols/irc/irc.c	Mon Feb 21 01:25:28 2011 +0000
@@ -41,6 +41,8 @@
 
 static void irc_ison_buddy_init(char *name, struct irc_buddy *ib, GList **list);
 
+static void irc_who_channel(PurpleConversation *conv, struct irc_conn *irc);
+
 static const char *irc_blist_icon(PurpleAccount *a, PurpleBuddy *b);
 static GList *irc_status_types(PurpleAccount *account);
 static GList *irc_actions(PurplePlugin *plugin, gpointer context);
@@ -232,6 +234,26 @@
 	*list = g_list_append(*list, ib);
 }
 
+
+gboolean irc_who_channel_timeout(struct irc_conn *irc)
+{
+	// WHO all of our channels.
+	g_list_foreach(purple_get_conversations(), (GFunc)irc_who_channel, (gpointer)irc);
+	
+	return TRUE;
+}
+
+static void irc_who_channel(PurpleConversation *conv, struct irc_conn *irc)
+{
+	if (purple_conversation_get_account(conv) == irc->account && purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
+		char *buf = irc_format(irc, "vc", "WHO", purple_conversation_get_name(conv));
+		
+		purple_debug(PURPLE_DEBUG_INFO, "irc", "Performing periodic who on %s", purple_conversation_get_name(conv));
+		irc_send(irc, buf);
+		g_free(buf);
+	}
+}
+
 static void irc_ison_one(struct irc_conn *irc, struct irc_buddy *ib)
 {
 	char *buf;
@@ -517,6 +539,8 @@
 	}
 	if (irc->timer)
 		purple_timeout_remove(irc->timer);
+	if (irc->who_channel_timer)
+		purple_timeout_remove(irc->who_channel_timer);
 	g_hash_table_destroy(irc->cmds);
 	g_hash_table_destroy(irc->msgs);
 	g_hash_table_destroy(irc->buddies);
--- a/libpurple/protocols/irc/irc.h	Mon Feb 21 01:18:49 2011 +0000
+++ b/libpurple/protocols/irc/irc.h	Mon Feb 21 01:25:28 2011 +0000
@@ -55,6 +55,7 @@
 	char *server;
 	int fd;
 	guint timer;
+	guint who_channel_timer;
 	GHashTable *buddies;
 
 	gboolean ison_outstanding;
@@ -106,6 +107,7 @@
 
 int irc_send(struct irc_conn *irc, const char *buf);
 gboolean irc_blist_timeout(struct irc_conn *irc);
+gboolean irc_who_channel_timeout(struct irc_conn *irc);
 void irc_buddy_query(struct irc_conn *irc);
 
 char *irc_escape_privmsg(const char *text, gssize length);
@@ -164,6 +166,7 @@
 void irc_msg_unknown(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_wallops(struct irc_conn *irc, const char *name, const char *from, char **args);
 void irc_msg_whois(struct irc_conn *irc, const char *name, const char *from, char **args);
+void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args);
 
 void irc_msg_ignore(struct irc_conn *irc, const char *name, const char *from, char **args);
 
--- a/libpurple/protocols/irc/msgs.c	Mon Feb 21 01:18:49 2011 +0000
+++ b/libpurple/protocols/irc/msgs.c	Mon Feb 21 01:25:28 2011 +0000
@@ -110,6 +110,8 @@
 	irc_blist_timeout(irc);
 	if (!irc->timer)
 		irc->timer = purple_timeout_add_seconds(45, (GSourceFunc)irc_blist_timeout, (gpointer)irc);
+    if (!irc->who_channel_timer)
+        irc->who_channel_timer = purple_timeout_add_seconds(300, (GSourceFunc)irc_who_channel_timeout, (gpointer)irc);
 }
 
 void irc_msg_default(struct irc_conn *irc, const char *name, const char *from, char **args)
@@ -400,6 +402,59 @@
 	memset(&irc->whois, 0, sizeof(irc->whois));
 }
 
+void irc_msg_who(struct irc_conn *irc, const char *name, const char *from, char **args)
+{
+	if (!strcmp(name, "352")) {
+		PurpleConversation *conv;
+		PurpleConvChat *chat;
+		PurpleConvChatBuddy *cb;
+		
+		char *userhost, *realname;
+		
+		PurpleConvChatBuddyFlags flags;
+		GList *keys = NULL, *values = NULL;
+		
+		conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, args[1], irc->account);
+		if (!conv) {
+			purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got a WHO response for %s, which doesn't exist\n", args[1]);
+			return;
+		}
+
+		cb = purple_conv_chat_cb_find(PURPLE_CONV_CHAT(conv), args[5]);
+		if (!cb) {
+			purple_debug(PURPLE_DEBUG_ERROR, "irc", "Got a WHO response for %s who isn't a buddy.\n", args[5]);
+			return;
+		}
+
+		chat = PURPLE_CONV_CHAT(conv);
+		
+		userhost = g_strdup_printf("%s@%s", args[2], args[3]);
+		realname = g_strdup(args[8]);
+		
+		keys = g_list_prepend(keys, "userhost");
+		values = g_list_prepend(values, userhost);
+		
+		keys = g_list_prepend(keys, "realname");
+		values = g_list_prepend(values, realname);
+		
+		purple_conv_chat_cb_set_attributes(chat, cb, keys, values);
+		
+		g_list_free(keys);
+		g_list_free(values);
+		
+		g_free(userhost);
+		g_free(realname);
+		
+		flags = purple_conv_chat_user_get_flags(chat, cb->name);
+
+		if (args[6][0] == 'G' && !(flags & PURPLE_CBFLAGS_AWAY)) {
+			purple_conv_chat_user_set_flags(chat, cb->name, flags | PURPLE_CBFLAGS_AWAY);
+		} else if(args[6][0] == 'H' && (flags & PURPLE_CBFLAGS_AWAY)) {
+			purple_conv_chat_user_set_flags(chat, cb->name, flags & ~PURPLE_CBFLAGS_AWAY);
+		}
+	}
+}
+
 void irc_msg_list(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
 	if (!irc->roomlist)
@@ -797,7 +852,10 @@
 {
 	PurpleConnection *gc = purple_account_get_connection(irc->account);
 	PurpleConversation *convo;
-	char *nick = irc_mask_nick(from), *userhost;
+	PurpleConvChat *chat;
+	PurpleConvChatBuddy *cb;
+
+	char *nick = irc_mask_nick(from), *userhost, *buf;
 	struct irc_buddy *ib;
 	static int id = 1;
 
@@ -820,6 +878,12 @@
 		}
 		purple_conversation_set_data(convo, IRC_NAMES_FLAG,
 					   GINT_TO_POINTER(FALSE));
+		
+		// Get the real name and user host for all participants.
+		buf = irc_format(irc, "vc", "WHO", args[0]);
+		irc_send(irc, buf);
+		g_free(buf);
+		
 		/* Until purple_conversation_present does something that
 		 * one would expect in Pidgin, this call produces buggy
 		 * behavior both for the /join and auto-join cases. */
@@ -835,8 +899,16 @@
 	}
 
 	userhost = irc_mask_userhost(from);
-	purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), nick, userhost, PURPLE_CBFLAGS_NONE, TRUE);
-
+	chat = PURPLE_CONV_CHAT(convo);
+	
+	purple_conv_chat_add_user(chat, nick, userhost, PURPLE_CBFLAGS_NONE, TRUE);
+	
+	cb = purple_conv_chat_cb_find(chat, nick);
+	
+	if (cb) {
+		purple_conv_chat_cb_set_attribute(chat, cb, "userhost", userhost);		
+	}
+	
 	if ((ib = g_hash_table_lookup(irc->buddies, nick)) != NULL) {
 		ib->new_online_status = TRUE;
 		irc_buddy_status(nick, ib, irc);
--- a/libpurple/protocols/irc/parse.c	Mon Feb 21 01:18:49 2011 +0000
+++ b/libpurple/protocols/irc/parse.c	Mon Feb 21 01:25:28 2011 +0000
@@ -65,6 +65,7 @@
 	{ "319", "nn:", irc_msg_whois },	/* Whois channels		*/
 	{ "320", "nn:", irc_msg_whois },	/* Whois (fn ident)		*/
 	{ "314", "nnnvv:", irc_msg_whois },	/* Whowas user			*/
+	{ "315", "nt:", irc_msg_who }, /* end of WHO channel */
 	{ "369", "nt:", irc_msg_endwhois },	/* End of WHOWAS		*/
 	{ "321", "*", irc_msg_list },		/* Start of list		*/
 	{ "322", "ncv:", irc_msg_list },	/* List.			*/
@@ -73,6 +74,7 @@
 	{ "331", "nc:",	irc_msg_topic },	/* No channel topic		*/
 	{ "332", "nc:", irc_msg_topic },	/* Channel topic		*/
 	{ "333", "*", irc_msg_ignore },		/* Topic setter stuff		*/
+	{ "352", "nvcvnvvv:", irc_msg_who },	/* Channel WHO			*/
 	{ "353", "nvc:", irc_msg_names },	/* Names list			*/
 	{ "366", "nc:", irc_msg_names },	/* End of names			*/
 	{ "367", "ncnnv", irc_msg_ban },	/* Ban list			*/