cpw.darkrain42.irc: 8b61c737: Pluck zac's PURPLE_CBFLAGS_AWAY + irc su...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Sun Jul 12 17:30:27 EDT 2009


-----------------------------------------------------------------
Revision: 8b61c7377aa6cc0a70bad84c90cac96a45ddd45e
Ancestor: 53abc38e3dfd2e9f8ae8c3e6532379d4b0dc333b
Author: darkrain42 at pidgin.im
Date: 2009-07-12T19:13:19
Branch: im.pidgin.cpw.darkrain42.irc
URL: http://d.pidgin.im/viewmtn/revision/info/8b61c7377aa6cc0a70bad84c90cac96a45ddd45e

Modified files:
        libpurple/conversation.c libpurple/conversation.h
        libpurple/protocols/irc/irc.c libpurple/protocols/irc/irc.h
        libpurple/protocols/irc/msgs.c
        libpurple/protocols/irc/parse.c

ChangeLog: 

Pluck zac's PURPLE_CBFLAGS_AWAY + irc support changes.

*** Plucked rev e458e71beb6cabc19c7d0fa57cd3c4cb699a9b76 (zacw at adiumx.com):
Add a GHashTable to PurpleConvChatBuddy to store attributes of a buddy. Specifically, userhost and realname for IRC contacts.

*** Plucked rev 9fe8480e88fe4bea198b87f796810e35f34e6756 (zacw at adiumx.com):
Every 5 minutes, perform a WHO on our channels. Add a CB flag for \"away\" and set (or unset) appropriately on our channel occupants.

*** Plucked rev 57a700ccec4236d1b78682cd24d735b38604d0ea (zacw at adiumx.com):
Add a function to update multiple attributes at once, so we don't end up calling update several times per user.

*** Plucked rev 094626e87db8585973e6d853818b32a11e16e9ce (zacw at adiumx.com):
When building the attributes, set the GLists instead of not.

*** Plucked rev 1e35623360b0e8ccb5b6f537879a7eaa5a2a4cbe (zacw at adiumx.com):
C89-ify. Use g_list_prepend instead of g_list_append. Check if \"cb\" is non-NULL before accessing.

*** Plucked rev 20eb54f179628d0eb03d21edf024d7748d1964d8 (zacw at adiumx.com):
Use g_hash_table_destroy instead of ..._unref. Generate the GList* separately instead of using ..._get_keys.

*** Plucked rev 3710668ffc22fd2a9f1cafc4e319391a40548144 (zacw at adiumx.com):
Avoid crashing in purple_conv_chat_cb_get_attribute when key is NULL.

*** Plucked rev d93b477da5818c974015593be1087ea7794baac2 (zacw at adiumx.com):
When updating an IRC participant from the WHO response, avoid performing a second cb lookup to get the flags.


