Mercurial > pidgin.yaz
changeset 23570:5dafc77b169e
propagate from branch 'im.pidgin.pidgin' (head 3fc4df7332983d84a3632b6372c6f7c894b529a3)
to branch 'im.pidgin.cpw.qulogic.msn' (head 52e1d7af9c625e154c0c5cb4d4c124396e878dd1)
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Sat, 12 Jul 2008 07:32:05 +0000 |
parents | 35673f4abf46 (current diff) a2f06797a1b0 (diff) |
children | af2cfc9a42b3 |
files | libpurple/protocols/msn/soap2.c libpurple/protocols/msn/soap2.h |
diffstat | 33 files changed, 3073 insertions(+), 3181 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/msn/Makefile.am Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/Makefile.am Sat Jul 12 07:32:05 2008 +0000 @@ -50,10 +50,8 @@ slpmsg.h \ slpsession.c \ slpsession.h \ - soap.c\ - soap.h\ - soap2.c \ - soap2.h \ + soap.c \ + soap.h \ state.c \ state.h \ switchboard.c \
--- a/libpurple/protocols/msn/command.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/command.c Sat Jul 12 07:32:05 2008 +0000 @@ -36,53 +36,6 @@ return TRUE; } -/* - * check the command is the command with payload content - * if it is return TRUE - * else return FALSE - */ -static gboolean -msn_check_payload_cmd(const char *str) -{ - g_return_val_if_fail(str != NULL, FALSE); - - if((!strcmp(str,"ADL")) || - (!strcmp(str,"GCF")) || - (!strcmp(str,"SG")) || - (!strcmp(str,"MSG")) || - (!strcmp(str,"RML")) || - (!strcmp(str,"UBX")) || - (!strcmp(str,"UBN")) || - (!strcmp(str,"UUM")) || - (!strcmp(str,"UBM")) || - (!strcmp(str,"FQY")) || - (!strcmp(str,"UUN")) || - (!strcmp(str,"UUX")) || - (!strcmp(str,"IPG")) || - (is_num(str))){ - return TRUE; - } - - return FALSE; -} - -/* - * set command Payload length - */ -static void -msn_set_payload_len(MsnCommand *cmd) -{ - char *param; - int len = 0; - - if (msn_check_payload_cmd(cmd->command) && (cmd->param_count > 0)){ - param = cmd->params[cmd->param_count - 1]; - len = is_num(param) ? atoi(param) : 0; - } - - cmd->payload_len = len; -} - MsnCommand * msn_command_from_string(const char *string) { @@ -103,26 +56,23 @@ if (cmd->params != NULL) { - char *param; int c; for (c = 0; cmd->params[c]; c++); cmd->param_count = c; - param = cmd->params[0]; - - cmd->trId = is_num(param) ? atoi(param) : 0; + if (cmd->param_count) { + char *param = cmd->params[0]; + cmd->trId = is_num(param) ? atoi(param) : 0; + } else { + cmd->trId = 0; + } } else { cmd->trId = 0; } - /* khc: Huh! */ - /*add payload Length checking*/ - msn_set_payload_len(cmd); - purple_debug_info("MSNP14","get payload len:%" G_GSIZE_FORMAT "\n", cmd->payload_len); - msn_command_ref(cmd); return cmd;
--- a/libpurple/protocols/msn/contact.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/contact.c Sat Jul 12 07:32:05 2008 +0000 @@ -1,5 +1,5 @@ /** - * @file contact.c + * @file contact.c * get MSN contacts via SOAP request * created by MaYuan<mayuan2006@gmail.com> * @@ -28,7 +28,8 @@ #include "contact.h" #include "xmlnode.h" #include "group.h" -#include "soap2.h" +#include "soap.h" +#include "nexus.h" const char *MsnSoapPartnerScenarioText[] = { @@ -49,29 +50,10 @@ }; typedef struct { - MsnContact *contact; + MsnSession *session; MsnSoapPartnerScenario which; } GetContactListCbData; -/* new a contact */ -MsnContact * -msn_contact_new(MsnSession *session) -{ - MsnContact *contact; - - contact = g_new0(MsnContact, 1); - contact->session = session; - - return contact; -} - -/* destroy the contact */ -void -msn_contact_destroy(MsnContact *contact) -{ - g_free(contact); -} - MsnCallbackState * msn_callback_state_new(MsnSession *session) { @@ -82,6 +64,22 @@ return state; } +MsnCallbackState * +msn_callback_state_dup(MsnCallbackState *state) +{ + MsnCallbackState *new_state = g_new0(MsnCallbackState, 1); + + new_state->session = state->session; + new_state->who = g_strdup(state->who); + new_state->uid = g_strdup(state->uid); + new_state->old_group_name = g_strdup(state->old_group_name); + new_state->new_group_name = g_strdup(state->new_group_name); + new_state->guid = g_strdup(state->guid); + /* The rest should be made new */ + + return new_state; +} + void msn_callback_state_free(MsnCallbackState *state) { @@ -93,6 +91,7 @@ g_free(state->old_group_name); g_free(state->new_group_name); g_free(state->guid); + xmlnode_free(state->body); g_free(state); } @@ -177,56 +176,60 @@ return 0; } -/*get User Type*/ -static int -msn_get_user_type(char *type) +/* get Network */ +/* QuLogic: These names don't really refer to the MsnNetwork, + * but I haven't yet written the code to properly use them. + */ +static MsnNetwork +msn_get_network(char *type) { g_return_val_if_fail(type != NULL, 0); if (!strcmp(type,"Regular")) { - return MSN_USER_TYPE_PASSPORT; + return MSN_NETWORK_PASSPORT; } if (!strcmp(type,"Live")) { - return MSN_USER_TYPE_PASSPORT; + return MSN_NETWORK_PASSPORT; } if (!strcmp(type,"LivePending")) { - return MSN_USER_TYPE_PASSPORT; + return MSN_NETWORK_PASSPORT; } - return MSN_USER_TYPE_UNKNOWN; + return MSN_NETWORK_UNKNOWN; } /* Create the AddressBook in the server, if we don't have one */ static void msn_create_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - 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); + if (resp && xmlnode_get_child(resp->xml, "Body/Fault") == NULL) { + purple_debug_info("msn", "Address Book successfully created!\n"); + msn_get_address_book((MsnSession *)data, MSN_PS_INITIAL, NULL, NULL); } else { - purple_debug_info("msnab", "Address Book creation failed!\n"); + purple_debug_info("msn", "Address Book creation failed!\n"); } } static void -msn_create_address_book(MsnContact * contact) +msn_create_address_book(MsnSession *session) { gchar *body; - g_return_if_fail(contact != NULL); - g_return_if_fail(contact->session != NULL); - g_return_if_fail(contact->session->user != NULL); - g_return_if_fail(contact->session->user->passport != NULL); + g_return_if_fail(session != NULL); + g_return_if_fail(session->user != NULL); + g_return_if_fail(session->user->passport != NULL); + + purple_debug_info("msn", "Creating an Address Book.\n"); - purple_debug_info("msnab","Creating an Address Book.\n"); + body = g_markup_printf_escaped(MSN_ADD_ADDRESSBOOK_TEMPLATE, + msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), + session->user->passport); - body = g_strdup_printf(MSN_ADD_ADDRESSBOOK_TEMPLATE, contact->session->user->passport); - - msn_soap_message_send(contact->session, + msn_soap_message_send(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); + session); g_free(body); } @@ -240,7 +243,7 @@ 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, MembershipID: %s\n", + purple_debug_info("msn", "CL: %s name: %s, Type: %s, MembershipID: %s\n", node, passport, type, member_id == NULL ? "(null)" : member_id); if (member_id) { @@ -259,7 +262,7 @@ { xmlnode *type; - if ((type = msn_soap_xml_get(service, "Info/Handle/Type"))) { + if ((type = xmlnode_get_child(service, "Info/Handle/Type"))) { char *type_str = xmlnode_get_data(type); if (g_str_equal(type_str, "Profile")) { @@ -269,11 +272,11 @@ char *lastchange_str = xmlnode_get_data(lastchange); xmlnode *membership; - purple_debug_info("msncl","last change: %s\n", lastchange_str); + purple_debug_info("msn", "CL last change: %s\n", lastchange_str); purple_account_set_string(session->account, "CLLastChange", lastchange_str); - for (membership = msn_soap_xml_get(service, + for (membership = xmlnode_get_child(service, "Memberships/Membership"); membership; membership = xmlnode_get_next_twin(membership)) { @@ -282,10 +285,10 @@ MsnListId list = msn_get_memberrole(role_str); xmlnode *member; - purple_debug_info("msncl", "MemberRole role: %s, list: %d\n", + purple_debug_info("msn", "CL MemberRole role: %s, list: %d\n", role_str, list); - for (member = msn_soap_xml_get(membership, "Members/Member"); + for (member = xmlnode_get_child(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")) { @@ -310,7 +313,7 @@ /*parse contact list*/ static void -msn_parse_contact_list(MsnContact *contact, xmlnode *node) +msn_parse_contact_list(MsnSession *session, xmlnode *node) { xmlnode *fault, *faultnode; @@ -321,18 +324,18 @@ * * this is not handled yet */ - if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + if ((fault = xmlnode_get_child(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", + purple_debug_info("msn", "Retrieving contact list failed: %s\n", faultstring); g_free(faultstring); } - if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) { char *errorcode = xmlnode_get_data(faultnode); if (g_str_equal(errorcode, "ABDoesNotExist")) { - msn_create_address_book(contact); + msn_create_address_book(session); g_free(errorcode); return; } @@ -340,14 +343,14 @@ g_free(errorcode); } - msn_get_contact_list(contact, MSN_PS_INITIAL, NULL); + msn_get_contact_list(session, MSN_PS_INITIAL, NULL); } else { xmlnode *service; - for (service = msn_soap_xml_get(node, "Body/FindMembershipResponse/" + for (service = xmlnode_get_child(node, "Body/FindMembershipResponse/" "FindMembershipResult/Services/Service"); service; service = xmlnode_get_next_twin(service)) { - msn_parse_each_service(contact->session, service); + msn_parse_each_service(session, service); } } } @@ -357,8 +360,7 @@ gpointer data) { GetContactListCbData *cb_data = data; - MsnContact *contact = cb_data->contact; - MsnSession *session = contact->session; + MsnSession *session = cb_data->session; g_return_if_fail(session != NULL); @@ -366,9 +368,9 @@ const char *abLastChange; const char *dynamicItemLastChange; - purple_debug_misc("msncl","Got the contact list!\n"); + purple_debug_misc("msn", "Got the contact list!\n"); - msn_parse_contact_list(cb_data->contact, resp->xml); + msn_parse_contact_list(session, resp->xml); abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); dynamicItemLastChange = purple_account_get_string(session->account, @@ -379,9 +381,9 @@ /* 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); + msn_get_address_book(session, MSN_PS_INITIAL, abLastChange, dynamicItemLastChange); #else - msn_get_address_book(contact, MSN_PS_INITIAL, NULL, NULL); + msn_get_address_book(session, MSN_PS_INITIAL, NULL, NULL); #endif } } @@ -391,24 +393,26 @@ /*SOAP get contact list*/ void -msn_get_contact_list(MsnContact * contact, +msn_get_contact_list(MsnSession *session, const MsnSoapPartnerScenario partner_scenario, const char *update_time) { gchar *body = NULL; gchar *update_str = NULL; - GetContactListCbData cb_data = { contact, partner_scenario }; + GetContactListCbData cb_data = { session, partner_scenario }; const gchar *partner_scenario_str = MsnSoapPartnerScenarioText[partner_scenario]; - purple_debug_misc("MSNCL","Getting Contact List.\n"); + purple_debug_misc("msn", "Getting Contact List.\n"); - if ( update_time != NULL ) { - purple_debug_info("MSNCL","Last update time: %s\n",update_time); + if (update_time != NULL) { + purple_debug_info("msn", "CL Last update time: %s\n", update_time); update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time); } - body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, update_str ? update_str : ""); + body = g_markup_printf_escaped(MSN_GET_CONTACT_TEMPLATE, partner_scenario_str, + msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), + update_str ? update_str : ""); - msn_soap_message_send(contact->session, + msn_soap_message_send(session, msn_soap_message_new(MSN_GET_CONTACT_SOAP_ACTION, xmlnode_from_str(body, -1)), MSN_CONTACT_SERVER, MSN_GET_CONTACT_POST_URL, @@ -419,12 +423,11 @@ } static void -msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node) +msn_parse_addressbook_groups(MsnSession *session, xmlnode *node) { - MsnSession *session = contact->session; xmlnode *group; - purple_debug_info("MSNAB","msn_parse_addressbook_groups()\n"); + purple_debug_info("msn", "msn_parse_addressbook_groups()\n"); for(group = xmlnode_get_child(node, "Group"); group; group = xmlnode_get_next_twin(group)){ @@ -444,7 +447,7 @@ continue; } - purple_debug_info("MsnAB","group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)"); + purple_debug_info("msn", "AB group_id: %s, name: %s\n", group_id, group_name ? group_name : "(null)"); if ((purple_find_group(group_name)) == NULL){ PurpleGroup *g = purple_group_new(group_name); purple_blist_add_group(g, NULL); @@ -507,18 +510,19 @@ } static void -msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node) +msn_parse_addressbook_contacts(MsnSession *session, xmlnode *node) { - MsnSession *session = contact->session; xmlnode *contactNode; - char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL, *mobile_number = NULL; + char *passport = NULL, *Name = NULL, *uid = NULL, *type = NULL, *mobile_number = NULL, *alias = NULL; gboolean mobile = FALSE; + PurpleConnection *pc = purple_account_get_connection(session->account); for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; contactNode = xmlnode_get_next_twin(contactNode)) { xmlnode *contactId, *contactInfo, *contactType, *passportName, *displayName, *guid, *groupIds, *messenger_user; + xmlnode *annotation; MsnUser *user; - MsnUserType usertype; + MsnNetwork networkId; if (!(contactId = xmlnode_get_child(contactNode,"contactId")) || !(contactInfo = xmlnode_get_child(contactNode, "contactInfo")) @@ -527,10 +531,11 @@ g_free(passport); g_free(Name); + g_free(alias); g_free(uid); g_free(type); g_free(mobile_number); - passport = Name = uid = type = mobile_number = NULL; + passport = Name = uid = type = mobile_number = alias = NULL; mobile = FALSE; uid = xmlnode_get_data(contactId); @@ -547,7 +552,7 @@ } /* ignore non-messenger contacts */ - if((messenger_user = xmlnode_get_child(contactInfo, "isMessengerUser"))) { + if ((messenger_user = xmlnode_get_child(contactInfo, "isMessengerUser"))) { char *is_messenger_user = xmlnode_get_data(messenger_user); if(is_messenger_user && !strcmp(is_messenger_user, "false")) { @@ -558,7 +563,7 @@ g_free(is_messenger_user); } - usertype = msn_get_user_type(type); + networkId = msn_get_network(type); passportName = xmlnode_get_child(contactInfo, "passportName"); if (passportName == NULL) { xmlnode *emailsNode, *contactEmailNode, *emailNode; @@ -572,7 +577,7 @@ /*TODO: need to support the Mobile type*/ continue; } - for(contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode; + for (contactEmailNode = xmlnode_get_child(emailsNode, "ContactEmail"); contactEmailNode; contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){ if (!(messengerEnabledNode = xmlnode_get_child(contactEmailNode, "isMessengerEnabled"))) { /* XXX: Should this be a continue instead of a break? It seems like it'd cause unpredictable results otherwise. */ @@ -586,15 +591,15 @@ passport = xmlnode_get_data(emailNode); } - if(msnEnabled && !strcmp(msnEnabled, "true")) { + if (msnEnabled && !strcmp(msnEnabled, "true")) { /*Messenger enabled, Get the Passport*/ - purple_debug_info("MsnAB", "Yahoo User %s\n", passport ? passport : "(null)"); - usertype = MSN_USER_TYPE_YAHOO; + purple_debug_info("msn", "AB Yahoo User %s\n", passport ? passport : "(null)"); + networkId = MSN_NETWORK_YAHOO; g_free(msnEnabled); break; } else { /*TODO maybe we can just ignore it in Purple?*/ - purple_debug_info("MSNAB", "Other type user\n"); + purple_debug_info("msn", "AB Other type user\n"); } g_free(msnEnabled); @@ -611,24 +616,33 @@ else Name = g_strdup(passport); + for (annotation = xmlnode_get_child(contactInfo, "annotations/Annotation"); + annotation; annotation = xmlnode_get_next_twin(annotation)) { + char *name; + name = xmlnode_get_data(xmlnode_get_child(annotation, "Name")); + if (!strcmp(name, "AB.NickName")) + alias = xmlnode_get_data(xmlnode_get_child(annotation, "Value")); + g_free(name); + } + mobile = msn_parse_addressbook_mobile(contactInfo, &mobile_number); - purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s} mobile:{%s} mobile number:{%s}\n", - passport, uid ? uid : "(null)", Name ? Name : "(null)", + purple_debug_misc("msn", "AB passport:{%s} uid:{%s} display:{%s} alias: {%s} mobile:{%s} mobile number:{%s}\n", + passport, uid ? uid : "(null)", Name ? Name : "(null)", alias ? alias : "(null)", mobile ? "true" : "false", mobile_number ? mobile_number : "(null)"); user = msn_userlist_find_add_user(session->userlist, passport, Name); msn_user_set_uid(user, uid); - msn_user_set_type(user, usertype); + msn_user_set_network(user, networkId); msn_user_set_mobile_phone(user, mobile_number); groupIds = xmlnode_get_child(contactInfo, "groupIds"); if (groupIds) { for (guid = xmlnode_get_child(groupIds, "guid"); guid; - guid = xmlnode_get_next_twin(guid)){ + guid = xmlnode_get_next_twin(guid)) { char *group_id = xmlnode_get_data(guid); msn_user_add_group_id(user, group_id); - purple_debug_misc("MsnAB", "guid:%s\n", group_id ? group_id : "(null)"); + purple_debug_misc("msn", "AB guid:%s\n", group_id ? group_id : "(null)"); g_free(group_id); } } else { @@ -639,12 +653,14 @@ msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL); - if(mobile && user) + if (mobile && user) { user->mobile = TRUE; purple_prpl_got_user_status(session->account, user->passport, "mobile", NULL); purple_prpl_got_user_status(session->account, user->passport, "available", NULL); } + if (alias) + purple_serv_got_private_alias(pc, passport, alias); } g_free(passport); @@ -655,30 +671,27 @@ } static gboolean -msn_parse_addressbook(MsnContact * contact, xmlnode *node) +msn_parse_addressbook(MsnSession *session, xmlnode *node) { - MsnSession * session; xmlnode *result; xmlnode *groups; xmlnode *contacts; xmlnode *abNode; xmlnode *fault; - session = contact->session; - - if ((fault = msn_soap_xml_get(node, "Body/Fault"))) { + if ((fault = xmlnode_get_child(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); + purple_debug_info("msn", "AB Faultstring: %s\n", faultstring); g_free(faultstring); } - if ((faultnode = msn_soap_xml_get(fault, "detail/errorcode"))) { + if ((faultnode = xmlnode_get_child(fault, "detail/errorcode"))) { gchar *errorcode = xmlnode_get_data(faultnode); - purple_debug_info("MSNAB", "Error Code: %s\n", errorcode); + purple_debug_info("msn", "AB Error Code: %s\n", errorcode); if (g_str_equal(errorcode, "ABDoesNotExist")) { g_free(errorcode); @@ -690,24 +703,24 @@ return FALSE; } - result = msn_soap_xml_get(node, "Body/ABFindAllResponse/ABFindAllResult"); - if(result == NULL){ - purple_debug_misc("MSNAB","receive no address book update\n"); + result = xmlnode_get_child(node, "Body/ABFindAllResponse/ABFindAllResult"); + if (result == NULL) { + purple_debug_misc("msn", "Received no address book update\n"); return TRUE; } /* 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"); + groups = xmlnode_get_child(result, "groups"); if (groups != NULL) { - msn_parse_addressbook_groups(contact, groups); + msn_parse_addressbook_groups(session, groups); } /*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("msn", "AB 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); @@ -716,33 +729,33 @@ /*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); - if ((purple_find_group(MSN_NON_IM_GROUP_NAME)) == NULL){ + purple_debug_misc("msn", "AB 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); } /*Process contact List*/ - purple_debug_info("MSNAB","process contact list...\n"); - contacts =xmlnode_get_child(result,"contacts"); + purple_debug_info("msn", "Process contact list...\n"); + contacts = xmlnode_get_child(result, "contacts"); if (contacts != NULL) { - msn_parse_addressbook_contacts(contact, contacts); + msn_parse_addressbook_contacts(session, contacts); } - abNode =xmlnode_get_child(result,"ab"); - if(abNode != NULL){ + abNode = xmlnode_get_child(result, "ab"); + if (abNode != NULL) { xmlnode *node2; char *tmp = NULL; 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("msn", "AB lastchanged Time:{%s}\n", tmp ? tmp : "(null)"); purple_account_set_string(session->account, "ablastChange", tmp); g_free(tmp); tmp = NULL; if ((node2 = xmlnode_get_child(abNode, "DynamicItemLastChanged"))) tmp = xmlnode_get_data(node2); - purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)"); + purple_debug_info("msn", "AB DynamicItemLastChanged :{%s}\n", tmp ? tmp : "(null)"); purple_account_set_string(session->account, "DynamicItemLastChanged", tmp); g_free(tmp); } @@ -753,19 +766,16 @@ static void msn_get_address_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - MsnContact *contact = data; - MsnSession *session; + MsnSession *session = data; if (resp == NULL) return; - g_return_if_fail(contact != NULL); - session = contact->session; g_return_if_fail(session != NULL); - purple_debug_misc("MSNAB", "Got the Address Book!\n"); + purple_debug_misc("msn", "Got the Address Book!\n"); - if (msn_parse_addressbook(contact, resp->xml)) { + if (msn_parse_addressbook(session, resp->xml)) { if (!session->logged_in) { msn_send_privacy(session->account->gc); msn_notification_dump_contact(session); @@ -776,7 +786,7 @@ send timestamps) */ /* - msn_get_address_book(contact, NULL, NULL); + msn_get_address_book(session, NULL, NULL); */ msn_session_disconnect(session); purple_connection_error_reason(session->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to retrieve MSN Address Book")); @@ -785,13 +795,13 @@ /*get the address book*/ void -msn_get_address_book(MsnContact *contact, +msn_get_address_book(MsnSession *session, MsnSoapPartnerScenario partner_scenario, const char *LastChanged, const char *dynamicItemLastChange) { char *body, *update_str = NULL; - purple_debug_misc("MSNAB","Getting Address Book\n"); + purple_debug_misc("msn", "Getting Address Book\n"); /*build SOAP and POST it*/ if (dynamicItemLastChange != NULL) @@ -799,18 +809,120 @@ 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 : ""); + body = g_markup_printf_escaped(MSN_GET_ADDRESS_TEMPLATE, + MsnSoapPartnerScenarioText[partner_scenario], + msn_nexus_get_token_str(session->nexus, MSN_AUTH_CONTACTS), + update_str ? update_str : ""); - msn_soap_message_send(contact->session, + msn_soap_message_send(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); + session); g_free(update_str); g_free(body); } +/*************************************************************** + * Contact Operations + ***************************************************************/ + +static const char * +msn_contact_operation_str(MsnCallbackAction action) +{ + /* Make sure this is large enough when adding more */ + static char buf[BUF_LEN]; + buf[0] = '\0'; + + if (action & MSN_ADD_BUDDY) + strcat(buf, "Adding Buddy,"); + if (action & MSN_MOVE_BUDDY) + strcat(buf, "Moving Buddy,"); + if (action & MSN_ACCEPTED_BUDDY) + strcat(buf, "Accepted Buddy,"); + if (action & MSN_DENIED_BUDDY) + strcat(buf, "Denied Buddy,"); + if (action & MSN_ADD_GROUP) + strcat(buf, "Adding Group,"); + if (action & MSN_DEL_GROUP) + strcat(buf, "Deleting Group,"); + if (action & MSN_RENAME_GROUP) + strcat(buf, "Renaming Group,"); + if (action & MSN_UPDATE_INFO) + strcat(buf, "Updating Contact Info,"); + + return buf; +} + +static gboolean msn_contact_request(MsnCallbackState *state); + +static void +msn_contact_request_cb(MsnSoapMessage *req, MsnSoapMessage *resp, + gpointer data) +{ + MsnCallbackState *state = data; + xmlnode *faultcode; + char *faultcode_str; + + if (resp == NULL) { + purple_debug_error("msn", + "Operation {%s} failed. No response received from server.\n", + msn_contact_operation_str(state->action)); + return; + } + + faultcode = xmlnode_get_child(resp->xml, "Body/Fault/faultcode"); + + if (faultcode == NULL) { + /* No errors */ + if (state->cb) + ((MsnSoapCallback)state->cb)(req, resp, data); + msn_callback_state_free(state); + return; + } + + faultcode_str = xmlnode_get_data(faultcode); + + if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { + purple_debug_info("msn", + "Contact Operation {%s} failed because of bad token." + " Updating token now and retrying operation.\n", + msn_contact_operation_str(state->action)); + /* Token has expired, so renew it, and try again later */ + msn_nexus_update_token(state->session->nexus, MSN_AUTH_CONTACTS, + (GSourceFunc)msn_contact_request, data); + } + else + { + /* We don't know how to respond to this faultcode, so just log it */ + /* XXX: Probably should notify the user or undo the change or something? */ + char *str = xmlnode_to_str(xmlnode_get_child(resp->xml, "Body/Fault"), NULL); + purple_debug_error("msn", "Operation {%s} Failed, SOAP Fault was: %s\n", + msn_contact_operation_str(state->action), str); + g_free(str); + msn_callback_state_free(state); + } + + g_free(faultcode_str); +} + +static gboolean +msn_contact_request(MsnCallbackState *state) +{ + if (state->token == NULL) + state->token = xmlnode_get_child(state->body, + "Header/ABAuthHeader/TicketToken"); + /* delete old & replace with new token */ + xmlnode_free(state->token->child); + xmlnode_insert_data(state->token, + msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1); + msn_soap_message_send(state->session, + msn_soap_message_new(state->post_action, xmlnode_copy(state->body)), + MSN_CONTACT_SERVER, state->post_url, msn_contact_request_cb, state); + return FALSE; +} + static void msn_add_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) @@ -818,33 +930,32 @@ MsnCallbackState *state = data; MsnSession *session = state->session; + MsnUserList *userlist; + MsnUser *user; + g_return_if_fail(session != NULL); - if (resp != NULL) { - MsnUserList *userlist = session->userlist; - MsnUser *user; + userlist = session->userlist; - purple_debug_info("MSNCL","Contact added successfully\n"); + purple_debug_info("msn", "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(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(session, state->who); - - user = msn_userlist_find_add_user(userlist, state->who, state->who); - msn_user_add_group_id(user, state->guid); + /* 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); } - msn_callback_state_free(state); + msn_notification_send_fqy(session, state->who); + + user = msn_userlist_find_add_user(userlist, state->who, state->who); + msn_user_add_group_id(user, state->guid); } /* add a Contact in MSN_INDIVIDUALS_GROUP */ void -msn_add_contact(MsnContact *contact, MsnCallbackState *state, const char *passport) +msn_add_contact(MsnSession *session, MsnCallbackState *state, const char *passport) { gchar *body = NULL; gchar *contact_xml = NULL; @@ -861,16 +972,16 @@ 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); + purple_debug_info("msn", "Adding contact %s to contact list\n", 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_CONTACT_ADD_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_add_contact_read_cb; + msn_contact_request(state); g_free(contact_xml); g_free(body); @@ -887,41 +998,35 @@ userlist = state->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); - } + if (msn_userlist_add_buddy_to_group(userlist, state->who, + state->new_group_name)) { + purple_debug_info("msn", "Contact %s added to group %s successfully!\n", state->who, state->new_group_name); + } else { + purple_debug_info("msn", "Contact %s added to group %s successfully on server, but failed in the local list\n", state->who, state->new_group_name); + } - if (state->action & MSN_ADD_BUDDY) { - MsnUser *user = msn_userlist_find_user(userlist, state->who); - - if ( !msn_user_is_yahoo(state->session->account, state->who) ) { + if (state->action & MSN_ADD_BUDDY) { + MsnUser *user = msn_userlist_find_user(userlist, 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_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 (msn_userlist_user_is_in_list(user, MSN_LIST_PL)) { + msn_del_contact_from_list(state->session, NULL, state->who, MSN_LIST_PL); + return; } } - msn_callback_state_free(state); + if (state->action & MSN_MOVE_BUDDY) { + msn_del_contact_from_group(state->session, state->who, state->old_group_name); + } } void -msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, +msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state, const char *passport, const char *groupId) { MsnUserList *userlist; @@ -931,37 +1036,33 @@ g_return_if_fail(passport != NULL); g_return_if_fail(groupId != NULL); - g_return_if_fail(contact != NULL); - g_return_if_fail(contact->session != NULL); - g_return_if_fail(contact->session->userlist != NULL); + g_return_if_fail(session != NULL); - userlist = contact->session->userlist; + userlist = session->userlist; if (!strcmp(groupId, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(groupId, MSN_NON_IM_GROUP_ID)) { user = msn_userlist_find_add_user(userlist, passport, passport); if (state->action & MSN_ADD_BUDDY) { - msn_add_contact(contact, state, passport); + msn_add_contact(session, state, passport); return; } if (state->action & MSN_MOVE_BUDDY) { msn_user_add_group_id(user, groupId); - msn_del_contact_from_group(contact, passport, state->old_group_name); - } else { - msn_callback_state_free(state); + msn_del_contact_from_group(session, passport, state->old_group_name); } return; } - purple_debug_info("MSNCL", "Adding user %s to group %s\n", passport, + purple_debug_info("msn", "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("MSNCL", "Unable to retrieve user %s from the userlist!\n", passport); + purple_debug_warning("msn", "Unable to retrieve user %s from the userlist!\n", passport); msn_callback_state_free(state); return; /* guess this never happened! */ } @@ -974,11 +1075,11 @@ body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE, groupId, contact_xml); - 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_ADD_CONTACT_GROUP_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_add_contact_to_group_read_cb; + msn_contact_request(state); g_free(contact_xml); g_free(body); @@ -989,24 +1090,19 @@ gpointer data) { MsnCallbackState *state = data; - - if (resp != NULL) { - MsnUserList *userlist = state->session->userlist; - MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid); - - purple_debug_info("MSNCL","Delete contact successful\n"); + MsnUserList *userlist = state->session->userlist; + MsnUser *user = msn_userlist_find_user_with_id(userlist, state->uid); - if (user != NULL) { - msn_userlist_remove_user(userlist, user); - } + purple_debug_info("msn", "Delete contact successful\n"); + + if (user != NULL) { + msn_userlist_remove_user(userlist, user); } - - msn_callback_state_free(state); } /*delete a Contact*/ void -msn_delete_contact(MsnContact *contact, const char *contactId) +msn_delete_contact(MsnSession *session, const char *contactId) { gchar *body = NULL; gchar *contact_id_xml = NULL ; @@ -1015,17 +1111,18 @@ g_return_if_fail(contactId != NULL); contact_id_xml = g_strdup_printf(MSN_CONTACT_ID_XML, contactId); - state = msn_callback_state_new(contact->session); + state = msn_callback_state_new(session); msn_callback_state_set_uid(state, contactId); /* build SOAP request */ - purple_debug_info("MSNCL","Deleting contact with contactId: %s\n", contactId); + purple_debug_info("msn", "Deleting contact with contactId: %s\n", contactId); body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE, contact_id_xml); - 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); + + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_CONTACT_DEL_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_delete_contact_read_cb; + msn_contact_request(state); g_free(contact_id_xml); g_free(body); @@ -1037,20 +1134,16 @@ { MsnCallbackState *state = data; - 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); - } + if (msn_userlist_rem_buddy_from_group(state->session->userlist, + state->who, state->old_group_name)) { + purple_debug_info("msn", "Contact %s deleted successfully from group %s\n", state->who, state->old_group_name); + } else { + purple_debug_info("msn", "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); } void -msn_del_contact_from_group(MsnContact *contact, const char *passport, const char *group_name) +msn_del_contact_from_group(MsnSession *session, const char *passport, const char *group_name) { MsnUserList * userlist; MsnUser *user; @@ -1060,24 +1153,22 @@ g_return_if_fail(passport != NULL); g_return_if_fail(group_name != NULL); - g_return_if_fail(contact != NULL); - g_return_if_fail(contact->session != NULL); - g_return_if_fail(contact->session->userlist != NULL); + g_return_if_fail(session != NULL); - userlist = contact->session->userlist; + userlist = session->userlist; groupId = msn_userlist_find_group_id(userlist, group_name); if (groupId != NULL) { - purple_debug_info("MSNCL", "Deleting user %s from group %s\n", passport, group_name); + purple_debug_info("msn", "Deleting user %s from group %s\n", passport, group_name); } else { - purple_debug_warning("MSNCL", "Unable to retrieve group id from group %s !\n", group_name); + purple_debug_warning("msn", "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("MSNCL", "Unable to retrieve user from passport %s!\n", passport); + purple_debug_warning("msn", "Unable to retrieve user from passport %s!\n", passport); return; } @@ -1086,7 +1177,7 @@ return; } - state = msn_callback_state_new(contact->session); + state = msn_callback_state_new(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); @@ -1094,11 +1185,11 @@ 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_CONTACT_DEL_GROUP_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_del_contact_from_group_read_cb; + msn_contact_request(state); g_free(contact_id_xml); g_free(body); @@ -1109,32 +1200,75 @@ msn_update_contact_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - if (resp) - purple_debug_info("MSN CL","Contact updated successfully\n"); - else - purple_debug_info("MSN CL","Contact updated successfully\n"); + purple_debug_info("msn", "Contact updated successfully\n"); } -/* Update a contact's nickname */ +/* Update a contact's info */ void -msn_update_contact(MsnContact *contact, const char* nickname) +msn_update_contact(MsnSession *session, const char *passport, MsnContactUpdateType type, const char* value) { - gchar *body = NULL, *escaped_nickname; + MsnCallbackState *state; + xmlnode *contact; + xmlnode *contact_info; + xmlnode *changes; + + purple_debug_info("msn", "Update contact information with new %s: %s\n", + type==MSN_UPDATE_DISPLAY ? "display name" : "alias", value); + purple_debug_info("msn", "passport=%s\n", passport); + g_return_if_fail(passport != NULL); + contact_info = xmlnode_new("contactInfo"); + changes = xmlnode_new("propertiesChanged"); - purple_debug_info("MSN CL","Update contact information with new friendly name: %s\n", nickname); + switch (type) { + xmlnode *annotations; + xmlnode *display; + xmlnode *a, *n, *v; + case MSN_UPDATE_DISPLAY: + display = xmlnode_new_child(contact_info, "displayName"); + xmlnode_insert_data(display, value, -1); + xmlnode_insert_data(changes, "DisplayName", -1); + break; - escaped_nickname = g_markup_escape_text(nickname, -1); + case MSN_UPDATE_ALIAS: + annotations = xmlnode_new_child(contact_info, "annotations"); + xmlnode_insert_data(changes, "Annotation ", -1); - body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, escaped_nickname); + a = xmlnode_new_child(annotations, "Annotation"); + n = xmlnode_new_child(a, "Name"); + xmlnode_insert_data(n, "AB.NickName", -1); + v = xmlnode_new_child(a, "Value"); + xmlnode_insert_data(v, value, -1); + break; + + default: + g_return_if_reached(); + } + + + + state = msn_callback_state_new(session); - 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); + state->body = xmlnode_from_str(MSN_CONTACT_UPDATE_TEMPLATE, -1); + state->action = MSN_UPDATE_INFO; + state->post_action = MSN_CONTACT_UPDATE_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_update_contact_read_cb; + + contact = xmlnode_get_child(state->body, "Body/ABContactUpdate/contacts/Contact"); + xmlnode_insert_child(contact, contact_info); + xmlnode_insert_child(contact, changes); - g_free(escaped_nickname); - g_free(body); + if (!strcmp(passport, "Me")) { + xmlnode *contactType = xmlnode_new_child(contact_info, "contactType"); + xmlnode_insert_data(contactType, "Me", -1); + } else { + MsnUser *user = msn_userlist_find_user(session->userlist, passport); + xmlnode *contactId = xmlnode_new_child(contact, "contactId"); + msn_callback_state_set_uid(state, user->uid); + xmlnode_insert_data(contactId, state->uid, -1); + } + + msn_contact_request(state); } static void @@ -1144,74 +1278,70 @@ MsnCallbackState *state = data; MsnSession *session = state->session; - if (resp != NULL) { - purple_debug_info("MSN CL", "Contact %s deleted successfully from %s list on server!\n", state->who, MsnMemberRole[state->list_id]); + purple_debug_info("msn", "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(session->userlist, state->who); + if (state->list_id == MSN_LIST_PL) { + MsnUser *user = msn_userlist_find_user(session->userlist, state->who); + MsnCallbackState *new_state = msn_callback_state_dup(state); - if (user != NULL) - msn_user_unset_op(user, MSN_LIST_PL_OP); + if (user != NULL) + msn_user_unset_op(user, MSN_LIST_PL_OP); - msn_add_contact_to_list(session->contact, state, state->who, MSN_LIST_RL); - return; - } 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_add_contact_to_list(session, new_state, state->who, MSN_LIST_RL); + return; + } else if (state->list_id == MSN_LIST_AL) { + purple_privacy_permit_remove(session->account, state->who, TRUE); + msn_add_contact_to_list(session, 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, NULL, state->who, MSN_LIST_AL); } - msn_callback_state_free(state); } void -msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, +msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state, const gchar *passport, const MsnListId list) { gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; MsnUser *user; - g_return_if_fail(contact != NULL); + g_return_if_fail(session != NULL); g_return_if_fail(passport != NULL); g_return_if_fail(list < 5); - purple_debug_info("MSN CL", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); + purple_debug_info("msn", "Deleting contact %s from %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(contact->session); + state = msn_callback_state_new(session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); if (list == MSN_LIST_PL) { - g_return_if_fail(contact->session != NULL); - g_return_if_fail(contact->session->userlist != NULL); + g_return_if_fail(session->userlist != NULL); - user = msn_userlist_find_user(contact->session->userlist, passport); + user = msn_userlist_find_user(session->userlist, passport); partner_scenario = MSN_PS_CONTACT_API; member = g_strdup_printf(MSN_MEMBER_MEMBERSHIPID_XML, user->membership_id[MSN_LIST_PL]); } else { /* list == MSN_LIST_AL || list == MSN_LIST_BL */ partner_scenario = MSN_PS_BLOCK_UNBLOCK; - + member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, passport); } - body = g_strdup_printf( MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE, - MsnSoapPartnerScenarioText[partner_scenario], - MsnMemberRole[list], - member); + body = g_strdup_printf(MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE, + MsnSoapPartnerScenarioText[partner_scenario], + MsnMemberRole[list], member); - 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION; + state->post_url = MSN_SHARE_POST_URL; + state->cb = msn_del_contact_from_list_read_cb; + msn_contact_request(state); g_free(member); g_free(body); @@ -1225,47 +1355,41 @@ g_return_if_fail(state != NULL); g_return_if_fail(state->session != NULL); - g_return_if_fail(state->session->contact != NULL); + + purple_debug_info("msn", "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(state->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 (state->action & MSN_DENIED_BUDDY) { + if (user != NULL) { + msn_user_set_op(user, MSN_LIST_RL_OP); + } - 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->action & MSN_DENIED_BUDDY) { + msn_add_contact_to_list(state->session, 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); } } - - msn_callback_state_free(state); } void -msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, +msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state, const gchar *passport, const MsnListId list) { gchar *body = NULL, *member = NULL; MsnSoapPartnerScenario partner_scenario; - g_return_if_fail(contact != NULL); + g_return_if_fail(session != NULL); g_return_if_fail(passport != NULL); g_return_if_fail(list < 5); - purple_debug_info("MSN CL", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); + purple_debug_info("msn", "Adding contact %s to %s list\n", passport, MsnMemberRole[list]); if (state == NULL) { - state = msn_callback_state_new(contact->session); + state = msn_callback_state_new(session); } msn_callback_state_set_list_id(state, list); msn_callback_state_set_who(state, passport); @@ -1275,15 +1399,14 @@ member = g_strdup_printf(MSN_MEMBER_PASSPORT_XML, state->who); body = g_strdup_printf(MSN_CONTACT_ADD_TO_LIST_TEMPLATE, - MsnSoapPartnerScenarioText[partner_scenario], - MsnMemberRole[list], - member); + MsnSoapPartnerScenarioText[partner_scenario], + MsnMemberRole[list], 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION; + state->post_url = MSN_SHARE_POST_URL; + state->cb = msn_add_contact_to_list_read_cb; + msn_contact_request(state); g_free(member); g_free(body); @@ -1293,24 +1416,23 @@ static void msn_gleams_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { - if (resp != NULL) - purple_debug_info("MSNP14","Gleams read done\n"); - else - purple_debug_info("MSNP14","Gleams read failed\n"); + purple_debug_info("msn", "Gleams read done\n"); } /*get the gleams info*/ void -msn_get_gleams(MsnContact *contact) +msn_get_gleams(MsnSession *session) { MsnSoapReq *soap_request; - purple_debug_info("MSNP14","msn get gleams info...\n"); - 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); + purple_debug_info("msn", "msn get gleams info...\n"); + + state = msn_callback_state_new(session); + state->body = xmlnode_from_str(MSN_GLEAMS_TEMPLATE, -1); + state->post_action = MSN_GET_GLEAMS_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_gleams_read_cb; + msn_contact_request(state); } #endif @@ -1323,68 +1445,62 @@ msn_group_read_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { MsnCallbackState *state = data; + MsnSession *session; + MsnUserList *userlist; - purple_debug_info("MSNCL", "Group request successful.\n"); + purple_debug_info("msn", "Group request successful.\n"); g_return_if_fail(state->session != NULL); g_return_if_fail(state->session->userlist != NULL); - g_return_if_fail(state->session->contact != NULL); + + session = state->session; + userlist = session->userlist; - if (resp == NULL) { - msn_callback_state_free(state); - return; + if (state->action & MSN_RENAME_GROUP) { + msn_userlist_rename_group_id(session->userlist, + state->guid, + state->new_group_name); } - if (state) { - MsnSession *session = state->session; - MsnUserList *userlist = session->userlist; - - if (state->action & MSN_RENAME_GROUP) { - msn_userlist_rename_group_id(session->userlist, - state->guid, - state->new_group_name); - } + if (state->action & MSN_ADD_GROUP) { + /* the response is taken from + http://telepathy.freedesktop.org/wiki/Pymsn/MSNP/ContactListActions + should copy it to msnpiki some day */ + xmlnode *guid_node = xmlnode_get_child(resp->xml, + "Body/ABGroupAddResponse/ABGroupAddResult/guid"); - if (state->action & MSN_ADD_GROUP) { - /* 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); - 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); + /* create and add the new group to the userlist */ + purple_debug_info("msn", "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(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); - g_free(guid); - return; - } - g_free(guid); - } else { - purple_debug_info("MSNCL", "Adding group %s failed\n", + 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) { + /* This will be freed when the add contact callback fires */ + MsnCallbackState *new_state = msn_callback_state_dup(state); + msn_add_contact_to_group(session, new_state, state->who, guid); + g_free(guid); + return; } + g_free(guid); + } else { + purple_debug_info("msn", "Adding group %s failed\n", + state->new_group_name); } - - if (state->action & MSN_DEL_GROUP) { - GList *l; + } - 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); - } + if (state->action & MSN_DEL_GROUP) { + GList *l; + + 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); } } @@ -1393,11 +1509,12 @@ msn_add_group(MsnSession *session, MsnCallbackState *state, const char* group_name) { char *body = NULL; + char *escaped_group_name = NULL; g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - purple_debug_info("MSNCL","Adding group %s to contact list.\n", group_name); + purple_debug_info("msn", "Adding group %s to contact list.\n", group_name); if (state == NULL) { state = msn_callback_state_new(session); @@ -1409,14 +1526,16 @@ /* escape group name's html special chars so it can safely be sent * in a XML SOAP request */ - body = g_markup_printf_escaped(MSN_GROUP_ADD_TEMPLATE, group_name); + escaped_group_name = g_markup_escape_text(group_name, -1); + body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE, escaped_group_name); - 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_GROUP_ADD_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_group_read_cb; + msn_contact_request(state); + g_free(escaped_group_name); g_free(body); } @@ -1431,7 +1550,7 @@ g_return_if_fail(session != NULL); g_return_if_fail(group_name != NULL); - purple_debug_info("MSNCL","Deleting group %s from contact list\n", group_name); + purple_debug_info("msn", "Deleting group %s from contact list\n", group_name); guid = msn_userlist_find_group_id(session->userlist, group_name); @@ -1439,12 +1558,12 @@ * we need to delete nothing */ if (guid == NULL) { - purple_debug_info("MSNCL", "Group %s guid not found, returning.\n", group_name); + purple_debug_info("msn", "Group %s guid not found, returning.\n", group_name); return; } if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { - // XXX add back PurpleGroup since it isn't really removed in the server? + /* XXX add back PurpleGroup since it isn't really removed in the server? */ return; } @@ -1454,11 +1573,11 @@ body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE, guid); - 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_GROUP_DEL_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_group_read_cb; + msn_contact_request(state); g_free(body); } @@ -1470,13 +1589,14 @@ gchar *body = NULL; const gchar * guid; MsnCallbackState *state; + char *escaped_group_name; 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); - purple_debug_info("MSN CL", "Renaming group %s to %s.\n", old_group_name, new_group_name); + purple_debug_info("msn", "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) @@ -1487,20 +1607,22 @@ msn_callback_state_set_new_group_name(state, new_group_name); if ( !strcmp(guid, MSN_INDIVIDUALS_GROUP_ID) || !strcmp(guid, MSN_NON_IM_GROUP_ID) ) { - msn_add_group(session, state, new_group_name); - // XXX move every buddy there (we probably need to fix concurrent SOAP reqs first) + MsnCallbackState *new_state = msn_callback_state_dup(state); + msn_add_group(session, new_state, new_group_name); + /* XXX move every buddy there (we probably need to fix concurrent SOAP reqs first) */ } msn_callback_state_set_action(state, MSN_RENAME_GROUP); - body = g_markup_printf_escaped(MSN_GROUP_RENAME_TEMPLATE, - guid, new_group_name); + escaped_group_name = g_markup_escape_text(new_group_name, -1); + body = g_strdup_printf(MSN_GROUP_RENAME_TEMPLATE, guid, 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); + state->body = xmlnode_from_str(body, -1); + state->post_action = MSN_GROUP_RENAME_SOAP_ACTION; + state->post_url = MSN_ADDRESS_BOOK_POST_URL; + state->cb = msn_group_read_cb; + msn_contact_request(state); + g_free(escaped_group_name); g_free(body); }
--- a/libpurple/protocols/msn/contact.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/contact.h Sat Jul 12 07:32:05 2008 +0000 @@ -25,25 +25,33 @@ #ifndef _MSN_CONTACT_H_ #define _MSN_CONTACT_H_ +#include "session.h" + +#define MSN_APPLICATION_ID "CFE80F9D-180F-4399-82AB-413F33A1FA11" + #define MSN_CONTACT_SERVER "contacts.msn.com" /* Get Contact List */ #define MSN_GET_CONTACT_POST_URL "/abservice/SharingService.asmx" #define MSN_GET_CONTACT_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" -#define MSN_GET_CONTACT_UPDATE_XML "<View>Full</View>"\ + +#define MSN_GET_CONTACT_UPDATE_XML \ + "<View>Full</View>"\ "<deltasOnly>true</deltasOnly>"\ "<lastChange>%s</lastChange>" + #define MSN_GET_CONTACT_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\ "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>"\ "<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>"\ + "<TicketToken>%s</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ @@ -72,15 +80,20 @@ #define MSN_ADD_ADDRESSBOOK_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABAdd" #define MSN_ADD_ADDRESSBOOK_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>Initial</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>%s</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -98,7 +111,8 @@ /* Get AddressBook */ #define MSN_GET_ADDRESS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" #define MSN_GET_ADDRESS_FULL_TIME "0001-01-01T00:00:00.0000000-08:00" -#define MSN_GET_ADDRESS_UPDATE_XML "<deltasOnly>true</deltasOnly>"\ +#define MSN_GET_ADDRESS_UPDATE_XML \ + "<deltasOnly>true</deltasOnly>"\ "<lastChange>%s</lastChange>" #define MSN_GET_GLEAM_UPDATE_XML \ @@ -107,15 +121,20 @@ "<dynamicItemLastChange>%s</dynamicItemLastChange>" #define MSN_GET_ADDRESS_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>%s</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>%s</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -131,15 +150,20 @@ /*Gleams SOAP request template*/ #define MSN_GET_GLEAMS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" #define MSN_GLEAMS_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>Initial</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -157,34 +181,78 @@ * Contact Management SOAP actions *******************************************************/ -/* Add a new contact t*/ +/* Add a new contact */ #define MSN_CONTACT_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" -#define MSN_CONTACT_LIVE_PENDING_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><contactType>LivePending</contactType><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></contactInfo></Contact>" +#define MSN_CONTACT_LIVE_PENDING_XML \ + "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<contactInfo>"\ + "<contactType>LivePending</contactType>"\ + "<passportName>%s</passportName>"\ + "<isMessengerUser>true</isMessengerUser>"\ + "</contactInfo>"\ + "</Contact>" -#define MSN_CONTACT_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<contactInfo>"\ - "<passportName>%s</passportName>"\ - "<isSmtp>false</isSmtp>"\ - "<isMessengerUser>true</isMessengerUser>"\ - "</contactInfo>"\ - "</Contact>" +#define MSN_CONTACT_XML \ + "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<contactInfo>"\ + "<passportName>%s</passportName>"\ + "<isSmtp>false</isSmtp>"\ + "<isMessengerUser>true</isMessengerUser>"\ + "</contactInfo>"\ + "</Contact>" -#define MSN_CONTACT_DISPLAYNAME_XML "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\"><contactInfo><displayName>%s</displayName><passportName>%s</passportName><isMessengerUser>true</isMessengerUser></contactInfo></Contact>" - -#define MSN_ADD_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>ContactSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><options><EnableAllowListManagement>true</EnableAllowListManagement></options></ABContactAdd></soap:Body></soap:Envelope>" +#define MSN_CONTACT_DISPLAYNAME_XML \ + "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<contactInfo>"\ + "<displayName>%s</displayName>"\ + "<passportName>%s</passportName>"\ + "<isMessengerUser>true</isMessengerUser>"\ + "</contactInfo>"\ + "</Contact>" -/* Add a contact to a group */ -#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactAdd" -#define MSN_ADD_CONTACT_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +#define MSN_ADD_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>ContactSave</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<contacts>%s</contacts>"\ + "<options>"\ + "<EnableAllowListManagement>true</EnableAllowListManagement>"\ + "</options>"\ + "</ABContactAdd>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/* Add a contact to a group */ +#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactAdd" +#define MSN_ADD_CONTACT_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>ContactSave</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -207,25 +275,81 @@ /* Delete a contact from the Contact List */ #define MSN_CONTACT_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" #define MSN_CONTACT_ID_XML "<Contact><contactId>%s</contactId></Contact>" -#define MSN_DEL_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts></ABContactDelete></soap:Body></soap:Envelope>" - -/* Remove a contact from a group */ -#define MSN_CONTACT_DEL_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactDelete" -#define MSN_CONTACT_DEL_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><contacts>%s</contacts><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupContactDelete></soap:Body></soap:Envelope>" - - -/* Update Contact Nickname */ -#define MSN_CONTACT_UPDATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" -#define MSN_CONTACT_UPDATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +#define MSN_DEL_CONTACT_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>Timer</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<contacts>%s</contacts>"\ + "</ABContactDelete>"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/* Remove a contact from a group */ +#define MSN_CONTACT_DEL_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactDelete" +#define MSN_CONTACT_DEL_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>Timer</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABGroupContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<contacts>%s</contacts>"\ + "<groupFilter>"\ + "<groupIds>"\ + "<guid>%s</guid>"\ + "</groupIds>"\ + "</groupFilter>"\ + "</ABGroupContactDelete>"\ + "</soap:Body>"\ +"</soap:Envelope>" + + +/* Update Contact Information */ +#define MSN_CONTACT_UPDATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" +#define MSN_CONTACT_UPDATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>Timer</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -233,18 +357,13 @@ "<abId>00000000-0000-0000-0000-000000000000</abId>"\ "<contacts>"\ "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<contactInfo>"\ - "<contactType>Me</contactType>"\ - "<displayName>%s</displayName>"\ - "</contactInfo>"\ - "<propertiesChanged>DisplayName</propertiesChanged>"\ + ""\ "</Contact>"\ "</contacts>"\ "</ABContactUpdate>"\ "</soap:Body>"\ "</soap:Envelope>" - /******************************************************* * Add/Delete contact from lists SOAP actions *******************************************************/ @@ -255,30 +374,37 @@ #define MSN_ADD_MEMBER_TO_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" #define MSN_DELETE_MEMBER_FROM_LIST_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" -#define MSN_MEMBER_PASSPORT_XML "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ - "<Type>Passport</Type>"\ - "<State>Accepted</State>"\ - "<PassportName>%s</PassportName>"\ - "</Member>" +#define MSN_MEMBER_PASSPORT_XML \ + "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ + "<Type>Passport</Type>"\ + "<State>Accepted</State>"\ + "<PassportName>%s</PassportName>"\ + "</Member>" -#define MSN_MEMBER_MEMBERSHIPID_XML "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ - "<Type>Passport</Type>"\ - "<MembershipId>%u</MembershipId>"\ - "<State>Accepted</State>"\ - "</Member>" +#define MSN_MEMBER_MEMBERSHIPID_XML \ + "<Member xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"PassportMember\">"\ + "<Type>Passport</Type>"\ + "<MembershipId>%u</MembershipId>"\ + "<State>Accepted</State>"\ + "</Member>" /* first delete contact from allow list */ #define MSN_CONTACT_DELECT_FROM_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>%s</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -301,15 +427,20 @@ "</soap:Envelope>" #define MSN_CONTACT_ADD_TO_LIST_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ "<soap:Header>"\ "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ - "<ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId>"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ "<IsMigration>false</IsMigration>"\ "<PartnerScenario>%s</PartnerScenario>"\ "</ABApplicationHeader>"\ "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ "</ABAuthHeader>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -339,36 +470,124 @@ /* add a group */ #define MSN_GROUP_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupAdd" -#define MSN_GROUP_ADD_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo><GroupInfo><name>%s</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo></groupInfo></ABGroupAdd></soap:Body></soap:Envelope>" +#define MSN_GROUP_ADD_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>GroupSave</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<groupAddOptions>"\ + "<fRenameOnMsgrConflict>false</fRenameOnMsgrConflict>"\ + "</groupAddOptions>"\ + "<groupInfo>"\ + "<GroupInfo>"\ + "<name>%s</name>"\ + "<groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType>"\ + "<fMessenger>false</fMessenger>"\ + "<annotations>"\ + "<Annotation>"\ + "<Name>MSN.IM.Display</Name>"\ + "<Value>1</Value>"\ + "</Annotation>"\ + "</annotations>"\ + "</GroupInfo>"\ + "</groupInfo>"\ + "</ABGroupAdd>"\ + "</soap:Body>"\ +"</soap:Envelope>" /* delete a group */ #define MSN_GROUP_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupDelete" -#define MSN_GROUP_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds><guid>%s</guid></groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>" +#define MSN_GROUP_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>Timer</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<groupFilter>"\ + "<groupIds>"\ + "<guid>%s</guid>"\ + "</groupIds>"\ + "</groupFilter>"\ + "</ABGroupDelete>"\ + "</soap:Body>"\ +"</soap:Envelope>" /* change a group's name */ #define MSN_GROUP_RENAME_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupUpdate" -#define MSN_GROUP_RENAME_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groups><Group><groupId>%s</groupId><groupInfo><name>%s</name></groupInfo><propertiesChanged>GroupName </propertiesChanged></Group></groups></ABGroupUpdate></soap:Body></soap:Envelope>" +#define MSN_GROUP_RENAME_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\">"\ + "<soap:Header>"\ + "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ApplicationId>" MSN_APPLICATION_ID "</ApplicationId>"\ + "<IsMigration>false</IsMigration>"\ + "<PartnerScenario>Timer</PartnerScenario>"\ + "</ABApplicationHeader>"\ + "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<ManagedGroupRequest>false</ManagedGroupRequest>"\ + "<TicketToken>EMPTY</TicketToken>"\ + "</ABAuthHeader>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<ABGroupUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">"\ + "<abId>00000000-0000-0000-0000-000000000000</abId>"\ + "<groups>"\ + "<Group>"\ + "<groupId>%s</groupId>"\ + "<groupInfo>"\ + "<name>%s</name>"\ + "</groupInfo>"\ + "<propertiesChanged>GroupName </propertiesChanged>"\ + "</Group>"\ + "</groups>"\ + "</ABGroupUpdate>"\ + "</soap:Body>"\ +"</soap:Envelope>" typedef enum { - MSN_ADD_BUDDY = 0x01, - MSN_MOVE_BUDDY = 0x02, - MSN_ACCEPTED_BUDDY = 0x04, - MSN_DENIED_BUDDY = 0x08, - MSN_ADD_GROUP = 0x10, - MSN_DEL_GROUP = 0x20, - MSN_RENAME_GROUP = 0x40, + MSN_ADD_BUDDY = 0x01, + MSN_MOVE_BUDDY = 0x02, + MSN_ACCEPTED_BUDDY = 0x04, + MSN_DENIED_BUDDY = 0x08, + MSN_ADD_GROUP = 0x10, + MSN_DEL_GROUP = 0x20, + MSN_RENAME_GROUP = 0x40, + MSN_UPDATE_INFO = 0x80, } MsnCallbackAction; -typedef struct _MsnContact MsnContact; - -struct _MsnContact -{ - MsnSession *session; - - MsnSoapConn *soapconn; -}; - typedef struct _MsnCallbackState MsnCallbackState; struct _MsnCallbackState @@ -381,6 +600,11 @@ MsnListId list_id; MsnCallbackAction action; MsnSession *session; + xmlnode *body; + xmlnode *token; + const gchar *post_action; + const gchar *post_url; + /* MsnSoapCallback */ void *cb; }; typedef enum @@ -392,13 +616,18 @@ MSN_PS_BLOCK_UNBLOCK } MsnSoapPartnerScenario; +typedef enum +{ + MSN_UPDATE_DISPLAY, /* Real display name */ + MSN_UPDATE_ALIAS, /* Aliased display name */ + MSN_UPDATE_COMMENT +} MsnContactUpdateType; + /************************************************ * function prototype ************************************************/ -MsnContact * msn_contact_new(MsnSession *session); -void msn_contact_destroy(MsnContact *contact); - MsnCallbackState * msn_callback_state_new(MsnSession *session); +MsnCallbackState * msn_callback_state_dup(MsnCallbackState *state); 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); @@ -411,24 +640,24 @@ void msn_callback_state_set_action(MsnCallbackState *state, MsnCallbackAction action); -void msn_contact_connect(MsnContact *contact); -void msn_get_contact_list(MsnContact * contact, +void msn_contact_connect(MsnSession *session); +void msn_get_contact_list(MsnSession *session, const MsnSoapPartnerScenario partner_scenario, const char *update); -void msn_get_address_book(MsnContact *contact, +void msn_get_address_book(MsnSession *session, const MsnSoapPartnerScenario partner_scenario, const char * update, const char * gupdate); /* contact SOAP operations */ -void msn_update_contact(MsnContact *contact, const char* nickname); +void msn_update_contact(MsnSession *session, const char *passport, MsnContactUpdateType type, const char* value); -void msn_add_contact(MsnContact *contact, MsnCallbackState *state, +void msn_add_contact(MsnSession *session, MsnCallbackState *state, const char *passport); -void msn_delete_contact(MsnContact *contact, const char *contactId); +void msn_delete_contact(MsnSession *session, const char *contactId); -void msn_add_contact_to_group(MsnContact *contact, MsnCallbackState *state, +void msn_add_contact_to_group(MsnSession *session, MsnCallbackState *state, const char *passport, const char *groupId); -void msn_del_contact_from_group(MsnContact *contact, const char *passport, +void msn_del_contact_from_group(MsnSession *session, const char *passport, const char *group_name); /* group operations */ void msn_add_group(MsnSession *session, MsnCallbackState *state, @@ -438,12 +667,10 @@ const char *new_group_name); /* lists operations */ -void msn_add_contact_to_list(MsnContact *contact, MsnCallbackState *state, +void msn_add_contact_to_list(MsnSession *session, MsnCallbackState *state, const gchar *passport, const MsnListId list); -void msn_del_contact_from_list(MsnContact *contact, MsnCallbackState *state, +void msn_del_contact_from_list(MsnSession *session, MsnCallbackState *state, const gchar *passport, const MsnListId list); -void msn_contact_connect_init(MsnSoapConn *soapconn); - #endif /* _MSN_CONTACT_H_ */
--- a/libpurple/protocols/msn/group.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/group.h Sat Jul 12 07:32:05 2008 +0000 @@ -30,16 +30,8 @@ #include "session.h" #include "user.h" -#include "soap.h" #include "userlist.h" -#define MSN_ADD_GROUPS "<GroupInfo><name>test111</name><groupType>C8529CE2-6EAD-434d-881F-341E17DB3FF8</groupType><fMessenger>false</fMessenger><annotations><Annotation><Name>MSN.IM.Display</Name><Value>1</Value></Annotation></annotations></GroupInfo>" - -#define MSN_ADD_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>GroupSave</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupAdd xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupAddOptions><fRenameOnMsgrConflict>false</fRenameOnMsgrConflict></groupAddOptions><groupInfo>%s</groupInfo></ABGroupAdd></soap:Body></soap:Envelope>" - -#define MSN_GROUP_IDS "<guid>9e57e654-59f0-44d1-aedc-0a7500b7e51f</guid>" -#define MSN_DELETE_GROUP_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\"><soap:Header><ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ApplicationId>09607671-1C32-421F-A6A6-CBFAA51AB5F4</ApplicationId><IsMigration>false</IsMigration><PartnerScenario>Timer</PartnerScenario></ABApplicationHeader><ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\"><ManagedGroupRequest>false</ManagedGroupRequest></ABAuthHeader></soap:Header><soap:Body><ABGroupDelete xmlns=\"http://www.msn.com/webservices/AddressBook\"><abId>00000000-0000-0000-0000-000000000000</abId><groupFilter><groupIds>%s</groupIds></groupFilter></ABGroupDelete></soap:Body></soap:Envelope>" - #define MSN_INDIVIDUALS_GROUP_ID "1983" #define MSN_INDIVIDUALS_GROUP_NAME "Other Contacts" @@ -52,15 +44,14 @@ struct _MsnGroup { MsnSession *session; /**< The MSN session. */ - MsnSoapConn *soapconn; char *id; /**< The group ID. */ char *name; /**< The name of the group. */ }; -/**************************************************************************/ -/** @name Group API */ -/**************************************************************************/ +/************************************************************************** + ** @name Group API * + **************************************************************************/ /*@{*/ /** @@ -114,4 +105,6 @@ * @return The name. */ const char *msn_group_get_name(const MsnGroup *group); + #endif /* _MSN_GROUP_H_ */ +
--- a/libpurple/protocols/msn/httpconn.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/httpconn.c Sat Jul 12 07:32:05 2008 +0000 @@ -588,7 +588,8 @@ if (httpconn->virgin) { - host = "gateway.messenger.hotmail.com"; + /* QuLogic: This doesn't look right to me, but it still seems to work */ + host = MSN_HTTPCONN_SERVER; /* The first time servconn->host is the host we should connect to. */ params = g_strdup_printf("Action=open&Server=%s&IP=%s",
--- a/libpurple/protocols/msn/msn.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/msn.c Sat Jul 12 07:32:05 2008 +0000 @@ -27,6 +27,7 @@ #include "msn.h" #include "accountopt.h" +#include "contact.h" #include "msg.h" #include "page.h" #include "pluginpref.h" @@ -393,6 +394,29 @@ } static void +msn_show_blocked_text(PurplePluginAction *action) +{ + PurpleConnection *pc = (PurpleConnection *) action->context; + MsnSession *session; + char *title; + + session = pc->proto_data; + + title = g_strdup_printf(_("Blocked Text for %s"), session->account->username); + if (session->blocked_text == NULL) { + purple_notify_formatted(pc, title, title, NULL, _("No text is blocked for this account."), NULL, NULL); + } else { + char *blocked_text; + blocked_text = g_strdup_printf(_("MSN servers are currently blocking the following regular expressions:<br/>%s"), + session->blocked_text); + + purple_notify_formatted(pc, title, title, NULL, blocked_text, NULL, NULL); + g_free(blocked_text); + } + g_free(title); +} + +static void msn_show_hotmail_inbox(PurplePluginAction *action) { PurpleConnection *gc; @@ -567,6 +591,30 @@ return "msn"; } +static const char * +msn_list_emblems(PurpleBuddy *b) +{ + MsnUser *user = b->proto_data; + + if (user != NULL) { + if (user->clientid & MSN_CLIENT_CAP_BOT) + return "bot"; + if (user->clientid & MSN_CLIENT_CAP_WIN_MOBILE) + return "hiptop"; /* XXX: Rename to Mobile / Use different icon? */ +#if 0 + /* XXX: Since we don't support this, there's no point in showing it just yet */ + if (user->clientid & MSN_CLIENT_CAP_SCHANNEL) + return "secure"; +#endif + if (user->clientid & MSN_CLIENT_CAP_WEBMSGR) + return "web"; + if (user->networkid == MSN_NETWORK_YAHOO) + return "yahoo"; + } + + return NULL; +} + /* * Set the User status text */ @@ -808,6 +856,11 @@ msn_show_set_mobile_pages); m = g_list_append(m, act); + m = g_list_append(m, NULL); + act = purple_plugin_action_new(_("View Blocked Text..."), + msn_show_blocked_text); + m = g_list_append(m, act); + account = purple_connection_get_account(gc); user = msn_normalize(account, purple_account_get_username(account)); @@ -1042,15 +1095,20 @@ { PurpleAccount *account; PurpleBuddy *buddy = purple_find_buddy(gc->account, who); + MsnSession *session; + MsnSwitchBoard *swboard; MsnMessage *msg; char *msgformat; char *msgtext; const char *username; - purple_debug_info("MSNP14","send IM {%s} to %s\n",message,who); + purple_debug_info("msn", "send IM {%s} to %s\n",message,who); account = purple_connection_get_account(gc); username = purple_account_get_username(account); + session = gc->proto_data; + swboard = msn_session_find_swboard(session, who); + if (buddy) { PurplePresence *p = purple_buddy_get_presence(buddy); if (purple_presence_is_status_primitive_active(p, PURPLE_STATUS_MOBILE)) { @@ -1062,10 +1120,12 @@ } msn_import_html(message, &msgformat, &msgtext); - if(msn_user_is_online(account, who)|| - msn_user_is_yahoo(account, who)){ - /*User online,then send Online Instant Message*/ - + if (msn_user_is_online(account, who)|| + msn_user_is_yahoo(account, who) || + swboard != NULL){ + /*User online or have a swboard open because it's invisible + * and sent us a message,then send Online Instant Message*/ + if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564) { g_free(msgformat); @@ -1081,22 +1141,19 @@ g_free(msgformat); g_free(msgtext); - purple_debug_info("MSNP14","prepare to send online Message\n"); + purple_debug_info("msn", "prepare to send online Message\n"); if (g_ascii_strcasecmp(who, username)) { - MsnSession *session; - MsnSwitchBoard *swboard; MsnEmoticon *smile; GSList *smileys; GString *emoticons = NULL; - session = gc->proto_data; if(msn_user_is_yahoo(account,who)){ /*we send the online and offline Message to Yahoo User via UBM*/ - purple_debug_info("MSNP14","send to Yahoo User\n"); + purple_debug_info("msn", "send to Yahoo User\n"); uum_send_msg(session,msg); }else{ - purple_debug_info("MSNP14","send via switchboard\n"); + purple_debug_info("msn", "send via switchboard\n"); swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM); smileys = msn_msg_grab_emoticons(message, username); while (smileys) { @@ -1145,19 +1202,20 @@ } msn_message_destroy(msg); - }else { + } else { /*send Offline Instant Message,only to MSN Passport User*/ - MsnSession *session; char *friendname; - purple_debug_info("MSNP14","prepare to send offline Message\n"); - session = gc->proto_data; + purple_debug_info("msn", "prepare to send offline Message\n"); friendname = msn_encode_mime(account->username); msn_oim_prep_send_msg_info(session->oim, purple_account_get_username(account), - friendname, who, message); + friendname, who, msgtext); msn_oim_send_msg(session->oim); + + g_free(msgformat); + g_free(msgtext); g_free(friendname); } @@ -1298,7 +1356,7 @@ userlist = session->userlist; who = msn_normalize(gc->account, buddy->name); - purple_debug_info("MSN","Add user:%s to group:%s\n", who, (group && group->name) ? group->name : "(null)"); + purple_debug_info("msn", "Add user:%s to group:%s\n", who, (group && group->name) ? group->name : "(null)"); if (!session->logged_in) { #if 0 @@ -1369,10 +1427,10 @@ msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); /* delete contact from Block list and add it to Allow in the callback */ - msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL); + msn_del_contact_from_list(session, NULL, who, MSN_LIST_BL); } else { /* just add the contact to Allow list */ - msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_AL); + msn_add_contact_to_list(session, NULL, who, MSN_LIST_AL); } @@ -1397,10 +1455,10 @@ msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); /* delete contact from Allow list and add it to Block in the callback */ - msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL); + msn_del_contact_from_list(session, NULL, who, MSN_LIST_AL); } else { /* just add the contact to Block list */ - msn_add_contact_to_list(session->contact, NULL, who, MSN_LIST_BL); + msn_add_contact_to_list(session, NULL, who, MSN_LIST_BL); } msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); @@ -1423,7 +1481,7 @@ msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_AL); - msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_AL); + msn_del_contact_from_list(session, NULL, who, MSN_LIST_AL); if (user != NULL && user->list_op & MSN_LIST_RL_OP) msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_BL); @@ -1446,7 +1504,7 @@ msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); - msn_del_contact_from_list(session->contact, NULL, who, MSN_LIST_BL); + msn_del_contact_from_list(session, NULL, who, MSN_LIST_BL); if (user != NULL && user->list_op & MSN_LIST_RL_OP) msn_userlist_add_buddy_to_list(userlist, who, MSN_LIST_AL); @@ -1574,6 +1632,15 @@ } } +static void msn_alias_buddy(PurpleConnection *pc, const char *name, const char *alias) +{ + MsnSession *session; + + session = pc->proto_data; + + msn_update_contact(session, name, MSN_UPDATE_ALIAS, alias); +} + static void msn_group_buddy(PurpleConnection *gc, const char *who, const char *old_group_name, const char *new_group_name) @@ -1669,12 +1736,12 @@ session = gc->proto_data; cmdproc = session->notification->cmdproc; - purple_debug_info("MSN", "Remove group %s\n", group->name); + purple_debug_info("msn", "Remove group %s\n", group->name); /*we can't delete the default group*/ if(!strcmp(group->name, MSN_INDIVIDUALS_GROUP_NAME)|| !strcmp(group->name, MSN_NON_IM_GROUP_NAME)) { - purple_debug_info("MSN", "This group can't be removed, returning.\n"); + purple_debug_info("msn", "This group can't be removed, returning.\n"); return ; } @@ -1739,7 +1806,7 @@ } static void msn_got_photo(PurpleUtilFetchUrlData *url_data, gpointer data, - const gchar *url_text, size_t len, const gchar *error_message); + const gchar *url_text, gsize len, const gchar *error_message); #endif @@ -2174,7 +2241,7 @@ #if PHOTO_SUPPORT /* Find the URL to the photo; must be before the marshalling [Bug 994207] */ photo_url_text = msn_get_photo_url(url_text); - purple_debug_info("MSNP14","photo url:{%s}\n", photo_url_text ? photo_url_text : "(null)"); + purple_debug_info("msn", "photo url:{%s}\n", photo_url_text ? photo_url_text : "(null)"); /* Marshall the existing state */ info2_data = g_new0(MsnGetInfoStepTwoData, 1); @@ -2375,7 +2442,7 @@ NULL, /* protocol_options */ {"png", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_SEND}, /* icon_spec */ msn_list_icon, /* list_icon */ - NULL, /* list_emblems */ + msn_list_emblems, /* list_emblems */ msn_status_text, /* status_text */ msn_tooltip_text, /* tooltip_text */ msn_status_types, /* away_states */ @@ -2411,7 +2478,7 @@ NULL, /* register_user */ NULL, /* get_cb_info */ NULL, /* get_cb_away */ - NULL, /* alias_buddy */ + msn_alias_buddy, /* alias_buddy */ msn_group_buddy, /* group_buddy */ msn_rename_group, /* rename_group */ NULL, /* buddy_free */ @@ -2484,11 +2551,11 @@ PurpleAccountOption *option; option = purple_account_option_string_new(_("Server"), "server", - WLM_SERVER); + MSN_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("Port"), "port", WLM_PORT); + option = purple_account_option_int_new(_("Port"), "port", MSN_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
--- a/libpurple/protocols/msn/msn.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/msn.h Sat Jul 12 07:32:05 2008 +0000 @@ -57,35 +57,25 @@ #define MSN_BUF_LEN 8192 -#define USEROPT_MSNSERVER 3 +/* Windows Live Messenger Server*/ #define MSN_SERVER "messenger.hotmail.com" #define MSN_HTTPCONN_SERVER "gateway.messenger.hotmail.com" -#define USEROPT_MSNPORT 4 #define MSN_PORT 1863 +#define WLM_PROT_VER 15 -/* Windows Live Messenger Server*/ -#define WLM_SERVER "muser.messenger.hotmail.com" -#define WLM_PORT 1863 -#define WLM_PROT_VER 13 -/*This MSNP14 Support chat with Yahoo Messenger*/ -#define WLM_YAHOO_PROT_VER 14 - -#define WLM_MAX_PROTOCOL 14 -#define WLM_MIN_PROTOCOL 13 +#define WLM_MAX_PROTOCOL 15 +#define WLM_MIN_PROTOCOL 15 #define MSN_TYPING_RECV_TIMEOUT 6 #define MSN_TYPING_SEND_TIMEOUT 4 -#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders"w3 -#define PASSPORT_URL "http://lc1.law13.hotmail.passport.com/cgi-bin/dologin?login=" #define PROFILE_URL "http://spaces.live.com/profile.aspx?mem=" #define PHOTO_URL " contactparams:photopreauthurl=\"" -#define USEROPT_HOTMAIL 0 - #define BUDDY_ALIAS_MAXLEN 387 -#define MSN_FT_GUID "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" +#define MSN_FT_GUID "5D3E02AB-6190-11D3-BBBB-00C04F795683" +#define MSN_OBJ_GUID "A4268EEC-FEC5-49E5-95C3-F126696BDBF6" #define MSN_CLIENTINFO \ "Client-Name: Purple/" VERSION "\r\n" \ @@ -107,18 +97,25 @@ typedef enum { - MSN_CLIENT_CAP_WIN_MOBILE = 0x00001, - MSN_CLIENT_CAP_UNKNOWN_1 = 0x00002, - MSN_CLIENT_CAP_INK_GIF = 0x00004, - MSN_CLIENT_CAP_INK_ISF = 0x00008, - MSN_CLIENT_CAP_VIDEO_CHAT = 0x00010, - MSN_CLIENT_CAP_BASE = 0x00020, - MSN_CLIENT_CAP_MSNMOBILE = 0x00040, - MSN_CLIENT_CAP_MSNDIRECT = 0x00080, - MSN_CLIENT_CAP_WEBMSGR = 0x00100, - MSN_CLIENT_CAP_DIRECTIM = 0x04000, - MSN_CLIENT_CAP_WINKS = 0x08000, - MSN_CLIENT_CAP_SEARCH = 0x10000 + MSN_CLIENT_CAP_WIN_MOBILE = 0x000001, + MSN_CLIENT_CAP_INK_GIF = 0x000004, + MSN_CLIENT_CAP_INK_ISF = 0x000008, + MSN_CLIENT_CAP_VIDEO_CHAT = 0x000010, + MSN_CLIENT_CAP_PACKET = 0x000020, + MSN_CLIENT_CAP_MSNMOBILE = 0x000040, + MSN_CLIENT_CAP_MSNDIRECT = 0x000080, + MSN_CLIENT_CAP_WEBMSGR = 0x000200, + MSN_CLIENT_CAP_TGW = 0x000800, + MSN_CLIENT_CAP_SPACE = 0x001000, + MSN_CLIENT_CAP_MCE = 0x002000, + MSN_CLIENT_CAP_DIRECTIM = 0x004000, + MSN_CLIENT_CAP_WINKS = 0x008000, + MSN_CLIENT_CAP_SEARCH = 0x010000, + MSN_CLIENT_CAP_BOT = 0x020000, + MSN_CLIENT_CAP_VOICEIM = 0x040000, + MSN_CLIENT_CAP_SCHANNEL = 0x080000, + MSN_CLIENT_CAP_SIP_INVITE = 0x100000, + MSN_CLIENT_CAP_SDRIVE = 0x400000 } MsnClientCaps; @@ -129,19 +126,18 @@ MSN_CLIENT_VER_6_1 = 0x20, /* MSNC2 */ MSN_CLIENT_VER_6_2 = 0x30, /* MSNC3 */ MSN_CLIENT_VER_7_0 = 0x40, /* MSNC4 */ - MSN_CLIENT_VER_7_5 = 0x50 /* MSNC5 */ + MSN_CLIENT_VER_7_5 = 0x50, /* MSNC5 */ + MSN_CLIENT_VER_8_0 = 0x60, /* MSNC6 */ + MSN_CLIENT_VER_8_1 = 0x70, /* MSNC7 */ + MSN_CLIENT_VER_8_5 = 0x80 /* MSNC8 */ } MsnClientVerId; #define MSN_CLIENT_ID_VERSION MSN_CLIENT_VER_7_0 -#define MSN_CLIENT_ID_RESERVED_1 0x00 -#define MSN_CLIENT_ID_RESERVED_2 0x00 -#define MSN_CLIENT_ID_CAPABILITIES MSN_CLIENT_CAP_BASE +#define MSN_CLIENT_ID_CAPABILITIES MSN_CLIENT_CAP_PACKET #define MSN_CLIENT_ID \ ((MSN_CLIENT_ID_VERSION << 24) | \ - (MSN_CLIENT_ID_RESERVED_1 << 16) | \ - (MSN_CLIENT_ID_RESERVED_2 << 8) | \ (MSN_CLIENT_ID_CAPABILITIES)) void msn_act_id(PurpleConnection *gc, const char *entry);
--- a/libpurple/protocols/msn/msnutils.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/msnutils.c Sat Jul 12 07:32:05 2008 +0000 @@ -23,8 +23,8 @@ */ #include "msn.h" #include "msnutils.h" -#include "time.h" -//#include <openssl/md5.h> + +#include "cipher.h" char *rand_guid(void); @@ -465,132 +465,118 @@ host = g_strdup(str); - if ((c = strchr(host, ':')) != NULL){ + if ((c = strchr(host, ':')) != NULL) { *c = '\0'; port = atoi(c + 1); - }else{ + } else { port = 1863; } *ret_host = host; *ret_port = port; } -/*************************************************************************** - * MSN Time Related Funciton - ***************************************************************************/ -#if 0 -int -msn_convert_iso8601(const char *timestr,struct tm tm_time) -{ - char temp[64]; - struct tm ctime; - time_t ts; - - purple_debug_info("MSNP14","convert string is{%s}\n",timestr); - tzset(); - /*copy string first*/ - memset(temp, 0, sizeof(temp)); - strncpy(temp, timestr, strlen(timestr)); - - /*convert via strptime()*/ - memset(&ctime, 0, sizeof(struct tm)); - strptime(temp, "%d %b %Y %T %Z", &ctime); - ts = mktime(&ctime) - timezone; - localtime_r(&ts, tm_time); -} -#endif /*************************************************************************** * MSN Challenge Computing Function ***************************************************************************/ /* - * Handle MSN Chanllege computation - *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges + * Handle MSN Challenge computation + * This algorithm references + * http://imfreedom.org/wiki/index.php/MSN:NS/Challenges */ #define BUFSIZE 256 void msn_handle_chl(char *input, char *output) { - PurpleCipher *cipher; - PurpleCipherContext *context; - char *productKey = MSNP13_WLM_PRODUCT_KEY, - *productID = MSNP13_WLM_PRODUCT_ID, - *hexChars = "0123456789abcdef", - buf[BUFSIZE]; - unsigned char md5Hash[16], *newHash; - unsigned int *md5Parts, *chlStringParts, newHashParts[5]; + PurpleCipher *cipher; + PurpleCipherContext *context; + const guchar productKey[] = MSNP15_WLM_PRODUCT_KEY; + const guchar productID[] = MSNP15_WLM_PRODUCT_ID; + const char hexChars[] = "0123456789abcdef"; + char buf[BUFSIZE]; + unsigned char md5Hash[16]; + unsigned char *newHash; + unsigned int *md5Parts; + unsigned int *chlStringParts; + unsigned int newHashParts[5]; - long long nHigh=0, nLow=0; - - int i; + long long nHigh = 0, nLow = 0; - /* Create the MD5 hash by using Purple MD5 algorithm*/ - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); + int len; + int i; - purple_cipher_context_append(context, (const guchar *)input, - strlen(input)); - purple_cipher_context_append(context, (const guchar *)productKey, - strlen(productKey)); - purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); - purple_cipher_context_destroy(context); + /* Create the MD5 hash by using Purple MD5 algorithm */ + cipher = purple_ciphers_find_cipher("md5"); + context = purple_cipher_context_new(cipher, NULL); + + purple_cipher_context_append(context, (guchar *)input, strlen(input)); + purple_cipher_context_append(context, productKey, sizeof(productKey) - 1); + purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); + purple_cipher_context_destroy(context); - /* Split it into four integers */ - md5Parts = (unsigned int *)md5Hash; - for(i=0; i<4; i++){ - /* adjust endianess */ - md5Parts[i] = GUINT_TO_LE(md5Parts[i]); + /* Split it into four integers */ + md5Parts = (unsigned int *)md5Hash; + for (i = 0; i < 4; i++) { + /* adjust endianess */ + md5Parts[i] = GUINT_TO_LE(md5Parts[i]); - /* & each integer with 0x7FFFFFFF */ - /* and save one unmodified array for later */ - newHashParts[i] = md5Parts[i]; - md5Parts[i] &= 0x7FFFFFFF; - } + /* & each integer with 0x7FFFFFFF */ + /* and save one unmodified array for later */ + newHashParts[i] = md5Parts[i]; + md5Parts[i] &= 0x7FFFFFFF; + } - /* make a new string and pad with '0' */ - snprintf(buf, BUFSIZE-5, "%s%s", input, productID); - i = strlen(buf); - memset(&buf[i], '0', 8 - (i % 8)); - buf[i + (8 - (i % 8))]='\0'; - - /* split into integers */ - chlStringParts = (unsigned int *)buf; + /* make a new string and pad with '0' to length that's a multiple of 8 */ + snprintf(buf, BUFSIZE - 5, "%s%s", input, productID); + len = strlen(buf); + if ((len % 8) != 0) { + int fix = 8 - (len % 8); + memset(&buf[len], '0', fix); + buf[len + fix] = '\0'; + len += fix; + } - /* this is magic */ - for (i=0; i<(strlen(buf)/4)-1; i+=2){ - long long temp; + /* split into integers */ + chlStringParts = (unsigned int *)buf; - chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); - chlStringParts[i+1] = GUINT_TO_LE(chlStringParts[i+1]); + /* this is magic */ + for (i = 0; i < (strlen(buf) / 4); i += 2) { + long long temp; - temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; - nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; - nLow=nLow + nHigh + temp; - } - nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF; - nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF; + chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); + chlStringParts[i + 1] = GUINT_TO_LE(chlStringParts[i + 1]); + + temp = (0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF; + temp = (md5Parts[0] * (temp + nLow) + md5Parts[1]) % 0x7FFFFFFF; + nHigh += temp; - newHashParts[0]^=nHigh; - newHashParts[1]^=nLow; - newHashParts[2]^=nHigh; - newHashParts[3]^=nLow; + temp = ((long long)chlStringParts[i + 1] + temp) % 0x7FFFFFFF; + nLow = (md5Parts[2] * temp + md5Parts[3]) % 0x7FFFFFFF; + nHigh += nLow; + } + nLow = (nLow + md5Parts[1]) % 0x7FFFFFFF; + nHigh = (nHigh + md5Parts[3]) % 0x7FFFFFFF; - /* adjust endianness */ - for(i=0; i<4; i++) - newHashParts[i] = GUINT_TO_LE(newHashParts[i]); - - /* make a string of the parts */ - newHash = (unsigned char *)newHashParts; + newHashParts[0] ^= nLow; + newHashParts[1] ^= nHigh; + newHashParts[2] ^= nLow; + newHashParts[3] ^= nHigh; - /* convert to hexadecimal */ - for (i=0; i<16; i++) - { - output[i*2]=hexChars[(newHash[i]>>4)&0xF]; - output[(i*2)+1]=hexChars[newHash[i]&0xF]; - } + /* adjust endianness */ + for(i = 0; i < 4; i++) + newHashParts[i] = GUINT_TO_LE(newHashParts[i]); + + /* make a string of the parts */ + newHash = (unsigned char *)newHashParts; - output[32]='\0'; + /* convert to hexadecimal */ + for (i = 0; i < 16; i++) + { + output[i * 2] = hexChars[(newHash[i] >> 4) & 0xF]; + output[(i * 2) + 1] = hexChars[newHash[i] & 0xF]; + } -// purple_debug_info("MSNP14","chl output{%s}\n",output); + output[32] = '\0'; } +
--- a/libpurple/protocols/msn/nexus.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/nexus.c Sat Jul 12 07:32:05 2008 +0000 @@ -22,11 +22,27 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "msn.h" -#include "soap2.h" +#include "soap.h" #include "nexus.h" #include "notification.h" -#undef NEXUS_LOGIN_TWN +/************************************************************************** + * Valid Ticket Tokens + **************************************************************************/ + +#define SSO_VALID_TICKET_DOMAIN 0 +#define SSO_VALID_TICKET_POLICY 1 +static char *ticket_domains[][2] = { + /* http://msnpiki.msnfanatic.com/index.php/MSNP15:SSO */ + /* {"Domain", "Policy Ref URI"}, Purpose */ + {"messengerclear.live.com", NULL}, /* Authentication for messenger. */ + {"messenger.msn.com", "?id=507"}, /* Authentication for receiving OIMs. */ + {"contacts.msn.com", "MBI"}, /* Authentication for the Contact server. */ + {"messengersecure.live.com", "MBI_SSL"}, /* Authentication for sending OIMs. */ + {"spaces.live.com", "MBI"}, /* Authentication for the Windows Live Spaces */ + {"livecontacts.live.com", "MBI"}, /* Live Contacts API, a simplified version of the Contacts SOAP service */ + {"storage.live.com", "MBI"}, /* Storage REST API */ +}; /************************************************************************** * Main @@ -36,12 +52,17 @@ msn_nexus_new(MsnSession *session) { MsnNexus *nexus; + int i; nexus = g_new0(MsnNexus, 1); nexus->session = session; - nexus->challenge_data = g_hash_table_new_full(g_str_hash, - g_str_equal, g_free, g_free); + nexus->token_len = sizeof(ticket_domains) / sizeof(char *[2]); + nexus->tokens = g_new0(MsnTicketToken, nexus->token_len); + + for (i = 0; i < nexus->token_len; i++) + nexus->tokens[i].token = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); return nexus; } @@ -49,79 +70,293 @@ void msn_nexus_destroy(MsnNexus *nexus) { - if (nexus->challenge_data != NULL) - g_hash_table_destroy(nexus->challenge_data); + int i; + for (i = 0; i < nexus->token_len; i++) { + g_hash_table_destroy(nexus->tokens[i].token); + g_free(nexus->tokens[i].secret); + } + + g_free(nexus->tokens); + g_free(nexus->policy); + g_free(nexus->nonce); + g_free(nexus->cipher); + g_free(nexus->secret); + g_free(nexus); +} + +/************************************************************************** + * RPS/SSO Authentication + **************************************************************************/ + +static char * +rps_create_key(const char *key, int key_len, const char *data, size_t data_len) +{ + const guchar magic[] = "WS-SecureConversation"; + const int magic_len = sizeof(magic) - 1; + + PurpleCipherContext *hmac; + guchar hash1[20], hash2[20], hash3[20], hash4[20]; + char *result; + + hmac = purple_cipher_context_new_by_name("hmac", NULL); + + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); + purple_cipher_context_append(hmac, magic, magic_len); + purple_cipher_context_append(hmac, (guchar *)data, data_len); + purple_cipher_context_digest(hmac, sizeof(hash1), hash1, NULL); + + purple_cipher_context_reset(hmac, NULL); + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); + purple_cipher_context_append(hmac, hash1, 20); + purple_cipher_context_append(hmac, magic, magic_len); + purple_cipher_context_append(hmac, (guchar *)data, data_len); + purple_cipher_context_digest(hmac, sizeof(hash2), hash2, NULL); + + purple_cipher_context_reset(hmac, NULL); + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); + purple_cipher_context_append(hmac, hash1, 20); + purple_cipher_context_digest(hmac, sizeof(hash3), hash3, NULL); + + purple_cipher_context_reset(hmac, NULL); + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); + purple_cipher_context_append(hmac, hash3, sizeof(hash3)); + purple_cipher_context_append(hmac, magic, magic_len); + purple_cipher_context_append(hmac, (guchar *)data, data_len); + purple_cipher_context_digest(hmac, sizeof(hash4), hash4, NULL); + + purple_cipher_context_destroy(hmac); + + result = g_malloc(24); + memcpy(result, hash2, sizeof(hash2)); + memcpy(result + sizeof(hash2), hash4, 4); + + return result; +} + +static char * +des3_cbc(const char *key, const char *iv, const char *data, int len, gboolean decrypt) +{ + PurpleCipherContext *des3; + char *out; + size_t outlen; - g_free(nexus->challenge_data_str); - g_free(nexus); + des3 = purple_cipher_context_new_by_name("des3", NULL); + purple_cipher_context_set_key(des3, (guchar *)key); + purple_cipher_context_set_batch_mode(des3, PURPLE_CIPHER_BATCH_MODE_CBC); + purple_cipher_context_set_iv(des3, (guchar *)iv, 8); + + out = g_malloc(len); + if (decrypt) + purple_cipher_context_decrypt(des3, (guchar *)data, len, (guchar *)out, &outlen); + else + purple_cipher_context_encrypt(des3, (guchar *)data, len, (guchar *)out, &outlen); + + purple_cipher_context_destroy(des3); + + return out; +} + +#define CRYPT_MODE_CBC 1 +#define CIPHER_TRIPLE_DES 0x6603 +#define HASH_SHA1 0x8004 +static char * +msn_rps_encrypt(MsnNexus *nexus) +{ + MsnUsrKey *usr_key; + const char magic1[] = "SESSION KEY HASH"; + const char magic2[] = "SESSION KEY ENCRYPTION"; + PurpleCipherContext *hmac; + size_t len; + guchar hash[20]; + char *key1, *key2, *key3; + gsize key1_len; + int *iv; + char *nonce_fixed; + char *cipher; + char *response; + + usr_key = g_malloc(sizeof(MsnUsrKey)); + usr_key->size = GUINT32_TO_LE(28); + usr_key->crypt_mode = GUINT32_TO_LE(CRYPT_MODE_CBC); + usr_key->cipher_type = GUINT32_TO_LE(CIPHER_TRIPLE_DES); + usr_key->hash_type = GUINT32_TO_LE(HASH_SHA1); + usr_key->iv_len = GUINT32_TO_LE(8); + usr_key->hash_len = GUINT32_TO_LE(20); + usr_key->cipher_len = GUINT32_TO_LE(72); + + key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len); + key2 = rps_create_key(key1, key1_len, magic1, sizeof(magic1) - 1); + key3 = rps_create_key(key1, key1_len, magic2, sizeof(magic2) - 1); + + iv = (int *)usr_key->iv; + iv[0] = rand(); + iv[1] = rand(); + + len = strlen(nexus->nonce); + hmac = purple_cipher_context_new_by_name("hmac", NULL); + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key2, 24); + purple_cipher_context_append(hmac, (guchar *)nexus->nonce, len); + purple_cipher_context_digest(hmac, 20, hash, NULL); + purple_cipher_context_destroy(hmac); + + /* We need to pad this to 72 bytes, apparently */ + nonce_fixed = g_malloc(len + 8); + memcpy(nonce_fixed, nexus->nonce, len); + memset(nonce_fixed + len, 0x08, 8); + cipher = des3_cbc(key3, usr_key->iv, nonce_fixed, len + 8, FALSE); + g_free(nonce_fixed); + + memcpy(usr_key->hash, hash, 20); + memcpy(usr_key->cipher, cipher, 72); + + g_free(key1); + g_free(key2); + g_free(key3); + g_free(cipher); + + response = purple_base64_encode((guchar *)usr_key, sizeof(MsnUsrKey)); + + g_free(usr_key); + + return response; } /************************************************************************** * Login **************************************************************************/ +/* Used to specify which token to update when only doing single updates */ +typedef struct _MsnNexusUpdateData MsnNexusUpdateData; +struct _MsnNexusUpdateData { + MsnNexus *nexus; + int id; + GSourceFunc cb; + gpointer data; +}; + +static gboolean +nexus_parse_token(MsnNexus *nexus, int id, xmlnode *node) +{ + char *token_str, *expiry_str; + const char *id_str; + char **elems, **cur, **tokens; + xmlnode *token = xmlnode_get_child(node, "RequestedSecurityToken/BinarySecurityToken"); + xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret"); + xmlnode *expires = xmlnode_get_child(node, "LifeTime/Expires"); + + if (!token) + return FALSE; + + /* Use the ID that the server sent us */ + if (id == -1) { + id_str = xmlnode_get_attrib(token, "Id"); + if (id_str == NULL) + return FALSE; + + id = atol(id_str + 7) - 1; /* 'Compact#' or 'PPToken#' */ + if (id >= nexus->token_len) + return FALSE; /* Where did this come from? */ + } + + token_str = xmlnode_get_data(token); + if (token_str == NULL) + return FALSE; + + g_hash_table_remove_all(nexus->tokens[id].token); + + elems = g_strsplit(token_str, "&", 0); + + for (cur = elems; *cur != NULL; cur++) { + tokens = g_strsplit(*cur, "=", 2); + g_hash_table_insert(nexus->tokens[id].token, tokens[0], tokens[1]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + g_strfreev(elems); + g_free(token_str); + + if (secret) + nexus->tokens[id].secret = xmlnode_get_data(secret); + else + nexus->tokens[id].secret = NULL; + + /* Yay for MS using ISO-8601 */ + expiry_str = xmlnode_get_data(expires); + nexus->tokens[id].expiry = purple_str_to_time(expiry_str, + FALSE, NULL, NULL, NULL); + g_free(expiry_str); + + purple_debug_info("msn", "Updated ticket for domain '%s', expires at %" G_GINT64_FORMAT ".\n", + ticket_domains[id][SSO_VALID_TICKET_DOMAIN], + (gint64)nexus->tokens[id].expiry); + return TRUE; +} + +static gboolean +nexus_parse_collection(MsnNexus *nexus, int id, xmlnode *collection) +{ + xmlnode *node; + gboolean result; + + node = xmlnode_get_child(collection, "RequestSecurityTokenResponse"); + + if (!node) + return FALSE; + + result = TRUE; + for (; node && result; node = node->next) { + xmlnode *endpoint = xmlnode_get_child(node, "AppliesTo/EndpointReference/Address"); + char *address = xmlnode_get_data(endpoint); + + if (g_str_equal(address, "http://Passport.NET/tb")) { + /* This node contains the stuff for updating tokens. */ + char *data; + xmlnode *cipher = xmlnode_get_child(node, "RequestedSecurityToken/EncryptedData/CipherData/CipherValue"); + xmlnode *secret = xmlnode_get_child(node, "RequestedProofToken/BinarySecret"); + + nexus->cipher = xmlnode_get_data(cipher); + data = xmlnode_get_data(secret); + nexus->secret = (char *)purple_base64_decode(data, NULL); + g_free(data); + + } else { + result = nexus_parse_token(nexus, id, node); + } + g_free(address); + } + + return result; +} + static void nexus_got_response_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) { MsnNexus *nexus = data; MsnSession *session = nexus->session; - xmlnode *node; + const char *ticket; + char *response; if (resp == NULL) { msn_session_set_error(session, MSN_ERROR_SERVCONN, _("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); - - 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*/ - 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); - msn_nexus_destroy(nexus); - session->nexus = NULL; - - return; - } + if (!nexus_parse_collection(nexus, -1, + xmlnode_get_child(resp->xml, + "Body/RequestSecurityTokenResponseCollection"))) { + msn_session_set_error(session, MSN_ERROR_SERVCONN, _("Windows Live ID authentication:Invalid response")); + return; } - /* we must have failed! */ - msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication: cannot find authenticate token in server response")); + ticket = msn_nexus_get_token_str(nexus, MSN_AUTH_MESSENGER); + response = msn_rps_encrypt(nexus); + msn_got_login_params(session, ticket, response); + g_free(response); } /*when connect, do the SOAP Style windows Live ID authentication */ @@ -129,92 +364,258 @@ msn_nexus_connect(MsnNexus *nexus) { MsnSession *session = nexus->session; - char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; - char *fs0,*fs; const char *username; char *password; - char *tail; -#ifdef NEXUS_LOGIN_TWN - char *challenge_str; -#else - char *rst1_str,*rst2_str,*rst3_str; -#endif + GString *domains; + char *request; + int i; MsnSoapMessage *soap; - purple_debug_info("MSN Nexus","Starting Windows Live ID authentication\n"); + purple_debug_info("msn", "Starting Windows Live ID authentication\n"); msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); - /*prepare the Windows Live ID authentication token*/ username = purple_account_get_username(session->account); password = g_strndup(purple_connection_get_password(session->account->gc), 16); - lc = (char *)g_hash_table_lookup(nexus->challenge_data, "lc"); - id = (char *)g_hash_table_lookup(nexus->challenge_data, "id"); - tw = (char *)g_hash_table_lookup(nexus->challenge_data, "tw"); - fs0= (char *)g_hash_table_lookup(nexus->challenge_data, "fs"); - ru = (char *)g_hash_table_lookup(nexus->challenge_data, "ru"); - ct = (char *)g_hash_table_lookup(nexus->challenge_data, "ct"); - kpp= (char *)g_hash_table_lookup(nexus->challenge_data, "kpp"); - kv = (char *)g_hash_table_lookup(nexus->challenge_data, "kv"); - ver= (char *)g_hash_table_lookup(nexus->challenge_data, "ver"); - rn = (char *)g_hash_table_lookup(nexus->challenge_data, "rn"); - tpf= (char *)g_hash_table_lookup(nexus->challenge_data, "tpf"); + purple_debug_info("msn", "Logging on %s, with policy '%s', nonce '%s'\n", + username, nexus->policy, nexus->nonce); + + domains = g_string_new(NULL); + for (i = 0; i < nexus->token_len; i++) { + g_string_append_printf(domains, MSN_SSO_RST_TEMPLATE, + i+1, + ticket_domains[i][SSO_VALID_TICKET_DOMAIN], + ticket_domains[i][SSO_VALID_TICKET_POLICY] != NULL ? + ticket_domains[i][SSO_VALID_TICKET_POLICY] : + nexus->policy); + } + + request = g_strdup_printf(MSN_SSO_TEMPLATE, username, password, domains->str); + g_free(password); + g_string_free(domains, TRUE); + + soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); + g_free(request); + msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, + nexus_got_response_cb, nexus); +} - /* - * add some fail-safe code to avoid windows Purple Crash bug #1540454 - * If any of these string is NULL, will return Authentication Fail! - * for when windows g_strdup_printf() implementation get NULL point,It crashed! - */ - if(!(lc && id && tw && ru && ct && kpp && kv && ver && tpf)){ - purple_debug_error("MSN Nexus","WLM Authenticate Key Error!\n"); - msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); - g_free(password); - msn_nexus_destroy(nexus); - session->nexus = NULL; +static void +nexus_got_update_cb(MsnSoapMessage *req, MsnSoapMessage *resp, gpointer data) +{ + MsnNexusUpdateData *ud = data; + MsnNexus *nexus = ud->nexus; + char iv[8] = {0,0,0,0,0,0,0,0}; + xmlnode *enckey; + char *tmp; + char *nonce; + gsize len; + char *key; + +#if 0 + char *decrypted_pp; +#endif + char *decrypted_data; + + purple_debug_info("msn", "Got Update Response for %s.\n", ticket_domains[ud->id][SSO_VALID_TICKET_DOMAIN]); + + enckey = xmlnode_get_child(resp->xml, "Header/Security/DerivedKeyToken"); + while (enckey) { + if (g_str_equal(xmlnode_get_attrib(enckey, "Id"), "EncKey")) + break; + enckey = xmlnode_get_next_twin(enckey); + } + if (!enckey) { + purple_debug_error("msn", "Invalid response in token update.\n"); return; } - /* - * in old MSN NS server's "USR TWN S" return,didn't include fs string - * so we use a default "1" for fs. - */ - if(fs0){ - fs = g_strdup(fs0); - }else{ - fs = g_strdup("1"); + tmp = xmlnode_get_data(xmlnode_get_child(enckey, "Nonce")); + nonce = (char *)purple_base64_decode(tmp, &len); + key = rps_create_key(nexus->secret, 24, nonce, len); + g_free(tmp); + g_free(nonce); + +#if 0 + /* Don't know what this is for yet */ + tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, + "Header/EncryptedPP/EncryptedData/CipherData/CipherValue")); + if (tmp) { + decrypted_pp = des3_cbc(key, iv, tmp, len, TRUE); + g_free(tmp); + purple_debug_info("msn", "Got Response Header EncryptedPP: %s\n", decrypted_pp); + g_free(decrypted_pp); + } +#endif + + tmp = xmlnode_get_data(xmlnode_get_child(resp->xml, + "Body/EncryptedData/CipherData/CipherValue")); + if (tmp) { + char *unescaped; + xmlnode *rstresponse; + + unescaped = (char *)purple_base64_decode(tmp, &len); + g_free(tmp); + + decrypted_data = des3_cbc(key, iv, unescaped, len, TRUE); + g_free(unescaped); + purple_debug_info("msn", "Got Response Body EncryptedData: %s\n", decrypted_data); + + rstresponse = xmlnode_from_str(decrypted_data, -1); + if (g_str_equal(rstresponse->name, "RequestSecurityTokenResponse")) + nexus_parse_token(nexus, ud->id, rstresponse); + else + nexus_parse_collection(nexus, ud->id, rstresponse); + g_free(decrypted_data); } -#ifdef NEXUS_LOGIN_TWN - challenge_str = g_strdup_printf( - "lc=%s&id=%s&tw=%s&fs=%s&ru=%s&ct=%s&kpp=%s&kv=%s&ver=%s&rn=%s&tpf=%s\r\n", - lc,id,tw,fs,ru,ct,kpp,kv,ver,rn,tpf - ); + if (ud->cb) + purple_timeout_add(0, ud->cb, ud->data); - /*build the SOAP windows Live ID XML body */ - tail = g_strdup_printf(TWN_ENVELOP_TEMPLATE, username, password, challenge_str); - g_free(challenge_str); -#else - rst1_str = g_strdup_printf( - "id=%s&tw=%s&fs=%s&kpp=%s&kv=%s&ver=%s&rn=%s", - id,tw,fs,kpp,kv,ver,rn - ); - rst2_str = g_strdup_printf( - "fs=%s&id=%s&kv=%s&rn=%s&tw=%s&ver=%s", - fs,id,kv,rn,tw,ver - ); - rst3_str = g_strdup_printf("id=%s",id); - tail = g_strdup_printf(TWN_LIVE_ENVELOP_TEMPLATE,username,password,rst1_str,rst2_str,rst3_str); - g_free(rst1_str); - g_free(rst2_str); - g_free(rst3_str); -#endif - g_free(fs); - g_free(password); - - soap = msn_soap_message_new(NULL, xmlnode_from_str(tail, -1)); - g_free(tail); - msn_soap_message_send(nexus->session, soap, MSN_TWN_SERVER, TWN_POST_URL, - nexus_got_response_cb, nexus); + g_free(ud); } +void +msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data) +{ + MsnSession *session = nexus->session; + MsnNexusUpdateData *ud; + PurpleCipherContext *sha1; + PurpleCipherContext *hmac; + + char *key; + + guchar digest[20]; + + struct tm *tm; + time_t now; + char *now_str; + char *timestamp; + char *timestamp_b64; + + char *domain; + char *domain_b64; + + char *signedinfo; + gint32 nonce[6]; + int i; + char *nonce_b64; + char *signature_b64; + guchar signature[20]; + + char *request; + MsnSoapMessage *soap; + + purple_debug_info("msn", + "Updating ticket for user '%s' on domain '%s'\n", + purple_account_get_username(session->account), + ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); + + ud = g_new0(MsnNexusUpdateData, 1); + ud->nexus = nexus; + ud->id = id; + ud->cb = cb; + ud->data = data; + + sha1 = purple_cipher_context_new_by_name("sha1", NULL); + + domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE, + id, + ticket_domains[id][SSO_VALID_TICKET_DOMAIN], + ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ? + ticket_domains[id][SSO_VALID_TICKET_POLICY] : + nexus->policy); + purple_cipher_context_append(sha1, (guchar *)domain, strlen(domain)); + purple_cipher_context_digest(sha1, 20, digest, NULL); + domain_b64 = purple_base64_encode(digest, 20); + + now = time(NULL); + tm = gmtime(&now); + now_str = g_strdup(purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); + now += 5*60; + tm = gmtime(&now); + timestamp = g_strdup_printf(MSN_SSO_TIMESTAMP_TEMPLATE, + now_str, + purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); + purple_cipher_context_reset(sha1, NULL); + purple_cipher_context_append(sha1, (guchar *)timestamp, strlen(timestamp)); + purple_cipher_context_digest(sha1, 20, digest, NULL); + timestamp_b64 = purple_base64_encode(digest, 20); + g_free(now_str); + + purple_cipher_context_destroy(sha1); + + signedinfo = g_strdup_printf(MSN_SSO_SIGNEDINFO_TEMPLATE, + id, + domain_b64, + timestamp_b64); + + for (i = 0; i < 6; i++) + nonce[i] = rand(); + nonce_b64 = purple_base64_encode((guchar *)&nonce, sizeof(nonce)); + + key = rps_create_key(nexus->secret, 24, (char *)nonce, sizeof(nonce)); + hmac = purple_cipher_context_new_by_name("hmac", NULL); + purple_cipher_context_set_option(hmac, "hash", "sha1"); + purple_cipher_context_set_key_with_len(hmac, (guchar *)key, 24); + purple_cipher_context_append(hmac, (guchar *)signedinfo, strlen(signedinfo)); + purple_cipher_context_digest(hmac, 20, signature, NULL); + purple_cipher_context_destroy(hmac); + signature_b64 = purple_base64_encode(signature, 20); + + request = g_strdup_printf(MSN_SSO_TOKEN_UPDATE_TEMPLATE, + nexus->cipher, + nonce_b64, + timestamp, + signedinfo, + signature_b64, + domain); + + g_free(nonce_b64); + g_free(domain_b64); + g_free(timestamp_b64); + g_free(timestamp); + g_free(key); + g_free(signature_b64); + g_free(signedinfo); + g_free(domain); + + soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); + g_free(request); + msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, + nexus_got_update_cb, ud); +} + +GHashTable * +msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id) +{ + g_return_val_if_fail(nexus != NULL, NULL); + g_return_val_if_fail(id < nexus->token_len, NULL); + + return nexus->tokens[id].token; +} + +const char * +msn_nexus_get_token_str(MsnNexus *nexus, MsnAuthDomains id) +{ + static char buf[1024]; + GHashTable *token = msn_nexus_get_token(nexus, id); + const char *msn_t; + const char *msn_p; + gint ret; + + g_return_val_if_fail(token != NULL, NULL); + + msn_t = g_hash_table_lookup(token, "t"); + msn_p = g_hash_table_lookup(token, "p"); + + g_return_val_if_fail(msn_t != NULL, NULL); + g_return_val_if_fail(msn_p != NULL, NULL); + + ret = g_snprintf(buf, sizeof(buf) - 1, "t=%s&p=%s", msn_t, msn_p); + g_return_val_if_fail(ret != -1, NULL); + + return buf; +} +
--- a/libpurple/protocols/msn/nexus.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/nexus.h Sat Jul 12 07:32:05 2008 +0000 @@ -24,127 +24,210 @@ #ifndef _MSN_NEXUS_H_ #define _MSN_NEXUS_H_ -#include "soap.h" +/* Index into ticket_tokens in nexus.c Keep updated! */ +typedef enum +{ + MSN_AUTH_MESSENGER = 0, + MSN_AUTH_MESSENGER_WEB = 1, + MSN_AUTH_CONTACTS = 2, + MSN_AUTH_LIVE_SECURE = 3, + MSN_AUTH_SPACES = 4, + MSN_AUTH_LIVE_CONTACTS = 5, + MSN_AUTH_STORAGE = 6 +} MsnAuthDomains; -/*#define MSN_TWN_SERVER "loginnet.passport.com"*/ -#define MSN_TWN_SERVER "login.live.com" +#define MSN_SSO_SERVER "login.live.com" +#define SSO_POST_URL "/RST.srf" -#define TWN_START_TOKEN "<wsse:BinarySecurityToken Id=\"PPToken1\">" -#define TWN_END_TOKEN "</wsse:BinarySecurityToken>" +#define MSN_SSO_RST_TEMPLATE \ +"<wst:RequestSecurityToken xmlns=\"http://schemas.xmlsoap.org/ws/2004/04/trust\" Id=\"RST%d\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo xmlns=\"http://schemas.xmlsoap.org/ws/2002/12/policy\">"\ + "<wsa:EndpointReference xmlns=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\">"\ + "<wsa:Address>%s</wsa:Address>"\ + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"%s\"></wsse:PolicyReference>"\ +"</wst:RequestSecurityToken>" -#define TWN_POST_URL "/RST.srf" -#define TWN_ENVELOP_TEMPLATE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\ - "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ - "<Header>"\ - "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ - "<ps:HostingApp>{3:B}</ps:HostingApp>"\ - "<ps:BinaryVersion>4</ps:BinaryVersion>"\ - "<ps:UIVersion>1</ps:UIVersion>"\ - "<ps:Cookies></ps:Cookies>"\ - "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>"\ - "</ps:AuthInfo>"\ - "<wsse:Security>"\ - "<wsse:UsernameToken Id=\"user\">"\ - "<wsse:Username>%s</wsse:Username>"\ - "<wsse:Password>%s</wsse:Password>"\ - "</wsse:UsernameToken>"\ - "</wsse:Security>"\ - "</Header>"\ - "<Body>"\ - "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\ - "<wst:RequestSecurityToken Id=\"RST0\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ +#define MSN_SSO_TEMPLATE "<?xml version='1.0' encoding='utf-8'?>"\ +"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\""\ + " xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\""\ + " xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\""\ + " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""\ + " xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\""\ + " xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\""\ + " xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ + "<Header>"\ + "<ps:AuthInfo"\ + " xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\""\ + " Id=\"PPAuthInfo\">"\ + "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ + "<ps:BinaryVersion>4</ps:BinaryVersion>"\ + "<ps:UIVersion>1</ps:UIVersion>"\ + "<ps:Cookies></ps:Cookies>"\ + "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>"\ + "</ps:AuthInfo>"\ + "<wsse:Security>"\ + "<wsse:UsernameToken Id=\"user\">"\ + "<wsse:Username>%s</wsse:Username>"\ + "<wsse:Password>%s</wsse:Password>"\ + "</wsse:UsernameToken>"\ + "</wsse:Security>"\ + "</Header>"\ + "<Body>"\ + "<ps:RequestMultipleSecurityTokens"\ + " xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\""\ + " Id=\"RSTS\">"\ + "<wst:RequestSecurityToken Id=\"RST0\">"\ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ + "<wsp:AppliesTo>"\ + "<wsa:EndpointReference>"\ "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "</wst:RequestSecurityToken>"\ - "<wst:RequestSecurityToken Id=\"RST1\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>messenger.msn.com</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "<wsse:PolicyReference URI=\"?%s\">"\ - "</wsse:PolicyReference>"\ - "</wst:RequestSecurityToken>"\ - "</ps:RequestMultipleSecurityTokens>"\ - "</Body>"\ - "</Envelope>" + "</wsa:EndpointReference>"\ + "</wsp:AppliesTo>"\ + "</wst:RequestSecurityToken>"\ + "%s" /* Other RSTn tokens */\ + "</ps:RequestMultipleSecurityTokens>"\ + "</Body>"\ +"</Envelope>" + +#define MSN_SSO_AUTHINFO_TEMPLATE \ +"<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ + "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ + "<ps:BinaryVersion>4</ps:BinaryVersion>"\ + "<ps:UIVersion>1</ps:UIVersion>"\ + "<ps:Cookies></ps:Cookies>"\ + "<ps:RequestParams>AQAAAAIAAABsYwQAAAA0MTA1</ps:RequestParams>"\ +"</ps:AuthInfo>" +/* Not sure what's editable here, so I'll just hard-code the SHA1 hash */ +#define MSN_SSO_AUTHINFO_SHA1_BASE64 "d2IeTF4DAkPEa/tVETHznsivEpc=" + +#define MSN_SSO_TIMESTAMP_TEMPLATE \ +"<wsu:Timestamp xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" Id=\"Timestamp\">"\ + "<wsu:Created>%s</wsu:Created>"\ + "<wsu:Expires>%s</wsu:Expires>"\ +"</wsu:Timestamp>" -#define TWN_LIVE_START_TOKEN "<wsse:BinarySecurityToken Id=\"PPToken1\">" -#define TWN_LIVE_END_TOKEN "</wsse:BinarySecurityToken>" -#define TWN_LIVE_ENVELOP_TEMPLATE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"\ -"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ - "<Header>"\ - "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">"\ - "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>"\ - "<ps:BinaryVersion>4</ps:BinaryVersion>"\ - "<ps:UIVersion>1</ps:UIVersion>"\ - "<ps:Cookies></ps:Cookies>"\ - "<ps:RequestParams>AQAAAAIAAABsYwQAAAAyMDUy</ps:RequestParams>"\ - "</ps:AuthInfo>"\ - "<wsse:Security>"\ - "<wsse:UsernameToken Id=\"user\">"\ - "<wsse:Username>%s</wsse:Username>"\ - "<wsse:Password>%s</wsse:Password>"\ - "</wsse:UsernameToken>"\ - "</wsse:Security>"\ - "</Header>"\ - "<Body>"\ - "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">"\ - "<wst:RequestSecurityToken Id=\"RST0\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>http://Passport.NET/tb</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "</wst:RequestSecurityToken>"\ - "<wst:RequestSecurityToken Id=\"RST1\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>messenger.msn.com</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ - "</wst:RequestSecurityToken>"\ - "<wst:RequestSecurityToken Id=\"RST2\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>contacts.msn.com</wsa:Address>"\ - "</wsa:EndpointReference>"\ - "</wsp:AppliesTo>"\ - "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ - " </wst:RequestSecurityToken>"\ - "<wst:RequestSecurityToken Id=\"RST3\">"\ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>"\ - "<wsp:AppliesTo>"\ - "<wsa:EndpointReference>"\ - "<wsa:Address>voice.messenger.msn.com</wsa:Address>"\ - "</wsa:EndpointReference>"\ - " </wsp:AppliesTo>"\ - "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>"\ - "</wst:RequestSecurityToken>"\ - "</ps:RequestMultipleSecurityTokens>"\ - "</Body>"\ +#define MSN_SSO_SIGNEDINFO_TEMPLATE \ +"<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"\ + "<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod>"\ + "<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"></SignatureMethod>"\ + "<Reference URI=\"#RST%d\">"\ + "<Transforms>"\ + "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ + "</Transforms>"\ + "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ + "<DigestValue>%s</DigestValue>"\ + "</Reference>"\ + "<Reference URI=\"#Timestamp\">"\ + "<Transforms>"\ + "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ + "</Transforms>"\ + "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ + "<DigestValue>%s</DigestValue>"\ + "</Reference>"\ + "<Reference URI=\"#PPAuthInfo\">"\ + "<Transforms>"\ + "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform>"\ + "</Transforms>"\ + "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></DigestMethod>"\ + "<DigestValue>" MSN_SSO_AUTHINFO_SHA1_BASE64 "</DigestValue>"\ + "</Reference>"\ +"</SignedInfo>" + +#define MSN_SSO_TOKEN_UPDATE_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<Envelope"\ + " xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\""\ + " xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\""\ + " xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\""\ + " xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\""\ + " xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\""\ + " xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\""\ + " xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\""\ + " xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">"\ + "<Header>"\ + MSN_SSO_AUTHINFO_TEMPLATE /* ps:AuthInfo */ \ + "<wsse:Security>"\ + "<EncryptedData xmlns=\"http://www.w3.org/2001/04/xmlenc#\" Id=\"BinaryDAToken0\" Type=\"http://www.w3.org/2001/04/xmlenc#Element\">"\ + "<EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#tripledes-cbc\"></EncryptionMethod>"\ + "<ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">"\ + "<ds:KeyName>http://Passport.NET/STS</ds:KeyName>"\ + "</ds:KeyInfo>"\ + "<CipherData>"\ + "<CipherValue>%s</CipherValue>"\ + "</CipherData>"\ + "</EncryptedData>"\ + "<wssc:DerivedKeyToken Id=\"SignKey\">"\ + "<wsse:RequestedTokenReference>"\ + "<wsse:KeyIdentifier ValueType=\"http://docs.oasis-open.org/wss/2004/XX/oasis-2004XX-wss-saml-token-profile-1.0#SAMLAssertionID\" />"\ + "<wsse:Reference URI=\"#BinaryDAToken0\" />"\ + "</wsse:RequestedTokenReference>"\ + "<wssc:Nonce>%s</wssc:Nonce>"\ + "</wssc:DerivedKeyToken>"\ + "%s" /* wsu:Timestamp */\ + "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"\ + "%s" /* SignedInfo */\ + "<SignatureValue>%s</SignatureValue>"\ + "<KeyInfo>"\ + "<wsse:SecurityTokenReference>"\ + "<wsse:Reference URI=\"#SignKey\" />"\ + "</wsse:SecurityTokenReference>"\ + "</KeyInfo>"\ + "</Signature>"\ + "</wsse:Security>"\ + "</Header>"\ + "<Body>"\ + "%s" /* wst:RequestSecurityToken */ \ + "</Body>"\ "</Envelope>" +typedef struct _MsnUsrKey MsnUsrKey; +struct _MsnUsrKey +{ + int size; /* 28. Does not count data */ + int crypt_mode; /* CRYPT_MODE_CBC (1) */ + int cipher_type; /* TripleDES (0x6603) */ + int hash_type; /* SHA1 (0x8004) */ + int iv_len; /* 8 */ + int hash_len; /* 20 */ + int cipher_len; /* 72 */ + /* Data */ + char iv[8]; + char hash[20]; + char cipher[72]; +}; + +typedef struct _MsnTicketToken MsnTicketToken; +struct _MsnTicketToken { + GHashTable *token; + char *secret; + time_t expiry; +}; + typedef struct _MsnNexus MsnNexus; struct _MsnNexus { MsnSession *session; - char * challenge_data_str; - GHashTable *challenge_data; + + /* From server via USR command */ + char *policy; + char *nonce; + + /* From server via SOAP stuff */ + char *cipher; + char *secret; + MsnTicketToken *tokens; + int token_len; }; void msn_nexus_connect(MsnNexus *nexus); MsnNexus *msn_nexus_new(MsnSession *session); void msn_nexus_destroy(MsnNexus *nexus); +GHashTable *msn_nexus_get_token(MsnNexus *nexus, MsnAuthDomains id); +const char *msn_nexus_get_token_str(MsnNexus *nexus, MsnAuthDomains id); +void msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data); +#endif /* _MSN_NEXUS_H_ */ -#endif /* _MSN_NEXUS_H_ */
--- a/libpurple/protocols/msn/notification.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/notification.c Sat Jul 12 07:32:05 2008 +0000 @@ -23,6 +23,7 @@ */ #include "msn.h" #include "notification.h" +#include "contact.h" #include "state.h" #include "error.h" #include "msnutils.h" @@ -104,7 +105,6 @@ vers = g_string_new(""); -/* for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) */ for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) g_string_append_printf(vers, " MSNP%d", i); @@ -132,7 +132,7 @@ servconn = notification->servconn; msn_servconn_set_connect_cb(servconn, connect_cb); - notification->in_use = msn_servconn_connect(servconn, host, port); + notification->in_use = msn_servconn_connect(servconn, host, port, TRUE); return notification->in_use; } @@ -195,7 +195,7 @@ **************************************************************************/ void -msn_got_login_params(MsnSession *session, const char *login_params) +msn_got_login_params(MsnSession *session, const char *ticket, const char *response) { MsnCmdProc *cmdproc; @@ -203,7 +203,7 @@ msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END); - msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params); + msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response); } static void @@ -212,8 +212,8 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", - purple_account_get_username(account)); + + msn_cmdproc_send(cmdproc, "USR", "SSO I %s", purple_account_get_username(account)); } static void @@ -228,43 +228,16 @@ if (!g_ascii_strcasecmp(cmd->params[1], "OK")) { /* authenticate OK */ - /* friendly name part no longer true in msnp11 */ -#if 0 - const char *friendly = purple_url_decode(cmd->params[3]); - - purple_connection_set_display_name(gc, friendly); -#endif msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN); - -// msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); - //TODO we should use SOAP contact to fetch contact list } - else if (!g_ascii_strcasecmp(cmd->params[1], "TWN")) + else if (!g_ascii_strcasecmp(cmd->params[1], "SSO")) { - /* Passport authentication */ - char **elems, **cur, **tokens; + /* RPS authentication */ session->nexus = msn_nexus_new(session); - /* Parse the challenge data. */ - session->nexus->challenge_data_str = g_strdup(cmd->params[3]); - elems = g_strsplit(cmd->params[3], ",", 0); - - for (cur = elems; *cur != NULL; cur++) - { - tokens = g_strsplit(*cur, "=", 2); - if(tokens[0] && tokens[1]) - { - purple_debug_info("MSNP14","challenge %p,key:%s,value:%s\n", - session->nexus->challenge_data,tokens[0],tokens[1]); - g_hash_table_insert(session->nexus->challenge_data, tokens[0], tokens[1]); - /* Don't free each of the tokens, only the array. */ - g_free(tokens); - } else - g_strfreev(tokens); - } - - g_strfreev(elems); + session->nexus->policy = g_strdup(cmd->params[3]); + session->nexus->nonce = g_strdup(cmd->params[4]); msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START); @@ -327,14 +300,13 @@ } /* - * Windows Live Messenger 8.0 + * Windows Live Messenger 8.5 * Notice :CVR String discriminate! * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx * to see the Local ID */ msn_cmdproc_send(cmdproc, "CVR", -// "0x0409 winnt 5.1 i386 MSG80BETA 8.0.0689 msmsgs %s", - "0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s", + "0x0409 winnt 5.1 i386 MSNMSGR 8.5.1288 msmsgs %s", purple_account_get_username(account)); } @@ -345,7 +317,9 @@ static void out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - if (!g_ascii_strcasecmp(cmd->params[0], "OTH")) + if (cmd->param_count == 0) + msn_session_set_error(cmdproc->session, -1, NULL); + else if (!g_ascii_strcasecmp(cmd->params[0], "OTH")) msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER, NULL); else if (!g_ascii_strcasecmp(cmd->params[0], "SSD")) @@ -377,7 +351,7 @@ msg = msn_message_new_from_cmd(cmdproc->session, cmd); - msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM); + msn_message_parse_payload(msg, payload, len, MSG_LINE_DEM, MSG_BODY_DEM); #ifdef MSN_DEBUG_NS msn_message_show_readable(msg, "Notification", TRUE); #endif @@ -390,23 +364,19 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_info("MSNP14","Processing MSG... \n"); - if(cmd->payload_len == 0){ - return; - } + purple_debug_info("msn", "Processing MSG... \n"); + /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued * command and we are processing it */ - if (cmd->payload == NULL) - { + if (cmd->payload == NULL) { cmdproc->last_cmd->payload_cb = msg_cmd_post; - cmdproc->servconn->payload_len = atoi(cmd->params[2]); - } - else - { + cmd->payload_len = atoi(cmd->params[2]); + + } else { g_return_if_fail(cmd->payload_cb != NULL); #if 0 /* glib on win32 doesn't correctly support precision modifiers for a string */ - purple_debug_info("MSNP14", "MSG payload:{%.*s}\n", cmd->payload_len, cmd->payload); + purple_debug_info("msn", "MSG payload:{%.*s}\n", cmd->payload_len, cmd->payload); #endif cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); } @@ -425,7 +395,7 @@ cmdproc = session->notification->cmdproc; g_return_if_fail(msg != NULL); payload = msn_message_gen_payload(msg, &payload_len); - purple_debug_info("MSNP14", + purple_debug_info("msn", "send UUM, payload{%s}, strlen:%" G_GSIZE_FORMAT ", len:%" G_GSIZE_FORMAT "\n", payload, strlen(payload), payload_len); type = msg->type; @@ -435,6 +405,7 @@ msn_cmdproc_send_trans(cmdproc, trans); } +#if 0 static void ubm_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) @@ -444,7 +415,7 @@ const char *passport; const char *content_type; - purple_debug_info("MSNP14","Process UBM payload:%.*s\n", (guint)len, payload); + purple_debug_info("msn", "Process UBM payload:%.*s\n", (guint)len, payload); msg = msn_message_new_from_cmd(cmdproc->session, cmd); msn_message_parse_payload(msg, payload, len,MSG_LINE_DEM,MSG_BODY_DEM); @@ -456,7 +427,7 @@ passport = msg->remote_user; content_type = msn_message_get_content_type(msg); - purple_debug_info("MSNP14", "type:%s\n", content_type); + purple_debug_info("msn", "type:%s\n", content_type); if(!strcmp(content_type,"text/plain")){ const char *value; const char *body; @@ -508,25 +479,24 @@ } msn_message_destroy(msg); } +#endif /*Yahoo msg process*/ static void ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_info("MSNP14","Processing UBM... \n"); - if(cmd->payload_len == 0){ - return; - } + purple_debug_info("msn", "Processing UBM... \n"); + /* NOTE: cmd is not always cmdproc->last_cmd, sometimes cmd is a queued * command and we are processing it */ - if (cmd->payload == NULL){ - cmdproc->last_cmd->payload_cb = ubm_cmd_post; - cmdproc->servconn->payload_len = atoi(cmd->params[2]); - }else{ + if (cmd->payload == NULL) { + cmdproc->last_cmd->payload_cb = msg_cmd_post; + cmd->payload_len = atoi(cmd->params[4]); + } else { g_return_if_fail(cmd->payload_cb != NULL); - purple_debug_info("MSNP14", "UBM payload:{%.*s}\n", (guint)(cmd->payload_len), cmd->payload); - ubm_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len); + purple_debug_info("msn", "UBM payload:{%.*s}\n", (guint)(cmd->payload_len), cmd->payload); + msg_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len); } } @@ -540,27 +510,8 @@ MsnTransaction *trans; char buf[33]; -#if 0 - cipher = purple_ciphers_find_cipher("md5"); - context = purple_cipher_context_new(cipher, NULL); - purple_cipher_context_append(context, (const guchar *)cmd->params[1], - strlen(cmd->params[1])); - challenge_resp = MSNP13_WLM_PRODUCT_KEY; - - purple_cipher_context_append(context, (const guchar *)challenge_resp, - strlen(challenge_resp)); - purple_cipher_context_digest(context, sizeof(digest), digest, NULL); - purple_cipher_context_destroy(context); - - for (i = 0; i < 16; i++) - { - g_snprintf(buf + (i*2), 3, "%02x", digest[i]); - } -#else msn_handle_chl(cmd->params[1], buf); -#endif -// purple_debug_info("MSNP14","<<challenge:{%s}:{%s}\n",cmd->params[1],buf); - trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP13_WLM_PRODUCT_ID); + trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP15_WLM_PRODUCT_ID); msn_transaction_set_payload(trans, buf, 32); @@ -572,7 +523,7 @@ **************************************************************************/ /* add contact to xmlnode */ static void -msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport, MsnListOp list_op, MsnUserType type) +msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport, MsnListOp list_op, MsnNetwork networkId) { xmlnode *d_node,*c_node; char **tokens; @@ -581,7 +532,7 @@ g_return_if_fail(passport != NULL); - purple_debug_info("MSNP14","Passport: %s, type: %d\n", passport, type); + purple_debug_info("msn", "Passport: %s, type: %d\n", passport, networkId); tokens = g_strsplit(passport, "@", 2); email = tokens[0]; domain = tokens[1]; @@ -615,16 +566,16 @@ c_node = xmlnode_new("c"); xmlnode_set_attrib(c_node, "n", email); - purple_debug_info("MSNP14", "list_op: %d\n", list_op); + purple_debug_info("msn", "list_op: %d\n", list_op); g_snprintf(fmt_str, sizeof(fmt_str), "%d", list_op); xmlnode_set_attrib(c_node, "l", fmt_str); - if (type != MSN_USER_TYPE_UNKNOWN) - g_snprintf(fmt_str, sizeof(fmt_str), "%d", type); + if (networkId != MSN_NETWORK_UNKNOWN) + g_snprintf(fmt_str, sizeof(fmt_str), "%d", networkId); else if (msn_user_is_yahoo(session->account, passport)) - g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_YAHOO); + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_NETWORK_YAHOO); else - g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_USER_TYPE_PASSPORT); + g_snprintf(fmt_str, sizeof(fmt_str), "%d", MSN_NETWORK_PASSPORT); /*mobile*/ //type_str = g_strdup_printf("4"); @@ -639,7 +590,7 @@ msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len) { MsnTransaction *trans; - purple_debug_info("MSN Notification","Sending ADL with payload: %s\n", payload); + purple_debug_info("msn", "Sending ADL with payload: %s\n", payload); trans = msn_transaction_new(cmdproc, "ADL", "%i", payload_len); msn_transaction_set_payload(trans, payload, payload_len); msn_cmdproc_send_trans(cmdproc, trans); @@ -670,7 +621,7 @@ continue; msn_add_contact_xml(session, adl_node, user->passport, - user->list_op & MSN_LIST_OP_MASK, user->type); + user->list_op & MSN_LIST_OP_MASK, user->networkid); /* each ADL command may contain up to 150 contacts */ if (++adl_count % 150 == 0 || l->next == NULL) { @@ -743,14 +694,14 @@ { xmlnode *root, *domain_node; - purple_debug_misc("MSN Notification", "Parsing received ADL XML data\n"); + purple_debug_misc("msn", "Parsing received ADL XML data\n"); g_return_if_fail(payload != NULL); root = xmlnode_from_str(payload, (gssize) len); if (root == NULL) { - purple_debug_info("MSN Notification", "Invalid XML!\n"); + purple_debug_info("msn", "Invalid XML in ADL!\n"); return; } for (domain_node = xmlnode_get_child(root, "d"); domain_node; domain_node = xmlnode_get_next_twin(domain_node)) { @@ -760,33 +711,18 @@ domain = xmlnode_get_attrib(domain_node, "n"); for (contact_node = xmlnode_get_child(domain_node, "c"); contact_node; contact_node = xmlnode_get_next_twin(contact_node)) { -// gchar *name = NULL, *friendlyname = NULL, *passport= NULL; const gchar *list; gint list_op = 0; -// name = xmlnode_get_attrib(contact_node, "n"); list = xmlnode_get_attrib(contact_node, "l"); if (list != NULL) { list_op = atoi(list); } -// friendlyname = xmlnode_get_attrib(contact_node, "f"); - -// passport = g_strdup_printf("%s@%s", name, domain); - -// if (friendlyname != NULL) { -// decoded_friendlyname = g_strdup(purple_url_decode(friendlyname)); -// } else { -// decoded_friendlyname = g_strdup(passport); -// } if (list_op & MSN_LIST_RL_OP) { /* someone is adding us */ -// got_new_entry(cmdproc->session->account->gc, passport, decoded_friendly_name); - msn_get_contact_list(cmdproc->session->contact, MSN_PS_PENDING_LIST, NULL); + msn_get_contact_list(cmdproc->session, MSN_PS_PENDING_LIST, NULL); } - -// g_free(decoded_friendly_name); -// g_free(passport); } } @@ -805,11 +741,12 @@ session = cmdproc->session; - if ( !strcmp(cmd->params[1], "OK")) { + if (!strcmp(cmd->params[1], "OK")) { /* ADL ack */ msn_session_finish_login(session); } else { cmdproc->last_cmd->payload_cb = adl_cmd_parse; + cmd->payload_len = atoi(cmd->params[1]); } return; @@ -827,7 +764,7 @@ account = session->account; gc = purple_account_get_connection(account); - purple_debug_error("msn","ADL error\n"); + purple_debug_error("msn", "ADL error\n"); reason = g_strdup_printf(_("Unknown error (%d)"), error); purple_notify_error(gc, NULL, _("Unable to add user"), reason); g_free(reason); @@ -837,36 +774,34 @@ fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) { - purple_debug_info("MSN Notification","FQY payload:\n%s\n", payload); + purple_debug_info("msn", "FQY payload:\n%s\n", payload); g_return_if_fail(cmdproc->session != NULL); - g_return_if_fail(cmdproc->session->contact != NULL); -// msn_notification_post_adl(cmdproc, payload, len); -// msn_get_address_book(cmdproc->session->contact, MSN_AB_SAVE_CONTACT, NULL, NULL); +/* msn_notification_post_adl(cmdproc, payload, len); */ +/* msn_get_address_book(cmdproc->session, MSN_AB_SAVE_CONTACT, NULL, NULL); */ } static void fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_info("MSNP14","Process FQY\n"); + purple_debug_info("msn", "Process FQY\n"); cmdproc->last_cmd->payload_cb = fqy_cmd_post; + cmd->payload_len = atoi(cmd->params[1]); +} + +static void +rml_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + if (payload != NULL) + purple_debug_info("msn", "Received RML:\n%s\n", payload); } static void rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { -#if 0 - MsnTransaction *trans; - char * payload; -#endif - - purple_debug_info("MSNP14","Process RML\n"); -#if 0 - trans = msn_transaction_new(cmdproc, "RML",""); - - msn_transaction_set_payload(trans, payload, strlen(payload)); - - msn_cmdproc_send_trans(cmdproc, trans); -#endif + purple_debug_info("msn", "Process RML\n"); + cmd->payload_len = atoi(cmd->params[1]); + cmdproc->last_cmd->payload_cb = rml_cmd_post; } static void @@ -975,7 +910,7 @@ msn_userlist_move_buddy(userlist, data->who, data->old_group_name, group_name); g_free(data->old_group_name); } else { - // msn_add_contact_to_group(userlist, data, data->who, group_name); + /* msn_add_contact_to_group(userlist, data, data->who, group_name); */ } } } @@ -1017,7 +952,7 @@ /* Tell libpurple that the user has signed off */ user = msn_userlist_find_user(cmdproc->session->userlist, cmd->params[0]); - user->status = "offline"; + msn_user_set_state(user, NULL); msn_user_update(user); /* If we have an open MsnSlpLink with the user then close it */ @@ -1036,7 +971,7 @@ MsnUser *user; MsnObject *msnobj; unsigned long clientid; - int wlmclient; + int networkid; const char *state, *passport, *friendly; session = cmdproc->session; @@ -1046,7 +981,7 @@ state = cmd->params[1]; passport = cmd->params[2]; /*if a contact is actually on the WLM part or the yahoo part*/ - wlmclient = atoi(cmd->params[3]); + networkid = atoi(cmd->params[3]); friendly = purple_url_decode(cmd->params[4]); user = msn_userlist_find_user(session->userlist, passport); @@ -1055,7 +990,7 @@ msn_user_set_friendly_name(user, friendly); - if (session->protocol_ver >= 9 && cmd->param_count == 8) + if (cmd->param_count == 7) { msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6])); msn_user_set_object(user, msnobj); @@ -1063,6 +998,8 @@ clientid = strtoul(cmd->params[5], NULL, 10); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->phone.mobile && user->phone.mobile[0] == '+'); + msn_user_set_clientid(user, clientid); + msn_user_set_network(user, networkid); msn_user_set_state(user, state); msn_user_update(user); @@ -1131,7 +1068,7 @@ static void ipg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - cmdproc->servconn->payload_len = atoi(cmd->params[0]); + cmd->payload_len = atoi(cmd->params[0]); cmdproc->last_cmd->payload_cb = ipg_cmd_post; } @@ -1144,7 +1081,7 @@ MsnUser *user; MsnObject *msnobj; unsigned long clientid; - int wlmclient; + int networkid; const char *state, *passport, *friendly, *old_friendly; session = cmdproc->session; @@ -1153,7 +1090,7 @@ state = cmd->params[0]; passport = cmd->params[1]; - wlmclient = atoi(cmd->params[2]); + networkid = atoi(cmd->params[2]); friendly = purple_url_decode(cmd->params[3]); user = msn_userlist_find_user(session->userlist, passport); @@ -1165,22 +1102,22 @@ msn_user_set_friendly_name(user, friendly); } - if (session->protocol_ver >= 9) + if (cmd->param_count == 6) { - if (cmd->param_count == 7) - { - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); - msn_user_set_object(user, msnobj); - } - else - { - msn_user_set_object(user, NULL); - } + msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); + msn_user_set_object(user, msnobj); + } + else + { + msn_user_set_object(user, NULL); } clientid = strtoul(cmd->params[4], NULL, 10); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->phone.mobile && user->phone.mobile[0] == '+'); + msn_user_set_clientid(user, clientid); + msn_user_set_network(user, networkid); + msn_user_set_state(user, state); msn_user_update(user); } @@ -1231,35 +1168,6 @@ } static void -rea_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) -{ - MsnSession *session; - PurpleAccount *account; - PurpleConnection *gc; - const char *friendly; - char *username; - - session = cmdproc->session; - account = session->account; - username = g_strdup(purple_normalize(account, - purple_account_get_username(account))); - - /* Only set display name if our *own* friendly name changed! */ - if (strcmp(username, purple_normalize(account, cmd->params[2]))) - { - g_free(username); - return; - } - - g_free(username); - - gc = account->gc; - friendly = purple_url_decode(cmd->params[3]); - - purple_connection_set_display_name(gc, friendly); -} - -static void prp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session = cmdproc->session; @@ -1292,7 +1200,7 @@ if (!strcmp(type, "MFN")) { friendlyname = purple_url_decode(cmd->params[2]); - msn_update_contact(session->contact, friendlyname); + msn_update_contact(session, "Me", MSN_UPDATE_DISPLAY, friendlyname); purple_connection_set_display_name( purple_account_get_connection(session->account), @@ -1629,42 +1537,59 @@ gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, size_t len) { - xmlnode * root; - gchar * buf; - int xmllen; + xmlnode *root; + xmlnode *policy; g_return_if_fail(cmd->payload != NULL); if ( (root = xmlnode_from_str(cmd->payload, cmd->payload_len)) == NULL) { - purple_debug_error("MSN","Unable to parse GCF payload into a XML tree"); + purple_debug_error("msn", "Unable to parse GCF payload into a XML tree"); return; } - buf = xmlnode_to_formatted_str(root, &xmllen); + + g_free(cmdproc->session->blocked_text); + cmdproc->session->blocked_text = NULL; + + /* We need a get_child with attrib... */ + policy = xmlnode_get_child(root, "Policy"); + while (policy) { + if (g_str_equal(xmlnode_get_attrib(policy, "type"), "SHIELDS")) + break; + policy = xmlnode_get_next_twin(policy); + } - /* get the payload content */ - purple_debug_info("MSNP14","GCF command payload:\n%.*s\n", xmllen, buf); + if (policy) { + GString *blocked = g_string_new(NULL); + xmlnode *imtext = xmlnode_get_child(policy, + "config/block/regexp/imtext"); + while (imtext) { + const char *value = xmlnode_get_attrib(imtext, "value"); + g_string_append_printf(blocked, "%s<br/>\n", + purple_base64_decode(value, NULL)); + imtext = xmlnode_get_next_twin(imtext); + } - g_free(buf); + cmdproc->session->blocked_text = g_string_free(blocked, FALSE); + } + xmlnode_free(root); } static void gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_info("MSNP14","Processing GCF command\n"); + purple_debug_info("msn", "Processing GCF command\n"); + cmdproc->last_cmd->payload_cb = gcf_cmd_post; - return; + cmd->payload_len = atoi(cmd->params[1]); } static void sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_info("MSNP14","Processing SBS... \n"); - if(cmd->payload_len == 0){ - return; - } + purple_debug_info("msn", "Processing SBS... \n"); /*get the payload content*/ } @@ -1710,17 +1635,26 @@ static void ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_misc("MSNP14","UBX received.\n"); - if(cmd->payload_len == 0){ - return; - } + purple_debug_misc("msn", "UBX received.\n"); cmdproc->last_cmd->payload_cb = ubx_cmd_post; + cmd->payload_len = atoi(cmd->params[2]); +} + +static void +uux_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + /* Do Nothing, right now. */ + if (payload != NULL) + purple_debug_info("msn", "UUX payload:\n%s\n", payload); } static void uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_misc("MSNP14","UUX received.\n"); + purple_debug_misc("msn", "UUX received.\n"); + cmdproc->last_cmd->payload_cb = uux_cmd_post; + cmd->payload_len = atoi(cmd->params[1]); } /************************************************************************** @@ -1774,17 +1708,16 @@ /*starting retrieve the contact list*/ clLastChange = purple_account_get_string(session->account, "CLLastChange", NULL); - session->contact = msn_contact_new(session); #ifdef MSN_PARTIAL_LISTS /* msn_userlist_load defeats all attempts at trying to detect blist sync issues */ msn_userlist_load(session); - msn_get_contact_list(session->contact, MSN_PS_INITIAL, clLastChange); + msn_get_contact_list(session, MSN_PS_INITIAL, clLastChange); #else /* always get the full list? */ - msn_get_contact_list(session->contact, MSN_PS_INITIAL, NULL); + msn_get_contact_list(session, MSN_PS_INITIAL, NULL); #endif #if 0 - msn_contact_connect(session->contact); + msn_contact_connect(session); #endif } @@ -1857,10 +1790,6 @@ /* This isn't an official message. */ return; - /*new a oim session*/ -// session->oim = msn_oim_new(session); -// msn_oim_connect(session->oim); - table = msn_message_get_hashtable_from_body(msg); mdata = g_hash_table_lookup(table, "Mail-Data"); @@ -1918,7 +1847,7 @@ static void delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { - purple_debug_misc("MSN Notification","Delete OIM message.\n"); + purple_debug_misc("msn", "Delete OIM message.\n"); } static void @@ -2037,7 +1966,7 @@ adl_node->child = NULL; msn_add_contact_xml(notification->session, adl_node, who, list_op, - MSN_USER_TYPE_PASSPORT); + MSN_NETWORK_PASSPORT); payload = xmlnode_to_str(adl_node,&payload_len); xmlnode_free(adl_node); @@ -2063,12 +1992,12 @@ rml_node = xmlnode_new("ml"); rml_node->child = NULL; - msn_add_contact_xml(notification->session, rml_node, who, list_op, MSN_USER_TYPE_PASSPORT); + msn_add_contact_xml(notification->session, rml_node, who, list_op, MSN_NETWORK_PASSPORT); payload = xmlnode_to_str(rml_node, &payload_len); xmlnode_free(rml_node); - purple_debug_info("MSN Notification","Send RML with payload:\n%s\n", payload); + purple_debug_info("msn", "Send RML with payload:\n%s\n", payload); trans = msn_transaction_new(cmdproc, "RML","%" G_GSIZE_FORMAT, strlen(payload)); msn_transaction_set_payload(trans, payload, strlen(payload)); msn_cmdproc_send_trans(cmdproc, trans); @@ -2081,25 +2010,19 @@ void msn_notification_init(void) { - /* TODO: check prp, blp */ - cbs_table = msn_table_new(); /* Synchronous */ msn_table_add_cmd(cbs_table, "CHG", "CHG", NULL); msn_table_add_cmd(cbs_table, "CHG", "ILN", iln_cmd); msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd); -// msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd); /* Removed as of MSNP13 */ msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd); msn_table_add_cmd(cbs_table, "USR", "GCF", gcf_cmd); -// msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd); /* Removed as of MSNP13 */ msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd); msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd); - msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd); msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd); msn_table_add_cmd(cbs_table, "BLP", "BLP", blp_cmd); -// msn_table_add_cmd(cbs_table, "BLP", "BLP", NULL); msn_table_add_cmd(cbs_table, "REG", "REG", reg_cmd); msn_table_add_cmd(cbs_table, "ADG", "ADG", adg_cmd); msn_table_add_cmd(cbs_table, "RMG", "RMG", rmg_cmd); @@ -2137,7 +2060,6 @@ msn_table_add_error(cbs_table, "ADL", adl_error); msn_table_add_error(cbs_table, "REG", reg_error); msn_table_add_error(cbs_table, "RMG", rmg_error); - /* msn_table_add_error(cbs_table, "REA", rea_error); */ msn_table_add_error(cbs_table, "USR", usr_error); msn_table_add_msg_type(cbs_table,
--- a/libpurple/protocols/msn/notification.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/notification.h Sat Jul 12 07:32:05 2008 +0000 @@ -25,6 +25,11 @@ #define _MSN_NOTIFICATION_H_ /*MSN protocol challenge info*/ + +/*MSNP15 challenge: WLM 8.5.1288.816*/ +#define MSNP15_WLM_PRODUCT_KEY "ILTXC!4IXB5FB*PX" +#define MSNP15_WLM_PRODUCT_ID "PROD0119GSJUC$18" + /*MSNP13 challenge*/ #define MSNP13_WLM_PRODUCT_KEY "O4BG@C7BWLYQX?5G" #define MSNP13_WLM_PRODUCT_ID "PROD01065C%ZFN6F" @@ -81,6 +86,6 @@ */ void msn_notification_close(MsnNotification *notification); -void msn_got_login_params(MsnSession *session, const char *login_params); +void msn_got_login_params(MsnSession *session, const char *ticket, const char *response); #endif /* _MSN_NOTIFICATION_H_ */
--- a/libpurple/protocols/msn/oim.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/oim.c Sat Jul 12 07:32:05 2008 +0000 @@ -24,7 +24,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" -#include "soap2.h" +#include "soap.h" #include "oim.h" #include "msnutils.h" @@ -41,6 +41,7 @@ } MsnOimRecvData; /*Local Function Prototype*/ +static void msn_parse_oim_xml(MsnOim *oim, xmlnode *node); 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, @@ -72,7 +73,7 @@ { MsnOimSendReq *request; - purple_debug_info("OIM", "destroy the OIM %p\n", oim); + purple_debug_info("msn", "destroy the OIM %p\n", oim); g_free(oim->run_id); g_free(oim->challenge); @@ -114,6 +115,155 @@ } /**************************************** + * Manage OIM Tokens + ****************************************/ +typedef struct _MsnOimRequestData { + MsnOim *oim; + gboolean send; + const char *action; + const char *host; + const char *url; + xmlnode *body; + MsnSoapCallback cb; + gpointer cb_data; +} MsnOimRequestData; + +static void msn_oim_request_helper(MsnOimRequestData *data); + +static void +msn_oim_request_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer req_data) +{ + MsnOimRequestData *data = (MsnOimRequestData *)req_data; + xmlnode *fault = NULL; + xmlnode *faultcode = NULL; + + fault = xmlnode_get_child(response->xml, "Body/Fault"); + if (fault) + faultcode = xmlnode_get_child(fault, "faultcode"); + + if (faultcode) { + gchar *faultcode_str = xmlnode_get_data(faultcode); + + if (faultcode_str && g_str_equal(faultcode_str, "q0:BadContextToken")) { + purple_debug_warning("msn", "OIM Request Error, Updating token now."); + msn_nexus_update_token(data->oim->session->nexus, + data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, + (GSourceFunc)msn_oim_request_helper, data); + g_free(faultcode_str); + return; + + } else if (faultcode_str && g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { + if (xmlnode_get_child(fault, "detail/RequiredAuthPolicy") != NULL) { + purple_debug_warning("msn", "OIM Request Error, Updating token now."); + msn_nexus_update_token(data->oim->session->nexus, + data->send ? MSN_AUTH_LIVE_SECURE : MSN_AUTH_MESSENGER_WEB, + (GSourceFunc)msn_oim_request_helper, data); + g_free(faultcode_str); + return; + } + } + g_free(faultcode_str); + } + + if (data->cb) + data->cb(request, response, data->cb_data); + xmlnode_free(data->body); + g_free(data); +} + +static void +msn_oim_request_helper(MsnOimRequestData *data) +{ + MsnSession *session = data->oim->session; + + if (data->send) { + /* The Sending of OIM's uses a different token for some reason. */ + xmlnode *ticket; + ticket = xmlnode_get_child(data->body, "Header/Ticket"); + xmlnode_set_attrib(ticket, "passport", + msn_nexus_get_token_str(session->nexus, MSN_AUTH_LIVE_SECURE)); + } + else + { + xmlnode *passport; + xmlnode *xml_t; + xmlnode *xml_p; + GHashTable *token; + const char *msn_t; + const char *msn_p; + + token = msn_nexus_get_token(session->nexus, MSN_AUTH_MESSENGER_WEB); + g_return_if_fail(token != NULL); + + msn_t = g_hash_table_lookup(token, "t"); + msn_p = g_hash_table_lookup(token, "p"); + + g_return_if_fail(msn_t != NULL); + g_return_if_fail(msn_p != NULL); + + passport = xmlnode_get_child(data->body, "Header/PassportCookie"); + xml_t = xmlnode_get_child(passport, "t"); + xml_p = xmlnode_get_child(passport, "p"); + + /* frees old token text, or the 'EMPTY' text if first time */ + xmlnode_free(xml_t->child); + xmlnode_free(xml_p->child); + + xmlnode_insert_data(xml_t, msn_t, -1); + xmlnode_insert_data(xml_p, msn_p, -1); + } + + msn_soap_message_send(session, + msn_soap_message_new(data->action, xmlnode_copy(data->body)), + data->host, data->url, msn_oim_request_cb, data); +} + + +static void +msn_oim_make_request(MsnOim *oim, gboolean send, const char *action, + const char *host, const char *url, xmlnode *body, MsnSoapCallback cb, + gpointer cb_data) +{ + MsnOimRequestData *data = g_new0(MsnOimRequestData, 1); + data->oim = oim; + data->send = send; + data->action = action; + data->host = host; + data->url = url; + data->body = body; + data->cb = cb; + data->cb_data = cb_data; + + msn_oim_request_helper(data); +} + +/**************************************** + * OIM GetMetadata request + * **************************************/ +static void +msn_oim_get_metadata_cb(MsnSoapMessage *request, MsnSoapMessage *response, + gpointer data) +{ + MsnOim *oim = data; + + if (response) { + msn_parse_oim_xml(oim, + xmlnode_get_child(response->xml, "Body/GetMetadataResponse/MD")); + } +} + +/* Post to get the OIM Metadata */ +static void +msn_oim_get_metadata(MsnOim *oim) +{ + msn_oim_make_request(oim, FALSE, MSN_OIM_GET_METADATA_ACTION, + MSN_OIM_RETRIEVE_HOST, MSN_OIM_RETRIEVE_URL, + xmlnode_from_str(MSN_OIM_GET_METADATA_TEMPLATE, -1), + msn_oim_get_metadata_cb, oim); +} + +/**************************************** * OIM send SOAP request * **************************************/ /*encode the message to OIM Message Format*/ @@ -122,9 +272,9 @@ { char *oim_body,*oim_base64; - purple_debug_info("MSN OIM","encode OIM Message...\n"); + purple_debug_info("msn", "encode OIM Message...\n"); oim_base64 = purple_base64_encode((const guchar *)body, strlen(body)); - purple_debug_info("MSN OIM","encoded base64 body:{%s}\n",oim_base64); + purple_debug_info("msn", "encoded base64 body:{%s}\n", oim_base64); oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE, oim->run_id,oim->send_seq,oim_base64); g_free(oim_base64); @@ -146,13 +296,13 @@ g_return_if_fail(msg != NULL); if (response == NULL) { - purple_debug_info("MSNP14", "cannot send OIM: %s\n", msg->oim_msg); + purple_debug_info("msn", "cannot send OIM: %s\n", msg->oim_msg); } else { - xmlnode *faultNode = msn_soap_xml_get(response->xml, "Body/Fault"); + xmlnode *faultNode = xmlnode_get_child(response->xml, "Body/Fault"); if (faultNode == NULL) { /*Send OK! return*/ - purple_debug_info("MSNP14", "sent OIM: %s\n", msg->oim_msg); + purple_debug_info("msn", "sent OIM: %s\n", msg->oim_msg); } else { xmlnode *faultcode = xmlnode_get_child(faultNode, "faultcode"); @@ -160,7 +310,7 @@ char *faultcode_str = xmlnode_get_data(faultcode); if (g_str_equal(faultcode_str, "q0:AuthenticationFailed")) { - xmlnode *challengeNode = msn_soap_xml_get(faultNode, + xmlnode *challengeNode = xmlnode_get_child(faultNode, "detail/LockKeyChallenge"); if (challengeNode == NULL) { @@ -168,13 +318,13 @@ g_free(oim->challenge); oim->challenge = NULL; - purple_debug_info("msnoim","resending OIM: %s\n", + purple_debug_info("msn", "Resending OIM: %s\n", msg->oim_msg); g_queue_push_head(oim->send_queue, msg); msn_oim_send_msg(oim); } else { - purple_debug_info("msnoim", - "can't find lock key for OIM: %s\n", + purple_debug_info("msn", + "Can't find lock key for OIM: %s\n", msg->oim_msg); } } else { @@ -186,13 +336,39 @@ g_free(oim->challenge); oim->challenge = g_strndup(buf, sizeof(buf)); g_free(challenge); - purple_debug_info("MSNP14","lockkey:{%s}\n",oim->challenge); + purple_debug_info("msn", "Found lockkey:{%s}\n", oim->challenge); /*repost the send*/ - purple_debug_info("MSNP14","resending OIM: %s\n", msg->oim_msg); + purple_debug_info("msn", "Resending OIM: %s\n", msg->oim_msg); g_queue_push_head(oim->send_queue, msg); msn_oim_send_msg(oim); } + } else { + /* Report the error */ + const char *str_reason; + + if (g_str_equal(faultcode_str, "q0:SystemUnavailable")) { + str_reason = _("Message was not sent because the system is " + "unavailable. This normally happens when the " + "user is blocked or does not exist."); + + } else if (g_str_equal(faultcode_str, "q0:SenderThrottleLimitExceeded")) { + str_reason = _("Message was not sent because messages " + "are being sent too quickly."); + + } else if (g_str_equal(faultcode_str, "q0:InvalidContent")) { + str_reason = _("Message was not sent because an unknown " + "encoding error occured."); + + } else { + str_reason = _("Message was not sent because an unknown " + "error occured."); + } + + msn_session_report_user(oim->session, msg->to_member, + str_reason, PURPLE_MESSAGE_ERROR); + msn_session_report_user(oim->session, msg->to_member, + msg->oim_msg, PURPLE_MESSAGE_RAW); } g_free(faultcode_str); @@ -217,24 +393,20 @@ msn_oim_send_msg(MsnOim *oim) { MsnOimSendReq *oim_request; - char *soap_body,*mspauth; + char *soap_body; char *msg_body; g_return_if_fail(oim != NULL); oim_request = g_queue_peek_head(oim->send_queue); g_return_if_fail(oim_request != NULL); - 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 - ); + purple_debug_info("msn", "Sending OIM: %s\n", oim_request->oim_msg); /* if we got the challenge lock key, we compute it * else we go for the SOAP fault and resend it. */ - if(oim->challenge == NULL){ - purple_debug_info("MSNP14","no lock key challenge,wait for SOAP Fault and Resend\n"); + if (oim->challenge == NULL){ + purple_debug_info("msn", "No lock key challenge, waiting for SOAP Fault and Resend\n"); } msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); @@ -242,23 +414,20 @@ oim_request->from_member, oim_request->friendname, oim_request->to_member, - mspauth, - MSNP13_WLM_PRODUCT_ID, + MSNP15_WLM_PRODUCT_ID, oim->challenge ? oim->challenge : "", oim->send_seq, msg_body); - 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); + msn_oim_make_request(oim, TRUE, MSN_OIM_SEND_SOAP_ACTION, MSN_OIM_SEND_HOST, + MSN_OIM_SEND_URL, xmlnode_from_str(soap_body, -1), 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); } @@ -272,13 +441,13 @@ { MsnOimRecvData *rdata = data; - if (response && msn_soap_xml_get(response->xml, "Body/Fault") == NULL) { - purple_debug_info("msnoim", "delete OIM success\n"); + if (response && xmlnode_get_child(response->xml, "Body/Fault") == NULL) { + purple_debug_info("msn", "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"); + purple_debug_info("msn", "Delete OIM failed\n"); } g_free(rdata); @@ -292,16 +461,12 @@ char *msgid = rdata->msg_id; char *soap_body; - purple_debug_info("MSNP14","Delete single OIM Message {%s}\n",msgid); - - soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, - oim->session->passport_info.t, oim->session->passport_info.p, msgid); + purple_debug_info("msn", "Delete single OIM Message {%s}\n",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); + soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, msgid); + + msn_oim_make_request(oim, FALSE, MSN_OIM_DEL_SOAP_ACTION, MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL, xmlnode_from_str(soap_body, -1), msn_oim_delete_read_cb, rdata); g_free(soap_body); } @@ -351,7 +516,7 @@ long sys_tzoff; #endif - if (!offset_positive) + if (offset_positive) tzoff *= -1; t.tm_year -= 1900; @@ -361,7 +526,7 @@ tzoff += sys_tzoff; #else #ifdef HAVE_TM_GMTOFF - tzoff -= t.tm_gmtoff; + tzoff += t.tm_gmtoff; #else # ifdef HAVE_TIMEZONE tzset(); /* making sure */ @@ -375,7 +540,7 @@ } } - purple_debug_info("MSNP14:OIM", "Can't parse timestamp %s\n", timestamp); + purple_debug_info("msn", "Can't parse timestamp %s\n", timestamp); return tval; } @@ -396,30 +561,30 @@ msn_message_parse_payload(message, msg_str, strlen(msg_str), MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); - purple_debug_info("MSNP14","oim body:{%s}\n",message->body); + purple_debug_info("msn", "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"); - if(strstr(from," ")){ + if (strstr(from," ")) { has_nick = 1; } - if(has_nick){ + if (has_nick) { tokens = g_strsplit(from , " " , 2); passport_str = g_strdup(tokens[1]); - purple_debug_info("MSNP14","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", - date,tokens[0],tokens[1],passport_str); + purple_debug_info("msn", "oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", + date, tokens[0], tokens[1], passport_str); g_strfreev(tokens); - }else{ + } else { passport_str = g_strdup(from); - purple_debug_info("MSNP14","oim Date:{%s},passport{%s}\n", - date,passport_str); + purple_debug_info("msn", "oim Date:{%s},passport{%s}\n", + date, passport_str); } start = strstr(passport_str,"<"); start += 1; end = strstr(passport_str,">"); passport = g_strndup(start,end - start); g_free(passport_str); - purple_debug_info("MSN OIM","oim Date:{%s},passport{%s}\n",date,passport); + purple_debug_info("msn", "oim Date:{%s},passport{%s}\n", date, passport); stamp = msn_oim_parse_timestamp(date); @@ -445,7 +610,7 @@ MsnOimRecvData *rdata = data; if (response != NULL) { - xmlnode *msg_node = msn_soap_xml_get(response->xml, + xmlnode *msg_node = xmlnode_get_child(response->xml, "Body/GetMessageResponse/GetMessageResult"); if (msg_node) { @@ -454,11 +619,11 @@ g_free(msg_str); } else { char *str = xmlnode_to_str(response->xml, NULL); - purple_debug_info("msnoim", "Unknown response: %s\n", str); + purple_debug_info("msn", "Unknown OIM response: %s\n", str); g_free(str); } } else { - purple_debug_info("msnoim", "Failed to get OIM\n"); + purple_debug_info("msn", "Failed to get OIM\n"); } } @@ -468,20 +633,37 @@ void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) { - xmlnode *node, *mNode; + xmlnode *node; + + purple_debug_info("msn", "%s\n", xmlmsg); + + if (!strcmp(xmlmsg, "too-large")) { + /* Too many OIM's to send via NS, so we need to request them via SOAP. */ + msn_oim_get_metadata(oim); + } else { + node = xmlnode_from_str(xmlmsg, -1); + msn_parse_oim_xml(oim, node); + xmlnode_free(node); + } +} + +static void +msn_parse_oim_xml(MsnOim *oim, xmlnode *node) +{ + xmlnode *mNode; xmlnode *iu_node; MsnSession *session = oim->session; - purple_debug_info("MSNP14:OIM", "%s\n", xmlmsg); + g_return_if_fail(node != NULL); - 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); + char *xmlmsg = xmlnode_to_str(node, NULL); + purple_debug_info("msn", "WTF is this? %s\n", xmlmsg); + g_free(xmlmsg); return; } - iu_node = msn_soap_xml_get(node, "E/IU"); + iu_node = xmlnode_get_child(node, "E/IU"); if (iu_node != NULL && purple_account_get_check_mail(session->account)) { @@ -515,7 +697,7 @@ if (rt_node != NULL) { rtime = xmlnode_get_data(rt_node); } -/* purple_debug_info("msnoim","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ +/* purple_debug_info("msn", "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); @@ -528,8 +710,6 @@ g_free(rtime); g_free(nickname); } - - xmlnode_free(node); } /*Post to get the Offline Instant Message*/ @@ -539,19 +719,16 @@ char *soap_body; MsnOimRecvData *data = g_new0(MsnOimRecvData, 1); - purple_debug_info("MSNP14","Get single OIM Message\n"); + purple_debug_info("msn", "Get single OIM Message\n"); data->oim = oim; data->msg_id = msgid; - soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, - oim->session->passport_info.t, oim->session->passport_info.p, msgid); + soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, msgid); - 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_make_request(oim, FALSE, MSN_OIM_GET_SOAP_ACTION, MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL, xmlnode_from_str(soap_body, -1), msn_oim_get_read_cb, + data); g_free(soap_body); }
--- a/libpurple/protocols/msn/oim.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/oim.h Sat Jul 12 07:32:05 2008 +0000 @@ -25,17 +25,41 @@ #ifndef _MSN_OIM_H_ #define _MSN_OIM_H_ -/*OIM Retrieve SOAP Template*/ +/* OIM Retrieval Info */ #define MSN_OIM_RETRIEVE_HOST "rsi.hotmail.com" #define MSN_OIM_RETRIEVE_URL "/rsi/rsi.asmx" + +/* OIM GetMetadata SOAP Template */ +#define MSN_OIM_GET_METADATA_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata" + +#define MSN_OIM_GET_METADATA_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ +"<soap:Envelope"\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ + "<soap:Header>"\ + "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ + "<t>EMPTY</t>"\ + "<p>EMPTY</p>"\ + "</PassportCookie>"\ + "</soap:Header>"\ + "<soap:Body>"\ + "<GetMetadata xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\" />"\ + "</soap:Body>"\ +"</soap:Envelope>" + +/*OIM GetMessage SOAP Template*/ #define MSN_OIM_GET_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage" #define MSN_OIM_GET_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ +"<soap:Envelope"\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ "<soap:Header>"\ "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<t>%s</t>"\ - "<p>%s</p>"\ + "<t>EMPTY</t>"\ + "<p>EMPTY</p>"\ "</PassportCookie>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -46,15 +70,18 @@ "</soap:Body>"\ "</soap:Envelope>" -/*OIM Delete SOAP Template*/ +/*OIM DeleteMessages SOAP Template*/ #define MSN_OIM_DEL_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages" #define MSN_OIM_DEL_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ +"<soap:Envelope"\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ "<soap:Header>"\ "<PassportCookie xmlns=\"http://www.hotmail.msn.com/ws/2004/09/oim/rsi\">"\ - "<t>%s</t>"\ - " <p>%s</p>"\ + "<t>EMPTY</t>"\ + "<p>EMPTY</p>"\ "</PassportCookie>"\ "</soap:Header>"\ "<soap:Body>"\ @@ -77,13 +104,23 @@ #define MSN_OIM_SEND_HOST "ows.messenger.msn.com" #define MSN_OIM_SEND_URL "/OimWS/oim.asmx" -#define MSN_OIM_SEND_SOAP_ACTION "http://messenger.msn.com/ws/2004/09/oim/Store" +#define MSN_OIM_SEND_SOAP_ACTION "http://messenger.live.com/ws/2006/09/oim/Store2" #define MSN_OIM_SEND_TEMPLATE "<?xml version=\"1.0\" encoding=\"utf-8\"?>"\ -"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ +"<soap:Envelope"\ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ + " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""\ + " xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"\ "<soap:Header>"\ - "<From memberName=\"%s\" friendlyName=\"%s\" xml:lang=\"en-US\" proxy=\"MSNMSGR\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\" msnpVer=\"MSNP14\" buildVer=\"8.0.0792\"/>"\ + "<From"\ + " memberName=\"%s\""\ + " friendlyName=\"%s\""\ + " xml:lang=\"en-US\""\ + " proxy=\"MSNMSGR\""\ + " xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\""\ + " msnpVer=\"MSNP15\""\ + " buildVer=\"8.5.1288\"/>"\ "<To memberName=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ - "<Ticket passport=\"%s\" appid=\"%s\" lockkey=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ + "<Ticket passport=\"EMPTY\" appid=\"%s\" lockkey=\"%s\" xmlns=\"http://messenger.msn.com/ws/2004/09/oim/\"/>"\ "<Sequence xmlns=\"http://schemas.xmlsoap.org/ws/2003/03/rm\">"\ "<Identifier xmlns=\"http://schemas.xmlsoap.org/ws/2002/07/utility\">http://messenger.msn.com</Identifier>"\ "<MessageNumber>%d</MessageNumber>"\ @@ -101,10 +138,8 @@ { MsnSession *session; - MsnSoapConn *retrieveconn; GList * oim_list; - MsnSoapConn *sendconn; char *challenge; char *run_id; gint send_seq;
--- a/libpurple/protocols/msn/servconn.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/servconn.c Sat Jul 12 07:32:05 2008 +0000 @@ -203,7 +203,7 @@ } gboolean -msn_servconn_connect(MsnServConn *servconn, const char *host, int port) +msn_servconn_connect(MsnServConn *servconn, const char *host, int port, gboolean force) { MsnSession *session; @@ -223,7 +223,7 @@ { /* HTTP Connection. */ - if (!servconn->httpconn->connected) + if (!servconn->httpconn->connected || force) if (!msn_httpconn_connect(servconn->httpconn, host, port)) return FALSE; @@ -393,21 +393,16 @@ len = read(servconn->fd, buf, sizeof(buf) - 1); servconn->session->account->gc->last_received = time(NULL); - if (len <= 0) { - switch (errno) { - - case 0: - - case EBADF: - case EAGAIN: return; + if (len < 0 && errno == EAGAIN) { + return; - default: purple_debug_error("msn", "servconn read error," - "len: %d, errno: %d, error: %s\n", - len, errno, g_strerror(errno)); - msn_servconn_got_error(servconn, - MSN_SERVCONN_ERROR_READ); - return; - } + } else if (len <= 0) { + purple_debug_error("msn", "servconn read error," + "len: %d, errno: %d, error: %s\n", + len, errno, g_strerror(errno)); + msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ); + + return; } buf[len] = '\0';
--- a/libpurple/protocols/msn/servconn.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/servconn.h Sat Jul 12 07:32:05 2008 +0000 @@ -115,8 +115,10 @@ * @param servconn The connection. * @param host The host. * @param port The port. + * @param force Force this servconn to connect to a new server. */ -gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port); +gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port, + gboolean force); /** * Disconnects.
--- a/libpurple/protocols/msn/session.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/session.c Sat Jul 12 07:32:05 2008 +0000 @@ -45,8 +45,6 @@ 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; session->protocol_ver = WLM_PROT_VER; return session; @@ -74,8 +72,9 @@ msn_userlist_destroy(session->userlist); g_free(session->psm); - g_free(session->passport_info.t); - g_free(session->passport_info.p); + + g_free(session->blocked_text); + g_free(session->passport_info.kv); g_free(session->passport_info.sid); g_free(session->passport_info.mspauth); @@ -93,15 +92,13 @@ if (session->nexus != NULL) msn_nexus_destroy(session->nexus); - if (session->contact != NULL) - msn_contact_destroy(session->contact); if (session->oim != NULL) msn_oim_destroy(session->oim); if (session->user != NULL) msn_user_destroy(session->user); - if (session->soap_table) + if (session->soap_table != NULL) g_hash_table_destroy(session->soap_table); if (session->soap_cleanup_handle) @@ -195,7 +192,7 @@ * passport - the one want to talk to you */ void -msn_session_report_user(MsnSession *session,const char *passport,char *msg,PurpleMessageFlags flags) +msn_session_report_user(MsnSession *session,const char *passport,const char *msg,PurpleMessageFlags flags) { PurpleConversation * conv;
--- a/libpurple/protocols/msn/session.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/session.h Sat Jul 12 07:32:05 2008 +0000 @@ -38,7 +38,6 @@ #include "cmdproc.h" #include "nexus.h" #include "httpconn.h" -#include "contact.h" #include "oim.h" #include "userlist.h" @@ -96,7 +95,6 @@ MsnNotification *notification; MsnNexus *nexus; - MsnContact *contact; MsnOim *oim; MsnSync *sync; @@ -109,12 +107,10 @@ /*psm info*/ char *psm; + char *blocked_text; + struct { - /*t and p, get via USR TWN*/ - char *t; - char *p; - char *kv; char *sid; char *mspauth; @@ -236,6 +232,6 @@ /*post message to User*/ void msn_session_report_user(MsnSession *session,const char *passport, - char *msg,PurpleMessageFlags flags); + const char *msg,PurpleMessageFlags flags); #endif /* _MSN_SESSION_H_ */
--- a/libpurple/protocols/msn/slp.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/slp.c Sat Jul 12 07:32:05 2008 +0000 @@ -44,7 +44,7 @@ static void send_decline(MsnSlpCall *slpcall, const char *branch, const char *type, const char *content); -void msn_request_user_display(MsnUser *user); +static void request_user_display(MsnUser *user); /************************************************************************** * Util @@ -251,7 +251,7 @@ got_sessionreq(MsnSlpCall *slpcall, const char *branch, const char *euf_guid, const char *context) { - if (!strcmp(euf_guid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6")) + if (!strcmp(euf_guid, MSN_OBJ_GUID)) { /* Emoticon or UserDisplay */ char *content; @@ -332,7 +332,7 @@ msn_slplink_queue_slpmsg(slplink, slpmsg); purple_imgstore_unref(img); } - else if (!strcmp(euf_guid, "5D3E02AB-6190-11D3-BBBB-00C04F795683")) + else if (!strcmp(euf_guid, MSN_FT_GUID)) { /* File Transfer */ PurpleAccount *account; @@ -384,7 +384,8 @@ purple_xfer_request(xfer); } - } + } else + purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid); } void @@ -781,16 +782,13 @@ got_emoticon(MsnSlpCall *slpcall, const guchar *data, gsize size) { - PurpleConversation *conv; - PurpleConnection *gc; - const char *who; + MsnSwitchBoard *swboard; - gc = slpcall->slplink->session->account->gc; - who = slpcall->slplink->remote_user; + swboard = slpcall->slplink->swboard; + conv = swboard->conv; - if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) { - + if (conv) { /* FIXME: it would be better if we wrote the data as we received it instead of all at once, calling write multiple times and close once at the very end @@ -808,6 +806,7 @@ { MsnSession *session; MsnSlpLink *slplink; + MsnSwitchBoard *swboard; MsnObject *obj; char **tokens; char *smile, *body_str; @@ -847,8 +846,9 @@ slplink = msn_session_get_slplink(session, who); - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, - session->account); + swboard = cmdproc->data; + slplink->swboard = swboard; + conv = swboard->conv; /* If the conversation doesn't exist then this is a custom smiley * used in the first message in a MSN conversation: we need to create @@ -930,7 +930,7 @@ username = user->passport; userlist->buddy_icon_window--; - msn_request_user_display(user); + request_user_display(user); #ifdef MSN_DEBUG_UD purple_debug_info("msn", "msn_release_buddy_icon_request(): buddy_icon_window-- yields =%d\n", @@ -1066,8 +1066,8 @@ msn_release_buddy_icon_request_timeout, userlist); } -void -msn_request_user_display(MsnUser *user) +static void +request_user_display(MsnUser *user) { PurpleAccount *account; MsnSession *session; @@ -1115,7 +1115,7 @@ session->userlist->buddy_icon_window++; #ifdef MSN_DEBUG_UD - purple_debug_info("msn", "msn_request_user_display(): buddy_icon_window++ yields =%d\n", + purple_debug_info("msn", "request_user_display(): buddy_icon_window++ yields =%d\n", session->userlist->buddy_icon_window); #endif
--- a/libpurple/protocols/msn/slplink.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/slplink.c Sat Jul 12 07:32:05 2008 +0000 @@ -774,8 +774,7 @@ context = gen_context(fn, fp); - msn_slp_call_invite(slpcall, "5D3E02AB-6190-11D3-BBBB-00C04F795683", 2, - context); + msn_slp_call_invite(slpcall, MSN_FT_GUID, 2, context); g_free(context); } @@ -805,8 +804,7 @@ slpcall->cb = cb; slpcall->end_cb = end_cb; - msn_slp_call_invite(slpcall, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", 1, - msnobj_base64); + msn_slp_call_invite(slpcall, MSN_OBJ_GUID, 1, msnobj_base64); g_free(msnobj_base64); }
--- a/libpurple/protocols/msn/soap.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/soap.c Sat Jul 12 07:32:05 2008 +0000 @@ -1,8 +1,7 @@ /** * @file soap.c - * SOAP connection related process - * Author - * MaYuan<mayuan2006@gmail.com> + * C file for SOAP connection related process + * * purple * * Purple is the legal property of its developers, whose names are too numerous @@ -23,856 +22,659 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "msn.h" + +#include "internal.h" + #include "soap.h" -#define MSN_SOAP_DEBUG -/*local function prototype*/ -void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step); +#include "session.h" + +#include "debug.h" +#include "xmlnode.h" + +#include <glib.h> +#if !defined(_WIN32) || !defined(_WINERROR_) +#include <error.h> +#endif + +#define SOAP_TIMEOUT (5 * 60) -/*setup the soap process step*/ -void -msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step) -{ -#ifdef MSN_SOAP_DEBUG - const char *MsnSoapStepText[] = - { - "Unconnected", - "Connecting", - "Connected", - "Processing", - "Connected Idle" - }; +typedef struct _MsnSoapRequest { + char *path; + MsnSoapMessage *message; + MsnSoapCallback cb; + gpointer cb_data; +} MsnSoapRequest; - purple_debug_info("MSN SOAP", "Setting SOAP process step to %s\n", MsnSoapStepText[step]); -#endif - soapconn->step = step; -} +typedef struct _MsnSoapConnection { + MsnSession *session; + char *host; -/*new a soap connection*/ -MsnSoapConn * -msn_soap_new(MsnSession *session,gpointer data, gboolean ssl) -{ - MsnSoapConn *soapconn; - - soapconn = g_new0(MsnSoapConn, 1); - soapconn->session = session; - soapconn->parent = data; - soapconn->ssl_conn = ssl; + time_t last_used; + PurpleSslConnection *ssl; + gboolean connected; - soapconn->gsc = NULL; - soapconn->input_handler = 0; - soapconn->output_handler = 0; - - msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); - soapconn->soap_queue = g_queue_new(); + guint event_handle; + GString *buf; + gsize handled_len; + gsize body_len; + int response_code; + gboolean headers_done; + gboolean close_when_done; - return soapconn; -} + MsnSoapMessage *message; -/*ssl soap connect callback*/ -void -msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond) -{ - MsnSoapConn * soapconn; - MsnSession *session; - gboolean soapconn_is_valid = FALSE; + 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); - purple_debug_misc("MSN SOAP","SOAP server connection established!\n"); - - soapconn = data; - g_return_if_fail(soapconn != NULL); +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); - session = soapconn->session; - g_return_if_fail(session != NULL); - - soapconn->gsc = gsc; +static void msn_soap_message_send_internal(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data, gboolean first); - msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED); +static void msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message); +static void msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect); +static gboolean msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, gboolean initial); +static void msn_soap_process(MsnSoapConnection *conn); - /*connection callback*/ - if (soapconn->connect_cb != NULL) { - soapconn_is_valid = soapconn->connect_cb(soapconn, gsc); - } +static gboolean +msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data) +{ + MsnSoapConnection *conn = value; + time_t *t = data; - if (!soapconn_is_valid) { - return; + if ((*t - conn->last_used) > SOAP_TIMEOUT * 2) { + purple_debug_info("soap", "cleaning up soap conn %p\n", conn); + return TRUE; } - /*we do the SOAP request here*/ - msn_soap_post_head_request(soapconn); -} - -/*ssl soap error callback*/ -static void -msn_soap_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) -{ - MsnSoapConn * soapconn = data; - - g_return_if_fail(data != NULL); - - purple_debug_warning("MSN SOAP","Soap connection error!\n"); - - msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); - - /*error callback*/ - if (soapconn->error_cb != NULL) { - soapconn->error_cb(soapconn, gsc, error); - } else { - msn_soap_post(soapconn, NULL); - } -} - -/*init the soap connection*/ -void -msn_soap_init(MsnSoapConn *soapconn,char * host, gboolean ssl, - MsnSoapSslConnectCbFunction connect_cb, - MsnSoapSslErrorCbFunction error_cb) -{ - purple_debug_misc("MSN SOAP","Initializing SOAP connection\n"); - g_free(soapconn->login_host); - soapconn->login_host = g_strdup(host); - soapconn->ssl_conn = ssl; - soapconn->connect_cb = connect_cb; - soapconn->error_cb = error_cb; + return FALSE; } -/*connect the soap connection*/ -void -msn_soap_connect(MsnSoapConn *soapconn) +static gboolean +msn_soap_cleanup_for_session(gpointer data) { - if (soapconn->ssl_conn) { - purple_ssl_connect(soapconn->session->account, soapconn->login_host, - PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, msn_soap_error_cb, - soapconn); - } else { + 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; + } } - msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTING); -} - - -static void -msn_soap_close_handler(guint *handler) -{ - if (*handler > 0) { - purple_input_remove(*handler); - *handler = 0; - } -#ifdef MSN_SOAP_DEBUG - else { - purple_debug_misc("MSN SOAP", "Handler inactive, not removing\n"); - } -#endif - -} - - -/*close the soap connection*/ -void -msn_soap_close(MsnSoapConn *soapconn) -{ - if (soapconn->ssl_conn) { - if (soapconn->gsc != NULL) { - purple_ssl_close(soapconn->gsc); - soapconn->gsc = NULL; - } - } else { - } - msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); + return TRUE; } -/*clean the unhandled SOAP request*/ -void -msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn) +static MsnSoapConnection * +msn_soap_get_connection(MsnSession *session, const char *host) { - MsnSoapReq *request; - - g_return_if_fail(soapconn != NULL); - - soapconn->body = NULL; - - while ((request = g_queue_pop_head(soapconn->soap_queue)) != NULL){ - if (soapconn->read_cb) { - soapconn->read_cb(soapconn); - } - msn_soap_request_free(request); - } -} - -/*destroy the soap connection*/ -void -msn_soap_destroy(MsnSoapConn *soapconn) -{ - g_free(soapconn->login_host); - - g_free(soapconn->login_path); + MsnSoapConnection *conn = NULL; - /*remove the write handler*/ - if (soapconn->output_handler > 0){ - purple_input_remove(soapconn->output_handler); - soapconn->output_handler = 0; - } - /*remove the read handler*/ - if (soapconn->input_handler > 0){ - purple_input_remove(soapconn->input_handler); - soapconn->input_handler = 0; - } - msn_soap_free_read_buf(soapconn); - msn_soap_free_write_buf(soapconn); - - /*close ssl connection*/ - msn_soap_close(soapconn); - - /*process the unhandled soap request*/ - msn_soap_clean_unhandled_requests(soapconn); - - g_queue_free(soapconn->soap_queue); - g_free(soapconn); -} - -/*check the soap is connected? - * if connected return 1 - */ -int -msn_soap_connected(MsnSoapConn *soapconn) -{ - if (soapconn->ssl_conn) { - return (soapconn->gsc == NULL ? 0 : 1); - } - return (soapconn->fd > 0 ? 1 : 0); -} - -/*read and append the content to the buffer*/ -static gssize -msn_soap_read(MsnSoapConn *soapconn) -{ - gssize len, requested_len; - char temp_buf[MSN_SOAP_READ_BUFF_SIZE]; - - if ( soapconn->need_to_read == 0 || soapconn->need_to_read > MSN_SOAP_READ_BUFF_SIZE) { - requested_len = MSN_SOAP_READ_BUFF_SIZE; - } - else { - requested_len = soapconn->need_to_read; + 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 ( soapconn->ssl_conn ) { - len = purple_ssl_read(soapconn->gsc, temp_buf, requested_len); - } else { - len = read(soapconn->fd, temp_buf, requested_len); + 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); - if ( len <= 0 ) { - switch (errno) { + return conn; +} - case 0: - case EBADF: /* we are sometimes getting this in Windows */ - case EAGAIN: return len; +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; +} - default : purple_debug_error("MSN SOAP", "Read error!" - "read len: %" G_GSSIZE_FORMAT ", error = %s\n", - len, g_strerror(errno)); - purple_input_remove(soapconn->input_handler); - //soapconn->input_handler = 0; - g_free(soapconn->read_buf); - soapconn->read_buf = NULL; - soapconn->read_len = 0; - /* TODO: error handling */ - return len; - } - } - else { - soapconn->read_buf = g_realloc(soapconn->read_buf, - soapconn->read_len + len + 1); - if ( soapconn->read_buf != NULL ) { - memcpy(soapconn->read_buf + soapconn->read_len, temp_buf, len); - soapconn->read_len += len; - soapconn->read_buf[soapconn->read_len] = '\0'; - } - else { - purple_debug_error("MSN SOAP", - "Failure re-allocating %" G_GSIZE_FORMAT " bytes of memory!\n", - soapconn->read_len + len + 1); - exit(EXIT_FAILURE); - } +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 = purple_timeout_add(0, msn_soap_connection_run, conn); +} -#if defined(MSN_SOAP_DEBUG) - if (len > 0) - purple_debug_info("MSN SOAP", - "Read %" G_GSIZE_FORMAT " bytes from SOAP server:\n%s\n", len, - soapconn->read_buf + soapconn->read_len - len); -#endif +static void +msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error, + gpointer data) +{ + MsnSoapConnection *conn = data; - return len; + /* sslconn already frees the connection in case of error */ + conn->ssl = NULL; + + g_hash_table_remove(conn->session->soap_table, conn->host); } -/*read the whole SOAP server response*/ -static void -msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) +static gboolean +msn_soap_handle_redirect(MsnSoapConnection *conn, const char *url) { - MsnSoapConn *soapconn = data; - MsnSession *session; - int len; - char * body_start,*body_len; - char *length_start,*length_end; -#ifdef MSN_SOAP_DEBUG -#if !defined(_WIN32) - gchar * formattedxml = NULL; - gchar * http_headers = NULL; - xmlnode * node = NULL; -#endif - purple_debug_misc("MSN SOAP", "msn_soap_read_cb()\n"); -#endif - session = soapconn->session; - g_return_if_fail(session != NULL); + char *host; + char *path; + + if (purple_url_parse(url, &host, NULL, &path, NULL, NULL)) { + msn_soap_message_send_internal(conn->session, + conn->current_request->message, host, path, + conn->current_request->cb, conn->current_request->cb_data, TRUE); - - /*read the request header*/ - len = msn_soap_read(soapconn); + msn_soap_request_destroy(conn->current_request, TRUE); + conn->current_request = NULL; - if ( len < 0 ) - return; + g_free(host); + g_free(path); - if (soapconn->read_buf == NULL) { - return; + return TRUE; } - if ( (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) - || ( strstr(soapconn->read_buf, "HTTP/1.1 301") != NULL ) ) - { - /* Redirect. */ - char *location, *c; + return FALSE; +} + +static gboolean +msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response) +{ + xmlnode *body = xmlnode_get_child(response->xml, "Body"); + xmlnode *fault = xmlnode_get_child(response->xml, "Fault"); + + if (fault) { + xmlnode *faultcode = xmlnode_get_child(fault, "faultcode"); + + if (faultcode != NULL) { + char *faultdata = xmlnode_get_data(faultcode); + + if (g_str_equal(faultdata, "psf:Redirect")) { + xmlnode *url = xmlnode_get_child(fault, "redirectUrl"); - purple_debug_info("MSN SOAP", "HTTP Redirect\n"); - location = strstr(soapconn->read_buf, "Location: "); - if (location == NULL) - { - c = (char *) g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n"); - if (c != NULL) { - /* we have read the whole HTTP headers and found no Location: */ - msn_soap_free_read_buf(soapconn); - msn_soap_post(soapconn, NULL); + if (url) { + char *urldata = xmlnode_get_data(url); + msn_soap_handle_redirect(conn, urldata); + g_free(urldata); + } + + g_free(faultdata); + msn_soap_message_destroy(response); + return TRUE; + } else if (g_str_equal(faultdata, "wsse:FailedAuthentication")) { + xmlnode *reason = xmlnode_get_child(fault, "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); + msn_soap_message_destroy(response); + return FALSE; } - return; - } - location = strchr(location, ' ') + 1; - - if ((c = strchr(location, '\r')) != NULL) - *c = '\0'; - else - return; - - /* Skip the http:// */ - if ((c = strchr(location, '/')) != NULL) - location = c + 2; - - if ((c = strchr(location, '/')) != NULL) - { - g_free(soapconn->login_path); - soapconn->login_path = g_strdup(c); - - *c = '\0'; - } - - g_free(soapconn->login_host); - soapconn->login_host = g_strdup(location); - - msn_soap_close_handler( &(soapconn->input_handler) ); - msn_soap_close(soapconn); - - if (purple_ssl_connect(session->account, soapconn->login_host, - PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, - msn_soap_error_cb, soapconn) == NULL) { - - purple_debug_error("MSN SOAP", "Unable to connect to %s !\n", soapconn->login_host); - // dispatch next request - msn_soap_post(soapconn, NULL); - } - } - /* Another case of redirection, active on May, 2007 - See http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener#Redirect - */ - else if (strstr(soapconn->read_buf, - "<faultcode>psf:Redirect</faultcode>") != NULL) - { - char *location, *c; - - if ( (location = strstr(soapconn->read_buf, "<psf:redirectUrl>") ) == NULL) - return; - - /* Omit the tag preceding the URL */ - location += strlen("<psf:redirectUrl>"); - if (location > soapconn->read_buf + soapconn->read_len) - return; - if ( (location = strstr(location, "://")) == NULL) - return; - - location += strlen("://"); /* Skip http:// or https:// */ - - if ( (c = strstr(location, "</psf:redirectUrl>")) != NULL ) - *c = '\0'; - else - return; - - if ( (c = strstr(location, "/")) != NULL ) - { - g_free(soapconn->login_path); - soapconn->login_path = g_strdup(c); - *c = '\0'; - } - - g_free(soapconn->login_host); - soapconn->login_host = g_strdup(location); - - msn_soap_close_handler( &(soapconn->input_handler) ); - msn_soap_close(soapconn); - - if (purple_ssl_connect(session->account, soapconn->login_host, - PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, - msn_soap_error_cb, soapconn) == NULL) { - - purple_debug_error("MSN SOAP", "Unable to connect to %s !\n", soapconn->login_host); - // dispatch next request - msn_soap_post(soapconn, NULL); + g_free(faultdata); } } - else if (strstr(soapconn->read_buf, "HTTP/1.1 401 Unauthorized") != NULL) - { - const char *error; - - purple_debug_error("MSN SOAP", "Received HTTP error 401 Unauthorized\n"); - if ((error = strstr(soapconn->read_buf, "WWW-Authenticate")) != NULL) - { - if ((error = strstr(error, "cbtxt=")) != NULL) - { - const char *c; - char *temp; - - error += strlen("cbtxt="); - - if ((c = strchr(error, '\n')) == NULL) - c = error + strlen(error); - - temp = g_strndup(error, c - error); - error = purple_url_decode(temp); - g_free(temp); - } - } - - msn_session_set_error(session, MSN_ERROR_AUTH, error); - } - /* Handle Passport 3.0 authentication failures. - * Further info: http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener - */ - else if (strstr(soapconn->read_buf, - "<faultcode>wsse:FailedAuthentication</faultcode>") != NULL) - { - gchar *faultstring; - - faultstring = strstr(soapconn->read_buf, "<faultstring>"); - - if (faultstring != NULL) - { - gchar *c; - faultstring += strlen("<faultstring>"); - if (faultstring < soapconn->read_buf + soapconn->read_len) { - c = strstr(soapconn->read_buf, "</faultstring>"); - if (c != NULL) { - *c = '\0'; - msn_session_set_error(session, MSN_ERROR_AUTH, faultstring); - } - } - } - - } - else if (strstr(soapconn->read_buf, "HTTP/1.1 503 Service Unavailable")) - { - msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL); - } - else if ((strstr(soapconn->read_buf, "HTTP/1.1 200 OK")) - ||(strstr(soapconn->read_buf, "HTTP/1.1 500"))) - { - gboolean soapconn_is_valid = FALSE; - - /*OK! process the SOAP body*/ - body_start = (char *)g_strstr_len(soapconn->read_buf, soapconn->read_len,"\r\n\r\n"); - if (!body_start) { - return; - } - body_start += 4; - - if (body_start > soapconn->read_buf + soapconn->read_len) - return; - - /* we read the content-length*/ - if ( (length_start = g_strstr_len(soapconn->read_buf, soapconn->read_len, "Content-Length: ")) != NULL) - length_start += strlen("Content-Length: "); - - if (length_start > soapconn->read_buf + soapconn->read_len) - return; - if ( (length_end = strstr(length_start, "\r\n")) == NULL ) - return; - - body_len = g_strndup(length_start, length_end - length_start); - - /*setup the conn body */ - soapconn->body = body_start; - soapconn->body_len = atoi(body_len); - g_free(body_len); -#ifdef MSN_SOAP_DEBUG - purple_debug_misc("MSN SOAP", - "SOAP bytes read so far: %" G_GSIZE_FORMAT ", Content-Length: %d\n", - soapconn->read_len, soapconn->body_len); -#endif - soapconn->need_to_read = (body_start - soapconn->read_buf + soapconn->body_len) - soapconn->read_len; - if ( soapconn->need_to_read > 0 ) { - return; - } - -#if defined(MSN_SOAP_DEBUG) && !defined(_WIN32) - - node = xmlnode_from_str(soapconn->body, soapconn->body_len); - - if (node != NULL) { - formattedxml = xmlnode_to_formatted_str(node, NULL); - http_headers = g_strndup(soapconn->read_buf, soapconn->body - soapconn->read_buf); - - purple_debug_info("MSN SOAP","Data with XML payload received from the SOAP server:\n%s%s\n", http_headers, formattedxml); - g_free(http_headers); - g_free(formattedxml); - xmlnode_free(node); - } - else - purple_debug_info("MSN SOAP","Data received from the SOAP server:\n%s\n", soapconn->read_buf); -#endif + if (fault || body) { + MsnSoapRequest *request = conn->current_request; + conn->current_request = NULL; + request->cb(request->message, response, + request->cb_data); + msn_soap_message_destroy(response); + msn_soap_request_destroy(request, FALSE); + } - /*remove the read handler*/ - msn_soap_close_handler( &(soapconn->input_handler) ); -// purple_input_remove(soapconn->input_handler); -// soapconn->input_handler = 0; - /* - * close the soap connection,if more soap request came, - * Just reconnect to do it, - * - * To solve the problem described below: - * When I post the soap request in one socket one after the other, - * The first read is ok, But the second soap read always got 0 bytes, - * Weird! - * */ - msn_soap_close(soapconn); - - /*call the read callback*/ - if ( soapconn->read_cb != NULL ) { - soapconn_is_valid = soapconn->read_cb(soapconn); - } - - if (!soapconn_is_valid) { - return; - } - - /* dispatch next request in queue */ - msn_soap_post(soapconn, NULL); - } - return; -} - -void -msn_soap_free_read_buf(MsnSoapConn *soapconn) -{ - g_return_if_fail(soapconn != NULL); - - if (soapconn->read_buf) { - g_free(soapconn->read_buf); - } - soapconn->read_buf = NULL; - soapconn->read_len = 0; - soapconn->need_to_read = 0; + return TRUE; } -void -msn_soap_free_write_buf(MsnSoapConn *soapconn) +static void +msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond) { - g_return_if_fail(soapconn != NULL); - - if (soapconn->write_buf) { - g_free(soapconn->write_buf); - } - soapconn->write_buf = NULL; - soapconn->written_len = 0; -} + MsnSoapConnection *conn = data; + int count = 0, cnt, perrno; + /* This buffer needs to be larger than any packets received from + login.live.com or Adium will fail to receive the packet + (something weird with the login.live.com server). With NSS it works + fine, so I believe it's some bug with OS X */ + char buf[16 * 1024]; -/*Soap write process func*/ -static void -msn_soap_write_cb(gpointer data, gint source, PurpleInputCondition cond) -{ - MsnSoapConn *soapconn = data; - int len, total_len; - - g_return_if_fail(soapconn != NULL); - if ( soapconn->write_buf == NULL ) { - purple_debug_error("MSN SOAP","SOAP write buffer is NULL\n"); - // msn_soap_check_conn_errors(soapconn); - // purple_input_remove(soapconn->output_handler); - // soapconn->output_handler = 0; - msn_soap_close_handler( &(soapconn->output_handler) ); - return; + if (conn->message == NULL) { + conn->message = msn_soap_message_new(NULL, NULL); } - total_len = strlen(soapconn->write_buf); - - /* - * write the content to SSL server, - */ - len = purple_ssl_write(soapconn->gsc, - soapconn->write_buf + soapconn->written_len, - total_len - soapconn->written_len); - - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0){ - /*SSL write error!*/ -// msn_soap_check_conn_errors(soapconn); - msn_soap_close_handler( &(soapconn->output_handler) ); -// purple_input_remove(soapconn->output_handler); -// soapconn->output_handler = 0; - - msn_soap_close(soapconn); + if (conn->buf == NULL) { + conn->buf = g_string_new_len(buf, 0); + } + + while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { + purple_debug_info("soap", "read %d bytes\n", cnt); + count += cnt; + g_string_append_len(conn->buf, buf, cnt); + } - /* TODO: notify of the error */ - purple_debug_error("MSN SOAP", "Error writing to SSL connection!\n"); - msn_soap_post(soapconn, NULL); - return; - } - soapconn->written_len += len; - - if (soapconn->written_len < total_len) + /* && count is necessary for Adium, on OS X the last read always + return an error, so we want to proceed anyway. See #5212 for + discussion on this and the above buffer size issues */ + if(cnt < 0 && errno == EAGAIN && count == 0) return; - msn_soap_close_handler( &(soapconn->output_handler) ); -// purple_input_remove(soapconn->output_handler); -// soapconn->output_handler = 0; - - /*clear the write buff*/ - msn_soap_free_write_buf(soapconn); - - /* Write finish! - * callback for write done - */ - if(soapconn->written_cb != NULL){ - soapconn->written_cb(soapconn); - } - /*maybe we need to read the input?*/ - if ( soapconn->input_handler == 0 ) { - soapconn->input_handler = purple_input_add(soapconn->gsc->fd, - PURPLE_INPUT_READ, msn_soap_read_cb, soapconn); - } -} - -/*write the buffer to SOAP connection*/ -void -msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb) -{ - if (soapconn == NULL) { - return; - } - - msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); - - /* Ideally this wouldn't ever be necessary, but i believe that it is leaking the previous value */ - g_free(soapconn->write_buf); - soapconn->write_buf = write_buf; - soapconn->written_len = 0; - soapconn->written_cb = written_cb; - - msn_soap_free_read_buf(soapconn); - - /*clear the read buffer first*/ - /*start the write*/ - soapconn->output_handler = purple_input_add(soapconn->gsc->fd, PURPLE_INPUT_WRITE, - msn_soap_write_cb, soapconn); - msn_soap_write_cb(soapconn, soapconn->gsc->fd, PURPLE_INPUT_WRITE); -} - -/* New a soap request*/ -MsnSoapReq * -msn_soap_request_new(const char *host,const char *post_url,const char *soap_action, - const char *body, const gpointer data_cb, - MsnSoapReadCbFunction read_cb, - MsnSoapWrittenCbFunction written_cb, - MsnSoapConnectInitFunction connect_init) -{ - MsnSoapReq *request; - - request = g_new0(MsnSoapReq, 1); - request->id = 0; - - request->login_host = g_strdup(host); - request->login_path = g_strdup(post_url); - request->soap_action = g_strdup(soap_action); - request->body = g_strdup(body); - request->data_cb = data_cb; - request->read_cb = read_cb; - request->written_cb = written_cb; - request->connect_init = connect_init; - - return request; -} - -/*free a soap request*/ -void -msn_soap_request_free(MsnSoapReq *request) -{ - g_return_if_fail(request != NULL); - - g_free(request->login_host); - g_free(request->login_path); - g_free(request->soap_action); - g_free(request->body); - request->read_cb = NULL; - request->written_cb = NULL; - request->connect_init = NULL; - - g_free(request); -} - -/*post the soap request queue's head request*/ -void -msn_soap_post_head_request(MsnSoapConn *soapconn) -{ - g_return_if_fail(soapconn != NULL); - g_return_if_fail(soapconn->soap_queue != NULL); - - if (soapconn->step == MSN_SOAP_CONNECTED || - soapconn->step == MSN_SOAP_CONNECTED_IDLE) { - - purple_debug_info("MSN SOAP", "Posting new request from head of the queue\n"); - - if ( !g_queue_is_empty(soapconn->soap_queue) ) { - MsnSoapReq *request; - - if ( (request = g_queue_pop_head(soapconn->soap_queue)) != NULL ) { - msn_soap_post_request(soapconn,request); - } - } else { - purple_debug_info("MSN SOAP", "No requests to process found.\n"); - msn_soap_set_process_step(soapconn, MSN_SOAP_CONNECTED_IDLE); + /* msn_soap_process could alter errno */ + perrno = errno; + msn_soap_process(conn); + + if (cnt < 0 && perrno != EAGAIN) { + purple_debug_info("soap", "read: %s\n", g_strerror(perrno)); + /* It's possible msn_soap_process closed the ssl connection */ + if (conn->ssl) { + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + msn_soap_connection_handle_next(conn); } } } -/*post the soap request , - * if not connected, Connected first. - */ -void -msn_soap_post(MsnSoapConn *soapconn, MsnSoapReq *request) -{ - MsnSoapReq *head_request; +static void +msn_soap_process(MsnSoapConnection *conn) { + gboolean handled = FALSE; + char *cursor; + char *linebreak; + + 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 (soapconn == NULL) - return; + 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 (request != NULL) { -#ifdef MSN_SOAP_DEBUG - purple_debug_misc("MSN SOAP", "Request added to the queue\n"); -#endif - g_queue_push_tail(soapconn->soap_queue, request); + 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 ( !g_queue_is_empty(soapconn->soap_queue)) { - - /* we may have to reinitialize the soap connection, so avoid - * reusing the connection for now */ + 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 (soapconn->step == MSN_SOAP_CONNECTED_IDLE) { - purple_debug_misc("MSN SOAP","Already connected to SOAP server, re-initializing\n"); - msn_soap_close_handler( &(soapconn->input_handler) ); - msn_soap_close_handler( &(soapconn->output_handler) ); - msn_soap_close(soapconn); + 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); } - if (!msn_soap_connected(soapconn) && (soapconn->step == MSN_SOAP_UNCONNECTED)) { + return; + } - /*not connected?and we have something to process connect it first*/ - purple_debug_misc("MSN SOAP","No connection to SOAP server. Connecting...\n"); - head_request = g_queue_peek_head(soapconn->soap_queue); + if (handled) { + msn_soap_connection_handle_next(conn); + } +} - if (head_request == NULL) { - purple_debug_error("MSN SOAP", "Queue is not empty, but failed to peek the head request!\n"); - return; - } +static void +msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond) +{ + msn_soap_write_cb_internal(data, fd, cond, FALSE); +} - if (head_request->connect_init != NULL) { - head_request->connect_init(soapconn); - } - msn_soap_connect(soapconn); - return; - } +static gboolean +msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond, + gboolean initial) +{ + MsnSoapConnection *conn = data; + int written; + + if (cond != PURPLE_INPUT_WRITE) return TRUE; -#ifdef MSN_SOAP_DEBUG - purple_debug_info("MSN SOAP", "Currently processing another SOAP request\n"); - } else { - purple_debug_info("MSN SOAP", "No requests left to dispatch\n"); -#endif + written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len, + conn->buf->len - conn->handled_len); + + if (written < 0 && errno == EAGAIN) + return TRUE; + else if (written <= 0) { + purple_ssl_close(conn->ssl); + conn->ssl = NULL; + if (!initial) msn_soap_connection_handle_next(conn); + return FALSE; } + conn->handled_len += written; + + if (conn->handled_len < conn->buf->len) + return TRUE; + + /* 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); + return TRUE; +} + +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; + + g_queue_pop_head(conn->queue); + + conn->buf = g_string_new(""); + + 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" + "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 : "", + 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); + if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) { + /* Not connected => reconnect and retry */ + purple_debug_info("soap", "not connected, reconnecting\n"); + + conn->connected = FALSE; + conn->current_request = NULL; + msn_soap_connection_sanitize(conn, FALSE); + + g_queue_push_head(conn->queue, req); + conn->event_handle = purple_timeout_add(0, msn_soap_connection_run, conn); + } + + 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); } -/*Post the soap request action*/ -void -msn_soap_post_request(MsnSoapConn *soapconn, MsnSoapReq *request) +static void +msn_soap_message_send_internal(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data, gboolean first) { - char * request_str = NULL; -#ifdef MSN_SOAP_DEBUG -#if !defined(_WIN32) - xmlnode * node; -#endif - purple_debug_misc("MSN SOAP","msn_soap_post_request()\n"); -#endif + 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; + } - msn_soap_set_process_step(soapconn, MSN_SOAP_PROCESSING); - request_str = g_strdup_printf( - "POST %s HTTP/1.1\r\n" - "SOAPAction: %s\r\n" - "Content-Type:text/xml; charset=utf-8\r\n" - "Cookie: MSPAuth=%s\r\n" - "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" - "Accept: */*\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", - request->login_path, - request->soap_action, - soapconn->session->passport_info.mspauth, - request->login_host, - strlen(request->body), - request->body - ); + 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 defined(MSN_SOAP_DEBUG) && !defined(_WIN32) - node = xmlnode_from_str(request->body, -1); - if (node != NULL) { - char *formattedstr = xmlnode_to_formatted_str(node, NULL); - purple_debug_info("MSN SOAP","Posting request to SOAP server:\n%s%s\n",request_str, formattedstr); - g_free(formattedstr); - xmlnode_free(node); + if (conn->current_request) { + msn_soap_request_destroy(conn->current_request, FALSE); + conn->current_request = NULL; } - else - purple_debug_info("MSN SOAP","Failed to parse SOAP request being sent:\n%s\n", request_str); -#endif +} + +static void +msn_soap_connection_handle_next(MsnSoapConnection *conn) +{ + msn_soap_connection_sanitize(conn, FALSE); - /*free read buffer*/ - // msn_soap_free_read_buf(soapconn); - /*post it to server*/ - soapconn->data_cb = request->data_cb; - msn_soap_write(soapconn, request_str, request->written_cb); + 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, FALSE); +} + +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 *message, + const char *name, const char *value) +{ + char *header = g_strdup_printf("%s: %s\r\n", name, value); + + message->headers = g_slist_prepend(message->headers, header); +} + +static void +msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message) +{ + g_free(req->path); + if (!keep_message) + msn_soap_message_destroy(req->message); + g_free(req); +} +
--- a/libpurple/protocols/msn/soap.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/soap.h Sat Jul 12 07:32:05 2008 +0000 @@ -1,8 +1,7 @@ /** * @file soap.h * header file for SOAP connection related process - * Author - * MaYuan<mayuan2006@gmail.com> + * * purple * * Purple is the legal property of its developers, whose names are too numerous @@ -23,144 +22,35 @@ * 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_SOAP_H_ -#define _MSN_SOAP_H_ -#define MSN_SOAP_READ_BUFF_SIZE 8192 - -/* define this to debug the communications with the SOAP server */ -/* #define MSN_SOAP_DEBUG */ - -#define MSN_SOAP_READ 1 -#define MSN_SOAP_WRITE 2 +#ifndef _MSN_SOAP_H +#define _MSN_SOAP_H -typedef enum -{ - MSN_SOAP_UNCONNECTED, - MSN_SOAP_CONNECTING, - MSN_SOAP_CONNECTED, - MSN_SOAP_PROCESSING, - MSN_SOAP_CONNECTED_IDLE -}MsnSoapStep; - -/* MSN SoapRequest structure*/ -typedef struct _MsnSoapReq MsnSoapReq; +#include "session.h" +#include "sslconn.h" +#include "xmlnode.h" -/* MSN Https connection structure*/ -typedef struct _MsnSoapConn MsnSoapConn; - -typedef void (*MsnSoapConnectInitFunction)(MsnSoapConn *); -typedef gboolean (*MsnSoapReadCbFunction)(MsnSoapConn *); -typedef void (*MsnSoapWrittenCbFunction)(MsnSoapConn *); - -typedef gboolean (*MsnSoapSslConnectCbFunction)(MsnSoapConn *, PurpleSslConnection *); -typedef void (*MsnSoapSslErrorCbFunction)(MsnSoapConn *, PurpleSslConnection *, PurpleSslErrorType); - +#include <glib.h> -struct _MsnSoapReq{ - /*request sequence*/ - int id; +typedef struct _MsnSoapMessage MsnSoapMessage; +typedef void (*MsnSoapCallback)(MsnSoapMessage *request, + MsnSoapMessage *response, gpointer cb_data); - char *login_host; - char *login_path; - char *soap_action; - - char *body; - - gpointer data_cb; - MsnSoapReadCbFunction read_cb; - MsnSoapWrittenCbFunction written_cb; - MsnSoapConnectInitFunction connect_init; +struct _MsnSoapMessage { + char *action; + xmlnode *xml; + GSList *headers; }; -struct _MsnSoapConn{ - MsnSession *session; - gpointer parent; - - char *login_host; - char *login_path; - char *soap_action; - - MsnSoapStep step; - /*ssl connection?*/ - gboolean ssl_conn; - /*normal connection*/ - guint fd; - /*SSL connection*/ - PurpleSslConnection *gsc; - /*ssl connection callback*/ - MsnSoapSslConnectCbFunction connect_cb; - /*ssl error callback*/ - MsnSoapSslErrorCbFunction error_cb; +MsnSoapMessage *msn_soap_message_new(const char *action, xmlnode *xml); - /*read handler*/ - guint input_handler; - /*write handler*/ - guint output_handler; - - /*Queue of SOAP request to send*/ - int soap_id; - GQueue *soap_queue; - - /*write buffer*/ - char *write_buf; - gsize written_len; - MsnSoapWrittenCbFunction written_cb; - - /*read buffer*/ - char *read_buf; - gsize read_len; - gsize need_to_read; - MsnSoapReadCbFunction read_cb; - - gpointer data_cb; +void msn_soap_message_add_header(MsnSoapMessage *req, + const char *name, const char *value); - /*HTTP reply body part*/ - char *body; - int body_len; -}; - - -/*Function Prototype*/ -/*Soap Request Function */ -MsnSoapReq *msn_soap_request_new(const char *host, const char *post_url, - const char *soap_action, const char *body, - const gpointer data_cb, - MsnSoapReadCbFunction read_cb, - MsnSoapWrittenCbFunction written_cb, - MsnSoapConnectInitFunction connect_init); - -void msn_soap_request_free(MsnSoapReq *request); -void msn_soap_post_request(MsnSoapConn *soapconn,MsnSoapReq *request); -void msn_soap_post_head_request(MsnSoapConn *soapconn); - -/*new a soap conneciton */ -MsnSoapConn *msn_soap_new(MsnSession *session, gpointer data, gboolean ssl); - -/*destroy */ -void msn_soap_destroy(MsnSoapConn *soapconn); +void msn_soap_message_send(MsnSession *session, + MsnSoapMessage *message, const char *host, const char *path, + MsnSoapCallback cb, gpointer cb_data); -/*init a soap conneciton */ -void msn_soap_init(MsnSoapConn *soapconn, char * host, gboolean ssl, - MsnSoapSslConnectCbFunction connect_cb, - MsnSoapSslErrorCbFunction error_cb); -void msn_soap_connect(MsnSoapConn *soapconn); -void msn_soap_close(MsnSoapConn *soapconn); - -/*write to soap*/ -void msn_soap_write(MsnSoapConn * soapconn, char *write_buf, MsnSoapWrittenCbFunction written_cb); -void msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request); +void msn_soap_message_destroy(MsnSoapMessage *message); -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); - -/*clean the unhandled requests*/ -void msn_soap_clean_unhandled_requests(MsnSoapConn *soapconn); - -/*check if the soap connection is connected*/ -int msn_soap_connected(MsnSoapConn *soapconn); -void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step); - -#endif/*_MSN_SOAP_H_*/ - +#endif
--- a/libpurple/protocols/msn/soap2.c Fri Jul 11 15:27:41 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,693 +0,0 @@ -/** - * @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 "internal.h" - -#include "soap2.h" - -#include "session.h" - -#include "debug.h" -#include "xmlnode.h" - -#include <glib.h> -#if !defined(_WIN32) || !defined(_WINERROR_) -#include <error.h> -#endif - -#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 void msn_soap_process(MsnSoapConnection *conn); - -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 = purple_timeout_add(0, msn_soap_connection_run, conn); -} - -static void -msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error, - gpointer data) -{ - MsnSoapConnection *conn = data; - - /* sslconn already frees the connection in case of error */ - conn->ssl = NULL; - - 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"); - xmlnode *fault = xmlnode_get_child(response->xml, "Fault"); - - if (fault) { - xmlnode *faultcode = xmlnode_get_child(fault, "faultcode"); - - if (faultcode != NULL) { - char *faultdata = xmlnode_get_data(faultcode); - - if (g_str_equal(faultdata, "psf:Redirect")) { - 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 (g_str_equal(faultdata, "wsse:FailedAuthentication")) { - 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); - } - } - - if (fault || body) { - MsnSoapRequest *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 = 0, cnt, perrno; - /* This buffer needs to be larger than any packets received from - login.live.com or Adium will fail to receive the packet - (something weird with the login.live.com server). With NSS it works - fine, so I believe it's some bug with OS X */ - char buf[16 * 1024]; - - if (conn->message == NULL) { - conn->message = msn_soap_message_new(NULL, NULL); - } - - if (conn->buf == NULL) { - conn->buf = g_string_new_len(buf, 0); - } - - while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) { - purple_debug_info("soap", "read %d bytes\n", cnt); - count += cnt; - g_string_append_len(conn->buf, buf, cnt); - } - - /* && count is necessary for Adium, on OS X the last read always - return an error, so we want to proceed anyway. See #5212 for - discussion on this and the above buffer size issues */ - if(cnt < 0 && errno == EAGAIN && count == 0) - return; - - // msn_soap_process could alter errno - perrno = errno; - msn_soap_process(conn); - - if (cnt < 0 && perrno != EAGAIN) { - purple_debug_info("soap", "read: %s\n", g_strerror(perrno)); - // It's possible msn_soap_process closed the ssl connection - if (conn->ssl) { - purple_ssl_close(conn->ssl); - conn->ssl = NULL; - msn_soap_connection_handle_next(conn); - } - } -} - -static void -msn_soap_process(MsnSoapConnection *conn) { - gboolean handled = FALSE; - char *cursor; - char *linebreak; - - 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)) { - msn_soap_message_destroy(message); - return; - } - msn_soap_message_destroy(message); - } - - 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 *message, - const char *name, const char *value) -{ - char *header = g_strdup_printf("%s: %s\r\n", name, value); - - message->headers = g_slist_prepend(message->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; -} -
--- a/libpurple/protocols/msn/soap2.h Fri Jul 11 15:27:41 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * @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 <glib.h> - -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
--- a/libpurple/protocols/msn/state.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/state.c Sat Jul 12 07:32:05 2008 +0000 @@ -151,15 +151,15 @@ xmlnode *payloadNode, *currentmediaNode; char *currentmedia; - purple_debug_info("msn","msn get CurrentMedia\n"); + purple_debug_info("msn", "Get CurrentMedia\n"); payloadNode = xmlnode_from_str(xml_str, len); - if (!payloadNode){ - purple_debug_error("msn","PSM XML parse Error!\n"); + if (!payloadNode) { + purple_debug_error("msn", "PSM XML parse Error!\n"); return NULL; } currentmediaNode = xmlnode_get_child(payloadNode, "CurrentMedia"); - if (currentmediaNode == NULL){ - purple_debug_info("msn","No CurrentMedia Node"); + if (currentmediaNode == NULL) { + purple_debug_info("msn", "No CurrentMedia Node"); xmlnode_free(payloadNode); return NULL; } @@ -177,15 +177,15 @@ xmlnode *payloadNode, *psmNode; char *psm; - purple_debug_info("MSNP14","msn get PSM\n"); + purple_debug_info("msn", "msn get PSM\n"); payloadNode = xmlnode_from_str(xml_str, len); if (!payloadNode){ - purple_debug_error("MSNP14","PSM XML parse Error!\n"); + purple_debug_error("msn", "PSM XML parse Error!\n"); return NULL; } psmNode = xmlnode_get_child(payloadNode, "PSM"); if (psmNode == NULL){ - purple_debug_info("MSNP14","No PSM status Node"); + purple_debug_info("msn", "No PSM status Node"); xmlnode_free(payloadNode); return NULL; } @@ -249,7 +249,7 @@ session->psm = msn_build_psm(statusline_stripped, media, NULL); payload = session->psm; - purple_debug_misc("MSNP14","Sending UUX command with payload: %s\n",payload); + purple_debug_misc("msn", "Sending UUX command with payload: %s\n", payload); trans = msn_transaction_new(cmdproc, "UUX", "%" G_GSIZE_FORMAT, strlen(payload)); msn_transaction_set_payload(trans, payload, strlen(payload)); msn_cmdproc_send_trans(cmdproc, trans);
--- a/libpurple/protocols/msn/switchboard.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/switchboard.c Sat Jul 12 07:32:05 2008 +0000 @@ -338,7 +338,7 @@ { g_return_if_fail(swboard != NULL); - purple_debug_warning("msg", "Error: Unable to call the user %s for reason %i\n", + purple_debug_warning("msn", "Error: Unable to call the user %s for reason %i\n", passport ? passport : "(null)", reason); /* TODO: if current_users > 0, this is probably a chat and an invite failed, @@ -540,7 +540,7 @@ payload = msn_message_gen_payload(msg, &payload_len); #ifdef MSN_DEBUG_SB - purple_debug_info("MSNP14","SB length:{%d}",payload_len); + purple_debug_info("msn", "SB length:{%d}", payload_len); msn_message_show_readable(msg, "SB SEND", FALSE); #endif @@ -628,7 +628,7 @@ g_return_if_fail(swboard != NULL); g_return_if_fail(msg != NULL); - purple_debug_info("MSNP14","switchboard send msg..\n"); + purple_debug_info("msn", "switchboard send msg..\n"); if (msn_switchboard_can_send(swboard)) release_msg(swboard, msg); else if (queue) @@ -662,7 +662,7 @@ g_return_if_fail(swboard != NULL); if (!(swboard->flag & MSN_SB_FLAG_IM) && (swboard->conv != NULL)) - purple_debug_error("msn_switchboard", "bye_cmd: helper bug\n"); + purple_debug_error("msn", "bye_cmd: helper bug\n"); if (swboard->conv == NULL) { @@ -752,15 +752,15 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - cmdproc->servconn->payload_len = atoi(cmd->params[2]); + cmd->payload_len = atoi(cmd->params[2]); cmdproc->last_cmd->payload_cb = msg_cmd_post; } static void ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { - purple_debug_misc("MSNP14","get UBM...\n"); - cmdproc->servconn->payload_len = atoi(cmd->params[4]); + purple_debug_misc("msn", "get UBM...\n"); + cmd->payload_len = atoi(cmd->params[4]); cmdproc->last_cmd->payload_cb = msg_cmd_post; } @@ -960,17 +960,40 @@ } static void -nudge_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +datacast_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { - MsnSwitchBoard *swboard; - PurpleAccount *account; - const char *user; + GHashTable *body; + const char *id; + body = msn_message_get_hashtable_from_body(msg); + + id = g_hash_table_lookup(body, "ID"); + + if (!strcmp(id, "1")) { + /* Nudge */ + MsnSwitchBoard *swboard; + PurpleAccount *account; + const char *user; - swboard = cmdproc->data; - account = cmdproc->session->account; - user = msg->remote_user; + swboard = cmdproc->data; + account = cmdproc->session->account; + user = msg->remote_user; + + serv_got_attention(account->gc, user, MSN_NUDGE); + + } else if (!strcmp(id, "2")) { + /* Wink */ - serv_got_attention(account->gc, user, MSN_NUDGE); + } else if (!strcmp(id, "3")) { + /* Voiceclip */ + + } else if (!strcmp(id, "4")) { + /* Action */ + + } else { + purple_debug_warning("msn", "Got unknown datacast with ID %s.\n", id); + } + + g_hash_table_destroy(body); } /************************************************************************** @@ -1059,7 +1082,7 @@ msn_servconn_set_connect_cb(swboard->servconn, connect_cb); msn_servconn_set_disconnect_cb(swboard->servconn, disconnect_cb); - return msn_servconn_connect(swboard->servconn, host, port); + return msn_servconn_connect(swboard->servconn, host, port, FALSE); } void @@ -1114,13 +1137,9 @@ } purple_debug_warning("msn", "cal_error: command %s gave error %i\n", trans->command, error); - purple_debug_warning("msn", "Will Use Offline Message to sendit\n"); - -// cal_error_helper(trans, reason); - /*offline Message send Process*/ while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL){ - purple_debug_warning("MSNP14","offline msg to send:{%s}\n",msg->body); + purple_debug_warning("msn", "Unable to send msg: {%s}\n", msg->body); /* The messages could not be sent due to a switchboard error */ swboard->error = MSN_SB_ERROR_USER_OFFLINE; msg_error_helper(swboard->cmdproc, msg, @@ -1170,7 +1189,7 @@ /* The conversation window was closed. */ return; - purple_debug_info("MSNP14","Switchboard:auth:{%s} socket:{%s}\n",cmd->params[4],cmd->params[2]); + purple_debug_info("msn", "Switchboard:auth:{%s} socket:{%s}\n", cmd->params[4], cmd->params[2]); msn_switchboard_set_auth_key(swboard, cmd->params[4]); msn_parse_socket(cmd->params[2], &host, &port); @@ -1313,7 +1332,7 @@ msn_table_add_msg_type(cbs_table, "text/x-mms-animemoticon", msn_emoticon_msg); msn_table_add_msg_type(cbs_table, "text/x-msnmsgr-datacast", - nudge_msg); + datacast_msg); #if 0 msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite", msn_invite_msg);
--- a/libpurple/protocols/msn/sync.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/sync.c Sat Jul 12 07:32:05 2008 +0000 @@ -216,8 +216,6 @@ void msn_sync_init(void) { - /* TODO: check prp, blp, bpr */ - cbs_table = msn_table_new(); /* Syncing */
--- a/libpurple/protocols/msn/user.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/user.c Sat Jul 12 07:32:05 2008 +0000 @@ -28,7 +28,7 @@ /*new a user object*/ MsnUser * msn_user_new(MsnUserList *userlist, const char *passport, - const char *store_name) + const char *friendly_name) { MsnUser *user; @@ -37,16 +37,7 @@ user->userlist = userlist; msn_user_set_passport(user, passport); - msn_user_set_store_name(user, store_name); - - /* - * XXX This seems to reset the friendly name from what it should be - * to the passport when moving users. So, screw it :) - */ -#if 0 - if (name != NULL) - msn_user_set_name(user, name); -#endif + msn_user_set_friendly_name(user, friendly_name); return user; } @@ -75,7 +66,6 @@ g_free(user->passport); g_free(user->friendly_name); - g_free(user->store_name); g_free(user->uid); g_free(user->phone.home); g_free(user->phone.work); @@ -92,37 +82,36 @@ msn_user_update(MsnUser *user) { PurpleAccount *account; + gboolean offline; account = user->userlist->session->account; - if (user->status != NULL) { - gboolean offline = (strcmp(user->status, "offline") == 0); + offline = (user->status == NULL); - if (!offline) { - purple_prpl_got_user_status(account, user->passport, user->status, - "message", user->statusline, NULL); + if (!offline) { + purple_prpl_got_user_status(account, user->passport, user->status, + "message", user->statusline, NULL); + } else { + if (user->mobile) { + purple_prpl_got_user_status(account, user->passport, "mobile", NULL); + purple_prpl_got_user_status(account, user->passport, "available", NULL); } else { - if (user->mobile) { - purple_prpl_got_user_status(account, user->passport, "mobile", NULL); - purple_prpl_got_user_status(account, user->passport, "available", NULL); - } else { - purple_prpl_got_user_status(account, user->passport, user->status, NULL); - } + purple_prpl_got_user_status(account, user->passport, "offline", NULL); } + } - if (!offline || !user->mobile) { - purple_prpl_got_user_status_deactive(account, user->passport, "mobile"); - } + if (!offline || !user->mobile) { + purple_prpl_got_user_status_deactive(account, user->passport, "mobile"); + } - if (!offline && user->media.title) { - purple_prpl_got_user_status(account, user->passport, "tune", - PURPLE_TUNE_ARTIST, user->media.artist, - PURPLE_TUNE_ALBUM, user->media.album, - PURPLE_TUNE_TITLE, user->media.title, - NULL); - } else { - purple_prpl_got_user_status_deactive(account, user->passport, "tune"); - } + if (!offline && user->media.title) { + purple_prpl_got_user_status(account, user->passport, "tune", + PURPLE_TUNE_ARTIST, user->media.artist, + PURPLE_TUNE_ALBUM, user->media.album, + PURPLE_TUNE_TITLE, user->media.title, + NULL); + } else { + purple_prpl_got_user_status_deactive(account, user->passport, "tune"); } if (user->idle) @@ -136,6 +125,11 @@ { const char *status; + if (state == NULL) { + user->status = NULL; + return; + } + if (!g_ascii_strcasecmp(state, "BSY")) status = "busy"; else if (!g_ascii_strcasecmp(state, "BRB")) @@ -199,18 +193,6 @@ } void -msn_user_set_store_name(MsnUser *user, const char *name) -{ - g_return_if_fail(user != NULL); - - if (name != NULL) - { - g_free(user->store_name); - user->store_name = g_strdup(name); - } -} - -void msn_user_set_uid(MsnUser *user, const char *uid) { g_return_if_fail(user != NULL); @@ -220,14 +202,6 @@ } void -msn_user_set_type(MsnUser *user, MsnUserType type) -{ - g_return_if_fail(user != NULL); - - user->type = type; -} - -void msn_user_set_op(MsnUser *user, int list_op) { g_return_if_fail(user != NULL); @@ -283,7 +257,7 @@ group_name = msn_userlist_find_group_name(userlist, group_id); - purple_debug_info("User","group id:%s,name:%s,user:%s\n", group_id, group_name, passport); + purple_debug_info("msn", "User: group id:%s,name:%s,user:%s\n", group_id, group_name, passport); g = purple_find_group(group_name); @@ -325,12 +299,9 @@ if (gc != NULL) session = gc->proto_data; - if ((session != NULL) && (session->protocol_ver == WLM_PROT_VER)) - return FALSE; - if ((session != NULL) && (user = msn_userlist_find_user(session->userlist, name)) != NULL) { - return (user->type == MSN_USER_TYPE_YAHOO); + return (user->networkid == MSN_NETWORK_YAHOO); } return (strstr(name,"@yahoo.") != NULL); } @@ -380,6 +351,22 @@ } void +msn_user_set_clientid(MsnUser *user, guint clientid) +{ + g_return_if_fail(user != NULL); + + user->clientid = clientid; +} + +void +msn_user_set_network(MsnUser *user, MsnNetwork network) +{ + g_return_if_fail(user != NULL); + + user->networkid = network; +} + +void msn_user_set_object(MsnUser *user, MsnObject *obj) { g_return_if_fail(user != NULL); @@ -422,14 +409,6 @@ } const char * -msn_user_get_store_name(const MsnUser *user) -{ - g_return_val_if_fail(user != NULL, NULL); - - return user->store_name; -} - -const char * msn_user_get_home_phone(const MsnUser *user) { g_return_val_if_fail(user != NULL, NULL); @@ -453,6 +432,14 @@ return user->phone.mobile; } +guint +msn_user_get_clientid(const MsnUser *user) +{ + g_return_val_if_fail(user != NULL, 0); + + return user->clientid; +} + MsnObject * msn_user_get_object(const MsnUser *user) {
--- a/libpurple/protocols/msn/user.h Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/user.h Sat Jul 12 07:32:05 2008 +0000 @@ -33,14 +33,14 @@ typedef enum { - MSN_USER_TYPE_UNKNOWN = 0x00, - MSN_USER_TYPE_PASSPORT = 0x01, - MSN_USER_TYPE_UNKNOWN1 = 0x02, - MSN_USER_TYPE_MOBILE = 0x04, - MSN_USER_TYPE_UNKNOWN2 = 0x08, - MSN_USER_TYPE_UNKNOWN3 = 0x10, - MSN_USER_TYPE_YAHOO = 0x20 -} MsnUserType; + MSN_NETWORK_UNKNOWN = 0x00, + MSN_NETWORK_PASSPORT = 0x01, + MSN_NETWORK_COMMUNICATOR = 0x02, + MSN_NETWORK_MOBILE = 0x04, + MSN_NETWORK_MNI = 0x08, + MSN_NETWORK_SMTP = 0x10, + MSN_NETWORK_YAHOO = 0x20 +} MsnNetwork; /** * Current media. @@ -60,7 +60,6 @@ MsnUserList *userlist; char *passport; /**< The passport account. */ - char *store_name; /**< The name stored in the server. */ char *friendly_name; /**< The friendly name. */ char * uid; /*< User Id */ @@ -88,7 +87,9 @@ GHashTable *clientcaps; /**< The client's capabilities. */ - MsnUserType type; /**< The user type */ + guint clientid; /**< The client's ID */ + + MsnNetwork networkid; /**< The user's network */ int list_op; /**< Which lists the user is in */ @@ -96,9 +97,9 @@ indexed by the list it belongs to */ }; -/**************************************************************************/ -/** @name User API */ -/**************************************************************************/ +/************************************************************************** + ** @name User API * + **************************************************************************/ /*@{*/ /** @@ -111,7 +112,7 @@ * @return A new user structure. */ MsnUser *msn_user_new(MsnUserList *userlist, const char *passport, - const char *store_name); + const char *friendly_name); /** * Destroys a user structure. @@ -171,14 +172,6 @@ void msn_user_set_friendly_name(MsnUser *user, const char *name); /** - * Sets the store name for a user. - * - * @param user The user. - * @param name The store name. - */ -void msn_user_set_store_name(MsnUser *user, const char *name); - -/** * Sets the buddy icon for a local user. * * @param user The user. @@ -227,7 +220,22 @@ void msn_user_set_work_phone(MsnUser *user, const char *number); void msn_user_set_uid(MsnUser *user, const char *uid); -void msn_user_set_type(MsnUser *user, MsnUserType type); + +/** + * Sets the client id for a user. + * + * @param user The user. + * @param clientid The client id. + */ +void msn_user_set_clientid(MsnUser *user, guint clientid); + +/** + * Sets the network id for a user. + * + * @param user The user. + * @param network The network id. + */ +void msn_user_set_network(MsnUser *user, MsnNetwork network); /** * Sets the mobile phone number for a user. @@ -273,15 +281,6 @@ const char *msn_user_get_friendly_name(const MsnUser *user); /** - * Returns the store name for a user. - * - * @param user The user. - * - * @return The store name. - */ -const char *msn_user_get_store_name(const MsnUser *user); - -/** * Returns the home phone number for a user. * * @param user The user. @@ -309,6 +308,24 @@ const char *msn_user_get_mobile_phone(const MsnUser *user); /** + * Returns the client id for a user. + * + * @param user The user. + * + * @return The user's client id. + */ +guint msn_user_get_clientid(const MsnUser *user); + +/** + * Returns the network id for a user. + * + * @param user The user. + * + * @return The user's network id. + */ +MsnNetwork msn_user_get_network(const MsnUser *user); + +/** * Returns the MSNObject for a user. * * @param user The user.
--- a/libpurple/protocols/msn/userlist.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msn/userlist.c Sat Jul 12 07:32:05 2008 +0000 @@ -24,6 +24,8 @@ #include "msn.h" #include "userlist.h" +#include "contact.h" + const char *lists[] = { "FL", "AL", "BL", "RL" }; typedef struct @@ -42,7 +44,7 @@ { MsnPermitAdd *pa = data; - purple_debug_misc("MSN Userlist", "Accepted the new buddy: %s\n", pa->who); + purple_debug_misc("msn", "Accepted the new buddy: %s\n", pa->who); if (PURPLE_CONNECTION_IS_VALID(pa->gc)) { @@ -51,7 +53,7 @@ msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_AL); - msn_del_contact_from_list(session->contact, NULL, pa->who, MSN_LIST_PL); + msn_del_contact_from_list(session, NULL, pa->who, MSN_LIST_PL); } g_free(pa->who); @@ -64,7 +66,7 @@ { MsnPermitAdd *pa = data; - purple_debug_misc("MSN Userlist", "Denied the new buddy: %s\n", pa->who); + purple_debug_misc("msn", "Denied the new buddy: %s\n", pa->who); if (PURPLE_CONNECTION_IS_VALID(pa->gc)) { @@ -75,7 +77,7 @@ msn_callback_state_set_action(state, MSN_DENIED_BUDDY); msn_userlist_add_buddy_to_list(userlist, pa->who, MSN_LIST_BL); - msn_del_contact_from_list(session->contact, state, pa->who, MSN_LIST_PL); + msn_del_contact_from_list(session, state, pa->who, MSN_LIST_PL); } g_free(pa->who); @@ -136,36 +138,6 @@ return FALSE; } -#if 0 -static const char* -get_store_name(MsnUser *user) -{ - const char *store_name; - - g_return_val_if_fail(user != NULL, NULL); - - store_name = msn_user_get_store_name(user); - - if (store_name != NULL) - store_name = purple_url_encode(store_name); - else - store_name = msn_user_get_passport(user); - - /* this might be a bit of a hack, but it should prevent notification server - * disconnections for people who have buddies with insane friendly names - * who added you to their buddy list from being disconnected. Stu. */ - /* Shx: What? Isn't the store_name obtained from the server, and hence it's - * below the BUDDY_ALIAS_MAXLEN ? */ - /* Stu: yeah, that's why it's a bit of a hack, as you pointed out, we're - * probably decoding the incoming store_name wrong, or something. bleh. */ - - if (strlen(store_name) > BUDDY_ALIAS_MAXLEN) - store_name = msn_user_get_passport(user); - - return store_name; -} -#endif - /************************************************************************** * Server functions **************************************************************************/ @@ -194,7 +166,7 @@ const char *passport; const char *friendly; - purple_debug_info("MSNP14","got add user...\n"); + purple_debug_info("msn", "got add user...\n"); account = session->account; passport = msn_user_get_passport(user); @@ -254,7 +226,7 @@ * looked at this. Maybe we should use the store * name instead? --KingAnt */ -// got_new_entry(gc, passport, friendly); +/* got_new_entry(gc, passport, friendly); */ } } @@ -340,7 +312,7 @@ gc = purple_account_get_connection(account); passport = msn_user_get_passport(user); - store = msn_user_get_store_name(user); + store = msn_user_get_friendly_name(user); msn_user_set_op(user, list_op); @@ -384,7 +356,7 @@ if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) { -// got_new_entry(gc, passport, store); +/* got_new_entry(gc, passport, store); */ } } @@ -454,7 +426,7 @@ user = msn_user_new(userlist, passport, userName); msn_userlist_add_user(userlist, user); } else { - msn_user_set_store_name(user, userName); + msn_user_set_friendly_name(user, userName); } return user; } @@ -482,11 +454,9 @@ { MsnUser *user = (MsnUser *)l->data; -// purple_debug_info("MsnUserList","user passport:%s,passport:%s\n",user->passport,passport); g_return_val_if_fail(user->passport != NULL, NULL); if (!g_strcasecmp(passport, user->passport)){ -// purple_debug_info("MsnUserList","return:%p\n",user); return user; } } @@ -647,7 +617,6 @@ g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); - g_return_if_fail(userlist->session->contact != NULL); g_return_if_fail(who != NULL); user = msn_userlist_find_user(userlist, who); @@ -656,7 +625,7 @@ /* delete the contact from address book via soap action */ if (user != NULL) { - msn_delete_contact(userlist->session->contact, user->uid); + msn_delete_contact(userlist->session, user->uid); } } @@ -674,7 +643,7 @@ if ( !msn_userlist_user_is_in_list(user, list_id)) { list = lists[list_id]; - purple_debug_info("MSN Userlist", "User %s is not in list %s, not removing.\n", who, list); + purple_debug_info("msn", "User %s is not in list %s, not removing.\n", who, list); return; } @@ -693,16 +662,10 @@ new_group_name = group_name == NULL ? MSN_INDIVIDUALS_GROUP_NAME : group_name; - g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); - - purple_debug_info("MSN Userlist", "Add user: %s to group: %s\n", who, new_group_name); - - 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); + purple_debug_info("msn", "Add user: %s to group: %s\n", who, new_group_name); if (!purple_email_is_valid(who)) { @@ -719,12 +682,16 @@ return; } + 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); + group_id = msn_userlist_find_group_id(userlist, new_group_name); if (group_id == NULL) { /* Whoa, we must add that group first. */ - purple_debug_info("MSN Userlist", "Adding user %s to a new group, creating group %s first\n", who, new_group_name); + purple_debug_info("msn", "Adding user %s to a new group, creating group %s first\n", who, new_group_name); msn_callback_state_set_action(state, MSN_ADD_BUDDY); @@ -742,23 +709,24 @@ if ( msn_userlist_user_is_in_list(user, MSN_LIST_FL) ) { - purple_debug_info("MSN Userlist", "User %s already exists\n", who); + purple_debug_info("msn", "User %s already exists\n", who); msn_userlist_rem_buddy_from_list(userlist, who, MSN_LIST_BL); if (msn_userlist_user_is_in_group(user, group_id)) { - purple_debug_info("MSN Userlist", "User %s is already in group %s, returning\n", who, new_group_name); + purple_debug_info("msn", "User %s is already in group %s, returning\n", who, new_group_name); + msn_callback_state_free(state); return; } } - purple_debug_info("MSN Userlist", "Adding user: %s to group id: %s\n", who, group_id); + purple_debug_info("msn", "Adding user: %s to group id: %s\n", who, group_id); msn_callback_state_set_action(state, MSN_ADD_BUDDY); /* Add contact in the Contact server with a SOAP request and if successful, send ADL with MSN_LIST_AL and MSN_LIST_FL and a FQY */ - msn_add_contact_to_group(userlist->session->contact, state, who, group_id); + msn_add_contact_to_group(userlist->session, state, who, group_id); } void @@ -777,14 +745,10 @@ if (msn_userlist_user_is_in_list(user, list_id)) { list = lists[list_id]; - purple_debug_info("MSN Userlist", "User '%s' is already in list: %s\n", who, list); + purple_debug_info("msn", "User '%s' is already in list: %s\n", who, list); return; } - //store_name = (user != NULL) ? get_store_name(user) : who; - - //purple_debug_info("MSN Userlist", "store_name = %s\n", store_name); - /* XXX: see XXX above, this should really be done when we get the response from the server */ @@ -804,15 +768,15 @@ g_return_val_if_fail(group_name != NULL, FALSE); g_return_val_if_fail(who != NULL, FALSE); - purple_debug_info("MSN Userlist","Adding buddy with passport %s to group %s\n", who, group_name); + purple_debug_info("msn", "Adding buddy with passport %s to group %s\n", who, group_name); if ( (group_id = (gchar *)msn_userlist_find_group_id(userlist, group_name)) == NULL) { - purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name); + purple_debug_error("msn", "Group %s has no guid!\n", group_name); return FALSE; } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("MSN Userlist", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!", who); return FALSE; } @@ -833,15 +797,15 @@ g_return_val_if_fail(group_name != NULL, FALSE); g_return_val_if_fail(who != NULL, FALSE); - purple_debug_info("MSN Userlist","Removing buddy with passport %s from group %s\n", who, group_name); + purple_debug_info("msn", "Removing buddy with passport %s from group %s\n", who, group_name); if ( (group_id = msn_userlist_find_group_id(userlist, group_name)) == NULL) { - purple_debug_error("MSN Userlist", "Group %s has no guid!\n", group_name); + purple_debug_error("msn", "Group %s has no guid!\n", group_name); return FALSE; } if ( (user = msn_userlist_find_user(userlist, who)) == NULL) { - purple_debug_error("MSN Userlist", "User %s not found!", who); + purple_debug_error("msn", "User %s not found!", who); return FALSE; } @@ -859,7 +823,6 @@ g_return_if_fail(userlist != NULL); g_return_if_fail(userlist->session != NULL); - g_return_if_fail(userlist->session->contact != NULL); state = msn_callback_state_new(userlist->session); msn_callback_state_set_who(state, who); @@ -878,7 +841,7 @@ /* add the contact to the new group, and remove it from the old one in * the callback */ - msn_add_contact_to_group(userlist->session->contact, state, who, new_group_id); + msn_add_contact_to_group(userlist->session, state, who, new_group_id); } /*load userlist from the Blist file cache*/
--- a/libpurple/protocols/msnp9/command.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/protocols/msnp9/command.c Sat Jul 12 07:32:05 2008 +0000 @@ -65,9 +65,12 @@ for (c = 0; cmd->params[c]; c++); cmd->param_count = c; - param = cmd->params[0]; - - cmd->trId = is_num(param) ? atoi(param) : 0; + if (cmd->param_count) { + char *param = cmd->params[0]; + cmd->trId = is_num(param) ? atoi(param) : 0; + } else { + cmd->trId = 0; + } } else cmd->trId = 0;
--- a/libpurple/xmlnode.c Fri Jul 11 15:27:41 2008 +0000 +++ b/libpurple/xmlnode.c Sat Jul 12 07:32:05 2008 +0000 @@ -728,6 +728,13 @@ return ret; } +static void +xmlnode_copy_foreach_ns(gpointer key, gpointer value, gpointer user_data) +{ + GHashTable *ret = (GHashTable *)user_data; + g_hash_table_insert(ret, g_strdup(key), g_strdup(value)); +} + xmlnode * xmlnode_copy(const xmlnode *src) { @@ -739,17 +746,23 @@ ret = new_node(src->name, src->type); ret->xmlns = g_strdup(src->xmlns); - if(src->data) { - if(src->data_sz) { + if (src->data) { + if (src->data_sz) { ret->data = g_memdup(src->data, src->data_sz); ret->data_sz = src->data_sz; } else { ret->data = g_strdup(src->data); } } + ret->prefix = g_strdup(src->prefix); + if (src->namespace_map) { + ret->namespace_map = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + g_hash_table_foreach(src->namespace_map, xmlnode_copy_foreach_ns, ret->namespace_map); + } - for(child = src->child; child; child = child->next) { - if(sibling) { + for (child = src->child; child; child = child->next) { + if (sibling) { sibling->next = xmlnode_copy(child); sibling = sibling->next; } else {