changeset 31822:6c660dc7cb6a

Moved the conversation attributes API and the IRC periodic WHO updates to i.p.p.next.minor, where they belong. applied changes from 3de680fff7ddd1b00149657afb7f6cd833000a90 through 7ee5e1d431651ed2b1a54bc942d63f35580af55c applied changes from e7c103fdfbc59bb2ca41a3c8813c4ff2847a673f through 22937ab220c41cd0c4a3f9e21e3db687db80da75 applied changes from 22937ab220c41cd0c4a3f9e21e3db687db80da75 through cba010d1c097d4e6599f08276ed9d894710c1074 applied changes from a694289accbec14c593b3636ef1f626fd8279805 through 8a43e3ddd7adacb208afe2d7ee3ea983c95901be
author Evan Schoenberg <evan.s@dreskin.net>
date Mon, 21 Feb 2011 23:08:47 +0000
parents 17a4b32f4d46
children d72d728226dc
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
diffstat 6 files changed, 222 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/conversation.c	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/conversation.c	Mon Feb 21 23:08:47 2011 +0000
@@ -2137,6 +2137,8 @@
 	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;
@@ -2169,6 +2171,7 @@
 	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);
@@ -2182,6 +2185,76 @@
 	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)
 {
--- a/libpurple/conversation.h	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/conversation.h	Mon Feb 21 23:08:47 2011 +0000
@@ -139,7 +139,8 @@
 	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. @since 2.8.0 */
 
 } PurpleConvChatBuddyFlags;
 
@@ -300,6 +301,9 @@
 	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@host, etc.
+                                    */
 };
 
 /**
@@ -513,6 +517,46 @@
 const char *purple_conversation_get_name(const PurpleConversation *conv);
 
 /**
+ * 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);
+
+/**
  * Enables or disables logging for this conversation.
  *
  * @param conv The conversation.
--- a/libpurple/protocols/irc/irc.c	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/protocols/irc/irc.c	Mon Feb 21 23:08:47 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	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/protocols/irc/irc.h	Mon Feb 21 23:08:47 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	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/protocols/irc/msgs.c	Mon Feb 21 23:08:47 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	Sun Jan 30 17:52:06 2011 +0000
+++ b/libpurple/protocols/irc/parse.c	Mon Feb 21 23:08:47 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			*/