Mercurial > pidgin
diff libpurple/protocols/msn/contact.c @ 20477:9a2a4a0c0003
Add the possibility to create an Address Book, useful for newly registered MSN users.
When changing friendly name, send the new one to the SOAP server in the PRP msn command callback, with escaped html entity chars. Fixes #1294 .
Handle EBADF error sometimes received in SOAP server read callback (observed in win32).
Misc cleanups.
author | Carlos Silva <typ0@pidgin.im> |
---|---|
date | Tue, 07 Aug 2007 02:37:58 +0000 |
parents | 530a92d50c5e |
children | 6a8463be5b23 |
line wrap: on
line diff
--- a/libpurple/protocols/msn/contact.c Mon Jul 23 18:16:58 2007 +0000 +++ b/libpurple/protocols/msn/contact.c Tue Aug 07 02:37:58 2007 +0000 @@ -30,8 +30,6 @@ #include "xmlnode.h" #include "group.h" -/*define This to debug the Contact Server*/ -#undef MSN_CONTACT_SOAP_DEBUG /*new a contact*/ MsnContact * @@ -122,6 +120,61 @@ return MSN_USER_TYPE_UNKNOWN; } +/* Create the AddressBook in the server, if we don't have one */ +static void +msn_create_address_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnContact *contact; + + contact = soapconn->parent; + g_return_if_fail(contact != NULL); + + if ( g_strstr_len(soapconn->read_buf, soapconn->read_len, "HTTP/1.1 200") ) { + purple_debug_info("MSN AddressBook", "Address Book successfully created!\n"); + msn_get_address_book(contact, NULL, NULL); + } + else { + purple_debug_warning("MSN AddressBook", "Failed to create the Address Book!\n"); + } + + msn_soap_free_read_buf(soapconn); + return; +} + +static void +msn_create_address_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MSN AddressBook","AddressBookAdd written\n"); + soapconn->read_cb = msn_create_address_cb; + + return; +} + +static void +msn_create_address_book(MsnContact * contact) +{ + MsnSoapReq *soap_request; + gchar *body; + + purple_debug_info("MSN AddressBook","Creating an Address Book.\n"); + + body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport); + + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_ADD_ADDRESSBOOK_SOAP_ACTION, + body, + msn_create_address_cb, + msn_create_address_written_cb); + msn_soap_post(contact->soapconn, soap_request, msn_contact_connect_init); + + g_free(body); + + return; +} + /*parse contact list*/ static void msn_parse_contact_list(MsnContact * contact) @@ -129,6 +182,7 @@ MsnSession * session; int list_op = 0; char * passport, *debugdata, *typedata; + xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; xmlnode *node, *body, *response, *result, *services; xmlnode *service, *memberships, *info, *handle, *handletype; xmlnode *LastChangeNode; @@ -140,18 +194,62 @@ session = contact->session; node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); - debugdata = xmlnode_to_formatted_str(node, NULL); - purple_debug_info("MSNCL","Received contact list, parsing:\n%s",debugdata); - g_free(debugdata); - - if(node == NULL){ + if (node == NULL) { purple_debug_error("MSNCL","Unable to parse SOAP data!\n"); return; } +#ifdef MSN_SOAP_DEBUG + debugdata = xmlnode_to_formatted_str(node, NULL); + purple_debug_info("MSNCL","Received contact list, parsing:\n%s", debugdata); + g_free(debugdata); +#endif + + purple_debug_info("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n",node,node->name,node->child->name,node->lastchild->name); body = xmlnode_get_child(node,"Body"); + + if (body == NULL) { + purple_debug_warning("MSNCL", "Failed to parse contact list Body node\n"); + xmlnode_free(node); + return; + } purple_debug_info("MSNCL","Body @ %p: Name: '%s'\n",body,body->name); + + /* Did we receive a <Fault> ? */ + if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { + purple_debug_info("MSNCL","Fault received from SOAP server!\n"); + + if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { + gchar * faultstring = xmlnode_get_data(faultstring); + purple_debug_info("MSNCL","Faultstring: %s\n", faultstring); + g_free(faultstring); + } + if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { + purple_debug_info("MSNCL","detail @ %p, name: %s\n",faultdetail, faultdetail->name); + + if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { + purple_debug_info("MSNCL","errorcode @ %p, name: %s\n",errorcode, errorcode->name); + + if (errorcode->child != NULL) { + gchar *errorcodestring = xmlnode_get_data(errorcode); + purple_debug_info("MSNCL", "Error Code: %s\n", errorcodestring); + + if ( !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + xmlnode_free(node); + g_free(errorcodestring); + msn_create_address_book(contact); + return; + } + g_free(errorcodestring); + } + } + } + xmlnode_free(node); + msn_get_contact_list(contact, NULL); + return; + } + response = xmlnode_get_child(body,"FindMembershipResponse"); if (response == NULL) { @@ -160,22 +258,29 @@ * <faultstring>Need to do full sync. Can't sync deltas Client * has too old a copy for us to do a delta sync</faultstring> */ + xmlnode_free(node); msn_get_contact_list(contact, NULL); return; } - purple_debug_info("MSNCL","Response @ %p: Name: '%s'\n",response,response->name); + purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name); result = xmlnode_get_child(response,"FindMembershipResult"); - if(result == NULL){ - purple_debug_warning("MSNCL","receive No Update!\n"); + if (result == NULL) { + purple_debug_warning("MSNCL","Received No Update!\n"); + xmlnode_free(node); return; } - purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n",result,result->name); + purple_debug_info("MSNCL","Result @ %p: Name: '%s'\n", result, result->name); - services = xmlnode_get_child(result,"Services"); + if ( (services = xmlnode_get_child(result,"Services")) == NULL) { + purple_debug_misc("MSNCL","No <Services> received.\n"); + xmlnode_free(node); + return; + } + purple_debug_info("MSNCL","Services @ %p\n",services); - for( service = xmlnode_get_child(services, "Service"); service; + for (service = xmlnode_get_child(services, "Service"); service; service = xmlnode_get_next_twin(service)) { purple_debug_info("MSNCL","Service @ %p\n",service); @@ -197,7 +302,7 @@ continue; } - purple_debug_info("MSNCL","processing '%s' Service\n",typedata); + purple_debug_info("MSNCL","processing '%s' Service\n", typedata); if ( !g_strcasecmp(typedata, "Profile") ) { /* Process Windows Live 'Messenger Roaming Identity' */ @@ -211,8 +316,9 @@ LastChangeNode = xmlnode_get_child(service, "LastChange"); LastChangeStr = xmlnode_get_data(LastChangeNode); purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr); - purple_account_set_string(session->account, "CLLastChange",LastChangeStr); - + purple_account_set_string(session->account, "CLLastChange", LastChangeStr); + g_free(LastChangeStr); + memberships = xmlnode_get_child(service,"Memberships"); if (memberships == NULL) { purple_debug_warning("MSNCL","Memberships = NULL, cleaning up and returning.\n"); @@ -221,7 +327,7 @@ return; } purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name); - for(membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; + for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; membershipnode = xmlnode_get_next_twin(membershipnode)){ xmlnode *roleNode; char *role; @@ -234,14 +340,15 @@ g_free(role); members = xmlnode_get_child(membershipnode,"Members"); - for(member = xmlnode_get_child(members, "Member"); member; + for (member = xmlnode_get_child(members, "Member"); member; member = xmlnode_get_next_twin(member)){ MsnUser *user; xmlnode * typeNode; char * type; - purple_debug_info("MSNCL","Member type: %s\n",xmlnode_get_attrib(member,"type")); - if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PassportMember")){ + purple_debug_info("MSNCL","Member type: %s\n", xmlnode_get_attrib(member,"type")); + + if( !g_strcasecmp(xmlnode_get_attrib(member,"type"), "PassportMember") ) { passportNode = xmlnode_get_child(member,"PassportName"); passport = xmlnode_get_data(passportNode); typeNode = xmlnode_get_child(member,"Type"); @@ -253,16 +360,18 @@ msn_got_lst_user(session, user, list_op, NULL); g_free(passport); } - if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PhoneMember")){ + + if (!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PhoneMember")) { } - if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"EmailMember")){ + + if (!g_strcasecmp(xmlnode_get_attrib(member,"type"),"EmailMember")) { xmlnode *emailNode; emailNode = xmlnode_get_child(member,"Email"); passport = xmlnode_get_data(emailNode); - purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n",passport,list_op); - user = msn_userlist_find_add_user(session->userlist,passport,NULL); - msn_got_lst_user(session,user,list_op,NULL); + purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport, list_op); + user = msn_userlist_find_add_user(session->userlist, passport, NULL); + msn_got_lst_user(session, user, list_op, NULL); g_free(passport); } } @@ -290,8 +399,8 @@ session = soapconn->session; g_return_if_fail(session != NULL); -#ifdef MSN_CONTACT_SOAP_DEBUG - purple_debug_info("msn", "soap contact server Reply: {%s}\n", soapconn->read_buf); +#ifdef MSN_SOAP_DEBUG + purple_debug_info("MSNCL", "SOAP server reply: \n%s\n", soapconn->read_buf); #endif msn_parse_contact_list(contact); /*free the read buffer*/ @@ -308,6 +417,7 @@ #else msn_get_address_book(contact, NULL, NULL); #endif + msn_soap_free_read_buf(soapconn); } static void @@ -330,21 +440,22 @@ purple_debug_info("::","msn_get_contact_list()\n"); - purple_debug_info("MSNP14","Getting Contact List...\n"); - if(update_time != NULL){ + purple_debug_info("MSNP14","Getting Contact List.\n"); + if ( update_time != NULL ) { purple_debug_info("MSNCL","last update time:{%s}\n",update_time); update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time); - }else{ + } else { update_str = g_strdup(""); } body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, update_str); + g_free(update_str); + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL,MSN_GET_CONTACT_SOAP_ACTION, body, msn_get_contact_list_cb, msn_get_contact_written_cb); msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); - g_free(update_str); g_free(body); } @@ -371,6 +482,7 @@ if (group_id == NULL){ /* Group of ungroupped buddies */ + g_free(group_name); continue; } @@ -413,11 +525,13 @@ friendly = xmlnode_get_data(xmlnode_get_child(contactInfo, "displayName")); purple_connection_set_display_name(session->account->gc, purple_url_decode(friendly)); g_free(friendly); + g_free(uid); + g_free(type); continue; /* Not adding own account as buddy to buddylist */ } usertype = msn_get_user_type(type); passportName = xmlnode_get_child(contactInfo,"passportName"); - if(passportName == NULL){ + if (passportName == NULL) { xmlnode *emailsNode, *contactEmailNode, *emailNode; xmlnode *messengerEnabledNode; char *msnEnabled; @@ -425,8 +539,10 @@ /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/ /*Yahoo User?*/ emailsNode = xmlnode_get_child(contactInfo,"emails"); - if(emailsNode == NULL){ + if (emailsNode == NULL) { /*TODO: need to support the Mobile type*/ + g_free(uid); + g_free(type); continue; } for(contactEmailNode = xmlnode_get_child(emailsNode,"ContactEmail");contactEmailNode; @@ -451,18 +567,20 @@ } g_free(msnEnabled); } - }else{ + } else { passport = xmlnode_get_data(passportName); } - if(passport == NULL){ + if (passport == NULL) { + g_free(uid); + g_free(type); continue; } displayName = xmlnode_get_child(contactInfo,"displayName"); - if(displayName == NULL){ + if (displayName == NULL) { Name = g_strdup(passport); - }else{ + } else { Name =xmlnode_get_data(displayName); } @@ -479,8 +597,8 @@ purple_debug_misc("MsnAB","parse guid...\n"); groupIds = xmlnode_get_child(contactInfo,"groupIds"); - if(groupIds){ - for(guid = xmlnode_get_child(groupIds, "guid");guid; + if (groupIds) { + for (guid = xmlnode_get_child(groupIds, "guid");guid; guid = xmlnode_get_next_twin(guid)){ char *group_id; group_id = xmlnode_get_data(guid); @@ -488,7 +606,7 @@ purple_debug_misc("MsnAB","guid:%s\n",group_id); g_free(group_id); } - }else{ + } else { /*not in any group,Then set default group*/ msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID); } @@ -505,23 +623,57 @@ xmlnode *groups; xmlnode *contacts; xmlnode *abNode; + xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; gchar *printabledata; session = contact->session; + + node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); if ( node == NULL ) { - purple_debug_error("MSN SOAP","Error parsing received Address Book with size %d:\n \"%s\"\n", contact->soapconn->body_len, contact->soapconn->body); + purple_debug_error("MSN AddressBook","Error parsing received Address Book with size %d:\n \"%s\"\n", contact->soapconn->body_len, contact->soapconn->body); return FALSE; } printabledata = xmlnode_to_formatted_str(node, NULL); - purple_debug_misc("MSN SOAP","Received Address Book with size %d:\n %s\n", contact->soapconn->body_len, (char *) printabledata); + purple_debug_misc("MSN AddressBook","Received Address Book with size %d:\n %s\n", contact->soapconn->body_len, (char *) printabledata); g_free(printabledata); - purple_debug_misc("MSN SOAP","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name); + purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name); + body = xmlnode_get_child(node,"Body"); - purple_debug_misc("MSN SOAP","body{%p},name:%s\n",body,body->name); + purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name); + + if ( (fault = xmlnode_get_child(body, "Fault")) != NULL) { + purple_debug_info("MSN AddressBook","Fault received from SOAP server!\n"); + + if ( (faultstringnode = xmlnode_get_child(fault, "faultstring")) != NULL ) { + gchar *faultstring = xmlnode_get_data(faultstring); + purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring); + g_free(faultstring); + } + if ( (faultdetail = xmlnode_get_child(fault, "detail")) != NULL ) { + purple_debug_info("MSN AddressBook","detail @ %p, name: %s\n",faultdetail, faultdetail->name); + + if ( (errorcode = xmlnode_get_child(faultdetail, "errorcode")) != NULL ) { + gchar *errorcodestring; + purple_debug_info("MSN AddressBook","errorcode @ %p, name: %s\n",errorcode, errorcode->name); + + errorcodestring = xmlnode_get_data(errorcode); + purple_debug_info("MSN AddressBook", "Error Code: %s\n", errorcodestring); + + if ( !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { + g_free(errorcodestring); + return TRUE; + } + g_free(errorcodestring); + } + } + return FALSE; + } + + response = xmlnode_get_child(body,"ABFindAllResponse"); if (response == NULL) { @@ -581,6 +733,8 @@ dynamicChange = xmlnode_get_data(DynamicItemLastChangedNode); purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n",dynamicChange); purple_account_set_string(session->account, "DynamicItemLastChanged", lastchange); + g_free(dynamicChange); + g_free(lastchange); } xmlnode_free(node); @@ -601,11 +755,20 @@ g_return_if_fail(session != NULL); // purple_debug_misc("msn", "soap contact server Reply: {%s}\n", soapconn->read_buf); - if (msn_parse_addressbook(contact)) { + if ( msn_parse_addressbook(contact) ) { + msn_soap_free_read_buf(soapconn); + msn_send_privacy(session->account->gc); msn_notification_dump_contact(session); } else { + /* This is making us loop infinitely when we fail to parse the address book, + disable for now (we should re-enable when we send timestamps) + */ + /* msn_get_address_book(contact, NULL, NULL); + */ + msn_session_disconnect(session); + purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book")); } /*free the read buffer*/ @@ -631,35 +794,37 @@ char *ab_update_str,*update_str; purple_debug_info("::","msn_get_address_book()\n"); + /*build SOAP and POST it*/ - if(LastChanged != NULL){ + if ( LastChanged != NULL ) { ab_update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML,LastChanged); - }else{ + } else { ab_update_str = g_strdup(""); } - if(dynamicItemLastChange != NULL){ + if ( dynamicItemLastChange != NULL ) { update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, dynamicItemLastChange); - }else{ + } else { update_str = g_strdup(ab_update_str); } g_free(ab_update_str); body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE,update_str); + g_free(update_str); + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION, body, msn_get_address_cb, msn_address_written_cb); msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); - g_free(update_str); g_free(body); } static void msn_add_contact_read_cb(gpointer data, gint source, PurpleInputCondition cond) { - purple_debug_info("MSNP14","add contact read done\n"); + purple_debug_info("MSNCL","Add contact read done\n"); } static void @@ -667,7 +832,7 @@ { MsnSoapConn * soapconn = data; - purple_debug_info("MSNP14","finish add contact written\n"); + purple_debug_info("MSNCL","Add contact request written\n"); soapconn->read_cb = msn_add_contact_read_cb; // msn_soap_read_cb(data,source,cond); } @@ -708,7 +873,7 @@ static void msn_delete_contact_read_cb(gpointer data, gint source, PurpleInputCondition cond) { - purple_debug_info("MSNP14","delete contact read done\n"); + purple_debug_info("MSNCL","Delete contact read done\n"); } static void @@ -716,7 +881,7 @@ { MsnSoapConn * soapconn = data; - purple_debug_info("MSNP14","delete contact written\n"); + purple_debug_info("MSNCL","Delete contact request written\n"); soapconn->read_cb = msn_delete_contact_read_cb; // msn_soap_read_cb(data,source,cond); } @@ -895,7 +1060,11 @@ static void msn_group_read_cb(gpointer data, gint source, PurpleInputCondition cond) { - purple_debug_info("MSNP14","Group read \n"); + MsnSoapConn * soapconn = data; + + purple_debug_info("MSNCL", "Add Group reply with the SOAP read_buf:\n%s\n",soapconn->read_buf); + purple_debug_info("MSNCL", "Add Group reply with the SOAP body:\n%s\n",soapconn->body); + } static void @@ -903,7 +1072,7 @@ { MsnSoapConn * soapconn = data; - purple_debug_info("MSNP14","finish Group written\n"); + purple_debug_info("MSNCL","Finished sending Add Group\n"); soapconn->read_cb = msn_group_read_cb; // msn_soap_read_cb(data,source,cond); } @@ -917,7 +1086,7 @@ g_return_if_fail(session != NULL); contact = session->contact; - purple_debug_info("::","msn_add_group...\n"); + purple_debug_info("::","msn_add_group()\n"); body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE,group_name); /*build SOAP and POST it*/ @@ -930,7 +1099,7 @@ } /*delete a group*/ -void msn_del_group(MsnSession *session,const char *guid) +void msn_del_group(MsnSession *session, const char *guid) { MsnSoapReq *soap_request; MsnContact *contact;