# HG changeset patch # User Jochen Kemnade # Date 1194081620 0 # Node ID f3a995c30205482c4495f7a5e44c0b0d6dac59e1 # Parent dd95454ddf902852a54a14b377c84852c8f08850# Parent 2bc214520c42c6ab0699a78c1a3eee3ec6fd8554 merge of '3cd7a16a03c0ecaa525bee4e96c8693925dc780a' and '868a040ee69c6e45b9132e7254a3f523e55385b2' diff -r dd95454ddf90 -r f3a995c30205 libpurple/example/nullclient.c --- a/libpurple/example/nullclient.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/example/nullclient.c Sat Nov 03 09:20:20 2007 +0000 @@ -269,6 +269,13 @@ PurpleAccount *account; PurpleSavedStatus *status; + /* libpurple's built-in DNS resolution forks processes to perform + * blocking lookups without blocking the main process. It does not + * handle SIGCHLD itself, so if the UI does not you quickly get an army + * of zombie subprocesses marching around. + */ + signal(SIGCHLD, SIG_IGN); + init_libpurple(); printf("libpurple initialized.\n"); diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/Makefile.am --- a/libpurple/protocols/msn/Makefile.am Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Sat Nov 03 09:20:20 2007 +0000 @@ -52,6 +52,8 @@ slpsession.h \ soap.c\ soap.h\ + soap2.c \ + soap2.h \ state.c \ state.h \ switchboard.c \ diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/Makefile.mingw --- a/libpurple/protocols/msn/Makefile.mingw Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Sat Nov 03 09:20:20 2007 +0000 @@ -61,6 +61,7 @@ slpmsg.c \ slpsession.c \ soap.c\ + soap2.c\ state.c \ switchboard.c \ sync.c \ diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/contact.c --- a/libpurple/protocols/msn/contact.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/contact.c Sat Nov 03 09:20:20 2007 +0000 @@ -28,6 +28,7 @@ #include "contact.h" #include "xmlnode.h" #include "group.h" +#include "soap2.h" const char *MsnSoapPartnerScenarioText[] = { @@ -47,6 +48,11 @@ "Pending" }; +typedef struct { + MsnContact *contact; + MsnSoapPartnerScenario which; +} GetContactListCbData; + /* new a contact */ MsnContact * msn_contact_new(MsnSession *session) @@ -55,7 +61,6 @@ contact = g_new0(MsnContact, 1); contact->session = session; - contact->soapconn = msn_soap_new(session,contact,1); return contact; } @@ -64,15 +69,18 @@ void msn_contact_destroy(MsnContact *contact) { - msn_soap_destroy(contact->soapconn); g_free(contact); } MsnCallbackState * -msn_callback_state_new(void) +msn_callback_state_new(MsnSession *session) { - return g_new0(MsnCallbackState, 1); -} + MsnCallbackState *state = g_new0(MsnCallbackState, 1); + + state->session = session; + + return state; +} void msn_callback_state_free(MsnCallbackState *state) @@ -151,36 +159,6 @@ state->action |= action; } -/*contact SOAP server login error*/ -static void -msn_contact_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - - msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server")); -} - -/*msn contact SOAP server connect process*/ -static gboolean -msn_contact_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnContact *contact; - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - - session = contact->session; - g_return_val_if_fail(session != NULL, FALSE); - - /*login ok!We can retrieve the contact list*/ -// msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); - return TRUE; -} - /*get MSN member role utility*/ static MsnListId msn_get_memberrole(const char *role) @@ -219,37 +197,20 @@ } /* Create the AddressBook in the server, if we don't have one */ -static gboolean -msn_create_address_cb(MsnSoapConn *soapconn) +static void +msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnContact *contact; - - if (soapconn->body == NULL) - return TRUE; - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - - purple_debug_info("MSN AddressBook", "Address Book successfully created!\n"); - msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); - -// msn_soap_free_read_buf(soapconn); - return TRUE; -} - -static void -msn_create_address_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN AddressBook","AddressBookAdd written\n"); - soapconn->read_cb = msn_create_address_cb; - - return; + if (resp && msn_soap_xml_get(resp->xml, "Body/Fault") == NULL) { + purple_debug_info("msnab", "Address Book successfully created!\n"); + msn_get_address_book((MsnContact *)data, MSN_PS_INITIAL, NULL, NULL); + } else { + purple_debug_info("msnab", "Address Book creation failed!\n"); + } } static void msn_create_address_book(MsnContact * contact) { - MsnSoapReq *soap_request; gchar *body; g_return_if_fail(contact != NULL); @@ -257,323 +218,184 @@ g_return_if_fail(contact->session->user != NULL); g_return_if_fail(contact->session->user->passport != NULL); - purple_debug_info("MSN AddressBook","Creating an Address Book.\n"); + purple_debug_info("msnab","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, - NULL, - msn_create_address_cb, - msn_create_address_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_ADD_ADDRESSBOOK_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_create_address_cb, + contact); g_free(body); - - return; +} + +static void +msn_parse_each_member(MsnSession *session, xmlnode *member, const char *node, + MsnListId list) +{ + char *passport = xmlnode_get_data(xmlnode_get_child(member, node)); + char *type = xmlnode_get_data(xmlnode_get_child(member, "type")); + char *member_id = xmlnode_get_data(xmlnode_get_child(member, "MembershipId")); + MsnUser *user = msn_userlist_find_add_user(session->userlist, passport, NULL); + + purple_debug_info("msncl","%s name: %s, Type: %s\n", node, passport, type); + + if (member_id) { + user->membership_id[list] = atoi(member_id); + } + + msn_got_lst_user(session, user, 1 << list, NULL); + + g_free(passport); + g_free(type); + g_free(member_id); +} + +static void +msn_parse_each_service(MsnSession *session, xmlnode *service) +{ + xmlnode *type; + + if ((type = msn_soap_xml_get(service, "Info/Handle/Type"))) { + char *type_str = xmlnode_get_data(type); + + if (g_str_equal(type_str, "Profile")) { + /* Process Windows Live 'Messenger Roaming Identity' */ + } else if (g_str_equal(type_str, "Messenger")) { + xmlnode *lastchange = xmlnode_get_child(service, "LastChange"); + char *lastchange_str = xmlnode_get_data(lastchange); + xmlnode *membership; + + purple_debug_info("msncl","last change: %s\n", lastchange_str); + purple_account_set_string(session->account, "CLLastChange", + lastchange_str); + + for (membership = msn_soap_xml_get(service, + "Memberships/Membership"); + membership; membership = xmlnode_get_next_twin(membership)) { + + xmlnode *role = xmlnode_get_child(membership, "MemberRole"); + char *role_str = xmlnode_get_data(role); + MsnListId list = msn_get_memberrole(role_str); + xmlnode *member; + + purple_debug_info("msncl", "MemberRole role: %s, list: %d\n", + role, list); + + for (member = msn_soap_xml_get(membership, "Members/Member"); + member; member = xmlnode_get_next_twin(member)) { + const char *member_type = xmlnode_get_attrib(member, "type"); + if (g_str_equal(member_type, "PassportMember")) { + msn_parse_each_member(session, member, "PassportName", + list); + } else if (g_str_equal(member_type, "PhoneMember")) { + + } else if (g_str_equal(member_type, "EmailMember")) { + msn_parse_each_member(session, member, "Email", list); + } + } + + g_free(role_str); + } + + g_free(lastchange_str); + } + + g_free(type_str); + } } /*parse contact list*/ static void -msn_parse_contact_list(MsnContact * contact) +msn_parse_contact_list(MsnContact *contact, xmlnode *node) { - MsnSession * session; - MsnListOp list_op = 0; - MsnListId list; - char * passport, *typedata; - xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; - xmlnode *node, *body, *response, *result, *services; - xmlnode *service, *memberships, *info, *handle, *handletype; - xmlnode *membershipnode, *members, *member, *passportNode; - - session = contact->session; - node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); - - if (node == NULL) { - purple_debug_error("MSNCL","Unable to parse SOAP data!\n"); - return; - } - - purple_debug_misc("MSNCL","Parsing contact list with size %d\n", contact->soapconn->body_len); + xmlnode *fault, *faultnode; - purple_debug_misc("MSNCL","Root node @ %p: Name: '%s', child: '%s', lastchild: '%s'\n", node, - node->name ? node->name : "(null)", - (node->child && node->child->name) ? node->child->name : "(null)", - (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); - - 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 ? */ - 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(faultstringnode); - purple_debug_info("MSNCL", "Faultstring: %s\n", faultstring ? faultstring : "(null)"); + /* we may get a response if our cache data is too old: + * + * Need to do full sync. Can't sync deltas Client + * has too old a copy for us to do a delta sync + * + * this is not handled yet + */ + if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { + char *faultstring = xmlnode_get_data(faultnode); + purple_debug_info("msncl", "Retrieving contact list failed: %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 ? errorcodestring : "(null)"); - - if (errorcodestring && !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, MSN_PS_INITIAL, NULL); - return; - } - - response = xmlnode_get_child(body,"FindMembershipResponse"); - - if (response == NULL) { - /* we may get a response if our cache data is too old: - * - * Need to do full sync. Can't sync deltas Client - * has too old a copy for us to do a delta sync - */ - xmlnode_free(node); - msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); - return; - } - purple_debug_info("MSNCL","FindMembershipResponse @ %p: Name: '%s'\n",response,response->name); + if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + char *errorcode = xmlnode_get_data(faultnode); - result = xmlnode_get_child(response,"FindMembershipResult"); - 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); - - if ( (services = xmlnode_get_child(result,"Services")) == NULL) { - purple_debug_misc("MSNCL","No received.\n"); - xmlnode_free(node); - return; - } - - purple_debug_info("MSNCL","Services @ %p\n",services); - - for (service = xmlnode_get_child(services, "Service"); service; - service = xmlnode_get_next_twin(service)) { - purple_debug_info("MSNCL","Service @ %p\n",service); + if (g_str_equal(errorcode, "ABDoesNotExist")) { + msn_create_address_book(contact); + g_free(errorcode); + return; + } - if ( (info = xmlnode_get_child(service,"Info")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Info' child node\n"); - continue; - } - if ( (handle = xmlnode_get_child(info,"Handle")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Handle' child node\n"); - continue; - } - if ( (handletype = xmlnode_get_child(handle,"Type")) == NULL ) { - purple_debug_error("MSNCL","Error getting 'Type' child node\n"); - continue; - } - - if ( (typedata = xmlnode_get_data(handletype)) == NULL) { - purple_debug_error("MSNCL","Error retrieving data from 'Type' child node\n"); - continue; - } - - purple_debug_info("MSNCL","processing '%s' Service\n", typedata); - - if ( !g_strcasecmp(typedata, "Profile") ) { - /* Process Windows Live 'Messenger Roaming Identity' */ - g_free(typedata); - continue; + g_free(errorcode); } - if ( !g_strcasecmp(typedata, "Messenger") ) { - char *LastChangeStr = NULL; - xmlnode *LastChangeNode; - - /*Last Change Node*/ - if ((LastChangeNode = xmlnode_get_child(service, "LastChange"))) - LastChangeStr = xmlnode_get_data(LastChangeNode); - purple_debug_info("MSNCL","LastChangeNode: '%s'\n",LastChangeStr ? LastChangeStr : "(null)"); - 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"); - g_free(typedata); - xmlnode_free(node); - return; - } - purple_debug_info("MSNCL","Memberships @ %p: Name: '%s'\n",memberships,memberships->name); - for (membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; - membershipnode = xmlnode_get_next_twin(membershipnode)){ - xmlnode *roleNode; - char *role = NULL; - list = 0; - - if ((roleNode = xmlnode_get_child(membershipnode,"MemberRole"))) { - role = xmlnode_get_data(roleNode); - list = msn_get_memberrole(role); - } - list_op = 1 << list; - - purple_debug_info("MSNCL","MemberRole role: %s, list_op: %d\n", role ? role : "(null)", list_op); - - g_free(role); - - members = xmlnode_get_child(membershipnode, "Members"); - for (member = xmlnode_get_child(members, "Member"); member; - member = xmlnode_get_next_twin(member)){ - MsnUser *user = NULL; - xmlnode *typeNode, *membershipIdNode = NULL; - gchar *type, *membershipId = NULL; - const char *member_type = xmlnode_get_attrib(member, "type"); - - if (!member_type) { - purple_debug_error("msn", "No Member Type specified for Member.\n"); - continue; - } - - if(!g_strcasecmp(member_type, "PassportMember") ) { - passport = type = NULL; - if ((passportNode = xmlnode_get_child(member, "PassportName"))) - passport = xmlnode_get_data(passportNode); - if ((typeNode = xmlnode_get_child(member, "Type"))) - type = xmlnode_get_data(typeNode); - purple_debug_info("MSNCL","Passport name: '%s', Type: %s\n", passport ? passport : "(null)", type ? type : "(null)"); - /* Why do we even bother parsing it just to free it??? */ - g_free(type); - - user = msn_userlist_find_add_user(session->userlist,passport,NULL); - g_free(passport); - - membershipIdNode = xmlnode_get_child(member,"MembershipId"); - if (membershipIdNode != NULL) { - membershipId = xmlnode_get_data(membershipIdNode); - if (membershipId != NULL) { - user->membership_id[list] = atoi(membershipId); - g_free(membershipId); - } - } + msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + } else { + xmlnode *service; - msn_got_lst_user(session, user, list_op, NULL); - } - else if (!g_strcasecmp(member_type, "PhoneMember")) { - purple_debug_info("msn", "Recieved Phone Member; ignoring.\n"); - } - else if (!g_strcasecmp(member_type, "EmailMember")) { - xmlnode *emailNode; - passport = NULL; - - if ((emailNode = xmlnode_get_child(member, "Email"))) - passport = xmlnode_get_data(emailNode); - purple_debug_info("MSNCL","Email Member: Name: '%s', list_op: %d\n", passport ? passport : "(null)", list_op); - - user = msn_userlist_find_add_user(session->userlist, passport, NULL); - g_free(passport); - - membershipIdNode = xmlnode_get_child(member,"MembershipId"); - if (membershipIdNode != NULL) { - membershipId = xmlnode_get_data(membershipIdNode); - if (membershipId != NULL) { - user->membership_id[list] = atoi(membershipId); - g_free(membershipId); - } - } - - msn_got_lst_user(session, user, list_op, NULL); - } else { - purple_debug_info("msn", "Unknown Member type: %s\n", member_type); - } - } - } + for (service = msn_soap_xml_get(node, "Body/FindMembershipResponse/" + "FindMembershipResult/Services/Service"); + service; service = xmlnode_get_next_twin(service)) { + msn_parse_each_service(contact->session, service); } - g_free(typedata); } - - xmlnode_free(node); /* Free the whole XML tree */ -} - -static gboolean -msn_get_contact_list_cb(MsnSoapConn *soapconn) -{ - MsnContact *contact; - MsnSession *session; - const char *abLastChange; - const char *dynamicItemLastChange; - gchar *partner_scenario; - - if (soapconn->body == NULL) - return TRUE; - - purple_debug_misc("MSNCL","Got the contact list!\n"); - - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - - partner_scenario = soapconn->data_cb; - - msn_parse_contact_list(contact); - /*free the read buffer*/ - msn_soap_free_read_buf(soapconn); - - abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); - dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL); - - if (!strcmp(partner_scenario, MsnSoapPartnerScenarioText[MSN_PS_INITIAL])) { - -#ifdef MSN_PARTIAL_LISTS - /* XXX: this should be enabled when we can correctly do partial - syncs with the server. Currently we need to retrieve the whole - list to detect sync issues */ - msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); -#else - msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); -#endif - } else { - msn_soap_free_read_buf(soapconn); - } - - return TRUE; } static void -msn_get_contact_written_cb(MsnSoapConn *soapconn) +msn_get_contact_list_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - purple_debug_misc("MSNCL","Sent SOAP request for the contact list.\n"); - soapconn->read_cb = msn_get_contact_list_cb; + GetContactListCbData *cb_data = data; + MsnContact *contact = cb_data->contact; + MsnSession *session = contact->session; + + g_return_if_fail(session != NULL); + + if (resp != NULL) { + const char *abLastChange; + const char *dynamicItemLastChange; + + purple_debug_misc("msncl","Got the contact list!\n"); + + msn_parse_contact_list(cb_data->contact, resp->xml); + abLastChange = purple_account_get_string(session->account, + "ablastChange", NULL); + dynamicItemLastChange = purple_account_get_string(session->account, + "dynamicItemLastChange", NULL); + + if (cb_data->which == MSN_PS_INITIAL) { +#ifdef MSN_PARTIAL_LISTS + /* XXX: this should be enabled when we can correctly do partial + syncs with the server. Currently we need to retrieve the whole + list to detect sync issues */ + msn_get_address_book(contact, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); +#else + msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); +#endif + } + } + + g_free(cb_data); } -/* SOAP get contact list*/ +/*SOAP get contact list*/ void -msn_get_contact_list(MsnContact * contact, const MsnSoapPartnerScenario partner_scenario, const char *update_time) +msn_get_contact_list(MsnContact * contact, + const MsnSoapPartnerScenario partner_scenario, const char *update_time) { - MsnSoapReq *soap_request; - gchar *body; + gchar *body = NULL; gchar *update_str = NULL; + GetContactListCbData cb_data = { contact, partner_scenario }; const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; purple_debug_misc("MSNCL","Getting Contact List.\n"); @@ -584,17 +406,14 @@ } body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? 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, - (gpointer) partner_scenario_str, - msn_get_contact_list_cb, - msn_get_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL, + msn_get_contact_list_cb, g_memdup(&cb_data, sizeof(cb_data))); + + g_free(update_str); g_free(body); } @@ -604,7 +423,7 @@ MsnSession *session = contact->session; xmlnode *group; - purple_debug_info("MsnAb","msn_parse_addressbook_groups()\n"); + purple_debug_info("MSNAB","msn_parse_addressbook_groups()\n"); for(group = xmlnode_get_child(node, "Group"); group; group = xmlnode_get_next_twin(group)){ @@ -756,81 +575,48 @@ } static gboolean -msn_parse_addressbook(MsnContact * contact) +msn_parse_addressbook(MsnContact * contact, xmlnode *node) { - MsnSession *session; - xmlnode * node,*body,*response,*result; + MsnSession * session; + xmlnode *result; xmlnode *groups; xmlnode *contacts; xmlnode *abNode; - xmlnode *fault, *faultstringnode, *faultdetail, *errorcode; + xmlnode *fault; session = contact->session; - node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); - if ( node == NULL ) { - purple_debug_error("MSN AddressBook","Error parsing Address Book with size %d\n", contact->soapconn->body_len); + if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + xmlnode *faultnode; + + if ((faultnode = xmlnode_get_child(fault, "faultstring"))) { + gchar *faultstring = xmlnode_get_data(faultnode); + purple_debug_info("MSNAB","Faultstring: %s\n", faultstring); + g_free(faultstring); + } + + if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + gchar *errorcode = xmlnode_get_data(faultnode); + + purple_debug_info("MSNAB", "Error Code: %s\n", errorcode); + + if (g_str_equal(errorcode, "ABDoesNotExist")) { + g_free(errorcode); + return TRUE; + } + } + return FALSE; } - purple_debug_misc("MSN AddressBook", "Parsing Address Book with size %d\n", contact->soapconn->body_len); - - purple_debug_misc("MSN AddressBook","node{%p},name:%s,child:%s,last:%s\n", node, - node->name ? node->name : "(null)", - (node->child && node->child->name) ? node->child->name : "(null)", - (node->lastchild && node->lastchild->name) ? node->lastchild->name : "(null)"); - - body = xmlnode_get_child(node,"Body"); - purple_debug_misc("MSN AddressBook","body{%p},name:%s\n",body,body->name); - - /* TODO: This appears to be used in a number of places and should be de-duplicated */ - 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(faultstringnode); - purple_debug_info("MSN AddressBook","Faultstring: %s\n", faultstring ? faultstring : "(null)"); - 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 ? errorcodestring : "(null)"); - - if (errorcodestring && !strncmp(errorcodestring, "ABDoesNotExist", 14) ) { - g_free(errorcodestring); - xmlnode_free(node); - return TRUE; - } - g_free(errorcodestring); - } - } - xmlnode_free(node); - return FALSE; + result = msn_soap_xml_get(node, "Body/ABFindAllResponse/ABFindAllResult"); + if(result == NULL){ + purple_debug_misc("MSNAB","receive no address book update\n"); + return TRUE; } - - response = xmlnode_get_child(body,"ABFindAllResponse"); - - if (response == NULL) { - xmlnode_free(node); - return FALSE; - } - - purple_debug_misc("MSN SOAP","response{%p},name:%s\n",response,response->name); - result = xmlnode_get_child(response,"ABFindAllResult"); - if(result == NULL){ - purple_debug_misc("MSNAB","receive no address book update\n"); - xmlnode_free(node); - return TRUE; - } - purple_debug_info("MSN SOAP","result{%p},name:%s\n",result,result->name); - + /* I don't see this "groups" tag documented on msnpiki, need to find out + if they are really there, and update msnpiki */ /*Process Group List*/ groups = xmlnode_get_child(result,"groups"); if (groups != NULL) { @@ -840,7 +626,7 @@ /*add a default No group to set up the no group Membership*/ msn_group_new(session->userlist, MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); - purple_debug_misc("MsnAB","group_id:%s name:%s\n", + purple_debug_misc("MSNAB","group_id:%s name:%s\n", MSN_INDIVIDUALS_GROUP_ID, MSN_INDIVIDUALS_GROUP_NAME); if ((purple_find_group(MSN_INDIVIDUALS_GROUP_NAME)) == NULL){ PurpleGroup *g = purple_group_new(MSN_INDIVIDUALS_GROUP_NAME); @@ -849,7 +635,7 @@ /*add a default No group to set up the no group Membership*/ msn_group_new(session->userlist, MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); - purple_debug_misc("MsnAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); + purple_debug_misc("MSNAB","group_id:%s name:%s\n", MSN_NON_IM_GROUP_ID, MSN_NON_IM_GROUP_NAME); if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){ PurpleGroup *g = purple_group_new(MSN_NON_IM_GROUP_NAME); purple_blist_add_group(g, NULL); @@ -869,7 +655,7 @@ if ((node2 = xmlnode_get_child(abNode, "lastChange"))) tmp = xmlnode_get_data(node2); - purple_debug_info("MsnAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); + purple_debug_info("MSNAB"," lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); purple_account_set_string(session->account, "ablastChange", tmp); g_free(tmp); tmp = NULL; @@ -880,68 +666,51 @@ g_free(tmp); } - xmlnode_free(node); - msn_soap_free_read_buf(contact->soapconn); return TRUE; } -static gboolean -msn_get_address_cb(MsnSoapConn *soapconn) +static void +msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnContact *contact; + MsnContact *contact = data; MsnSession *session; - if (soapconn->body == NULL) - return TRUE; + if (resp == NULL) + return; - contact = soapconn->parent; - g_return_val_if_fail(contact != NULL, TRUE); - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); + g_return_if_fail(contact != NULL); + session = contact->session; + g_return_if_fail(session != NULL); - purple_debug_misc("MSN AddressBook", "Got the Address Book!\n"); + purple_debug_misc("MSNAB", "Got the Address Book!\n"); - if ( msn_parse_addressbook(contact) ) { - //msn_soap_free_read_buf(soapconn); - + if (msn_parse_addressbook(contact, resp->xml)) { if (!session->logged_in) { msn_send_privacy(session->account->gc); msn_notification_dump_contact(session); } - - /*free the read buffer*/ - msn_soap_free_read_buf(soapconn); - return TRUE; } 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) + /* 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")); - return FALSE; } } -/**/ -static void -msn_address_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_misc("MSN AddressBook","Sent SOAP request for the Address Book.\n"); - soapconn->read_cb = msn_get_address_cb; -} - /*get the address book*/ void -msn_get_address_book(MsnContact *contact, const MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange) +msn_get_address_book(MsnContact *contact, + MsnSoapPartnerScenario partner_scenario, const char *LastChanged, + const char *dynamicItemLastChange) { - MsnSoapReq *soap_request; - char *body; - char *update_str = NULL; + char *body, *update_str = NULL; - purple_debug_misc("MSN AddressBook","Getting Address Book\n"); + purple_debug_misc("MSNAB","Getting Address Book\n"); /*build SOAP and POST it*/ if (dynamicItemLastChange != NULL) @@ -949,79 +718,58 @@ else if (LastChanged != NULL) update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, LastChanged); - body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE, MsnSoapPartnerScenarioText[partner_scenario], update_str ? 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, - NULL, - msn_get_address_cb, - msn_address_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_ADDRESS_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, msn_get_address_cb, + contact); + + g_free(update_str); g_free(body); } -static gboolean -msn_add_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; - MsnUserList *userlist; - MsnUser *user; - - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + MsnCallbackState *state = data; + MsnSession *session = state->session; - state = (MsnCallbackState *) soapconn->data_cb; + g_return_if_fail(session != NULL); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } + if (resp != NULL) { + MsnUserList *userlist = session->userlist; + MsnUser *user; - userlist = soapconn->session->userlist; - - purple_debug_info("MSNCL","Contact added successfully\n"); + purple_debug_info("MSNCL","Contact added successfully\n"); - // the code this block is replacing didn't send ADL for yahoo contacts, - // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts - - if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - } - msn_notification_send_fqy(soapconn->session, state->who); + // the code this block is replacing didn't send ADL for yahoo contacts, + // but i haven't confirmed this is WLM's behaviour wrt yahoo contacts + if ( !msn_user_is_yahoo(session->account, state->who) ) { + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } - user = msn_userlist_find_add_user(userlist, state->who, state->who); - msn_user_add_group_id(user, state->guid); - - msn_soap_free_read_buf(soapconn); - msn_callback_state_free(state); + msn_notification_send_fqy(session, state->who); - return TRUE; -} + user = msn_userlist_find_add_user(userlist, state->who, state->who); + msn_user_add_group_id(user, state->guid); + } -static void -msn_add_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Add contact request written\n"); - soapconn->read_cb = msn_add_contact_read_cb; + msn_callback_state_free(state); } /* add a Contact in MSN_INDIVIDUALS_GROUP */ void msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport) { - MsnSoapReq *soap_request; gchar *body = NULL; gchar *contact_xml = NULL; - g_return_if_fail(passport != NULL); -/* gchar *escaped_displayname; +#if 0 + gchar *escaped_displayname; if (displayname != NULL) { @@ -1030,87 +778,71 @@ escaped_displayname = passport; } contact_xml = g_strdup_printf(MSN_XML_ADD_CONTACT, escaped_displayname, passport); -*/ +#endif + purple_debug_info("MSNCL","Adding contact %s to contact list\n", passport); -// if ( !strcmp(state->guid, MSN_INDIVIDUALS_GROUP_ID) ) { - contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); -// } + contact_xml = g_strdup_printf(MSN_CONTACT_XML, passport); body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE, contact_xml); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_ADD_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_add_contact_read_cb, state); + g_free(contact_xml); - - /*build SOAP and POST it*/ - - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_ADD_SOAP_ACTION, - body, - state, - msn_add_contact_read_cb, - msn_add_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - g_free(body); } -static gboolean -msn_add_contact_to_group_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_to_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state; + MsnCallbackState *state = data; MsnUserList *userlist; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + g_return_if_fail(data != NULL); + + userlist = state->session->userlist; - userlist = soapconn->session->userlist; + if (resp != NULL) { + if (msn_userlist_add_buddy_to_group(userlist, state->who, + state->new_group_name)) { + purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); + } else { + purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + } - state = (MsnCallbackState *) soapconn->data_cb; + if (state->action & MSN_ADD_BUDDY) { + MsnUser *user = msn_userlist_find_user(userlist, state->who); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - if (msn_userlist_add_buddy_to_group(userlist, state->who, state->new_group_name) == TRUE) { - purple_debug_info("MSNCL", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); - } else { - purple_debug_info("MSNCL","Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + if ( !msn_user_is_yahoo(state->session->account, state->who) ) { + + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); + msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); + } + msn_notification_send_fqy(state->session, state->who); + + if (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) { + msn_del_contact_from_list(state->session->contact, NULL, state->who, MSN_LIST_PL); + msn_callback_state_free(state); + return; + } + } + + if (state->action & MSN_MOVE_BUDDY) { + msn_del_contact_from_group(state->session->contact, state->who, state->old_group_name); + } } - if (state->action & MSN_ADD_BUDDY) { - - if ( !msn_user_is_yahoo(soapconn->session->account, state->who) ) { - - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_AL); - msn_userlist_add_buddy_to_list(userlist, state->who, MSN_LIST_FL); - } - msn_notification_send_fqy(soapconn->session, state->who); - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_del_contact_from_group(soapconn->session->contact, state->who, state->old_group_name); - } else { - msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - } - return TRUE; -} - -static void -msn_add_contact_to_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Add contact to group request sent!\n"); - soapconn->read_cb = msn_add_contact_to_group_read_cb; + msn_callback_state_free(state); } void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, const char *passport, const char *groupId) { - MsnSoapReq *soap_request; MsnUserList *userlist; MsnUser *user; gchar *body = NULL, *contact_xml; @@ -1143,13 +875,14 @@ return; } - purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, msn_userlist_find_group_name(userlist, groupId)); user = msn_userlist_find_user(userlist, passport); if (user == NULL) { - purple_debug_warning("MSN CL", "Unable to retrieve user %s from the userlist!\n", passport); + purple_debug_warning("MSNCL", "Unable to retrieve user %s from the userlist!\n", passport); + msn_callback_state_free(state); + return; /* guess this never happened! */ } if (user != NULL && user->uid != NULL) { @@ -1159,60 +892,35 @@ } body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml); - g_free(contact_xml); - - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_ADD_CONTACT_GROUP_SOAP_ACTION, - body, - state, - msn_add_contact_to_group_read_cb, - msn_add_contact_to_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(state->session, + msn_soap_message_new(MSN_ADD_CONTACT_GROUP_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_add_contact_to_group_read_cb, state); + g_free(contact_xml); g_free(body); } - - -static gboolean -msn_delete_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_delete_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnUser *user; - MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; - MsnUserList *userlist; - - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); + MsnCallbackState *state = data; - userlist = soapconn->session->userlist; + if (resp != NULL) { + MsnUserList *userlist = state->session->userlist; + MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } + purple_debug_info("MSNCL","Delete contact successful\n"); - purple_debug_info("MSNCL","Delete contact successful\n"); - - user = msn_userlist_find_user_with_id(userlist, state->uid); - if (user != NULL) { - msn_userlist_remove_user(userlist, user); + if (user != NULL) { + msn_userlist_remove_user(userlist, user); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_delete_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSNCL","Delete contact request written\n"); - soapconn->read_cb = msn_delete_contact_read_cb; } /*delete a Contact*/ @@ -1221,72 +929,52 @@ { gchar *body = NULL; gchar *contact_id_xml = NULL ; - MsnSoapReq *soap_request; MsnCallbackState *state; g_return_if_fail(contactId != NULL); contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId); - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); msn_callback_state_set_uid(state, contactId); /* build SOAP request */ purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId); body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_DEL_SOAP_ACTION, - body, - state, - msn_delete_contact_read_cb, - msn_delete_contact_written_cb, - msn_contact_connect_init); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_DEL_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_delete_contact_read_cb, state); g_free(contact_id_xml); - - /* POST the SOAP request */ - msn_soap_post(contact->soapconn, soap_request); - g_free(body); } -static gboolean -msn_del_contact_from_group_read_cb(MsnSoapConn *soapconn) +static void +msn_del_contact_from_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = (MsnCallbackState *) soapconn->data_cb; + MsnCallbackState *state = data; - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - if (msn_userlist_rem_buddy_from_group(soapconn->session->userlist, state->who, state->old_group_name)) { - purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); - } else { - purple_debug_info("MSN CL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); + if (resp != NULL) { + if (msn_userlist_rem_buddy_from_group(state->session->userlist, + state->who, state->old_group_name)) { + purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); + } else { + purple_debug_info("MSNCL", "Contact %s deleted successfully from group %s in the server, but failed in the local list\n", state->who, state->old_group_name); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_del_contact_from_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Del contact from group request sent!\n"); - soapconn->read_cb = msn_del_contact_from_group_read_cb; } void msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name) { - MsnSoapReq *soap_request; MsnUserList * userlist; MsnUser *user; MsnCallbackState *state; - gchar *body = NULL, *contact_id_xml; + gchar *body, *contact_id_xml; const gchar *groupId; g_return_if_fail(passport != NULL); @@ -1299,16 +987,16 @@ groupId = msn_userlist_find_group_id(userlist, group_name); if (groupId != NULL) { - purple_debug_info("MSN CL", "Deleting user %s from group %s\n", passport, group_name); + purple_debug_info("MSNCL", "Deleting user %s from group %s\n", passport, group_name); } else { - purple_debug_warning("MSN CL", "Unable to retrieve group id from group %s !\n", group_name); + purple_debug_warning("MSNCL", "Unable to retrieve group id from group %s !\n", group_name); return; } user = msn_userlist_find_user(userlist, passport); if (user == NULL) { - purple_debug_warning("MSN CL", "Unable to retrieve user from passport %s!\n", passport); + purple_debug_warning("MSNCL", "Unable to retrieve user from passport %s!\n", passport); return; } @@ -1317,58 +1005,40 @@ return; } - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); msn_callback_state_set_who(state, passport); msn_callback_state_set_guid(state, groupId); msn_callback_state_set_old_group_name(state, group_name); contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, user->uid); body = g_strdup_printf(MSN_CONTACT_DEL_GROUP_TEMPLATE, contact_id_xml, groupId); + + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_DEL_GROUP_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_del_contact_from_group_read_cb, state); + g_free(contact_id_xml); - - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_DEL_GROUP_SOAP_ACTION, - body, - state, - msn_del_contact_from_group_read_cb, - msn_del_contact_from_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - g_free(body); } -static gboolean -msn_update_contact_read_cb(MsnSoapConn *soapconn) +static void +msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - if (soapconn->body == NULL) - return TRUE; - - purple_debug_info("MSN CL","Contact updated successfully\n"); - - return TRUE; -} - -static void -msn_update_contact_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Update contact information request sent\n"); - soapconn->read_cb = msn_update_contact_read_cb; + if (resp) + purple_debug_info("MSN CL","Contact updated successfully\n"); + else + purple_debug_info("MSN CL","Contact updated successfully\n"); } /* Update a contact's nickname */ - void msn_update_contact(MsnContact *contact, const char* nickname) { - MsnSoapReq *soap_request; - gchar *body, *escaped_nickname; - - /* I'm not sure this is right, but if it isn't, the rest of this function will need to be fixed */ - g_return_if_fail(nickname != NULL); + gchar *body = NULL, *escaped_nickname; purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname); @@ -1376,83 +1046,49 @@ body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_CONTACT_UPDATE_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_update_contact_read_cb, NULL); + g_free(escaped_nickname); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_CONTACT_UPDATE_SOAP_ACTION, - body, - NULL, - msn_update_contact_read_cb, - msn_update_contact_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); - g_free(body); } - -static gboolean -msn_del_contact_from_list_read_cb(MsnSoapConn *soapconn) +static void +msn_del_contact_from_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; + MsnSession *session = state->session; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE); - - state = (MsnCallbackState *) soapconn->data_cb; - - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + if (resp != NULL) { + purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - if (state->list_id == MSN_LIST_PL) { - MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who); - - if (user != NULL) - msn_user_unset_op(user, MSN_LIST_PL_OP); + if (state->list_id == MSN_LIST_PL) { + MsnUser *user = msn_userlist_find_user(session->userlist, state->who); - msn_add_contact_to_list(soapconn->session->contact, state, state->who, MSN_LIST_RL); - return TRUE; - } + if (user != NULL) + msn_user_unset_op(user, MSN_LIST_PL_OP); - if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_remove(soapconn->session->account, state->who, TRUE); - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); - msn_callback_state_free(state); - return TRUE; - } - - if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_remove(soapconn->session->account, state->who, TRUE); - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_AL); - msn_callback_state_free(state); - return TRUE; + msn_add_contact_to_list(session->contact, state, state->who, MSN_LIST_RL); + } else if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_remove(session->account, state->who, TRUE); + msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_BL); + } else if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_remove(session->account, state->who, TRUE); + msn_add_contact_to_list(session->contact, NULL, state->who, MSN_LIST_AL); + } } msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - - return TRUE; -} - -static void -msn_del_contact_from_list_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Delete contact from list SOAP request sent!\n"); - soapconn->read_cb = msn_del_contact_from_list_read_cb; } void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, const gchar *passport, const MsnListId list) { - MsnSoapReq *soap_request; gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; MsnUser *user; @@ -1464,7 +1100,7 @@ purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); @@ -1488,79 +1124,55 @@ MsnSoapPartnerScenarioText[partner_scenario], MsnMemberRole[list], member); - g_free(member); - soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, - MSN_SHARE_POST_URL, - MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION, - body, - state, - msn_del_contact_from_list_read_cb, - msn_del_contact_from_list_written_cb, - msn_contact_connect_init); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_SHARE_POST_URL, + msn_del_contact_from_list_read_cb, state); - msn_soap_post(contact->soapconn,soap_request); - + g_free(member); g_free(body); } -static gboolean -msn_add_contact_to_list_read_cb(MsnSoapConn *soapconn) +static void +msn_add_contact_to_list_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) { - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; - g_return_val_if_fail(soapconn->data_cb != NULL, TRUE); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, FALSE); - - state = (MsnCallbackState *) soapconn->data_cb; + g_return_if_fail(state != NULL); + g_return_if_fail(state->session != NULL); + g_return_if_fail(state->session->contact != NULL); - if (soapconn->body == NULL) { - msn_callback_state_free(state); - return TRUE; - } - - purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + if (resp != NULL) { + purple_debug_info("MSN CL", "Contact %s added successfully to %s list on server!\n", state->who, MsnMemberRole[state->list_id]); - if (state->list_id == MSN_LIST_RL) { - MsnUser *user = msn_userlist_find_user(soapconn->session->userlist, state->who); + if (state->list_id == MSN_LIST_RL) { + MsnUser *user = msn_userlist_find_user(state->session->userlist, state->who); - if (user != NULL) { - msn_user_set_op(user, MSN_LIST_RL_OP); - } + if (user != NULL) { + msn_user_set_op(user, MSN_LIST_RL_OP); + } + + if (state->action & MSN_DENIED_BUDDY) { - if (state->action & MSN_DENIED_BUDDY) { - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); - - msn_add_contact_to_list(soapconn->session->contact, NULL, state->who, MSN_LIST_BL); - return TRUE; + msn_add_contact_to_list(state->session->contact, NULL, state->who, MSN_LIST_BL); + } else if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_add(state->session->account, state->who, TRUE); + } else if (state->list_id == MSN_LIST_BL) { + purple_privacy_deny_add(state->session->account, state->who, TRUE); + } } } - if (state->list_id == MSN_LIST_AL) { - purple_privacy_permit_add(soapconn->session->account, state->who, TRUE); - } else if (state->list_id == MSN_LIST_BL) { - purple_privacy_deny_add(soapconn->session->account, state->who, TRUE); - } - msn_callback_state_free(state); - msn_soap_free_read_buf(soapconn); - return TRUE; -} - - -static void -msn_add_contact_to_list_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Add contact to list SOAP request sent!\n"); - soapconn->read_cb = msn_add_contact_to_list_read_cb; } void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, const gchar *passport, const MsnListId list) { - MsnSoapReq *soap_request; gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; @@ -1571,7 +1183,7 @@ purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(contact->session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); @@ -1585,37 +1197,24 @@ MsnMemberRole[list], member); - g_free(member); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_SHARE_POST_URL, + msn_add_contact_to_list_read_cb, state); - soap_request = msn_soap_request_new( MSN_CONTACT_SERVER, - MSN_SHARE_POST_URL, - MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION, - body, - state, - msn_add_contact_to_list_read_cb, - msn_add_contact_to_list_written_cb, - msn_contact_connect_init); - - msn_soap_post(contact->soapconn, soap_request); - + g_free(member); g_free(body); } - #if 0 -static gboolean -msn_gleams_read_cb(MsnSoapConn * soapconn) +static void +msn_gleams_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - purple_debug_info("MSN CL","Gleams read done\n"); - return TRUE; -} - -static void -msn_gleams_written_cb(MsnSoapConn * soapconn) -{ - purple_debug_info("MSNP14","finish Group written\n"); - soapconn->read_cb = msn_gleams_read_cb; -// msn_soap_read_cb(data,source,cond); + if (resp != NULL) + purple_debug_info("MSNP14","Gleams read done\n"); + else + purple_debug_info("MSNP14","Gleams read failed\n"); } /*get the gleams info*/ @@ -1625,16 +1224,11 @@ MsnSoapReq *soap_request; purple_debug_info("MSNP14","msn get gleams info...\n"); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GET_GLEAMS_SOAP_ACTION, - MSN_GLEAMS_TEMPLATE, - NULL, - msn_gleams_read_cb, - msn_gleams_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); + msn_soap_message_send(contact->session, + msn_soap_message_new(MSN_GET_GLEAMS_SOAP_ACTION, + xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_gleams_read_cb, NULL); } #endif @@ -1643,100 +1237,88 @@ * Group Operations ***************************************************************/ -static gboolean -msn_group_read_cb(MsnSoapConn *soapconn) +static void +msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnUserList *userlist; - MsnCallbackState *state = NULL; + MsnCallbackState *state = data; - purple_debug_info("MSN CL", "Group request successful.\n"); + purple_debug_info("MSNCL", "Group request successful.\n"); - g_return_val_if_fail(soapconn->session != NULL, FALSE); - g_return_val_if_fail(soapconn->session->userlist != NULL, TRUE); - g_return_val_if_fail(soapconn->session->contact != NULL, FALSE); + g_return_if_fail(state->session != NULL); + g_return_if_fail(state->session->userlist != NULL); + g_return_if_fail(state->session->contact != NULL); - state = (MsnCallbackState *) soapconn->data_cb; - - if (soapconn->body == NULL) { + if (resp == NULL) { msn_callback_state_free(state); - return TRUE; + return; } - + if (state) { - userlist = soapconn->session->userlist; + MsnSession *session = state->session; + MsnUserList *userlist = session->userlist; if (state->action & MSN_RENAME_GROUP) { - msn_userlist_rename_group_id(soapconn->session->userlist, + msn_userlist_rename_group_id(session->userlist, state->guid, state->new_group_name); } if (state->action & MSN_ADD_GROUP) { - gchar *guid, *endguid; - - guid = g_strstr_len(soapconn->read_buf, soapconn->read_len, ""); - guid += 6; - endguid = g_strstr_len(soapconn->read_buf, soapconn->read_len, ""); - *endguid = '\0'; - /* create and add the new group to the userlist */ - purple_debug_info("MSN CL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); - msn_group_new(soapconn->session->userlist, guid, state->new_group_name); + /* the response is taken from + http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions + should copy it to msnpiki some day */ + xmlnode *guid_node = msn_soap_xml_get(resp->xml, + "Body/ABGroupAddResponse/ABGroupAddResult/guid"); + + if (guid_node) { + char *guid = xmlnode_get_data(guid_node); + + /* create and add the new group to the userlist */ + purple_debug_info("MSNCL", "Adding group %s with guid = %s to the userlist\n", state->new_group_name, guid); + msn_group_new(session->userlist, guid, state->new_group_name); - if (state->action & MSN_ADD_BUDDY) { - msn_userlist_add_buddy(soapconn->session->userlist, - state->who, - state->new_group_name); - msn_callback_state_free(state); - return TRUE; - } - - if (state->action & MSN_MOVE_BUDDY) { - msn_add_contact_to_group(soapconn->session->contact, state, state->who, guid); - return TRUE; + g_free(guid); + + if (state->action & MSN_ADD_BUDDY) { + msn_userlist_add_buddy(session->userlist, + state->who, + state->new_group_name); + } else if (state->action & MSN_MOVE_BUDDY) { + msn_add_contact_to_group(session->contact, state, state->who, guid); + return; + } + } else { + purple_debug_info("MSNCL", "Adding group %s failed\n", + state->new_group_name); } } if (state->action & MSN_DEL_GROUP) { GList *l; - msn_userlist_remove_group_id(soapconn->session->userlist, state->guid); + msn_userlist_remove_group_id(session->userlist, state->guid); for (l = userlist->users; l != NULL; l = l->next) { msn_user_remove_group_id( (MsnUser *)l->data, state->guid); } - } msn_callback_state_free(state); } - - msn_soap_free_read_buf(soapconn); - return TRUE; -} - -static void -msn_group_written_cb(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN CL","Sent group request.\n"); - soapconn->read_cb = msn_group_read_cb; } /* add group */ void msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; char *body = NULL; - gchar *escaped_group_name; g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - contact = session->contact; - purple_debug_info("MSN CL","Adding group %s to contact list.\n", group_name); + purple_debug_info("MSNCL","Adding group %s to contact list.\n", group_name); if (state == NULL) { - state = msn_callback_state_new(); + state = msn_callback_state_new(session); } msn_callback_state_set_action(state, MSN_ADD_GROUP); @@ -1745,21 +1327,14 @@ /* escape group name's html special chars so it can safely be sent * in a XML SOAP request */ - escaped_group_name = g_markup_escape_text(group_name, -1); - body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name); - g_free(escaped_group_name); + body = g_markup_printf_escaped(MSN_GROUP_ADD_TEMPLATE, group_name); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_ADD_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn,soap_request); - + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_ADD_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); + g_free(body); } @@ -1767,8 +1342,6 @@ void msn_del_group(MsnSession *session, const gchar *group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; MsnCallbackState *state; char *body = NULL; const gchar *guid; @@ -1776,8 +1349,7 @@ g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - contact = session->contact; - purple_debug_info("MSN CL","Deleting group %s from contact list\n", group_name); + purple_debug_info("MSNCL","Deleting group %s from contact list\n", group_name); guid = msn_userlist_find_group_id(session->userlist, group_name); @@ -1785,7 +1357,7 @@ * we need to delete nothing */ if (guid == NULL) { - purple_debug_info("MSN CL", "Group %s guid not found, returning.\n", group_name); + purple_debug_info("MSNCL", "Group %s guid not found, returning.\n", group_name); return; } @@ -1794,21 +1366,17 @@ return; } - state = msn_callback_state_new(); + state = msn_callback_state_new(session); msn_callback_state_set_action(state, MSN_DEL_GROUP); msn_callback_state_set_guid(state, guid); body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid); - /*build SOAP and POST it*/ - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_DEL_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); + + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_DEL_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); g_free(body); } @@ -1817,24 +1385,22 @@ void msn_contact_rename_group(MsnSession *session, const char *old_group_name, const char *new_group_name) { - MsnSoapReq *soap_request; - MsnContact *contact; - gchar * escaped_group_name, *body = NULL; + gchar *body = NULL; const gchar * guid; - MsnCallbackState *state = msn_callback_state_new(); + MsnCallbackState *state; g_return_if_fail(session != NULL); g_return_if_fail(session->userlist != NULL); g_return_if_fail(old_group_name != NULL); g_return_if_fail(new_group_name != NULL); - contact = session->contact; purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name); guid = msn_userlist_find_group_id(session->userlist, old_group_name); if (guid == NULL) return; + state = msn_callback_state_new(session); msn_callback_state_set_guid(state, guid); msn_callback_state_set_new_group_name(state, new_group_name); @@ -1845,31 +1411,14 @@ msn_callback_state_set_action(state, MSN_RENAME_GROUP); - /* escape group name's html special chars so it can safely be sent - * in a XML SOAP request - */ - escaped_group_name = g_markup_escape_text(new_group_name, -1); - - body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, escaped_group_name); + body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE, + guid, new_group_name); - soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, - MSN_ADDRESS_BOOK_POST_URL, - MSN_GROUP_RENAME_SOAP_ACTION, - body, - state, - msn_group_read_cb, - msn_group_written_cb, - msn_contact_connect_init); - msn_soap_post(contact->soapconn, soap_request); - - g_free(escaped_group_name); + msn_soap_message_send(session, + msn_soap_message_new(MSN_GROUP_RENAME_SOAP_ACTION, + xmlnode_from_str(body, -1)), + MSN_CONTACT_SERVER, MSN_ADDRESS_BOOK_POST_URL, + msn_group_read_cb, state); + g_free(body); } - -void -msn_contact_connect_init(MsnSoapConn *soapconn) -{ - msn_soap_init(soapconn, MSN_CONTACT_SERVER, TRUE, - msn_contact_login_connect_cb, - msn_contact_login_error_cb); -} diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/contact.h --- a/libpurple/protocols/msn/contact.h Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/contact.h Sat Nov 03 09:20:20 2007 +0000 @@ -380,6 +380,7 @@ gchar * guid; MsnListId list_id; MsnCallbackAction action; + MsnSession *session; }; typedef enum @@ -397,7 +398,7 @@ MsnContact * msn_contact_new(MsnSession *session); void msn_contact_destroy(MsnContact *contact); -MsnCallbackState * msn_callback_state_new(void); +MsnCallbackState * msn_callback_state_new(MsnSession *session); void msn_callback_state_free(MsnCallbackState *state); void msn_callback_state_set_who(MsnCallbackState *state, const gchar *who); void msn_callback_state_set_uid(MsnCallbackState *state, const gchar *uid); diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Sat Nov 03 09:20:20 2007 +0000 @@ -956,21 +956,17 @@ }else { /*send Offline Instant Message,only to MSN Passport User*/ MsnSession *session; - MsnOim *oim; char *friendname; purple_debug_info("MSNP14","prepare to send offline Message\n"); session = gc->proto_data; - /* XXX/khc: hack */ - if (!session->oim) - session->oim = msn_oim_new(session); - oim = session->oim; friendname = msn_encode_mime(account->username); - msn_oim_prep_send_msg_info(oim, purple_account_get_username(account), - friendname, who, message); + msn_oim_prep_send_msg_info(session->oim, + purple_account_get_username(account), + friendname, who, message); + msn_oim_send_msg(session->oim); g_free(friendname); - msn_oim_send_msg(oim); } return 1; diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/nexus.c --- a/libpurple/protocols/msn/nexus.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Sat Nov 03 09:20:20 2007 +0000 @@ -22,15 +22,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" -#include "soap.h" +#include "soap2.h" #include "nexus.h" #include "notification.h" #undef NEXUS_LOGIN_TWN -/*Local Function Prototype*/ -static gboolean nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc); - /************************************************************************** * Main **************************************************************************/ @@ -42,8 +39,6 @@ nexus = g_new0(MsnNexus, 1); nexus->session = session; - /*we must use SSL connection to do Windows Live ID authentication*/ - nexus->soapconn = msn_soap_new(session,nexus,1); nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -57,193 +52,98 @@ if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); - msn_soap_destroy(nexus->soapconn); g_free(nexus); } -#if 0 /* khc */ -/************************************************************************** - * Util - **************************************************************************/ - -static gssize -msn_ssl_read(MsnNexus *nexus) -{ - gssize len; - char temp_buf[4096]; - - if ((len = purple_ssl_read(nexus->gsc, temp_buf, - sizeof(temp_buf))) > 0) - { - nexus->read_buf = g_realloc(nexus->read_buf, - nexus->read_len + len + 1); - strncpy(nexus->read_buf + nexus->read_len, temp_buf, len); - nexus->read_len += len; - nexus->read_buf[nexus->read_len] = '\0'; - } - - return len; -} - -static void -nexus_write_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnNexus *nexus = data; - int len, total_len; - - total_len = strlen(nexus->write_buf); - - len = purple_ssl_write(nexus->gsc, - nexus->write_buf + nexus->written_len, - total_len - nexus->written_len); - - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - /* TODO: notify of the error */ - return; - } - nexus->written_len += len; - - if (nexus->written_len < total_len) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - g_free(nexus->write_buf); - nexus->write_buf = NULL; - nexus->written_len = 0; - - nexus->written_cb(nexus, source, 0); -} - -#endif /************************************************************************** * Login **************************************************************************/ + static void -nexus_login_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) +nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnSession *session; + MsnNexus *nexus = data; + MsnSession *session = nexus->session; + xmlnode *node; + + if (resp == NULL) { + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); + return; + } + + node = msn_soap_xml_get(resp->xml, "Body/" + "RequestSecurityTokenResponseCollection/RequestSecurityTokenResponse"); + + for (; node; node = node->next) { + xmlnode *token = msn_soap_xml_get(node, + "RequestedSecurityToken/BinarySecurityToken"); + + if (token) { + char *token_str = xmlnode_get_data(token); + char **elems, **cur, **tokens; + char *msn_twn_t, *msn_twn_p, *cert_str; + + if (token_str == NULL) continue; + + elems = g_strsplit(token_str, "&", 0); - session = soapconn->session; - g_return_if_fail(session != NULL); + for (cur = elems; *cur != NULL; cur++){ + tokens = g_strsplit(*cur, "=", 2); + g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + + g_free(token_str); + g_strfreev(elems); + + msn_twn_t = g_hash_table_lookup(nexus->challenge_data, "t"); + msn_twn_p = g_hash_table_lookup(nexus->challenge_data, "p"); + + /*setup the t and p parameter for session*/ + if (session->passport_info.t != NULL){ + g_free(session->passport_info.t); + } + session->passport_info.t = g_strdup(msn_twn_t); - soapconn->gsc = NULL; + if (session->passport_info.p != NULL) + g_free(session->passport_info.p); + session->passport_info.p = g_strdup(msn_twn_p); + + cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); + msn_got_login_params(session, cert_str); - msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); - /* the above line will result in nexus being destroyed, so we don't want - * to destroy it here, or we'd crash */ + purple_debug_info("MSN Nexus","Close nexus connection!\n"); + g_free(cert_str); + msn_nexus_destroy(nexus); + session->nexus = NULL; + + return; + } + } + + /* we must have failed! */ + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication: cannot find authenticate token in server response")); } -/*process the SOAP reply, get the Authentication Info*/ -static gboolean -nexus_login_read_cb(MsnSoapConn *soapconn) +/*when connect, do the SOAP Style windows Live ID authentication */ +void +msn_nexus_connect(MsnNexus *nexus) { - MsnNexus *nexus; - MsnSession *session; - - char *base, *c; - char *msn_twn_t,*msn_twn_p; - char *login_params; - char **elems, **cur, **tokens; - char * cert_str; - - nexus = soapconn->parent; - g_return_val_if_fail(nexus != NULL, TRUE); - session = nexus->session; - g_return_val_if_fail(session != NULL, FALSE); - - /*reply OK, we should process the SOAP body*/ - purple_debug_info("MSN Nexus","TWN Server Windows Live ID Reply OK!\n"); - - //TODO: we should parse it using XML -#ifdef NEXUS_LOGIN_TWN - base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN); - base += strlen(TWN_START_TOKEN); - c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN); -#else - base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN); - base += strlen(TWN_LIVE_START_TOKEN); - c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN); -#endif - login_params = g_strndup(base, c - base); - - // purple_debug_info("msn", "TWN Cert: {%s}\n", login_params); - - /* Parse the challenge data. */ - elems = g_strsplit(login_params, "&", 0); - - for (cur = elems; *cur != NULL; cur++){ - tokens = g_strsplit(*cur, "=", 2); - g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } - - g_strfreev(elems); - - msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t"); - msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p"); - - /*setup the t and p parameter for session*/ - g_free(session->passport_info.t); - session->passport_info.t = g_strdup(msn_twn_t); - - g_free(session->passport_info.p); - session->passport_info.p = g_strdup(msn_twn_p); - - cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); - msn_got_login_params(session, cert_str); - - purple_debug_info("MSN Nexus","Close nexus connection!\n"); - g_free(cert_str); - g_free(login_params); - msn_nexus_destroy(nexus); - session->nexus = NULL; - - return FALSE; -} - -static void -nexus_login_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = nexus_login_read_cb; -// msn_soap_read_cb(data,source,cond); -} - - -/*when connect, do the SOAP Style windows Live ID authentication */ -gboolean -nexus_login_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnNexus * nexus; - MsnSession *session; + MsnSession *session = nexus->session; char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; char *fs0,*fs; char *username, *password; - char *request_str, *tail; + char *tail; #ifdef NEXUS_LOGIN_TWN char *challenge_str; #else char *rst1_str,*rst2_str,*rst3_str; #endif - - purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); - - g_return_val_if_fail(soapconn != NULL, FALSE); - nexus = soapconn->parent; - g_return_val_if_fail(nexus != NULL, TRUE); + MsnSoapMessage *soap; - session = soapconn->session; - g_return_val_if_fail(session != NULL, FALSE); - - msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); - + purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); /*prepare the Windows Live ID authentication token*/ @@ -272,10 +172,9 @@ msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); g_free(username); g_free(password); - purple_ssl_close(gsc); msn_nexus_destroy(nexus); session->nexus = NULL; - return FALSE; + return; } /* @@ -314,151 +213,8 @@ #endif g_free(fs); - soapconn->login_path = g_strdup(TWN_POST_URL); - request_str = g_strdup_printf( - "POST %s HTTP/1.1\r\n" - "Accept: text/*\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" - "Host: %s\r\n" - "Content-Length: %" G_GSIZE_FORMAT "\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n\r\n" - "%s", - soapconn->login_path, soapconn->login_host, strlen(tail), - tail); - -#ifdef MSN_SOAP_DEBUG - purple_debug_misc("MSN Nexus", "TWN Sending:\n%s\n", request_str); -#endif - g_free(tail); - g_free(username); - g_free(password); - - /*prepare to send the SOAP request*/ - msn_soap_write(soapconn, request_str, nexus_login_written_cb); - - return TRUE; + soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1)); + msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL, + nexus_got_response_cb, nexus); } -#if 0 /* khc */ -static void -nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnNexus *nexus = data; - int len; - - char *da_login; - char *base, *c; - - if (nexus->input_handler == 0) - /* TODO: Use purple_ssl_input_add()? */ - nexus->input_handler = purple_input_add(nexus->gsc->fd, - PURPLE_INPUT_READ, nexus_connect_written_cb, nexus); - - - /* Get the PassportURLs line. */ - len = msn_ssl_read(nexus); - - if (len < 0 && errno == EAGAIN) - return; - else if (len < 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - /* TODO: error handling */ - return; - } - - if (g_strstr_len(nexus->read_buf, nexus->read_len, - "\r\n\r\n") == NULL) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - base = strstr(nexus->read_buf, "PassportURLs"); - - if (base == NULL) - { - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - return; - } - - if ((da_login = strstr(base, "DALogin=")) != NULL) - { - /* skip over "DALogin=" */ - da_login += 8; - - if ((c = strchr(da_login, ',')) != NULL) - *c = '\0'; - - if ((c = strchr(da_login, '/')) != NULL) - { - nexus->login_path = g_strdup(c); - *c = '\0'; - } - - nexus->login_host = g_strdup(da_login); - } - - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - - purple_ssl_close(nexus->gsc); - - /* Now begin the connection to the login server. */ - nexus->gsc = purple_ssl_connect(nexus->session->account, - nexus->login_host, PURPLE_SSL_DEFAULT_PORT, - login_connect_cb, login_error_cb, nexus); -} - - -#endif - -/************************************************************************** - * Connect - **************************************************************************/ - -#if 0 /* khc */ -static void -nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond) -{ - MsnNexus *nexus; - MsnSession *session; - - nexus = data; - g_return_if_fail(nexus != NULL); - - session = nexus->session; - g_return_if_fail(session != NULL); - - msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH); - - nexus->write_buf = g_strdup("GET /rdr/pprdr.asp\r\n\r\n"); - nexus->written_len = 0; - - nexus->read_len = 0; - - nexus->written_cb = nexus_connect_written_cb; - - nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE, - nexus_write_cb, nexus); - - nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); -} - -#endif - -void -msn_nexus_connect(MsnNexus *nexus) -{ - /* Authenticate via Windows Live ID. */ - msn_soap_init(nexus->soapconn, MSN_TWN_SERVER, TRUE, nexus_login_connect_cb, nexus_login_error_cb); - msn_soap_connect(nexus->soapconn); -} diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/nexus.h --- a/libpurple/protocols/msn/nexus.h Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Sat Nov 03 09:20:20 2007 +0000 @@ -139,7 +139,6 @@ struct _MsnNexus { MsnSession *session; - MsnSoapConn *soapconn; char * challenge_data_str; GHashTable *challenge_data; }; diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Sat Nov 03 09:20:20 2007 +0000 @@ -1790,9 +1790,7 @@ return; /*new a oim session*/ - /* There are several things that call this */ - if (session->oim == NULL) - session->oim = msn_oim_new(session); +// session->oim = msn_oim_new(session); // msn_oim_connect(session->oim); table = msn_message_get_hashtable_from_body(msg); diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/oim.c --- a/libpurple/protocols/msn/oim.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/oim.c Sat Nov 03 09:20:20 2007 +0000 @@ -24,24 +24,31 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" -#include "soap.h" +#include "soap2.h" #include "oim.h" #include "msnutils.h" +typedef struct _MsnOimSendReq { + char *from_member; + char *friendname; + char *to_member; + char *oim_msg; +} MsnOimSendReq; + +typedef struct { + MsnOim *oim; + char *msg_id; +} MsnOimRecvData; + /*Local Function Prototype*/ -static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid); +static void msn_oim_post_single_get_msg(MsnOim *oim, char *msgid); static MsnOimSendReq *msn_oim_new_send_req(const char *from_member, - const char *friendname, - const char* to_member, - gint send_seq, - const char *msg); -static void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn); -static void msn_oim_send_connect_init(MsnSoapConn *soapconn); + const char *friendname, + const char* to_member, + const char *msg); static void msn_oim_free_send_req(MsnOimSendReq *req); -static void msn_oim_report_to_user(MsnOim *oim, const char *msg_str); -static void msn_oim_get_process(MsnOim *oim, const char *oim_msg); -static gchar *msn_oim_msg_to_str(MsnOim *oim, const char *body); -static void msn_oim_send_process(MsnOim *oim, const char *body, int len); +static void msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str); +static char *msn_oim_msg_to_str(MsnOim *oim, const char *body); /*new a OIM object*/ MsnOim * @@ -51,10 +58,7 @@ oim = g_new0(MsnOim, 1); oim->session = session; - oim->retrieveconn = msn_soap_new(session, oim, TRUE); - - oim->oim_list = NULL; - oim->sendconn = msn_soap_new(session, oim, TRUE); + oim->oim_list = NULL; oim->run_id = rand_guid(); oim->challenge = NULL; oim->send_queue = g_queue_new(); @@ -69,8 +73,6 @@ MsnOimSendReq *request; purple_debug_info("OIM","destroy the OIM \n"); - msn_soap_destroy(oim->retrieveconn); - msn_soap_destroy(oim->sendconn); g_free(oim->run_id); g_free(oim->challenge); @@ -84,8 +86,7 @@ static MsnOimSendReq * msn_oim_new_send_req(const char *from_member, const char*friendname, - const char* to_member, gint send_seq, - const char *msg) + const char* to_member, const char *msg) { MsnOimSendReq *request; @@ -93,7 +94,6 @@ request->from_member =g_strdup(from_member); request->friendname = g_strdup(friendname); request->to_member = g_strdup(to_member); - request->send_seq = send_seq; request->oim_msg = g_strdup(msg); return request; } @@ -130,135 +130,75 @@ return oim_body; } -/*oim SOAP server login error*/ -static void -msn_oim_send_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - - msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); -} - -/*msn oim SOAP server connect process*/ -static gboolean -msn_oim_send_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnOim *oim; - - oim = soapconn->parent; - g_return_val_if_fail(oim != NULL, TRUE); - - session = oim->session; - g_return_val_if_fail(session != NULL, FALSE); - - return TRUE; -} - /* * Process the send return SOAP string * If got SOAP Fault,get the lock key,and resend it. */ static void -msn_oim_send_process(MsnOim *oim, const char *body, int len) +msn_oim_send_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - xmlnode *responseNode, *bodyNode; - xmlnode *faultNode = NULL, *faultCodeNode, *faultstringNode; - xmlnode *detailNode, *challengeNode; - char *fault_code, *fault_text; + MsnOim *oim = data; + MsnOimSendReq *msg = g_queue_pop_head(oim->send_queue); + + g_return_if_fail(msg != NULL); - responseNode = xmlnode_from_str(body,len); + if (response == NULL) { + purple_debug_info("MSNP14", "cannot send OIM: %s\n", msg->oim_msg); + } else { + xmlnode *faultNode = msn_soap_xml_get(response->xml, "Body/Fault"); - g_return_if_fail(responseNode != NULL); + if (faultNode == NULL) { + /*Send OK! return*/ + purple_debug_info("MSNP14", "sent OIM: %s\n", msg->oim_msg); + } else { + xmlnode *faultcode = xmlnode_get_child(faultNode, "faultcode"); + + if (faultcode) { + char *faultcode_str = xmlnode_get_data(faultcode); - if ((bodyNode = xmlnode_get_child(responseNode, "Body"))) - faultNode = xmlnode_get_child(bodyNode, "Fault"); + if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { + xmlnode *challengeNode = msn_soap_xml_get(faultNode, + "detail/LockKeyChallenge"); - if (faultNode == NULL) { - /*Send OK! return*/ - MsnOimSendReq *request; + if (challengeNode == NULL) { + if (oim->challenge) { + g_free(oim->challenge); + oim->challenge = NULL; - xmlnode_free(responseNode); - request = g_queue_pop_head(oim->send_queue); - msn_oim_free_send_req(request); - /*send next buffered Offline Message*/ - msn_soap_post(oim->sendconn, NULL); - - return; - } + purple_debug_info("msnoim","resending OIM: %s\n", + msg->oim_msg); + g_queue_push_head(oim->send_queue, msg); + msn_oim_send_msg(oim); + return; + } else { + purple_debug_info("msnoim", + "can't find lock key for OIM: %s\n", + msg->oim_msg); + } + } else { + char buf[33]; - /*get the challenge,and repost it*/ - if (faultNode) - faultCodeNode = xmlnode_get_child(faultNode, "faultcode"); + char *challenge = xmlnode_get_data(challengeNode); + msn_handle_chl(challenge, buf); + + g_free(oim->challenge); + oim->challenge = g_strndup(buf, sizeof(buf)); + g_free(challenge); + purple_debug_info("MSNP14","lockkey:{%s}\n",oim->challenge); - if(faultCodeNode == NULL){ - purple_debug_info("MSN OIM", "No faultcode for failed Offline Message.\n"); - xmlnode_free(responseNode); - return; + /*repost the send*/ + purple_debug_info("MSNP14","resending OIM: %s\n", msg->oim_msg); + g_queue_push_head(oim->send_queue, msg); + msn_oim_send_msg(oim); + return; + } + } + } + } } - fault_code = xmlnode_get_data(faultCodeNode); -#if 0 - if(!strcmp(fault_code,"q0:AuthenticationFailed")){ - /*other Fault Reason?*/ - goto oim_send_process_fail; - } -#endif - - faultstringNode = xmlnode_get_child(faultNode, "faultstring"); - fault_text = xmlnode_get_data(faultstringNode); - purple_debug_info("MSN OIM", "Error sending Offline Message: %s (%s)\n", - fault_text ? fault_text : "(null)", fault_code ? fault_code : "(null)"); - - /* lock key fault reason, - * compute the challenge and resend it - */ - if ((detailNode = xmlnode_get_child(faultNode, "detail")) - && (challengeNode = xmlnode_get_child(detailNode, "LockKeyChallenge"))) { - g_free(oim->challenge); - oim->challenge = xmlnode_get_data(challengeNode); - - purple_debug_info("MSN OIM", "Retrying Offline IM with lockkey:{%s}\n", - oim->challenge ? oim->challenge : "(null)"); - - /*repost the send*/ - msn_oim_send_msg(oim); - - /* XXX: This needs to give up eventually (1 retry, maybe?) */ - } - - g_free(fault_text); - g_free(fault_code); - xmlnode_free(responseNode); -} - -static gboolean -msn_oim_send_read_cb(MsnSoapConn *soapconn) -{ - MsnSession *session = soapconn->session; - MsnOim * oim; - - if (soapconn->body == NULL) - return TRUE; - - g_return_val_if_fail(session != NULL, FALSE); - oim = soapconn->session->oim; - g_return_val_if_fail(oim != NULL, TRUE); - - purple_debug_info("MSN OIM","read buffer:{%s}\n", soapconn->body); - msn_oim_send_process(oim,soapconn->body,soapconn->body_len); - - return TRUE; -} - -static void -msn_oim_send_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_send_read_cb; -// msn_soap_read_cb(data,source,cond); + msn_oim_free_send_req(msg); } void @@ -266,45 +206,36 @@ const char* friendname, const char *tomember, const char * msg) { - MsnOimSendReq *request; - g_return_if_fail(oim != NULL); - request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg); - g_queue_push_tail(oim->send_queue,request); + g_queue_push_tail(oim->send_queue, + msn_oim_new_send_req(membername, friendname, tomember, msg)); } /*post send single message request to oim server*/ void msn_oim_send_msg(MsnOim *oim) { - MsnSoapReq *soap_request; MsnOimSendReq *oim_request; char *soap_body,*mspauth; - gchar *msg_body; - char buf[33]; + char *msg_body; g_return_if_fail(oim != NULL); - oim_request = g_queue_pop_head(oim->send_queue); + oim_request = g_queue_peek_head(oim->send_queue); g_return_if_fail(oim_request != NULL); - purple_debug_info("MSN OIM","send single OIM Message\n"); + purple_debug_info("MSNP14","sending OIM: %s\n", oim_request->oim_msg); mspauth = g_strdup_printf("t=%s&p=%s", oim->session->passport_info.t, oim->session->passport_info.p ); - g_queue_push_head(oim->send_queue,oim_request); /* if we got the challenge lock key, we compute it * else we go for the SOAP fault and resend it. */ - if(oim->challenge != NULL){ - msn_handle_chl(oim->challenge, buf); - }else{ - purple_debug_info("MSN OIM","no lock key challenge,wait for SOAP Fault and Resend\n"); - buf[0]='\0'; + if(oim->challenge == NULL){ + purple_debug_info("MSNP14","no lock key challenge,wait for SOAP Fault and Resend\n"); } - purple_debug_info("MSN OIM","get the lock key challenge {%s}\n",buf); msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE, @@ -313,117 +244,71 @@ oim_request->to_member, mspauth, MSNP13_WLM_PRODUCT_ID, - buf, - oim_request->send_seq, + oim->challenge ? oim->challenge : "", + oim->send_seq, msg_body); - soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST, - MSN_OIM_SEND_URL, - MSN_OIM_SEND_SOAP_ACTION, - soap_body, - NULL, - msn_oim_send_read_cb, - msn_oim_send_written_cb, - msn_oim_send_connect_init); + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_SEND_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_SEND_HOST, MSN_OIM_SEND_URL, msn_oim_send_read_cb, oim); + + /*increase the offline Sequence control*/ + if (oim->challenge != NULL) { + oim->send_seq++; + } + g_free(mspauth); g_free(msg_body); g_free(soap_body); - - /*increase the offline Sequence control*/ - if(oim->challenge != NULL){ - oim->send_seq++; - } - msn_soap_post(oim->sendconn,soap_request); } /**************************************** * OIM delete SOAP request * **************************************/ -static gboolean -msn_oim_delete_read_cb(MsnSoapConn *soapconn) +static void +msn_oim_delete_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - if (soapconn->body == NULL) - return TRUE; - purple_debug_info("MSN OIM","OIM delete read buffer:{%s}\n",soapconn->body); + MsnOimRecvData *rdata = data; - msn_soap_free_read_buf(soapconn); - /*get next single Offline Message*/ -// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ - return TRUE; -} + if (response && msn_soap_xml_get(response->xml, "Body/Fault") == NULL) { + purple_debug_info("msnoim", "delete OIM success\n"); + rdata->oim->oim_list = g_list_remove(rdata->oim->oim_list, + rdata->msg_id); + g_free(rdata->msg_id); + } else { + purple_debug_info("msnoim", "delete OIM failed\n"); + } -static void -msn_oim_delete_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_delete_read_cb; + g_free(rdata); } /*Post to get the Offline Instant Message*/ static void -msn_oim_post_delete_msg(MsnOim *oim,const char *msgid) +msn_oim_post_delete_msg(MsnOimRecvData *rdata) { - MsnSoapReq *soap_request; - gchar *soap_body; - const char *t,*p; + MsnOim *oim = rdata->oim; + char *msgid = rdata->msg_id; + char *soap_body; - g_return_if_fail(oim != NULL); - g_return_if_fail(msgid != NULL); - - purple_debug_info("MSN OIM","Delete single OIM Message {%s}\n",msgid); - t = oim->session->passport_info.t; - p = oim->session->passport_info.p; + purple_debug_info("MSNP14","Delete single OIM Message {%s}\n",msgid); soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, - t, - p, - msgid - ); - soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, - MSN_OIM_DEL_SOAP_ACTION, - soap_body, - NULL, - msn_oim_delete_read_cb, - msn_oim_delete_written_cb, - msn_oim_retrieve_connect_init); + oim->session->passport_info.t, oim->session->passport_info.p, msgid); + + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_DEL_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, + msn_oim_delete_read_cb, rdata); + g_free(soap_body); - msn_soap_post(oim->retrieveconn,soap_request); } /**************************************** * OIM get SOAP request * **************************************/ -/*oim SOAP server login error*/ -static void -msn_oim_get_error_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc, PurpleSslErrorType error) -{ - MsnSession *session; - - session = soapconn->session; - g_return_if_fail(session != NULL); - msn_soap_clean_unhandled_requests(soapconn); - -// msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); -} - -/*msn oim SOAP server connect process*/ -static gboolean -msn_oim_get_connect_cb(MsnSoapConn *soapconn, PurpleSslConnection *gsc) -{ - MsnSession * session; - MsnOim *oim; - - oim = soapconn->parent; - g_return_val_if_fail(oim != NULL, TRUE); - - session = oim->session; - g_return_val_if_fail(session != NULL, FALSE); - - purple_debug_info("MSN OIM","Connected and ready to get OIM!\n"); - - return TRUE; -} - /* like purple_str_to_time, but different. The format of the timestamp * is like this: 5 Sep 2007 21:42:12 -0700 */ static time_t @@ -435,9 +320,13 @@ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; + time_t tval = 0; struct tm t; memset(&t, 0, sizeof(t)); + time(&tval); + localtime_r(&tval, &t); + if (sscanf(timestamp, "%02d %03s %04d %02d:%02d:%02d %05s", &t.tm_mday, month_str, &t.tm_year, &t.tm_hour, &t.tm_min, &t.tm_sec, tz_str) == 7) { @@ -466,14 +355,13 @@ tzoff *= -1; t.tm_year -= 1900; - t.tm_isdst = 0; #ifdef _WIN32 if ((sys_tzoff = wpurple_get_tz_offset()) != -1) tzoff += sys_tzoff; #else #ifdef HAVE_TM_GMTOFF - tzoff += t.tm_gmtoff; + tzoff -= t.tm_gmtoff; #else # ifdef HAVE_TIMEZONE tzset(); /* making sure */ @@ -487,13 +375,13 @@ } } - purple_debug_info("MSN OIM:OIM", "Can't parse timestamp %s\n", timestamp); - return time(NULL); + purple_debug_info("MSNP14:OIM", "Can't parse timestamp %s\n", timestamp); + return tval; } /*Post the Offline Instant Message to User Conversation*/ static void -msn_oim_report_to_user(MsnOim *oim, const char *msg_str) +msn_oim_report_to_user(MsnOimRecvData *rdata, const char *msg_str) { MsnMessage *message; char *date,*from,*decode_msg; @@ -502,14 +390,13 @@ char *start,*end; int has_nick = 0; char *passport_str, *passport; - char *msg_id; time_t stamp; message = msn_message_new(MSN_MSG_UNKNOWN); msn_message_parse_payload(message, msg_str, strlen(msg_str), MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); - purple_debug_info("MSN OIM","oim body:{%s}\n",message->body); + purple_debug_info("MSNP14","oim body:{%s}\n",message->body); decode_msg = (char *)purple_base64_decode(message->body,&body_len); date = (char *)g_hash_table_lookup(message->attr_table, "Date"); from = (char *)g_hash_table_lookup(message->attr_table, "From"); @@ -519,12 +406,12 @@ if(has_nick){ tokens = g_strsplit(from , " " , 2); passport_str = g_strdup(tokens[1]); - purple_debug_info("MSN OIM","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", + purple_debug_info("MSNP14","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", date,tokens[0],tokens[1],passport_str); g_strfreev(tokens); }else{ passport_str = g_strdup(from); - purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n", + purple_debug_info("MSNP14","oim Date:{%s},passport{%s}\n", date,passport_str); } start = strstr(passport_str,"<"); @@ -536,66 +423,43 @@ stamp = msn_oim_parse_timestamp(date); - serv_got_im(oim->session->account->gc, passport, decode_msg, 0, stamp); + serv_got_im(rdata->oim->session->account->gc, passport, decode_msg, 0, + stamp); /*Now get the oim message ID from the oim_list. * and append to read list to prepare for deleting the Offline Message when sign out */ - if(oim->oim_list != NULL){ - msg_id = oim->oim_list->data; - msn_oim_post_delete_msg(oim,msg_id); - oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data); - g_free(msg_id); - } + msn_oim_post_delete_msg(rdata); g_free(passport); + g_free(decode_msg); } /* Parse the XML data, * prepare to report the OIM to user */ static void -msn_oim_get_process(MsnOim *oim, const char *oim_msg) -{ - xmlnode *oim_node,*bodyNode,*responseNode,*msgNode; - char *msg_str; - - oim_node = xmlnode_from_str(oim_msg, strlen(oim_msg)); - bodyNode = xmlnode_get_child(oim_node,"Body"); - responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse"); - msgNode = xmlnode_get_child(responseNode,"GetMessageResult"); - msg_str = xmlnode_get_data(msgNode); - purple_debug_info("OIM","msg:{%s}\n",msg_str); - msn_oim_report_to_user(oim,msg_str); - - g_free(msg_str); - xmlnode_free(oim_node); -} - -static gboolean -msn_oim_get_read_cb(MsnSoapConn *soapconn) +msn_oim_get_read_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) { - MsnOim * oim = soapconn->session->oim; - - if (soapconn->body == NULL) - return TRUE; + MsnOimRecvData *rdata = data; - purple_debug_info("MSN OIM","OIM get read buffer:{%s}\n",soapconn->body); - - /*we need to process the read message!*/ - msn_oim_get_process(oim,soapconn->body); - msn_soap_free_read_buf(soapconn); + if (response != NULL) { + xmlnode *msg_node = msn_soap_xml_get(response->xml, + "Body/GetMessageResponse/GetMessageResult"); - /*get next single Offline Message*/ -// msn_soap_post(soapconn,NULL); /* we already do this in soap.c */ - return TRUE; -} - -static void -msn_oim_get_written_cb(MsnSoapConn *soapconn) -{ - soapconn->read_cb = msn_oim_get_read_cb; -// msn_soap_read_cb(data,source,cond); + if (msg_node) { + char *msg_str = xmlnode_get_data(msg_node); + msn_oim_report_to_user(rdata, msg_str); + g_free(msg_str); + } else { + char *str = xmlnode_to_str(response->xml, NULL); + purple_debug_info("msnoim", "Unknown response: %s\n", str); + g_free(str); + } + } else { + purple_debug_info("msnoim", "Failed to get OIM\n"); + } } /* parse the oim XML data @@ -604,116 +468,88 @@ void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) { - xmlnode *node, *mNode,*ENode,*INode,*rtNode,*nNode; - char *passport,*msgid,*nickname, *unread, *rTime = NULL; + xmlnode *node, *mNode; + xmlnode *iu_node; MsnSession *session = oim->session; - purple_debug_info("MSN OIM:OIM", "%s", xmlmsg); + purple_debug_info("MSNP14:OIM", "%s", xmlmsg); - node = xmlnode_from_str(xmlmsg, strlen(xmlmsg)); - if (!node || !node->name || strcmp(node->name, "MD") != 0) { - if (node) - xmlnode_free(node); + node = xmlnode_from_str(xmlmsg, -1); + if (strcmp(node->name, "MD") != 0) { + purple_debug_info("msnoim", "WTF is this? %s\n", xmlmsg); + xmlnode_free(node); return; } - ENode = xmlnode_get_child(node, "E"); - INode = xmlnode_get_child(ENode, "IU"); - unread = xmlnode_get_data(INode); - - if (unread != NULL && purple_account_get_check_mail(session->account)) - { - int count = atoi(unread); + iu_node = msn_soap_xml_get(node, "E/IU"); - if (count > 0) - { - const char *passport; - const char *url; + if (iu_node != NULL && purple_account_get_check_mail(session->account)) + { + char *unread = xmlnode_get_data(iu_node); + const char *passport = msn_user_get_passport(session->user); + const char *url = session->passport_info.file; - passport = msn_user_get_passport(session->user); - url = session->passport_info.file; - - purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL, - &passport, &url, NULL, NULL); - } + /* XXX/khc: pretty sure this is wrong */ + purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, + NULL, &passport, &url, NULL, NULL); + g_free(unread); } for(mNode = xmlnode_get_child(node, "M"); mNode; mNode = xmlnode_get_next_twin(mNode)){ - /*email Node*/ - ENode = xmlnode_get_child(mNode,"E"); - passport = xmlnode_get_data(ENode); - /*Index */ - INode = xmlnode_get_child(mNode,"I"); - msgid = xmlnode_get_data(INode); - /*Nickname*/ - nNode = xmlnode_get_child(mNode,"N"); - nickname = xmlnode_get_data(nNode); - /*receive time*/ - rtNode = xmlnode_get_child(mNode,"RT"); - if(rtNode != NULL) - rTime = xmlnode_get_data(rtNode); -/* purple_debug_info("MSN OIM","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + char *passport, *msgid, *nickname, *rtime = NULL; + xmlnode *e_node, *i_node, *n_node, *rt_node; + + e_node = xmlnode_get_child(mNode, "E"); + passport = xmlnode_get_data(e_node); + + i_node = xmlnode_get_child(mNode, "I"); + msgid = xmlnode_get_data(i_node); + + n_node = xmlnode_get_child(mNode, "N"); + nickname = xmlnode_get_data(n_node); - oim->oim_list = g_list_append(oim->oim_list,strdup(msgid)); - msn_oim_post_single_get_msg(oim,msgid); + rt_node = xmlnode_get_child(mNode, "RT"); + if (rt_node != NULL) { + rtime = xmlnode_get_data(rt_node); + } +/* purple_debug_info("msnoim","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + + if (!g_list_find_custom(oim->oim_list, msgid, (GCompareFunc)strcmp)) { + oim->oim_list = g_list_append(oim->oim_list, msgid); + msn_oim_post_single_get_msg(oim, msgid); + msgid = NULL; + } + g_free(passport); g_free(msgid); - g_free(rTime); - rTime = NULL; + g_free(rtime); g_free(nickname); } - g_free(unread); + xmlnode_free(node); } /*Post to get the Offline Instant Message*/ static void -msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid) +msn_oim_post_single_get_msg(MsnOim *oim, char *msgid) { - MsnSoapReq *soap_request; - gchar *soap_body; - const char *t,*p; + char *soap_body; + MsnOimRecvData *data = g_new0(MsnOimRecvData, 1); - purple_debug_info("MSN OIM","Get single OIM Message\n"); - t = oim->session->passport_info.t; - p = oim->session->passport_info.p; + purple_debug_info("MSNP14","Get single OIM Message\n"); + + data->oim = oim; + data->msg_id = msgid; soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, - t, - p, - msgid - ); - soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, - MSN_OIM_RETRIEVE_URL, - MSN_OIM_GET_SOAP_ACTION, - soap_body, - NULL, - msn_oim_get_read_cb, - msn_oim_get_written_cb, - msn_oim_retrieve_connect_init); - g_free(soap_body); - msn_soap_post(oim->retrieveconn,soap_request); -} + oim->session->passport_info.t, oim->session->passport_info.p, msgid); -/*msn oim retrieve server connect init */ -static void -msn_oim_retrieve_connect_init(MsnSoapConn *soapconn) -{ - purple_debug_info("MSN OIM","Initializing OIM retrieve connection\n"); - msn_soap_init(soapconn, MSN_OIM_RETRIEVE_HOST, TRUE, - msn_oim_get_connect_cb, - msn_oim_get_error_cb); -} + msn_soap_message_send(oim->session, + msn_soap_message_new(MSN_OIM_GET_SOAP_ACTION, + xmlnode_from_str(soap_body, -1)), + MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, + msn_oim_get_read_cb, data); -/*Msn OIM Send Server Connect Init Function*/ -static void -msn_oim_send_connect_init(MsnSoapConn *sendconn) -{ - purple_debug_info("MSN OIM","Initializing OIM send connection\n"); - msn_soap_init(sendconn, MSN_OIM_SEND_HOST, TRUE, - msn_oim_send_connect_cb, - msn_oim_send_error_cb); + g_free(soap_body); } - -/* EOF oim.c*/ diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/oim.h --- a/libpurple/protocols/msn/oim.h Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/oim.h Sat Nov 03 09:20:20 2007 +0000 @@ -95,17 +95,6 @@ ""\ "" -typedef struct _MsnOimSendReq MsnOimSendReq; - -struct _MsnOimSendReq -{ - char *from_member; - char *friendname; - char *to_member; - char *oim_msg; - gint send_seq; -}; - typedef struct _MsnOim MsnOim; struct _MsnOim @@ -127,7 +116,6 @@ * **************************************************/ MsnOim * msn_oim_new(MsnSession *session); void msn_oim_destroy(MsnOim *oim); -void msn_oim_connect(MsnOim *oim); void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg); @@ -138,11 +126,5 @@ void msn_oim_send_msg(MsnOim *oim); -/*get the OIM message*/ -void msn_oim_get_msg(MsnOim *oim); - -/*report the oim message to the conversation*/ -void msn_oim_report_user(MsnOim *oim,const char *passport,char *msg); - #endif/* _MSN_OIM_H_*/ /*endof oim.h*/ diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/session.c Sat Nov 03 09:20:20 2007 +0000 @@ -24,6 +24,7 @@ #include "msn.h" #include "session.h" #include "notification.h" +#include "oim.h" #include "dialog.h" @@ -42,6 +43,7 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); + session->oim = msn_oim_new(session); /*if you want to chat with Yahoo Messenger*/ //session->protocol_ver = WLM_YAHOO_PROT_VER; @@ -99,6 +101,12 @@ if (session->user != NULL) msn_user_destroy(session->user); + if (session->soap_table) + g_hash_table_destroy(session->soap_table); + + if (session->soap_cleanup_handle) + purple_timeout_remove(session->soap_cleanup_handle); + g_free(session); } diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/session.h --- a/libpurple/protocols/msn/session.h Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/session.h Sat Nov 03 09:20:20 2007 +0000 @@ -126,6 +126,9 @@ char *client_ip; int client_port; } passport_info; + + GHashTable *soap_table; + int soap_cleanup_handle; }; /** diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Sat Nov 03 09:20:20 2007 +0000 @@ -39,22 +39,17 @@ char *tmp; char *dir; char *pload; - FILE *tf; int c; gsize pload_size; dir = send ? "send" : "recv"; c = send ? m_sc++ : m_rc++; tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c); - tf = g_fopen(tmp, "wb"); - if (tf == NULL) + pload = msn_message_gen_payload(msg, &pload_size); + if (!purple_util_write_data_to_file_absolute(tmp, pload, pload_size)) { - purple_debug_error("msn", "could not open debug file\n"); - return; + purple_debug_error("msn", "could not save debug file"); } - pload = msn_message_gen_payload(msg, &pload_size); - fwrite(pload, 1, pload_size, tf); - fclose(tf); g_free(tmp); } #endif diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/soap.c --- a/libpurple/protocols/msn/soap.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/soap.c Sat Nov 03 09:20:20 2007 +0000 @@ -308,7 +308,7 @@ } /*read the whole SOAP server response*/ -void +static void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnSoapConn *soapconn = data; diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/soap.h --- a/libpurple/protocols/msn/soap.h Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/soap.h Sat Nov 03 09:20:20 2007 +0000 @@ -154,7 +154,6 @@ void msn_soap_free_read_buf(MsnSoapConn *soapconn); void msn_soap_free_write_buf(MsnSoapConn *soapconn); void msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond); -void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond); /*clean the unhandled requests*/ void msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn); diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/soap2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap2.c Sat Nov 03 09:20:20 2007 +0000 @@ -0,0 +1,665 @@ +/** + * @file soap2.c + * C file for SOAP connection related process + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "soap2.h" + +#include "session.h" + +#include "debug.h" +#include "xmlnode.h" + +#include +#include + +#define SOAP_TIMEOUT (5 * 60) + +typedef struct _MsnSoapRequest { + char *path; + MsnSoapMessage *message; + MsnSoapCallback cb; + gpointer cb_data; +} MsnSoapRequest; + +typedef struct _MsnSoapConnection { + MsnSession *session; + char *host; + + time_t last_used; + PurpleSslConnection *ssl; + gboolean connected; + + guint event_handle; + GString *buf; + gsize handled_len; + gsize body_len; + int response_code; + gboolean headers_done; + gboolean close_when_done; + + MsnSoapMessage *message; + + GQueue *queue; + MsnSoapRequest *current_request; +} MsnSoapConnection; + +static void msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data); +static gboolean msn_soap_connection_run(gpointer data); + +static MsnSoapConnection *msn_soap_connection_new(MsnSession *session, + const char *host); +static void msn_soap_connection_handle_next(MsnSoapConnection *conn); +static void msn_soap_connection_destroy(MsnSoapConnection *conn); + +static void msn_soap_message_send_internal(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data, gboolean first); + +static void msn_soap_request_destroy(MsnSoapRequest *req); +static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect); + +static gboolean +msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data) +{ + MsnSoapConnection *conn = value; + time_t *t = data; + + if ((*t - conn->last_used) > SOAP_TIMEOUT * 2) { + purple_debug_info("soap", "cleaning up soap conn %p\n", conn); + return TRUE; + } + + return FALSE; +} + +static gboolean +msn_soap_cleanup_for_session(gpointer data) +{ + MsnSession *sess = data; + time_t t = time(NULL); + + purple_debug_info("soap", "session cleanup timeout\n"); + + if (sess->soap_table) { + g_hash_table_foreach_remove(sess->soap_table, msn_soap_cleanup_each, + &t); + + if (g_hash_table_size(sess->soap_table) == 0) { + purple_timeout_remove(sess->soap_cleanup_handle); + sess->soap_cleanup_handle = 0; + } + } + + return TRUE; +} + +static MsnSoapConnection * +msn_soap_get_connection(MsnSession *session, const char *host) +{ + MsnSoapConnection *conn = NULL; + + if (session->soap_table) { + conn = g_hash_table_lookup(session->soap_table, host); + } else { + session->soap_table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, (GDestroyNotify)msn_soap_connection_destroy); + } + + if (session->soap_cleanup_handle == 0) + session->soap_cleanup_handle = purple_timeout_add(SOAP_TIMEOUT * 1000, + msn_soap_cleanup_for_session, session); + + if (conn == NULL) { + conn = msn_soap_connection_new(session, host); + g_hash_table_insert(session->soap_table, conn->host, conn); + } + + conn->last_used = time(NULL); + + return conn; +} + +static MsnSoapConnection * +msn_soap_connection_new(MsnSession *session, const char *host) +{ + MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1); + conn->session = session; + conn->host = g_strdup(host); + conn->queue = g_queue_new(); + return conn; +} + +static void +msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl, + PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + + conn->connected = TRUE; + + if (conn->event_handle == 0) + conn->event_handle = g_idle_add(msn_soap_connection_run, conn); +} + +static void +msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error, + gpointer data) +{ + MsnSoapConnection *conn = data; + + g_hash_table_remove(conn->session->soap_table, conn->host); +} + +static gboolean +msn_soap_handle_redirect(MsnSoapConnection *conn, const char *url) +{ + char *c; + + /* Skip the http:// */ + if ((c = strchr(url, '/')) != NULL) + url += 2; + + if ((c = strchr(url, '/')) != NULL) { + char *host, *path; + + host = g_strndup(url, c - url); + path = g_strdup(c); + + msn_soap_message_send_internal(conn->session, + conn->current_request->message, host, path, + conn->current_request->cb, conn->current_request->cb_data, TRUE); + + msn_soap_request_destroy(conn->current_request); + conn->current_request = NULL; + + g_free(host); + g_free(path); + + return TRUE; + } + + return FALSE; +} + +static gboolean +msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response) +{ + xmlnode *body = xmlnode_get_child(response->xml, "Body"); + + if (body) { + MsnSoapRequest *request; + + if (strcmp(body->name, "Fault") == 0) { + xmlnode *fault = xmlnode_get_child(body, "faultcode"); + + if (fault != NULL) { + char *faultdata = xmlnode_get_data(fault); + + if (strcmp(faultdata, "psf:Redirect") == 0) { + xmlnode *url = xmlnode_get_child(body, "redirectUrl"); + + if (url) { + char *urldata = xmlnode_get_data(url); + msn_soap_handle_redirect(conn, urldata); + g_free(urldata); + } + + g_free(faultdata); + return TRUE; + } else if (strcmp(faultdata, "wsse:FailedAuthentication") == 0) { + xmlnode *reason = xmlnode_get_child(body, "faultstring"); + char *reasondata = xmlnode_get_data(reason); + + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_AUTH, + reasondata); + + g_free(reasondata); + g_free(faultdata); + return FALSE; + } + + g_free(faultdata); + } + } + + request = conn->current_request; + conn->current_request = NULL; + request->cb(request->message, response, + request->cb_data); + msn_soap_request_destroy(request); + } + + return TRUE; +} + +static void +msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + int count; + char buf[8192]; + char *linebreak; + char *cursor; + gboolean handled = FALSE; + + g_return_if_fail(cond == PURPLE_INPUT_READ); + + count = purple_ssl_read(conn->ssl, buf, sizeof(buf)); + purple_debug_info("soap", "read %d bytes\n", count); + if (count < 0 && errno == EAGAIN) + return; + else if (count <= 0) { + purple_debug_info("soap", "read: %s\n", strerror(errno)); + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + return; + } + + if (conn->message == NULL) { + conn->message = msn_soap_message_new(NULL, NULL); + } + + if (conn->buf == NULL) { + conn->buf = g_string_new_len(buf, count); + } else { + g_string_append_len(conn->buf, buf, count); + } + + purple_debug_info("soap", "current %s\n", conn->buf->str); + + cursor = conn->buf->str + conn->handled_len; + + if (!conn->headers_done) { + while ((linebreak = strstr(cursor, "\r\n")) != NULL) { + conn->handled_len = linebreak - conn->buf->str + 2; + + if (conn->response_code == 0) { + if (sscanf(cursor, "HTTP/1.1 %d", &conn->response_code) != 1) { + /* something horribly wrong */ + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + handled = TRUE; + break; + } else if (conn->response_code == 503) { + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL); + return; + } + } else if (cursor == linebreak) { + /* blank line */ + conn->headers_done = TRUE; + cursor = conn->buf->str + conn->handled_len; + break; + } else { + char *line = g_strndup(cursor, linebreak - cursor); + char *sep = strstr(line, ": "); + char *key = line; + char *value; + + if (sep == NULL) { + purple_debug_info("soap", "ignoring malformed line: %s\n", line); + g_free(line); + goto loop_end; + } + + value = sep + 2; + *sep = '\0'; + msn_soap_message_add_header(conn->message, key, value); + + if ((conn->response_code == 301 || conn->response_code == 300) + && strcmp(key, "Location") == 0) { + + msn_soap_handle_redirect(conn, value); + + handled = TRUE; + g_free(line); + break; + } else if (conn->response_code == 401 && + strcmp(key, "WWW-Authenticate") == 0) { + char *error = strstr(value, "cbtxt="); + + if (error) { + error += strlen("cbtxt="); + } + + msn_soap_connection_sanitize(conn, TRUE); + msn_session_set_error(conn->session, MSN_ERROR_AUTH, + error ? purple_url_decode(error) : NULL); + + g_free(line); + return; + } else if (strcmp(key, "Content-Length") == 0) { + conn->body_len = atoi(value); + } else if (strcmp(key, "Connection") == 0) { + if (strcmp(value, "close") == 0) { + conn->close_when_done = TRUE; + } + } + g_free(line); + } + + loop_end: + cursor = conn->buf->str + conn->handled_len; + } + } + + if (!handled && conn->headers_done) { + if (conn->buf->len - conn->handled_len >= + conn->body_len) { + xmlnode *node = xmlnode_from_str(cursor, conn->body_len); + + if (node == NULL) { + purple_debug_info("soap", "Malformed SOAP response: %s\n", + cursor); + } else { + MsnSoapMessage *message = conn->message; + conn->message = NULL; + message->xml = node; + + if (!msn_soap_handle_body(conn, message)) + return; + } + + msn_soap_connection_handle_next(conn); + } + + return; + } + + if (handled) { + msn_soap_connection_handle_next(conn); + } +} + +static void +msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond) +{ + MsnSoapConnection *conn = data; + int written; + + g_return_if_fail(cond == PURPLE_INPUT_WRITE); + + written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len, + conn->buf->len - conn->handled_len); + + if (written < 0 && errno == EAGAIN) + return; + else if (written <= 0) { + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); + return; + } + + conn->handled_len += written; + + if (conn->handled_len < conn->buf->len) + return; + + /* we are done! */ + g_string_free(conn->buf, TRUE); + conn->buf = NULL; + conn->handled_len = 0; + conn->body_len = 0; + conn->response_code = 0; + conn->headers_done = FALSE; + conn->close_when_done = FALSE; + + purple_input_remove(conn->event_handle); + conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ, + msn_soap_read_cb, conn); +} + +static gboolean +msn_soap_connection_run(gpointer data) +{ + MsnSoapConnection *conn = data; + MsnSoapRequest *req = g_queue_peek_head(conn->queue); + + conn->event_handle = 0; + + if (req) { + if (conn->ssl == NULL) { + conn->ssl = purple_ssl_connect(conn->session->account, conn->host, + 443, msn_soap_connected_cb, msn_soap_error_cb, conn); + } else if (conn->connected) { + int len = -1; + char *body = xmlnode_to_str(req->message->xml, &len); + GSList *iter; + char *authstr = NULL; + + g_queue_pop_head(conn->queue); + + conn->buf = g_string_new(""); + + if (conn->session->passport_info.mspauth) + authstr = g_strdup_printf("Cookie: MSPAuth=%s\r\n", + conn->session->passport_info.mspauth); + + + g_string_append_printf(conn->buf, + "POST %s HTTP/1.1\r\n" + "SOAPAction: %s\r\n" + "Content-Type:text/xml; charset=utf-8\r\n" + "%s" + "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" + "Accept: */*\r\n" + "Host: %s\r\n" + "Content-Length: %d\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n", + req->path, req->message->action ? req->message->action : "", + authstr ? authstr : "", conn->host, len); + + for (iter = req->message->headers; iter; iter = iter->next) { + g_string_append(conn->buf, (char *)iter->data); + g_string_append(conn->buf, "\r\n"); + } + + g_string_append(conn->buf, "\r\n"); + g_string_append(conn->buf, body); + + purple_debug_info("soap", "%s\n", conn->buf->str); + + conn->handled_len = 0; + conn->current_request = req; + + conn->event_handle = purple_input_add(conn->ssl->fd, + PURPLE_INPUT_WRITE, msn_soap_write_cb, conn); + msn_soap_write_cb(conn, conn->ssl->fd, PURPLE_INPUT_WRITE); + + g_free(authstr); + g_free(body); + } + } + + return FALSE; +} + +void +msn_soap_message_send(MsnSession *session, MsnSoapMessage *message, + const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data) +{ + msn_soap_message_send_internal(session, message, host, path, cb, cb_data, + FALSE); +} + +static void +msn_soap_message_send_internal(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data, gboolean first) +{ + MsnSoapConnection *conn = msn_soap_get_connection(session, host); + MsnSoapRequest *req = g_new0(MsnSoapRequest, 1); + + req->path = g_strdup(path); + req->message = message; + req->cb = cb; + req->cb_data = cb_data; + + if (first) { + g_queue_push_head(conn->queue, req); + } else { + g_queue_push_tail(conn->queue, req); + } + + if (conn->event_handle == 0) + conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, + conn); +} + +static void +msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect) +{ + if (conn->event_handle) { + purple_input_remove(conn->event_handle); + conn->event_handle = 0; + } + + if (conn->message) { + msn_soap_message_destroy(conn->message); + conn->message = NULL; + } + + if (conn->buf) { + g_string_free(conn->buf, TRUE); + conn->buf = NULL; + } + + if (conn->ssl && (disconnect || conn->close_when_done)) { + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + } + + if (conn->current_request) { + msn_soap_request_destroy(conn->current_request); + conn->current_request = NULL; + } +} + +static void +msn_soap_connection_handle_next(MsnSoapConnection *conn) +{ + msn_soap_connection_sanitize(conn, FALSE); + + conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn); + + if (conn->current_request) { + MsnSoapRequest *req = conn->current_request; + conn->current_request = NULL; + msn_soap_connection_destroy_foreach_cb(req, conn); + } +} + +static void +msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data) +{ + MsnSoapRequest *req = item; + + if (req->cb) + req->cb(req->message, NULL, req->cb_data); + + msn_soap_request_destroy(req); +} + +static void +msn_soap_connection_destroy(MsnSoapConnection *conn) +{ + if (conn->current_request) { + MsnSoapRequest *req = conn->current_request; + conn->current_request = NULL; + msn_soap_connection_destroy_foreach_cb(req, conn); + } + + msn_soap_connection_sanitize(conn, TRUE); + g_queue_foreach(conn->queue, msn_soap_connection_destroy_foreach_cb, conn); + g_queue_free(conn->queue); + + g_free(conn->host); + g_free(conn); +} + +MsnSoapMessage * +msn_soap_message_new(const char *action, xmlnode *xml) +{ + MsnSoapMessage *message = g_new0(MsnSoapMessage, 1); + + message->action = g_strdup(action); + message->xml = xml; + + return message; +} + +void +msn_soap_message_destroy(MsnSoapMessage *message) +{ + if (message) { + g_slist_foreach(message->headers, (GFunc)g_free, NULL); + g_slist_free(message->headers); + g_free(message->action); + if (message->xml) + xmlnode_free(message->xml); + g_free(message); + } +} + +void +msn_soap_message_add_header(MsnSoapMessage *req, + const char *name, const char *value) +{ + char *header = g_strdup_printf("%s: %s\r\n", name, value); + + req->headers = g_slist_prepend(req->headers, header); +} + +static void +msn_soap_request_destroy(MsnSoapRequest *req) +{ + g_free(req->path); + msn_soap_message_destroy(req->message); + g_free(req); +} + +xmlnode * +msn_soap_xml_get(xmlnode *parent, const char *node) +{ + xmlnode *ret = NULL; + char **tokens = g_strsplit(node, "/", -1); + int i; + + for (i = 0; tokens[i]; i++) { + if ((ret = xmlnode_get_child(parent, tokens[i])) != NULL) + parent = ret; + else + break; + } + + g_strfreev(tokens); + return ret; +} + diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/soap2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap2.h Sat Nov 03 09:20:20 2007 +0000 @@ -0,0 +1,58 @@ +/** + * @file soap2.h + * header file for SOAP connection related process + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MSN_SOAP2_H +#define _MSN_SOAP2_H + +#include "session.h" +#include "sslconn.h" +#include "xmlnode.h" + +#include + +typedef struct _MsnSoapMessage MsnSoapMessage; +typedef void (*MsnSoapCallback)(MsnSoapMessage *request, + MsnSoapMessage *response, gpointer cb_data); + +struct _MsnSoapMessage { + char *action; + xmlnode *xml; + GSList *headers; +}; + +MsnSoapMessage *msn_soap_message_new(const char *action, xmlnode *xml); + +void msn_soap_message_add_header(MsnSoapMessage *req, + const char *name, const char *value); + +void msn_soap_message_send(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data); + +void msn_soap_message_destroy(MsnSoapMessage *message); + +xmlnode *msn_soap_xml_get(xmlnode *parent, const char *node); + +#endif diff -r dd95454ddf90 -r f3a995c30205 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Fri Nov 02 09:59:24 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Sat Nov 03 09:20:20 2007 +0000 @@ -70,7 +70,7 @@ { MsnSession *session = pa->gc->proto_data; MsnUserList *userlist = session->userlist; - MsnCallbackState *state = msn_callback_state_new(); + MsnCallbackState *state = msn_callback_state_new(session); msn_callback_state_set_action(state, MSN_DENIED_BUDDY); @@ -680,7 +680,7 @@ purple_debug_info("MSN Userlist", "Add user: %s to group: %s\n", who, new_group_name); - state = msn_callback_state_new(); + state = msn_callback_state_new(userlist->session); msn_callback_state_set_who(state, who); msn_callback_state_set_new_group_name(state, new_group_name); @@ -841,7 +841,7 @@ g_return_if_fail(userlist->session != NULL); g_return_if_fail(userlist->session->contact != NULL); - state = msn_callback_state_new(); + state = msn_callback_state_new(userlist->session); msn_callback_state_set_who(state, who); msn_callback_state_set_action(state, MSN_MOVE_BUDDY); msn_callback_state_set_old_group_name(state, old_group_name); diff -r dd95454ddf90 -r f3a995c30205 pidgin/gtkdialogs.c