-------------- next part --------------
============================================================
--- libpurple/conversation.c	1a44bf93f933c38861f9e684c00211b5234c4ee2
+++ libpurple/conversation.c	e4a1006b2970594a741c3ccfd3c97bfedccc74fd
@@ -2083,6 +2083,8 @@ purple_conv_chat_cb_new(const char *name
 	cb->name = g_strdup(name);
 	cb->flags = flags;
 	cb->alias = g_strdup(alias);
+	cb->attributes = g_hash_table_new_full(g_str_hash, g_str_equal,
+										   g_free, g_free);
 
 	PURPLE_DBUS_REGISTER_POINTER(cb, PurpleConvChatBuddy);
 	return cb;
@@ -2115,6 +2117,7 @@ purple_conv_chat_cb_destroy(PurpleConvCh
 	g_free(cb->alias);
 	g_free(cb->alias_key);
 	g_free(cb->name);
+	g_hash_table_destroy(cb->attributes);
 
 	PURPLE_DBUS_UNREGISTER_POINTER(cb);
 	g_free(cb);
@@ -2128,7 +2131,77 @@ purple_conv_chat_cb_get_name(PurpleConvC
 	return cb->name;
 }
 
+const char *
+purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key)
+{
+	g_return_val_if_fail(cb != NULL, NULL);
+	g_return_val_if_fail(key != NULL, NULL);
+	
+	return g_hash_table_lookup(cb->attributes, key);
+}
+
+static void
+append_attribute_key(gpointer key, gpointer value, gpointer user_data)
+{
+	GList **list = user_data;
+	*list = g_list_prepend(*list, key);
+}
+
 GList *
+purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb)
+{
+	GList *keys = NULL;
+	
+	g_return_val_if_fail(cb != NULL, NULL);
+	
+	g_hash_table_foreach(cb->attributes, (GHFunc)append_attribute_key, &keys);
+	
+	return keys;
+}
+
+void
+purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	
+	g_return_if_fail(cb != NULL);
+	g_return_if_fail(key != NULL);
+	g_return_if_fail(value != NULL);
+	
+	g_hash_table_replace(cb->attributes, g_strdup(key), g_strdup(value));
+	
+	conv = purple_conv_chat_get_conversation(chat);
+	ops = purple_conversation_get_ui_ops(conv);
+	
+	if (ops != NULL && ops->chat_update_user != NULL)
+		ops->chat_update_user(conv, cb->name);
+}
+
+void
+purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values)
+{
+	PurpleConversation *conv;
+	PurpleConversationUiOps *ops;
+	
+	g_return_if_fail(cb != NULL);
+	g_return_if_fail(keys != NULL);
+	g_return_if_fail(values != NULL);
+	
+	while (keys != NULL && values != NULL) {
+		g_hash_table_replace(cb->attributes, g_strdup(keys->data), g_strdup(values->data));
+		keys = g_list_next(keys);
+		values = g_list_next(values);
+	}
+	
+	conv = purple_conv_chat_get_conversation(chat);
+	ops = purple_conversation_get_ui_ops(conv);
+	
+	if (ops != NULL && ops->chat_update_user != NULL)
+		ops->chat_update_user(conv, cb->name);
+}
+
+GList *
 purple_conversation_get_extended_menu(PurpleConversation *conv)
 {
 	GList *menu = NULL;
============================================================
--- libpurple/conversation.h	769452aaf88fa90cbeee16647d00cc617a2cf6b1
+++ libpurple/conversation.h	4410bcb069d6132e5deeae97a2b99c61b191bdee
@@ -139,8 +139,8 @@ typedef enum
 	PURPLE_CBFLAGS_HALFOP        = 0x0002, /**< Half-op                      */
 	PURPLE_CBFLAGS_OP            = 0x0004, /**< Channel Op or Moderator      */
 	PURPLE_CBFLAGS_FOUNDER       = 0x0008, /**< Channel Founder              */
-	PURPLE_CBFLAGS_TYPING        = 0x0010  /**< Currently typing             */
-
+	PURPLE_CBFLAGS_TYPING        = 0x0010, /**< Currently typing             */
+	PURPLE_CBFLAGS_AWAY			 = 0x0020  /**< Currently away				 */
 } PurpleConvChatBuddyFlags;
 
 #include "account.h"
@@ -300,6 +300,9 @@ struct _PurpleConvChatBuddy
 	PurpleConvChatBuddyFlags flags;  /**< A bitwise OR of flags for this participant,
 	                                  *   such as whether they are a channel operator.
 	                                  */
