# HG changeset patch # User Paul Aurich # Date 1298254494 0 # Node ID 6983801172815f6337acbf53a50d9e69fece3166 # Parent 9d7b2a7709d5b0d6f5eb148768e336a4659f04fd# Parent bb15e3331bf8ec669f9fded737b9110a20577c90 merge of '5a1200b2b4048e408dafc7a965a87d3429925cb4' and 'cba010d1c097d4e6599f08276ed9d894710c1074' diff -r 9d7b2a7709d5 -r 698380117281 libpurple/conversation.c --- a/libpurple/conversation.c Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/conversation.c Mon Feb 21 02:14:54 2011 +0000 @@ -1218,15 +1218,15 @@ c = purple_conv_im_get_conversation(im); + if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) { + purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING); + } + /* Pass this on to either the ops structure or the default write func. */ if (c->ui_ops != NULL && c->ui_ops->write_im != NULL) c->ui_ops->write_im(c, who, message, flags, mtime); else purple_conversation_write(c, who, message, flags, mtime); - - if ((flags & PURPLE_MESSAGE_RECV) == PURPLE_MESSAGE_RECV) { - purple_conv_im_set_typing_state(im, PURPLE_NOT_TYPING); - } } gboolean purple_conv_present_error(const char *who, PurpleAccount *account, const char *what) @@ -2135,6 +2135,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; @@ -2167,6 +2169,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); @@ -2180,6 +2183,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) { diff -r 9d7b2a7709d5 -r 698380117281 libpurple/conversation.h --- a/libpurple/conversation.h Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/conversation.h Mon Feb 21 02:14:54 2011 +0000 @@ -300,6 +300,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 +516,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. diff -r 9d7b2a7709d5 -r 698380117281 libpurple/protocols/irc/irc.c --- a/libpurple/protocols/irc/irc.c Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/protocols/irc/irc.c Mon Feb 21 02:14:54 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 9d7b2a7709d5 -r 698380117281 libpurple/protocols/irc/irc.h --- a/libpurple/protocols/irc/irc.h Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/protocols/irc/irc.h Mon Feb 21 02:14:54 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 9d7b2a7709d5 -r 698380117281 libpurple/protocols/irc/msgs.c --- a/libpurple/protocols/irc/msgs.c Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/protocols/irc/msgs.c Mon Feb 21 02:14:54 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 9d7b2a7709d5 -r 698380117281 libpurple/protocols/irc/parse.c --- a/libpurple/protocols/irc/parse.c Mon Feb 21 02:14:43 2011 +0000 +++ b/libpurple/protocols/irc/parse.c Mon Feb 21 02:14:54 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 */