Mercurial > pidgin
changeset 27545:5c17c400153d
merge of '0800f09f6994e5ae06fed4644a78d33ab4346866'
and '3e47f0f65ae33e37ab711ec7b2fd8aeeae1efcd7'
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Wed, 15 Jul 2009 04:27:22 +0000 |
parents | 205267108d6e (current diff) a756b4ed306e (diff) |
children | 70dcaa0b6fea 606a0e577b34 0d32c4c08deb |
files | |
diffstat | 6 files changed, 308 insertions(+), 37 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/yahoo/libymsg.c Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/libymsg.c Wed Jul 15 04:27:22 2009 +0000 @@ -2898,6 +2898,9 @@ case YAHOO_SERVICE_AUDIBLE: yahoo_process_audible(gc, pkt); break; + case YAHOO_SERVICE_CONTACT_DETAILS: + yahoo_process_contact_details(gc, pkt); + break; case YAHOO_SERVICE_FILETRANS_15: yahoo_process_filetrans_15(gc, pkt); break; @@ -3539,7 +3542,7 @@ g_free(yd->pending_chat_goto); g_strfreev(yd->profiles); - yahoo_personal_details_reset(&yd->ypd); + yahoo_personal_details_reset(&yd->ypd, TRUE); g_free(yd->current_list15_grp); @@ -3772,6 +3775,26 @@ if (presence != NULL) purple_notify_user_info_add_pair(user_info, _("Presence"), presence); + + if (full) { + YahooPersonalDetails *ypd = &f->ypd; + int i; + struct { + char *id; + char *text; + char *value; + } yfields[] = { + {"hp", N_("Home Phone Number"), ypd->phone.home}, + {"wp", N_("Work Phone Number"), ypd->phone.work}, + {"mo", N_("Mobile Phone Number"), ypd->phone.mobile}, + {NULL, NULL, NULL} + }; + for (i = 0; yfields[i].id; i++) { + if (!yfields[i].value || !*yfields[i].value) + continue; + purple_notify_user_info_add_pair(user_info, _(yfields[i].text), yfields[i].value); + } + } } static void yahoo_addbuddyfrommenu_cb(PurpleBlistNode *node, gpointer data) @@ -3848,6 +3871,16 @@ yahoo_doodle_initiate(gc, purple_buddy_get_name(b)); } +static void +yahoo_userinfo_blist_node(PurpleBlistNode *node, gpointer data) +{ + PurpleBuddy *b = (PurpleBuddy *)node; + PurpleAccount *account = purple_buddy_get_account(b); + PurpleConnection *gc = purple_account_get_connection(account); + + yahoo_set_userinfo_for_buddy(gc, b); +} + static GList *yahoo_buddy_menu(PurpleBuddy *buddy) { GList *m = NULL; @@ -3909,13 +3942,16 @@ act = purple_menu_action_new(_("Presence Settings"), NULL, NULL, build_presence_submenu(f, gc)); m = g_list_append(m, act); - } - - if (f) { + act = purple_menu_action_new(_("Start Doodling"), PURPLE_CALLBACK(yahoo_doodle_blist_node), NULL, NULL); m = g_list_append(m, act); + + act = purple_menu_action_new(_("Set User Info..."), + PURPLE_CALLBACK(yahoo_userinfo_blist_node), + NULL, NULL); + m = g_list_append(m, act); } return m;
--- a/libpurple/protocols/yahoo/yahoo_aliases.c Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_aliases.c Wed Jul 15 04:27:22 2009 +0000 @@ -53,9 +53,10 @@ gchar *who; }; -void yahoo_personal_details_reset(YahooPersonalDetails *ypd) +void yahoo_personal_details_reset(YahooPersonalDetails *ypd, gboolean all) { - g_free(ypd->id); + if (all) + g_free(ypd->id); g_free(ypd->names.first); g_free(ypd->names.last); g_free(ypd->names.middle); @@ -104,6 +105,7 @@ for(item = xmlnode_get_child(contacts, "ct"); item; item = xmlnode_get_next_twin(item)) { /* Yahoo replies with two types of contact (ct) record, we are only interested in the alias ones */ if ((yid = xmlnode_get_attrib(item, "yi"))) { + YahooPersonalDetails *ypd = NULL; /* Grab all the bits of information we can */ fn = xmlnode_get_attrib(item, "fn"); ln = xmlnode_get_attrib(item, "ln"); @@ -148,23 +150,29 @@ yahoo_update_alias(gc, yid, buddy_alias); purple_debug_info("yahoo", "Sent updated alias '%s'\n", buddy_alias); } - } else { + } + + if (f != NULL) + ypd = &f->ypd; + else { /* May be the alias is for the account? */ const char *yidn = purple_normalize(account, yid); if (purple_strequal(yidn, purple_connection_get_display_name(gc))) { - yahoo_personal_details_reset(&yd->ypd); - - yd->ypd.id = g_strdup(id); + ypd = &yd->ypd; + } + } - yd->ypd.names.first = g_strdup(fn); - yd->ypd.names.middle = g_strdup(mn); - yd->ypd.names.last = g_strdup(ln); - yd->ypd.names.nick = g_strdup(nn); + if (ypd) { + yahoo_personal_details_reset(ypd, TRUE); + ypd->id = g_strdup(id); + ypd->names.first = g_strdup(fn); + ypd->names.middle = g_strdup(mn); + ypd->names.last = g_strdup(ln); + ypd->names.nick = g_strdup(nn); - yd->ypd.phone.work = g_strdup(wp); - yd->ypd.phone.home = g_strdup(hp); - yd->ypd.phone.mobile = g_strdup(mo); - } + ypd->phone.work = g_strdup(wp); + ypd->phone.home = g_strdup(hp); + ypd->phone.mobile = g_strdup(mo); } g_free(full_name); @@ -388,6 +396,57 @@ * User Info Update Functions **************************************************************************/ +#if 0 +/* This block of code can be used to send our contact details to + * everyone in the buddylist. But with the official messenger, + * doing this pops a conversation window at the receiver's end, + * which is stupid, and thus not really surprising. */ + +struct yahoo_userinfo { + struct yahoo_data *yd; + char *xml; +}; + +static void +yahoo_send_userinfo_to_user(struct yahoo_userinfo *yui, const char *who) +{ + struct yahoo_packet *pkt; + PurpleConnection *gc; + + gc = yui->yd->gc; + pkt = yahoo_packet_new(YAHOO_SERVICE_CONTACT_DETAILS, 0, 0); + yahoo_packet_hash(pkt, "siisis", + 1, purple_connection_get_display_name(gc), + 13, 1, /* This creates a conversation window in the official client */ + 302, 5, + 5, who, + 303, 5, + 280, yui->xml); + yahoo_packet_send_and_free(pkt, yui->yd); +} + +static void +yahoo_send_userinfo_foreach(gpointer key, gpointer value, gpointer data) +{ + const char *who = key; + YahooFriend *f = value; + + if (f->status != YAHOO_STATUS_OFFLINE) { + yahoo_send_userinfo_to_user(data, who); + } +} + +static void +yahoo_sent_userinfo_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, const gchar *url_text, size_t len, const gchar *error_message) +{ + struct yahoo_userinfo *yui = user_data; + yahoo_fetch_aliases_cb(url_data, yui->yd->gc, url_text, len, error_message); + g_hash_table_foreach(yui->yd->friends, yahoo_send_userinfo_foreach, yui); + g_free(yui->xml); + g_free(yui); +} +#endif + static void yahoo_set_userinfo_cb(PurpleConnection *gc, PurpleRequestFields *fields) { @@ -408,8 +467,8 @@ xmlnode_set_attrib(node, "cc", "1"); /* XXX: ? */ xmlnode_set_attrib(ct, "e", "1"); - xmlnode_set_attrib(ct, "yi", purple_connection_get_display_name(gc)); - xmlnode_set_attrib(ct, "id", yd->ypd.id); + xmlnode_set_attrib(ct, "yi", purple_request_fields_get_string(fields, "yname")); + xmlnode_set_attrib(ct, "id", purple_request_fields_get_string(fields, "yid")); xmlnode_set_attrib(ct, "pr", "0"); for (i = 0; yfields[i]; i++) { @@ -418,6 +477,7 @@ } content = xmlnode_to_formatted_str(node, &len); + xmlnode_free(node); purple_url_parse(yd->jp ? YAHOOJP_USERINFO_URL : YAHOO_USERINFO_URL, &webaddress, NULL, &webpage, NULL, NULL); request = g_strdup_printf("POST %s HTTP/1.1\r\n" @@ -433,6 +493,30 @@ len + 4, content); +#if 0 + { + /* This is if we wanted to send our contact details to everyone + * in the buddylist. But this cannot be done now, because in the + * official messenger, doing this pops a conversation window at + * the receiver's end, which is stupid, and thus not really + * surprising. */ + struct yahoo_userinfo *ui = g_new(struct yahoo_userinfo, 1); + node = xmlnode_new("contact"); + + for (i = 0; yfields[i]; i++) { + const char *v = purple_request_fields_get_string(fields, yfields[i]); + if (v) { + xmlnode *nd = xmlnode_new_child(node, yfields[i]); + xmlnode_insert_data(nd, v, -1); + } + } + + ui->yd = yd; + ui->xml = xmlnode_to_str(node, NULL); + xmlnode_free(node); + } +#endif + url_data = purple_util_fetch_url_request_len_with_account(account, webaddress, FALSE, YAHOO_CLIENT_USERAGENT, TRUE, request, FALSE, -1, yahoo_fetch_aliases_cb, gc); @@ -443,28 +527,27 @@ g_free(webpage); g_free(content); g_free(request); - xmlnode_free(node); } -void yahoo_set_userinfo(PurpleConnection *gc) +static PurpleRequestFields * +request_fields_from_personal_details(YahooPersonalDetails *ypd, const char *id) { PurpleRequestFields *fields; PurpleRequestFieldGroup *group; PurpleRequestField *field; - struct yahoo_data *yd = purple_connection_get_protocol_data(gc); int i; struct { char *id; char *text; char *value; } yfields[] = { - {"fn", N_("First Name"), yd->ypd.names.first}, - {"ln", N_("Last Name"), yd->ypd.names.last}, - {"nn", N_("Nickname"), yd->ypd.names.nick}, - {"mn", N_("Middle Name"), yd->ypd.names.middle}, - {"hp", N_("Home Phone Number"), yd->ypd.phone.home}, - {"wp", N_("Work Phone Number"), yd->ypd.phone.work}, - {"mo", N_("Mobile Phone Number"), yd->ypd.phone.mobile}, + {"fn", N_("First Name"), ypd->names.first}, + {"ln", N_("Last Name"), ypd->names.last}, + {"nn", N_("Nickname"), ypd->names.nick}, + {"mn", N_("Middle Name"), ypd->names.middle}, + {"hp", N_("Home Phone Number"), ypd->phone.home}, + {"wp", N_("Work Phone Number"), ypd->phone.work}, + {"mo", N_("Mobile Phone Number"), ypd->phone.mobile}, {NULL, NULL, NULL} }; @@ -472,15 +555,164 @@ group = purple_request_field_group_new(NULL); purple_request_fields_add_group(fields, group); + field = purple_request_field_string_new("yname", "", id, FALSE); + purple_request_field_set_visible(field, FALSE); + purple_request_field_group_add_field(group, field); + + field = purple_request_field_string_new("yid", "", ypd->id, FALSE); + purple_request_field_set_visible(field, FALSE); + purple_request_field_group_add_field(group, field); + for (i = 0; yfields[i].id; i++) { field = purple_request_field_string_new(yfields[i].id, _(yfields[i].text), yfields[i].value, FALSE); purple_request_field_group_add_field(group, field); } + return fields; +} + +void yahoo_set_userinfo_for_buddy(PurpleConnection *gc, PurpleBuddy *buddy) +{ + PurpleRequestFields *fields; + YahooFriend *f; + const char *name; + + name = purple_buddy_get_name(buddy); + f = yahoo_friend_find(gc, name); + if (!f) + return; + + fields = request_fields_from_personal_details(&f->ypd, name); + purple_request_fields(gc, NULL, _("Set User Info"), NULL, fields, + _("OK"), G_CALLBACK(yahoo_set_userinfo_cb), + _("Cancel"), NULL, + purple_connection_get_account(gc), NULL, NULL, gc); +} + +void yahoo_set_userinfo(PurpleConnection *gc) +{ + struct yahoo_data *yd = purple_connection_get_protocol_data(gc); + PurpleRequestFields *fields = request_fields_from_personal_details(&yd->ypd, + purple_connection_get_display_name(gc)); purple_request_fields(gc, NULL, _("Set User Info"), NULL, fields, _("OK"), G_CALLBACK(yahoo_set_userinfo_cb), _("Cancel"), NULL, purple_connection_get_account(gc), NULL, NULL, gc); } +static gboolean +parse_contact_details(struct yahoo_data *yd, const char *who, const char *xml) +{ + xmlnode *node, *nd; + YahooFriend *f; + char *yid; + + node = xmlnode_from_str(xml, -1); + if (!node) { + purple_debug_info("yahoo", "Received malformed XML for contact details from '%s':\n%s\n", + who, xml); + return FALSE; + } + + nd = xmlnode_get_child(node, "yi"); + if (!nd || !(yid = xmlnode_get_data(nd))) { + xmlnode_free(node); + return FALSE; + } + + if (!purple_strequal(yid, who)) { + /* The user may not want to set the contact details about folks in the buddylist + to what some random dude might have sent. So it would be good if we popped + up a prompt requiring the user to confirm the details before we set them. + However, someone could send details about hundreds of users at the same time, + which would make things really bad. So for now, until we have a better way of + dealing with this, ignore this details. */ + purple_debug_info("yahoo", "Ignoring contact details sent by %s about %s\n", + who, yid); + g_free(yid); + xmlnode_free(node); + return FALSE; + } + + f = yahoo_friend_find(yd->gc, yid); + if (!f) { + g_free(yid); + xmlnode_free(node); + return FALSE; + } else { + int i; + YahooPersonalDetails *ypd = &f->ypd; + char *alias = NULL; + struct { + char *id; + char **field; + } details[] = { + {"fn", &ypd->names.first}, + {"mn", &ypd->names.middle}, + {"ln", &ypd->names.last}, + {"nn", &ypd->names.nick}, + {"wp", &ypd->phone.work}, + {"hp", &ypd->phone.home}, + {"mo", &ypd->phone.mobile}, + {NULL, NULL} + }; + + yahoo_personal_details_reset(ypd, FALSE); + + for (i = 0; details[i].id; i++) { + nd = xmlnode_get_child(node, details[i].id); + *details[i].field = nd ? xmlnode_get_data(nd) : NULL; + } + + if (ypd->names.nick) + alias = ypd->names.nick; + else if (ypd->names.first || ypd->names.last) { + alias = g_strstrip(g_strdup_printf("%s %s", + ypd->names.first ? ypd->names.first : "", + ypd->names.last ? ypd->names.last : "")); + } + + if (alias) { + serv_got_alias(yd->gc, yid, alias); + if (alias != ypd->names.nick) + g_free(alias); + } + } + + xmlnode_free(node); + g_free(yid); + return TRUE; +} + +/* I don't think this happens for MSN buddies. -- sad */ +void yahoo_process_contact_details(PurpleConnection *gc, struct yahoo_packet *pkt) +{ + GSList *l = pkt->hash; + const char *who = NULL, *xml = NULL; + struct yahoo_data *yd = purple_connection_get_protocol_data(gc); + + for (; l; l = l->next) { + struct yahoo_pair *pair = l->data; + switch (pair->key) { + case 4: + who = pair->value; /* This is the person who sent us the details. + But not necessarily about himself. */ + break; + case 5: + break; + case 13: + /* This is '1' if 'who' is sending the contact details about herself, + '0' if 'who' is sending the contact details she has about buddies + in her list. However, in all cases, the xml in key 280 always seems + to contain the yid of the person, so we may as well ignore this field + and look into the xml instead to see who the information is about. */ + break; + case 280: + xml = pair->value; + parse_contact_details(yd, who, xml); + break; + } + } +} +
--- a/libpurple/protocols/yahoo/yahoo_aliases.h Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_aliases.h Wed Jul 15 04:27:22 2009 +0000 @@ -36,5 +36,6 @@ void yahoo_update_alias(PurpleConnection *gc, const char *who, const char *alias); void yahoo_fetch_aliases(PurpleConnection *gc); void yahoo_set_userinfo(PurpleConnection *gc); -void yahoo_personal_details_reset(YahooPersonalDetails *ypd); - +void yahoo_set_userinfo_for_buddy(PurpleConnection *gc, PurpleBuddy *buddy); +void yahoo_personal_details_reset(YahooPersonalDetails *ypd, gboolean all); +void yahoo_process_contact_details(PurpleConnection *gc, struct yahoo_packet *pkt);
--- a/libpurple/protocols/yahoo/yahoo_friend.c Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_friend.c Wed Jul 15 04:27:22 2009 +0000 @@ -27,6 +27,7 @@ #include "debug.h" #include "yahoo_friend.h" +#include "yahoo_aliases.h" static YahooFriend *yahoo_friend_new(void) { @@ -124,13 +125,13 @@ void yahoo_friend_set_alias_id(YahooFriend *f, const char *alias_id) { - g_free(f->alias_id); - f->alias_id = g_strdup(alias_id); + g_free(f->ypd.id); + f->ypd.id = g_strdup(alias_id); } const char *yahoo_friend_get_alias_id(YahooFriend *f) { - return f->alias_id; + return f->ypd.id; } void yahoo_friend_free(gpointer p) @@ -139,7 +140,7 @@ g_free(f->msg); g_free(f->game); g_free(f->ip); - g_free(f->alias_id); + yahoo_personal_details_reset(&f->ypd, TRUE); g_free(f); }
--- a/libpurple/protocols/yahoo/yahoo_friend.h Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_friend.h Wed Jul 15 04:27:22 2009 +0000 @@ -56,7 +56,7 @@ YahooPresenceVisibility presence; int protocol; /* 1=LCS, 2=MSN*/ long int version_id; - gchar *alias_id; /* XXX: stick in a YahooPersonalDetails instead? */ + YahooPersonalDetails ypd; YahooP2PStatus p2p_status; gboolean p2p_packet_sent; /* 0:not sent, 1=sent */ gint session_id; /* session id of friend */
--- a/libpurple/protocols/yahoo/yahoo_packet.h Tue Jul 14 22:47:52 2009 +0000 +++ b/libpurple/protocols/yahoo/yahoo_packet.h Wed Jul 15 04:27:22 2009 +0000 @@ -98,6 +98,7 @@ YAHOO_SERVICE_AVATAR_UPDATE = 0xc7, YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8, YAHOO_SERVICE_AUDIBLE = 0xd0, + YAHOO_SERVICE_CONTACT_DETAILS = 0xd3, /* YAHOO_SERVICE_CHAT_SESSION = 0xd4,?? Reports start of chat session, gets an id from server */ YAHOO_SERVICE_AUTH_REQ_15 = 0xd6, YAHOO_SERVICE_FILETRANS_15 = 0xdc,