pidgin: 44089d25: Add support for receiving contact detail...
sadrul at pidgin.im
sadrul at pidgin.im
Tue Jul 14 23:15:34 EDT 2009
-----------------------------------------------------------------
Revision: 44089d25afaf6adbd5be6f061262c40da27d6c0e
Ancestor: 03e0254c6871c4730755a200d34d4adacdf40c66
Author: sadrul at pidgin.im
Date: 2009-07-14T21:08:56
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/44089d25afaf6adbd5be6f061262c40da27d6c0e
Modified files:
libpurple/protocols/yahoo/libymsg.c
libpurple/protocols/yahoo/yahoo_aliases.c
libpurple/protocols/yahoo/yahoo_aliases.h
libpurple/protocols/yahoo/yahoo_friend.c
libpurple/protocols/yahoo/yahoo_friend.h
libpurple/protocols/yahoo/yahoo_packet.h
ChangeLog:
Add support for receiving contact details from buddies.
Also, show some contact details (e.g. phone number) in the tooltip and in
'Get Info' when available.
-------------- next part --------------
============================================================
--- libpurple/protocols/yahoo/libymsg.c e33cd22aac41fafe85dd3c7a1bb7fa89a545b06e
+++ libpurple/protocols/yahoo/libymsg.c 780b6c489397cc0594a9ea7e8de980ad8b948b5d
@@ -2898,6 +2898,9 @@ static void yahoo_packet_process(PurpleC
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 @@ void yahoo_close(PurpleConnection *gc) {
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 @@ void yahoo_tooltip_text(PurpleBuddy *b,
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)
============================================================
--- libpurple/protocols/yahoo/yahoo_aliases.c 9e50ece5c3b9a56dd6b7308ae9ad9a9977acdb59
+++ libpurple/protocols/yahoo/yahoo_aliases.c 7417fdca20786811a40e1d33ae128ae39f1c85de
@@ -53,9 +53,10 @@ struct callback_data {
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 @@ yahoo_fetch_aliases_cb(PurpleUtilFetchUr
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_fetch_aliases_cb(PurpleUtilFetchUr
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);
+ ypd = &yd->ypd;
+ }
+ }
- yd->ypd.id = g_strdup(id);
+ 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.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);
-
- 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,7 +396,58 @@ yahoo_update_alias(PurpleConnection *gc,
* 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)
{
xmlnode *node = xmlnode_new("ab");
@@ -418,6 +477,7 @@ yahoo_set_userinfo_cb(PurpleConnection *
}
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 @@ yahoo_set_userinfo_cb(PurpleConnection *
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,7 +527,6 @@ yahoo_set_userinfo_cb(PurpleConnection *
g_free(webpage);
g_free(content);
g_free(request);
- xmlnode_free(node);
}
void yahoo_set_userinfo(PurpleConnection *gc)
@@ -484,3 +567,118 @@ void yahoo_set_userinfo(PurpleConnection
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;
+ }
+ }
+}
+
============================================================
--- libpurple/protocols/yahoo/yahoo_aliases.h 2f78edc635d0cdea40797e3ae6b2130cfded9f4e
+++ libpurple/protocols/yahoo/yahoo_aliases.h 8f5192edb5ef00f7e2cc7d90ca47a8ad3fb75897
@@ -36,5 +36,5 @@ void yahoo_set_userinfo(PurpleConnection
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_personal_details_reset(YahooPersonalDetails *ypd, gboolean all);
+void yahoo_process_contact_details(PurpleConnection *gc, struct yahoo_packet *pkt);
============================================================
--- libpurple/protocols/yahoo/yahoo_friend.c 1592f59dd509851ff2a48b0e239396472941c499
+++ libpurple/protocols/yahoo/yahoo_friend.c cff08d3825f7970066d5aec054dcd057091d9300
@@ -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(YahooFrie
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 @@ void yahoo_friend_free(gpointer p)
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);
}
============================================================
--- libpurple/protocols/yahoo/yahoo_friend.h ce5c0137b79e1a10fa8a4aad152cd1a6b21a47b3
+++ libpurple/protocols/yahoo/yahoo_friend.h e0bddcb998038fafe3d119e931383cc3e7ff379b
@@ -56,7 +56,7 @@ typedef struct _YahooFriend {
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 */
============================================================
--- libpurple/protocols/yahoo/yahoo_packet.h 75da8cacb622428d8f0e96717dd72624b09d56d0
+++ libpurple/protocols/yahoo/yahoo_packet.h f2dbb4a70d271a9138706b1e7fe3774cfd3671a6
@@ -98,6 +98,7 @@ enum yahoo_service { /* these are easier
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,
More information about the Commits
mailing list