# HG changeset patch # User Evan Schoenberg # Date 1298251528 0 # Node ID 167ea4b4765c3cbbf5e77af54205ca9a3ee576cb # Parent 06791ebf7681f95d8c2e335423feea089add6333 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. diff -r 06791ebf7681 -r 167ea4b4765c libpurple/protocols/irc/irc.c --- 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); diff -r 06791ebf7681 -r 167ea4b4765c libpurple/protocols/irc/irc.h --- 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); diff -r 06791ebf7681 -r 167ea4b4765c libpurple/protocols/irc/msgs.c --- 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); diff -r 06791ebf7681 -r 167ea4b4765c libpurple/protocols/irc/parse.c --- 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 */