+	GHashTable *attributes;			 /**< A hash table of attributes about the user, such as
+									  *   real name, user at host, etc.
+									  */
 };
 
 /**
@@ -1356,6 +1359,47 @@ const char *purple_conv_chat_cb_get_name
 const char *purple_conv_chat_cb_get_name(PurpleConvChatBuddy *cb);
 
 /**
+ * Get an attribute of a chat buddy
+ *
+ * @param cb	The chat buddy.
+ * @param key	The key of the attribute.
+ *
+ * @return The value of the attribute key.
+ */
+const char *purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy *cb, const char *key);
+
+/**
+ * Get the keys of all atributes of a chat buddy
+ *
+ * @param cb	The chat buddy.
+ *
+ * @return A list of the attributes of a chat buddy.
+ */
+GList *purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy *cb);
+	
+/**
+ * Set an attribute of a chat buddy
+ *
+ * @param chat	The chat.
+ * @param cb	The chat buddy.
+ * @param key	The key of the attribute.
+ * @param value	The value of the attribute.
+ */
+void purple_conv_chat_cb_set_attribute(PurpleConvChat *chat, PurpleConvChatBuddy *cb, const char *key, const char *value);
+
+/**
+ * Set attributes of a chat buddy
+ *
+ * @param chat	The chat.
+ * @param cb	The chat buddy.
+ * @param keys	A GList of the keys.
+ * @param values A GList of the values.
+ */
+void
+purple_conv_chat_cb_set_attributes(PurpleConvChat *chat, PurpleConvChatBuddy *cb, GList *keys, GList *values);
+
+	
+/**
  * Destroys a chat buddy
  *
  * @param cb The chat buddy to destroy
============================================================
--- libpurple/protocols/irc/irc.c	a02796a2798a16a8dd2606252755cf3ba56a1a3c
+++ libpurple/protocols/irc/irc.c	aa9db4f8de0063d38a27bf7dc994b4b995b0f549
@@ -40,6 +40,7 @@ static void irc_buddy_append(char *name,
 #define PING_TIMEOUT 60
 
 static void irc_buddy_append(char *name, struct irc_buddy *ib, GString *string);
+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);
@@ -218,6 +219,26 @@ static void irc_buddy_append(char *name,
 	g_string_append_printf(string, "%s ", name);
 }
 
+
+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;
@@ -498,6 +519,8 @@ static void irc_close(PurpleConnection *
 	}
 	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);
============================================================
--- libpurple/protocols/irc/irc.h	3ec9f203e62e5297a814a6840b6f16379471533c
+++ libpurple/protocols/irc/irc.h	9265c6d6c49780c0152e3401dfb5f31c7de9545c
@@ -55,6 +55,7 @@ struct irc_conn {
 	char *server;
 	int fd;
 	guint timer;
+	guint who_channel_timer;
 	GHashTable *buddies;
 
 	gboolean ison_outstanding;
@@ -103,6 +104,7 @@ gboolean irc_blist_timeout(struct irc_co
 
 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);
 
 char *irc_escape_privmsg(const char *text, gssize length);
 
@@ -160,6 +162,7 @@ void irc_msg_whois(struct irc_conn *irc,
 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);
 
============================================================
--- libpurple/protocols/irc/msgs.c	4805492a1a66fe1d66e07906bad49f34424c1e32
+++ libpurple/protocols/irc/msgs.c	279dad4841bdb83c242f71cde1527bdc43fbd2e6
@@ -109,6 +109,8 @@ static void irc_connected(struct irc_con
 	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)
@@ -399,6 +401,60 @@ void irc_msg_endwhois(struct irc_conn *i
 	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 = cb->flags;
+		
+		// (G|H)...
+		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)
@@ -785,7 +841,9 @@ void irc_msg_join(struct irc_conn *irc, 
 {
 	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;
 
@@ -808,6 +866,12 @@ void irc_msg_join(struct irc_conn *irc, 
 		}
 		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. */
@@ -823,8 +887,16 @@ void irc_msg_join(struct irc_conn *irc, 
 	}
 
 	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->flag = TRUE;
 		irc_buddy_status(nick, ib, irc);
============================================================
--- libpurple/protocols/irc/parse.c	c11997c11f4d9d31784bee342152c6813019b8a1
+++ libpurple/protocols/irc/parse.c	8fc0790367a4492c4e69edbc82fe613715c4710e
@@ -65,6 +65,7 @@ static struct _irc_msg {
 	{ "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 @@ static struct _irc_msg {
 	{ "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			*/


More information about the Commits mailing list