# HG changeset patch # User Ka-Hing Cheung # Date 1182484510 0 # Node ID c9bcf4f11e30ba0c7d5007bb864e6be152be4d51 # Parent a573a67c80a4f333861f9585c37cc355b7ad7c8a# Parent db286cc82bd13049a712ebb5ef332a0cd4d545ae propagate from branch 'im.pidgin.pidgin' (head d2f50519c5ed668dd980277afdc25d71ccb8a852) to branch 'im.pidgin.cpw.khc.msnp14' (head db21070ea9f1444ccaafe34fcc3dd308490ca743) diff -r a573a67c80a4 -r c9bcf4f11e30 COPYRIGHT --- a/COPYRIGHT Thu Jun 21 18:08:48 2007 +0000 +++ b/COPYRIGHT Fri Jun 22 03:55:10 2007 +0000 @@ -270,6 +270,7 @@ Eduardo Pérez Matt Perry Nathan Peterson +Sebastián E. Peyrott Celso Pinto Joao Luís Marques Pinto Aleksander Piotrowski diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/internal.h --- a/libpurple/internal.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/internal.h Fri Jun 22 03:55:10 2007 +0000 @@ -75,6 +75,7 @@ #ifndef _WIN32 #include #include +#include #endif #include #include diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/Makefile.am --- a/libpurple/protocols/msn/Makefile.am Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Fri Jun 22 03:55:10 2007 +0000 @@ -1,4 +1,6 @@ EXTRA_DIST = \ + directconn.c \ + directconn.h \ Makefile.mingw pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) @@ -8,10 +10,10 @@ cmdproc.h \ command.c \ command.h \ + contact.c\ + contact.h\ dialog.c \ dialog.h \ - directconn.c \ - directconn.h \ error.c \ error.h \ group.c \ @@ -30,6 +32,8 @@ notification.h \ object.c \ object.h \ + oim.c\ + oim.h\ page.c \ page.h \ servconn.c \ @@ -46,6 +50,8 @@ slpmsg.h \ slpsession.c \ slpsession.h \ + soap.c\ + soap.h\ state.c \ state.h \ switchboard.c \ @@ -60,8 +66,8 @@ user.h \ userlist.c \ userlist.h \ - msn-utils.c \ - msn-utils.h + msnutils.c \ + msnutils.h AM_CFLAGS = $(st) diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/Makefile.mingw --- a/libpurple/protocols/msn/Makefile.mingw Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Fri Jun 22 03:55:10 2007 +0000 @@ -39,6 +39,7 @@ ## C_SRC = cmdproc.c \ command.c \ + contact.c\ dialog.c \ directconn.c \ error.c \ @@ -50,6 +51,7 @@ nexus.c \ notification.c \ object.c \ + oim.c\ page.c \ servconn.c \ session.c \ @@ -58,6 +60,7 @@ slplink.c \ slpmsg.c \ slpsession.c \ + soap.c\ state.c \ switchboard.c \ sync.c \ @@ -65,7 +68,7 @@ transaction.c \ user.c \ userlist.c \ - msn-utils.c + msnutils.c OBJECTS = $(C_SRC:%.c=%.o) diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/README Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,55 @@ +MSNP14 Implementation +by Ma Yuan + +1. Introduction +------------- + +MSNP14 Protocol, proposed by Windows Live Messenger, is new, and there is no available implementation except the official one on Windows Platform. + +It has introduced many new features attractable to many users, such as: +* Offline Instant Message + You can send the offline Message to the offline User, + The message will be posted to that user the next time when he is online. + +* Communicate with Yahoo User + U can chat with the Yahoo User in MSN, That's Fantastic! Till now , + you can send text/Nudge to Yahoo User. + +* Windows Live ID authentition + WLM use the Window Live ID Authentication process,Known as Passport 3.0, + The procedure is totally different to the previous Passport 2.0 + +* Video/Audio Conversation + U can communicate with other's via Video/Audio. +(Though very interesting, not implemented in this version) + +2.New Features Added +----------------- + +Till now, This project has implemented the following Feature: +* Windows Live ID authentication. + +* Offline Instant Message +Now can send and receive the Offline Instant Message to MSN user and Yahoo User. + +*contact management +Can add/delete Contact +Can add/delete Group + +* Communicate with Yahoo User +Can send/receive Message/Nudge to Yahoo User. + +*. Changes to made to fit MSNP14 Protocol + +3. Reference +------------- + +The very useful sites of MSN Protocol: +MSNpiki site: +reverse engineer of MSN Protocol.up to dated. +http://msnpiki.msnfanatic.com/index.php/MSN_Protocol_Version_13 + +hypothetic site: +old MSN Protocol Introduction,but very useful for basic idea of MSN protocol +http://www.hypothetic.org/docs/msn/index.php + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/command.c --- a/libpurple/protocols/msn/command.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/command.c Fri Jun 22 03:55:10 2007 +0000 @@ -36,6 +36,50 @@ 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(char *str) +{ + 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")) || + (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) { @@ -70,7 +114,13 @@ cmd->trId = is_num(param) ? atoi(param) : 0; } else + { cmd->trId = 0; + } + + /*add payload Length checking*/ + msn_set_payload_len(cmd); + purple_debug_info("MaYuan","get payload len:%d\n",cmd->payload_len); msn_command_ref(cmd); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/contact.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.c Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,911 @@ +/** + * @file contact.c + * get MSN contacts via SOAP request + * created by MaYuan + * + * 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 "msn.h" +#include "soap.h" +#include "contact.h" +#include "xmlnode.h" +#include "group.h" + +/*define This to debug the Contact Server*/ +#undef MSN_CONTACT_SOAP_DEBUG + +/*new a contact*/ +MsnContact * +msn_contact_new(MsnSession *session) +{ + MsnContact *contact; + + contact = g_new0(MsnContact, 1); + contact->session = session; + contact->soapconn = msn_soap_new(session,contact,1); + + return contact; +} + +/*destroy the contact*/ +void +msn_contact_destroy(MsnContact *contact) +{ + msn_soap_destroy(contact->soapconn); + g_free(contact); +} + +/*contact SOAP server login error*/ +static void +msn_contact_login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +{ + MsnSoapConn *soapconn = data; + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + + msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to contact server")); +} + +/*msn contact SOAP server connect process*/ +static void +msn_contact_login_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnSession * session; + MsnContact *contact; + + contact = soapconn->parent; + g_return_if_fail(contact != NULL); + + session = contact->session; + g_return_if_fail(session != NULL); + + /*login ok!We can retrieve the contact list*/ +// msn_get_contact_list(contact,NULL); +} + +/*get MSN member role utility*/ +static int +msn_get_memberrole(char * role) +{ + if(!strcmp(role,"Allow")){ + return MSN_LIST_AL_OP; + }else if(!strcmp(role,"Block")){ + return MSN_LIST_BL_OP; + }else if(!strcmp(role,"Reverse")){ + return MSN_LIST_RL_OP; + }else if(!strcmp(role,"Pending")){ + return MSN_LIST_PL_OP; + } + return 0; +} + +/*get User Type*/ +static int +msn_get_user_type(char * type) +{ + if(!strcmp(type,"Regular")){ + return MSN_USER_TYPE_PASSPORT; + } + if(!strcmp(type,"Live")){ + return MSN_USER_TYPE_PASSPORT; + } + if(!strcmp(type,"LivePending")){ + return MSN_USER_TYPE_PASSPORT; + } + + return MSN_USER_TYPE_UNKNOWN; +} + +/*parse contact list*/ +static void +msn_parse_contact_list(MsnContact * contact) +{ + MsnSession * session; + int list_op =0; + char * passport; + xmlnode * node,*body,*response,*result,*services; + xmlnode *service,*memberships; + xmlnode *LastChangeNode; + xmlnode *membershipnode,*members,*member,*passportNode; + char *LastChangeStr; + + session = contact->session; + purple_debug_misc("MSNCL","parse contact list:{%s}\nsize:%d\n",contact->soapconn->body,contact->soapconn->body_len); + node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); + + if(node == NULL){ + purple_debug_misc("MSNCL","parse contact from str err!\n"); + return; + } + purple_debug_misc("MSNCL","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name); + body = xmlnode_get_child(node,"Body"); + purple_debug_misc("MSNCL","body{%p},name:%s\n",body,body->name); + response = xmlnode_get_child(body,"FindMembershipResponse"); + + if (response == NULL) { + /* we may get a response if our cache data is too old: + * + * Need to do full sync. Can't sync deltas Client + * has too old a copy for us to do a delta sync + */ + msn_get_contact_list(contact, NULL); + return; + } + + purple_debug_misc("MSNCL","response{%p},name:%s\n",response,response->name); + result =xmlnode_get_child(response,"FindMembershipResult"); + if(result == NULL){ + purple_debug_misc("MSNCL","receive No Update!\n"); + return; + } + purple_debug_misc("MSNCL","result{%p},name:%s\n",result,result->name); + services =xmlnode_get_child(result,"Services"); + purple_debug_misc("MSNCL","services{%p},name:%s\n",services,services->name); + service =xmlnode_get_child(services,"Service"); + purple_debug_misc("MSNCL","service{%p},name:%s\n",service,service->name); + + /*Last Change Node*/ + LastChangeNode = xmlnode_get_child(service,"LastChange"); + LastChangeStr = xmlnode_get_data(LastChangeNode); + purple_debug_misc("MSNCL","LastChangeNode0 %s\n",LastChangeStr); + purple_account_set_string(session->account, "CLLastChange",LastChangeStr); + purple_debug_misc("MSNCL","LastChangeNode %s\n",LastChangeStr); + + memberships =xmlnode_get_child(service,"Memberships"); + if (memberships == NULL) { + xmlnode_free(node); + return; + } + purple_debug_misc("MSNCL","memberships{%p},name:%s\n",memberships,memberships->name); + for(membershipnode = xmlnode_get_child(memberships, "Membership"); membershipnode; + membershipnode = xmlnode_get_next_twin(membershipnode)){ + xmlnode *roleNode; + char *role; + roleNode = xmlnode_get_child(membershipnode,"MemberRole"); + role=xmlnode_get_data(roleNode); + list_op = msn_get_memberrole(role); + purple_debug_misc("MSNCL","MemberRole role:%s,list_op:%d\n",role,list_op); + g_free(role); + members = xmlnode_get_child(membershipnode,"Members"); + for(member = xmlnode_get_child(members, "Member"); member; + member = xmlnode_get_next_twin(member)){ + MsnUser *user; + xmlnode * typeNode; + char * type; + + purple_debug_misc("MSNCL","type:%s\n",xmlnode_get_attrib(member,"type")); + if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PassportMember")){ + passportNode = xmlnode_get_child(member,"PassportName"); + passport = xmlnode_get_data(passportNode); + typeNode = xmlnode_get_child(member,"Type"); + type = xmlnode_get_data(typeNode); + purple_debug_misc("MSNCL","Passport name:%s,type:%s\n",passport,type); + g_free(type); + + user = msn_userlist_find_add_user(session->userlist,passport,NULL); + msn_got_lst_user(session, user, list_op, NULL); + g_free(passport); + } + if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"PhoneMember")){ + } + if(!g_strcasecmp(xmlnode_get_attrib(member,"type"),"EmailMember")){ + xmlnode *emailNode; + + emailNode = xmlnode_get_child(member,"Email"); + passport = xmlnode_get_data(emailNode); + purple_debug_info("MSNCL","Email Member :name:%s,list_op:%d\n",passport,list_op); + user = msn_userlist_find_add_user(session->userlist,passport,NULL); + msn_got_lst_user(session,user,list_op,NULL); + g_free(passport); + } + } + } + + xmlnode_free(node); +} + +static void +msn_get_contact_list_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnContact *contact; + MsnSession *session; + const char *abLastChange; + const char *dynamicItemLastChange; + + contact = soapconn->parent; + g_return_if_fail(contact != NULL); + session = soapconn->session; + g_return_if_fail(session != NULL); + +#ifdef MSN_CONTACT_SOAP_DEBUG + purple_debug_misc("msn", "soap contact server Reply: {%s}\n", soapconn->read_buf); +#endif + msn_parse_contact_list(contact); + /*free the read buffer*/ + msn_soap_free_read_buf(soapconn); + + abLastChange = purple_account_get_string(session->account, "ablastChange", NULL); + dynamicItemLastChange = purple_account_get_string(session->account, "dynamicItemLastChange", NULL); + +#ifdef MSN_PARTIAL_LISTS + /* XXX: this should be enabled when we can correctly do partial + syncs with the server. Currently we need to retrieve the whole + list to detect sync issues */ + msn_get_address_book(contact, abLastChange, dynamicItemLastChange); +#else + msn_get_address_book(contact, NULL, NULL); +#endif +} + +static void +msn_get_contact_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish contact written\n"); + soapconn->read_cb = msn_get_contact_list_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*SOAP get contact list*/ +void +msn_get_contact_list(MsnContact * contact, const char *update_time) +{ + MsnSoapReq *soap_request; + char *body = NULL; + char * update_str; + + purple_debug_info("MaYuan","Getting Contact List...\n"); + if(update_time != NULL){ + purple_debug_info("MSNCL","last update time:{%s}\n",update_time); + update_str = g_strdup_printf(MSN_GET_CONTACT_UPDATE_XML,update_time); + }else{ + update_str = g_strdup(""); + } + body = g_strdup_printf(MSN_GET_CONTACT_TEMPLATE, update_str); + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_GET_CONTACT_POST_URL,MSN_GET_CONTACT_SOAP_ACTION, + body, + msn_get_contact_list_cb, + msn_get_contact_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + g_free(update_str); + g_free(body); +} + +static void +msn_parse_addressbook_groups(MsnContact *contact, xmlnode *node) +{ + MsnSession *session = contact->session; + xmlnode *group; + + for(group = xmlnode_get_child(node, "Group"); group; + group = xmlnode_get_next_twin(group)){ + xmlnode *groupId, *groupInfo, *groupname; + char *group_id, *group_name; + + groupId = xmlnode_get_child(group,"groupId"); + group_id = xmlnode_get_data(groupId); + groupInfo = xmlnode_get_child(group,"groupInfo"); + groupname = xmlnode_get_child(groupInfo,"name"); + group_name = xmlnode_get_data(groupname); + + msn_group_new(session->userlist, group_id, group_name); + + if (group_id == NULL){ + /* Group of ungroupped buddies */ + continue; + } + + purple_debug_misc("MsnAB","group_id:%s name:%s\n",group_id,group_name); + if ((purple_find_group(group_name)) == NULL){ + PurpleGroup *g = purple_group_new(group_name); + purple_blist_add_group(g, NULL); + } + g_free(group_id); + g_free(group_name); + } +} + +static void +msn_parse_addressbook_contacts(MsnContact *contact, xmlnode *node) +{ + MsnSession *session = contact->session; + xmlnode *contactNode; + + for(contactNode = xmlnode_get_child(node, "Contact"); contactNode; + contactNode = xmlnode_get_next_twin(contactNode)){ + xmlnode *contactId,*contactInfo,*contactType,*passportName,*displayName,*guid; + xmlnode *groupIds; + MsnUser *user; + MsnUserType usertype; + char *passport,*Name,*uid,*type; + + passport = NULL; + + contactId= xmlnode_get_child(contactNode,"contactId"); + uid = xmlnode_get_data(contactId); + + contactInfo = xmlnode_get_child(contactNode,"contactInfo"); + contactType = xmlnode_get_child(contactInfo,"contactType"); + type = xmlnode_get_data(contactType); + + /*setup the Display Name*/ + if (!strcmp(type, "Me")){ + char *friendly; + friendly = xmlnode_get_data(xmlnode_get_child(contactInfo, "displayName")); + purple_connection_set_display_name(session->account->gc, purple_url_decode(friendly)); + g_free(friendly); + continue; /* Not adding own account as buddy to buddylist */ + } + usertype = msn_get_user_type(type); + passportName = xmlnode_get_child(contactInfo,"passportName"); + if(passportName == NULL){ + xmlnode *emailsNode, *contactEmailNode, *emailNode; + xmlnode *messengerEnabledNode; + char *msnEnabled; + + /*TODO: add it to the none-instant Messenger group and recognize as email Membership*/ + /*Yahoo User?*/ + emailsNode = xmlnode_get_child(contactInfo,"emails"); + if(emailsNode == NULL){ + /*TODO: need to support the Mobile type*/ + continue; + } + for(contactEmailNode = xmlnode_get_child(emailsNode,"ContactEmail");contactEmailNode; + contactEmailNode = xmlnode_get_next_twin(contactEmailNode) ){ + messengerEnabledNode = xmlnode_get_child(contactEmailNode,"isMessengerEnabled"); + if(messengerEnabledNode == NULL){ + break; + } + msnEnabled = xmlnode_get_data(messengerEnabledNode); + if(!strcmp(msnEnabled,"true")){ + /*Messenger enabled, Get the Passport*/ + emailNode = xmlnode_get_child(contactEmailNode,"email"); + passport = xmlnode_get_data(emailNode); + purple_debug_info("MsnAB","Yahoo User %s\n",passport); + usertype = MSN_USER_TYPE_YAHOO; + break; + }else{ + /*TODO maybe we can just ignore it in Purple?*/ + emailNode = xmlnode_get_child(contactEmailNode,"email"); + passport = xmlnode_get_data(emailNode); + purple_debug_info("MSNAB","Other type user\n"); + } + g_free(msnEnabled); + } + }else{ + passport = xmlnode_get_data(passportName); + } + + if(passport == NULL){ + continue; + } + + displayName = xmlnode_get_child(contactInfo,"displayName"); + if(displayName == NULL){ + Name = g_strdup(passport); + }else{ + Name =xmlnode_get_data(displayName); + } + + purple_debug_misc("MsnAB","passport:{%s} uid:{%s} display:{%s}\n", + passport,uid,Name); + + user = msn_userlist_find_add_user(session->userlist, passport,Name); + msn_user_set_uid(user,uid); + msn_user_set_type(user, usertype); + g_free(Name); + g_free(passport); + g_free(uid); + g_free(type); + + purple_debug_misc("MsnAB","parse guid...\n"); + groupIds = xmlnode_get_child(contactInfo,"groupIds"); + if(groupIds){ + for(guid = xmlnode_get_child(groupIds, "guid");guid; + guid = xmlnode_get_next_twin(guid)){ + char *group_id; + group_id = xmlnode_get_data(guid); + msn_user_add_group_id(user,group_id); + purple_debug_misc("MsnAB","guid:%s\n",group_id); + g_free(group_id); + } + }else{ + /*not in any group,Then set default group*/ + msn_user_add_group_id(user, MSN_INDIVIDUALS_GROUP_ID); + } + + msn_got_lst_user(session, user, MSN_LIST_FL_OP, NULL); + } +} + +static gboolean +msn_parse_addressbook(MsnContact * contact) +{ + MsnSession * session; + xmlnode * node,*body,*response,*result; + xmlnode *groups; + xmlnode *contacts; + xmlnode *abNode; + + session = contact->session; + purple_debug_misc("xml","parse addressbook:{%s}\nsize:%d\n",contact->soapconn->body,contact->soapconn->body_len); + node = xmlnode_from_str(contact->soapconn->body, contact->soapconn->body_len); + + if(node == NULL){ + purple_debug_misc("xml","parse from str err!\n"); + return FALSE; + } + purple_debug_misc("xml","node{%p},name:%s,child:%s,last:%s\n",node,node->name,node->child->name,node->lastchild->name); + body = xmlnode_get_child(node,"Body"); + purple_debug_misc("xml","body{%p},name:%s\n",body,body->name); + response = xmlnode_get_child(body,"ABFindAllResponse"); + + if (response == NULL) { + return FALSE; + } + + purple_debug_misc("xml","response{%p},name:%s\n",response,response->name); + result =xmlnode_get_child(response,"ABFindAllResult"); + if(result == NULL){ + purple_debug_misc("MSNAB","receive no address book update\n"); + return TRUE; + } + purple_debug_misc("xml","result{%p},name:%s\n",result,result->name); + + /*Process Group List*/ + groups = xmlnode_get_child(result,"groups"); + if (groups != NULL) { + msn_parse_addressbook_groups(contact, 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", + 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); + purple_blist_add_group(g, NULL); + } + + /*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){ + 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"); + if (contacts != NULL) { + msn_parse_addressbook_contacts(contact, contacts); + } + + abNode =xmlnode_get_child(result,"ab"); + if(abNode != NULL){ + xmlnode *LastChangeNode, *DynamicItemLastChangedNode; + char *lastchange, *dynamicChange; + + LastChangeNode = xmlnode_get_child(abNode,"lastChange"); + lastchange = xmlnode_get_data(LastChangeNode); + purple_debug_info("MsnAB"," lastchanged Time:{%s}\n",lastchange); + purple_account_set_string(session->account, "ablastChange", lastchange); + + DynamicItemLastChangedNode = xmlnode_get_child(abNode,"DynamicItemLastChanged"); + dynamicChange = xmlnode_get_data(DynamicItemLastChangedNode); + purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n",dynamicChange); + purple_account_set_string(session->account, "DynamicItemLastChanged", lastchange); + } + + xmlnode_free(node); + msn_soap_free_read_buf(contact->soapconn); + return TRUE; +} + +static void +msn_get_address_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + MsnContact *contact; + MsnSession *session; + + contact = soapconn->parent; + g_return_if_fail(contact != NULL); + session = soapconn->session; + g_return_if_fail(session != NULL); + +// purple_debug_misc("msn", "soap contact server Reply: {%s}\n", soapconn->read_buf); + if (msn_parse_addressbook(contact)) { + msn_notification_dump_contact(session); + msn_set_psm(session); + msn_session_finish_login(session); + } else { + msn_get_address_book(contact, NULL, NULL); + } + + /*free the read buffer*/ + msn_soap_free_read_buf(soapconn); +} + +/**/ +static void +msn_address_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish contact written\n"); + soapconn->read_cb = msn_get_address_cb; +} + +/*get the address book*/ +void +msn_get_address_book(MsnContact *contact, const char *LastChanged, const char *dynamicItemLastChange) +{ + MsnSoapReq *soap_request; + char *body = NULL; + char *ab_update_str,*update_str; + + purple_debug_info("MaYuan","msn_get_address_book()...\n"); + /*build SOAP and POST it*/ + if(LastChanged != NULL){ + ab_update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML,LastChanged); + }else{ + ab_update_str = g_strdup(""); + } + if(dynamicItemLastChange != NULL){ + update_str = g_strdup_printf(MSN_GET_ADDRESS_UPDATE_XML, + dynamicItemLastChange); + }else{ + update_str = g_strdup(ab_update_str); + } + g_free(ab_update_str); + + body = g_strdup_printf(MSN_GET_ADDRESS_TEMPLATE,update_str); + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_GET_ADDRESS_SOAP_ACTION, + body, + msn_get_address_cb, + msn_address_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + g_free(update_str); + g_free(body); +} + +static void +msn_add_contact_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","add contact read done\n"); +} + +static void +msn_add_contact_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish add contact written\n"); + soapconn->read_cb = msn_add_contact_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*add a Contact */ +void +msn_add_contact(MsnContact *contact,const char *passport,const char *groupId) +{ + MsnSoapReq *soap_request; + char *body = NULL; + char *contact_xml = NULL; + char *soap_action; + + purple_debug_info("MaYuan","msn add a contact...\n"); + contact_xml = g_strdup_printf(MSN_CONTACT_XML,passport); + if(groupId == NULL){ + body = g_strdup_printf(MSN_ADD_CONTACT_TEMPLATE,contact_xml); + g_free(contact_xml); + /*build SOAP and POST it*/ + soap_action = g_strdup(MSN_CONTACT_ADD_SOAP_ACTION); + }else{ + body = g_strdup_printf(MSN_ADD_CONTACT_GROUP_TEMPLATE,groupId,contact_xml); + g_free(contact_xml); + /*build SOAP and POST it*/ + soap_action = g_strdup(MSN_ADD_CONTACT_GROUP_SOAP_ACTION); + } + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,soap_action, + body, + msn_add_contact_read_cb, + msn_add_contact_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(soap_action); + g_free(body); +} + +static void +msn_delete_contact_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","delete contact read done\n"); +} + +static void +msn_delete_contact_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","delete contact written\n"); + soapconn->read_cb = msn_delete_contact_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*delete a Contact*/ +void +msn_delete_contact(MsnContact *contact,const char *contactId) +{ + char *body = NULL; + char *contact_xml = NULL ; + MsnSoapReq *soap_request; + + g_return_if_fail(contactId != NULL); + purple_debug_info("MaYuan","msn delete a contact,contactId:{%s}...\n",contactId); + contact_xml = g_strdup_printf(MSN_CONTACTS_DEL_XML,contactId); + body = g_strdup_printf(MSN_DEL_CONTACT_TEMPLATE,contact_xml); + g_free(contact_xml); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_CONTACT_DEL_SOAP_ACTION, + body, + msn_delete_contact_read_cb, + msn_delete_contact_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(body); +} + +#if 0 +static void +msn_update_contact_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","update contact read done\n"); +} + +static void +msn_update_contact_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","update contact written\n"); + soapconn->read_cb = msn_update_contact_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*update a contact's Nickname*/ +void +msn_update_contact(MsnContact *contact,const char* nickname) +{ + MsnSoapReq *soap_request; + char *body = NULL; + + purple_debug_info("MaYuan","msn unblock a contact...\n"); + + body = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE,nickname); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_CONTACT_UPDATE_SOAP_ACTION, + body, + msn_update_contact_read_cb, + msn_update_contact_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(body); +} +#endif + +static void +msn_block_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","block read done\n"); +} + +static void +msn_block_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish unblock written\n"); + soapconn->read_cb = msn_block_read_cb; +} + +/*block a Contact*/ +void +msn_block_contact(MsnContact *contact,const char* membership_id) +{ + MsnSoapReq *soap_request; + char *body = NULL; + + purple_debug_info("MaYuan","msn block a contact...\n"); + body = g_strdup_printf(MSN_CONTACT_DELECT_FROM_ALLOW_TEMPLATE,membership_id); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_SHARE_POST_URL,MSN_CONTACT_BLOCK_SOAP_ACTION, + body, + msn_block_read_cb, + msn_block_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(body); +} + +static void +msn_unblock_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","unblock read done\n"); +} + +static void +msn_unblock_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish unblock written\n"); + soapconn->read_cb = msn_unblock_read_cb; +} + +/*unblock a contact*/ +void +msn_unblock_contact(MsnContact *contact,const char* passport) +{ + MsnSoapReq *soap_request; + char *body = NULL; + + purple_debug_info("MaYuan","msn unblock a contact...\n"); + + body = g_strdup_printf(MSN_UNBLOCK_CONTACT_TEMPLATE,passport); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_SHARE_POST_URL,MSN_CONTACT_UNBLOCK_SOAP_ACTION, + body, + msn_unblock_read_cb, + msn_unblock_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(body); +} + +#if 0 +static void +msn_gleams_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","Gleams read done\n"); +} + +static void +msn_gleams_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish Group written\n"); + soapconn->read_cb = msn_gleams_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*get the gleams info*/ +void +msn_get_gleams(MsnContact *contact) +{ + MsnSoapReq *soap_request; + + purple_debug_info("MaYuan","msn get gleams info...\n"); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_GET_GLEAMS_SOAP_ACTION, + MSN_GLEAMS_TEMPLATE, + msn_gleams_read_cb, + msn_gleams_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); +} +#endif + +/*************************************************************** + * Group Operation + ***************************************************************/ +static void +msn_group_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + purple_debug_info("MaYuan","Group read \n"); +} + +static void +msn_group_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","finish Group written\n"); + soapconn->read_cb = msn_group_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/*add group*/ +void msn_add_group(MsnSession *session,const char* group_name) +{ + MsnSoapReq *soap_request; + MsnContact *contact ; + char *body = NULL; + + g_return_if_fail(session != NULL); + contact = session->contact; + purple_debug_info("MaYuan","msn add group...\n"); + + body = g_strdup_printf(MSN_GROUP_ADD_TEMPLATE,group_name); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_GROUP_ADD_SOAP_ACTION, + body, + msn_group_read_cb, + msn_group_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); +} + +/*delete a group*/ +void msn_del_group(MsnSession *session,const char *guid) +{ + MsnSoapReq *soap_request; + MsnContact *contact; + char *body = NULL; + + g_return_if_fail(session != NULL); + /*if group uid we need to del is NULL, + * we need to delete nothing + */ + g_return_if_fail(guid != NULL); + contact = session->contact; + purple_debug_info("MaYuan","msn del group...\n"); + + body = g_strdup_printf(MSN_GROUP_DEL_TEMPLATE,guid); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL,MSN_GROUP_DEL_SOAP_ACTION, + body, + msn_group_read_cb, + msn_group_written_cb); + msn_soap_post(contact->soapconn,soap_request,msn_contact_connect_init); + + g_free(body); +} + +void +msn_contact_connect_init(MsnSoapConn *soapconn) +{ + /* Authenticate via Windows Live ID. */ + purple_debug_info("MaYuan","msn_contact_connect...\n"); + + msn_soap_init(soapconn,MSN_CONTACT_SERVER,1, + msn_contact_login_connect_cb, + msn_contact_login_error_cb); +} diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/contact.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.h Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,236 @@ +/** + * @file contact.h Header file for contact.c + * Author + * MaYuan + * 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_CONTACT_H_ +#define _MSN_CONTACT_H_ + +#define MSN_CONTACT_SERVER "omega.contacts.msn.com" + +/*get contact list soap request template*/ +#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 "Full"\ + "true"\ + "%s" +#define MSN_GET_CONTACT_TEMPLATE ""\ +""\ + ""\ + ""\ + "09607671-1C32-421F-A6A6-CBFAA51AB5F4"\ + "false"\ + "Initial"\ + ""\ + ""\ + "false"\ + ""\ + ""\ + ""\ + ""\ + ""\ + ""\ + "Messenger"\ + "Invitation"\ + "SocialNetwork"\ + "Space"\ + "Profile"\ + ""\ + ""\ + "%s"\ + ""\ + ""\ +"" + +/************************************************ + * Address Book SOAP + * *********************************************/ +#define MSN_ADDRESS_BOOK_POST_URL "/abservice/abservice.asmx" +/*get addressbook soap request template*/ +#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 "true"\ + "%s" + +#define MSN_GET_GLEAM_UPDATE_XML \ + "%s"\ + "Gleam"\ + "%s" + +#define MSN_GET_ADDRESS_TEMPLATE ""\ +""\ + ""\ + ""\ + "09607671-1C32-421F-A6A6-CBFAA51AB5F4"\ + "false"\ + "Initial"\ + ""\ + ""\ + "false"\ + ""\ + ""\ + ""\ + ""\ + "00000000-0000-0000-0000-000000000000"\ + "Full"\ + "%s"\ + ""\ + ""\ +"" + +/*Gleams SOAP request template*/ +#define MSN_GET_GLEAMS_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" +#define MSN_GLEAMS_TEMPLATE ""\ +""\ + ""\ + ""\ + "09607671-1C32-421F-A6A6-CBFAA51AB5F4"\ + "false"\ + "Initial"\ + ""\ + ""\ + "false"\ + ""\ + ""\ + ""\ + ""\ + "00000000-0000-0000-0000-000000000000"\ + "Full"\ + "Gleam"\ + "0001-01-01T00:00:00.0000000-08:00"\ + ""\ + ""\ +"" + +/******************************************************* + * Contact Add/del SOAP Action + *******************************************************/ +/*add conatct soap request*/ +#define MSN_CONTACT_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" +#define MSN_CONTACT_XML "LivePending%strue" + +#define MSN_ADD_CONTACT_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseContactSavefalse00000000-0000-0000-0000-000000000000%strue" + +/*Contact Group Add*/ +#define MSN_ADD_CONTACT_GROUP_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupContactAdd" +#define MSN_ADD_CONTACT_GROUP_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseContactSavefalse00000000-0000-0000-0000-000000000000%s%struetrue" + +/*delete contact from contact list soap request template*/ +#define MSN_CONTACT_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" +#define MSN_CONTACTS_DEL_XML "%s" +#define MSN_DEL_CONTACT_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseTimerfalse00000000-0000-0000-0000-000000000000%s" + +#define MSN_MEMBER_TEMPLATE "PassportAccepted%s" + +/******************************************************* + * Contact Block/Unblock SOAP Action + *******************************************************/ +/*block means delete from allow list and add contact to block list*/ +#define MSN_SHARE_POST_URL "/abservice/SharingService.asmx" +#define MSN_CONTACT_BLOCK_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" +/*first delete contact from allow list*/ +#define MSN_CONTACT_DELECT_FROM_ALLOW_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseBlockUnblockfalse0MessengerAllowPassport%sAccepted" + +#define MSN_CONTACT_ADD_TO_BLOCK_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseBlockUnblockfalse0MessengerBlock%s" + +/*unblock means delete contact from block list*/ +#define MSN_CONTACT_UNBLOCK_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" +#define MSN_UNBLOCK_CONTACT_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseBlockUnblockfalse0MessengerBlock%s" + +/*Update Contact Nickname*/ +#define MSN_CONTACT_UPDATE_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" +#define MSN_CONTACT_UPDATE_TEMPLATE ""\ +""\ +""\ + ""\ + "09607671-1C32-421F-A6A6-CBFAA51AB5F4"\ + "false"\ + "Timer"\ + ""\ + ""\ + "false"\ + ""\ + ""\ + ""\ + ""\ + "00000000-0000-0000-0000-000000000000"\ + ""\ + ""\ + ""\ + "Me"\ + "%s"\ + ""\ + "DisplayName"\ + ""\ + ""\ + ""\ + ""\ +" " + +/******************************************************* + * Group SOAP Action + *******************************************************/ +/*add a group*/ +#define MSN_GROUP_ADD_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupAdd" +#define MSN_GROUP_ADD_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseGroupSavefalse00000000-0000-0000-0000-000000000000false%sC8529CE2-6EAD-434d-881F-341E17DB3FF8falseMSN.IM.Display1" + +/*delete a group*/ +#define MSN_GROUP_DEL_SOAP_ACTION "http://www.msn.com/webservices/AddressBook/ABGroupDelete" +#define MSN_GROUP_DEL_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseTimerfalse00000000-0000-0000-0000-000000000000%s" + + +typedef struct _MsnContact MsnContact; + +struct _MsnContact +{ + MsnSession *session; + + MsnSoapConn *soapconn; +}; + +/************************************************ + * function prototype + ************************************************/ +MsnContact * msn_contact_new(MsnSession *session); +void msn_contact_destroy(MsnContact *contact); + +void msn_contact_connect(MsnContact *contact); +void msn_get_contact_list(MsnContact * contact, const char *update); +void msn_get_address_book(MsnContact *contact, const char * update, const char * gupdate); + +/*contact SOAP Operation*/ +void msn_add_contact(MsnContact *contact,const char *passport,const char *groupId); +void msn_delete_contact(MsnContact *contact,const char *contactId); + + +/*group operation*/ +void msn_add_group(MsnSession *session,const char* group_name); +void msn_del_group(MsnSession *session,const char *guid); + +/*contact Block/unblock operation*/ +void msn_block_contact(MsnContact *contact,const char* membership_id); +void msn_unblock_contact(MsnContact *contact,const char* passport); + +void msn_contact_connect_init(MsnSoapConn *soapconn); + +#endif/* _MSN_CMDPROC_H_*/ + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/dialog.c --- a/libpurple/protocols/msn/dialog.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/dialog.c Fri Jun 22 03:55:10 2007 +0000 @@ -36,6 +36,7 @@ /* Remove the buddy referenced by the MsnAddRemData before the serverside list is changed. * If the buddy will be added, he'll be added back; if he will be removed, he won't be. */ +/* Actually with our MSNP14 code that isn't true yet, he won't be added back :( */ static void msn_complete_sync_issue(MsnAddRemData *data) { @@ -44,28 +45,32 @@ if (data->group != NULL) group = purple_find_group(data->group); - + if (group != NULL) buddy = purple_find_buddy_in_group(purple_connection_get_account(data->gc), data->who, group); else buddy = purple_find_buddy(purple_connection_get_account(data->gc), data->who); - + if (buddy != NULL) purple_blist_remove_buddy(buddy); } + static void msn_add_cb(MsnAddRemData *data) { - MsnSession *session; - MsnUserList *userlist; - +#if 0 + /* this *should* be necessary !! */ msn_complete_sync_issue(data); +#endif - session = data->gc->proto_data; - userlist = session->userlist; + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group); + msn_userlist_add_buddy(userlist, data->who, MSN_LIST_FL, data->group); + } g_free(data->group); g_free(data->who); @@ -75,15 +80,15 @@ static void msn_rem_cb(MsnAddRemData *data) { - MsnSession *session; - MsnUserList *userlist; - msn_complete_sync_issue(data); - session = data->gc->proto_data; - userlist = session->userlist; + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group); + msn_userlist_rem_buddy(userlist, data->who, MSN_LIST_FL, data->group); + } g_free(data->group); g_free(data->who); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/directconn.c --- a/libpurple/protocols/msn/directconn.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/directconn.c Fri Jun 22 03:55:10 2007 +0000 @@ -76,7 +76,6 @@ * Connection Functions **************************************************************************/ -#if 0 static int create_listener(int port) { @@ -160,7 +159,6 @@ return fd; } -#endif static size_t msn_directconn_write(MsnDirectConn *directconn, @@ -288,6 +286,11 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); return; @@ -302,6 +305,11 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); return; @@ -348,17 +356,22 @@ /* ERROR */ purple_debug_error("msn", "error reading\n"); + if (directconn->inpa) + purple_input_remove(directconn->inpa); + + close(directconn->fd); + msn_directconn_destroy(directconn); } } static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnDirectConn* directconn; int fd; - purple_debug_misc("msn", "directconn: connect_cb: %d\n", source); + purple_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond); directconn = data; directconn->connect_data = NULL; @@ -434,7 +447,6 @@ return FALSE; } -#if 0 void msn_directconn_listen(MsnDirectConn *directconn) { @@ -454,7 +466,6 @@ directconn->port = port; directconn->c = 0; } -#endif MsnDirectConn* msn_directconn_new(MsnSlpLink *slplink) diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/directconn.h --- a/libpurple/protocols/msn/directconn.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/directconn.h Fri Jun 22 03:55:10 2007 +0000 @@ -52,9 +52,7 @@ MsnDirectConn *msn_directconn_new(MsnSlpLink *slplink); gboolean msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port); -#if 0 void msn_directconn_listen(MsnDirectConn *directconn); -#endif void msn_directconn_send_msg(MsnDirectConn *directconn, MsnMessage *msg); void msn_directconn_parse_nonce(MsnDirectConn *directconn, const char *nonce); void msn_directconn_destroy(MsnDirectConn *directconn); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/group.c --- a/libpurple/protocols/msn/group.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/group.c Fri Jun 22 03:55:10 2007 +0000 @@ -25,18 +25,18 @@ #include "group.h" MsnGroup * -msn_group_new(MsnUserList *userlist, int id, const char *name) +msn_group_new(MsnUserList *userlist, const char *id, const char *name) { MsnGroup *group; - g_return_val_if_fail(id >= 0, NULL); + g_return_val_if_fail(id != NULL, NULL); g_return_val_if_fail(name != NULL, NULL); group = g_new0(MsnGroup, 1); msn_userlist_add_group(userlist, group); - group->id = id; + group->id = g_strdup(id); group->name = g_strdup(name); return group; @@ -47,17 +47,18 @@ { g_return_if_fail(group != NULL); + g_free(group->id); g_free(group->name); g_free(group); } void -msn_group_set_id(MsnGroup *group, int id) +msn_group_set_id(MsnGroup *group, const char *id) { g_return_if_fail(group != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); - group->id = id; + group->id = g_strdup(id); } void @@ -72,10 +73,10 @@ group->name = g_strdup(name); } -int +char* msn_group_get_id(const MsnGroup *group) { - g_return_val_if_fail(group != NULL, -1); + g_return_val_if_fail(group != NULL, NULL); return group->id; } diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/group.h --- a/libpurple/protocols/msn/group.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/group.h Fri Jun 22 03:55:10 2007 +0000 @@ -30,8 +30,21 @@ #include "session.h" #include "user.h" +#include "soap.h" +#include "userlist.h" -#include "userlist.h" +#define MSN_ADD_GROUPS "test111C8529CE2-6EAD-434d-881F-341E17DB3FF8falseMSN.IM.Display1" + +#define MSN_ADD_GROUP_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseGroupSavefalse00000000-0000-0000-0000-000000000000false%s" + +#define MSN_GROUP_IDS "9e57e654-59f0-44d1-aedc-0a7500b7e51f" +#define MSN_DELETE_GROUP_TEMPLATE "09607671-1C32-421F-A6A6-CBFAA51AB5F4falseTimerfalse00000000-0000-0000-0000-000000000000%s" + +#define MSN_INDIVIDUALS_GROUP_ID "1983" +#define MSN_INDIVIDUALS_GROUP_NAME "Other Contacts" + +#define MSN_NON_IM_GROUP_ID "email" +#define MSN_NON_IM_GROUP_NAME "Non-IM Contacts" /** * A group. @@ -39,8 +52,9 @@ struct _MsnGroup { MsnSession *session; /**< The MSN session. */ + MsnSoapConn *soapconn; - int id; /**< The group ID. */ + char *id; /**< The group ID. */ char *name; /**< The name of the group. */ }; @@ -58,7 +72,7 @@ * * @return A new group structure. */ -MsnGroup *msn_group_new(MsnUserList *userlist, int id, const char *name); +MsnGroup *msn_group_new(MsnUserList *userlist, const char *id, const char *name); /** * Destroys a group structure. @@ -73,7 +87,7 @@ * @param group The group. * @param id The ID. */ -void msn_group_set_id(MsnGroup *group, int id); +void msn_group_set_id(MsnGroup *group, const char *id); /** * Sets the name for a group. @@ -90,7 +104,7 @@ * * @return The ID. */ -int msn_group_get_id(const MsnGroup *group); +char* msn_group_get_id(const MsnGroup *group); /** * Returns the name for a group. diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/history.c --- a/libpurple/protocols/msn/history.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/history.c Fri Jun 22 03:55:10 2007 +0000 @@ -84,3 +84,4 @@ msn_transaction_destroy(trans); } } + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/msg.c Fri Jun 22 03:55:10 2007 +0000 @@ -126,7 +126,7 @@ msn_message_set_charset(msg, "UTF-8"); msn_message_set_flag(msg, 'A'); msn_message_set_attr(msg, "X-MMS-IM-Format", - "FN=MS%20Sans%20Serif; EF=; CO=0; PF=0"); + "FN=MS%20Sans%20Serif; EF=; CO=0; CS=86;PF=0"); message_cr = purple_str_add_cr(message); msn_message_set_bin_data(msg, message_cr, strlen(message_cr)); @@ -206,7 +206,8 @@ void msn_message_parse_payload(MsnMessage *msg, - const char *payload, size_t payload_len) + const char *payload, size_t payload_len, + const char *line_dem,const char *body_dem) { char *tmp_base, *tmp; const char *content_type; @@ -214,12 +215,11 @@ char **elems, **cur, **tokens; g_return_if_fail(payload != NULL); - tmp_base = tmp = g_malloc0(payload_len + 1); memcpy(tmp_base, payload, payload_len); /* Parse the attributes. */ - end = strstr(tmp, "\r\n\r\n"); + end = strstr(tmp, body_dem); /* TODO? some clients use \r delimiters instead of \r\n, the official client * doesn't send such messages, but does handle receiving them. We'll just * avoid crashing for now */ @@ -229,7 +229,7 @@ } *end = '\0'; - elems = g_strsplit(tmp, "\r\n", 0); + elems = g_strsplit(tmp, line_dem, 0); for (cur = elems; *cur != NULL; cur++) { @@ -240,6 +240,7 @@ key = tokens[0]; value = tokens[1]; + /*if not MIME content ,then return*/ if (!strcmp(key, "MIME-Version")) { g_strfreev(tokens); @@ -274,7 +275,7 @@ g_strfreev(elems); /* Proceed to the end of the "\r\n\r\n" */ - tmp = end + 4; + tmp = end + strlen(body_dem); /* Now we *should* be at the body. */ content_type = msn_message_get_content_type(msg); @@ -480,6 +481,7 @@ { memcpy(n, body, body_len); n += body_len; + *n = '\0'; } } diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msg.h --- a/libpurple/protocols/msn/msg.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/msg.h Fri Jun 22 03:55:10 2007 +0000 @@ -34,6 +34,12 @@ typedef void (*MsnMsgCb)(MsnMessage *, void *data); +#define MSG_BODY_DEM "\r\n\r\n" +#define MSG_LINE_DEM "\r\n" + +#define MSG_OIM_BODY_DEM "\n\n" +#define MSG_OIM_LINE_DEM "\n" + /* typedef enum { @@ -180,7 +186,8 @@ * @param payload_len The length of the payload. */ void msn_message_parse_payload(MsnMessage *msg, const char *payload, - size_t payload_len); + size_t payload_len, + const char *line_dem,const char *body_dem); /** * Destroys a message. diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msn-utils.c --- a/libpurple/protocols/msn/msn-utils.c Thu Jun 21 18:08:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,440 +0,0 @@ -/** - * @file msn-utils.c Utility functions - * - * 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 "msn.h" -#include "msn-utils.h" - -void -msn_parse_format(const char *mime, char **pre_ret, char **post_ret) -{ - char *cur; - GString *pre = g_string_new(NULL); - GString *post = g_string_new(NULL); - unsigned int colors[3]; - - if (pre_ret != NULL) *pre_ret = NULL; - if (post_ret != NULL) *post_ret = NULL; - - cur = strstr(mime, "FN="); - - if (cur && (*(cur = cur + 3) != ';')) - { - pre = g_string_append(pre, ""); - post = g_string_prepend(post, ""); - } - - cur = strstr(mime, "EF="); - - if (cur && (*(cur = cur + 3) != ';')) - { - while (*cur && *cur != ';') - { - pre = g_string_append_c(pre, '<'); - pre = g_string_append_c(pre, *cur); - pre = g_string_append_c(pre, '>'); - post = g_string_prepend_c(post, '>'); - post = g_string_prepend_c(post, *cur); - post = g_string_prepend_c(post, '/'); - post = g_string_prepend_c(post, '<'); - cur++; - } - } - - cur = strstr(mime, "CO="); - - if (cur && (*(cur = cur + 3) != ';')) - { - int i; - - i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); - - if (i > 0) - { - char tag[64]; - - if (i == 1) - { - colors[1] = 0; - colors[2] = 0; - } - else if (i == 2) - { - unsigned int temp = colors[0]; - - colors[0] = colors[1]; - colors[1] = temp; - colors[2] = 0; - } - else if (i == 3) - { - unsigned int temp = colors[2]; - - colors[2] = colors[0]; - colors[0] = temp; - } - - g_snprintf(tag, sizeof(tag), - "", - colors[0], colors[1], colors[2]); - - pre = g_string_append(pre, tag); - post = g_string_prepend(post, ""); - } - } - - cur = strstr(mime, "RL="); - - if (cur && (*(cur = cur + 3) != ';')) - { - if (*cur == '1') - { - /* RTL text was received */ - pre = g_string_append(pre, ""); - post = g_string_prepend(post, ""); - } - } - - cur = g_strdup(purple_url_decode(pre->str)); - g_string_free(pre, TRUE); - - if (pre_ret != NULL) - *pre_ret = cur; - else - g_free(cur); - - cur = g_strdup(purple_url_decode(post->str)); - g_string_free(post, TRUE); - - if (post_ret != NULL) - *post_ret = cur; - else - g_free(cur); -} - -/* - * We need this because we're only supposed to encode spaces in the font - * names. purple_url_encode() isn't acceptable. - */ -static const char * -encode_spaces(const char *str) -{ - static char buf[BUF_LEN]; - const char *c; - char *d; - - g_return_val_if_fail(str != NULL, NULL); - - for (c = str, d = buf; *c != '\0'; c++) - { - if (*c == ' ') - { - *d++ = '%'; - *d++ = '2'; - *d++ = '0'; - } - else - *d++ = *c; - } - - return buf; -} - -/* - * Taken from the zephyr plugin. - * This parses HTML formatting (put out by one of the gtkimhtml widgets - * and converts it to msn formatting. It doesn't deal with the tag closing, - * but gtkimhtml widgets give valid html. - * It currently deals properly with , , , , - * , , . - * It ignores and - */ -void -msn_import_html(const char *html, char **attributes, char **message) -{ - int len, retcount = 0; - const char *c; - char *msg; - char *fontface = NULL; - char fonteffect[4]; - char fontcolor[7]; - char direction = '0'; - - gboolean has_bold = FALSE; - gboolean has_italic = FALSE; - gboolean has_underline = FALSE; - gboolean has_strikethrough = FALSE; - - g_return_if_fail(html != NULL); - g_return_if_fail(attributes != NULL); - g_return_if_fail(message != NULL); - - len = strlen(html); - msg = g_malloc0(len + 1); - - memset(fontcolor, 0, sizeof(fontcolor)); - strcat(fontcolor, "0"); - memset(fonteffect, 0, sizeof(fonteffect)); - - for (c = html; *c != '\0';) - { - if (*c == '<') - { - if (!g_ascii_strncasecmp(c + 1, "br>", 3)) - { - msg[retcount++] = '\r'; - msg[retcount++] = '\n'; - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) - { - if (!has_italic) - { - strcat(fonteffect, "I"); - has_italic = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) - { - if (!has_bold) - { - strcat(fonteffect, "B"); - has_bold = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) - { - if (!has_underline) - { - strcat(fonteffect, "U"); - has_underline = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) - { - if (!has_strikethrough) - { - strcat(fonteffect, "S"); - has_strikethrough = TRUE; - } - c += 3; - } - else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) - { - c += 9; - - if (!g_ascii_strncasecmp(c, "mailto:", 7)) - c += 7; - - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - msg[retcount++] = *c++; - - if (*c != '\0') - c += 2; - - /* ignore descriptive string */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "", 4)) - c++; - - if (*c != '\0') - c += 4; - } - else if (!g_ascii_strncasecmp(c + 1, "span", 4)) - { - /* Bi-directional text support using CSS properties in span tags */ - c += 5; - - while (*c != '\0' && *c != '>') - { - while (*c == ' ') - c++; - if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) - { - c += 9; - direction = '1'; - } - else if (!g_ascii_strncasecmp(c, "style=\"", 7)) - { - /* Parse inline CSS attributes */ - char *attributes; - int attr_len = 0; - c += 7; - while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') - attr_len++; - if (*(c + attr_len) == '"') - { - char *attr_dir; - attributes = g_strndup(c, attr_len); - attr_dir = purple_markup_get_css_property(attributes, "direction"); - if (attr_dir && (!strncasecmp(attr_dir, "RTL", 3))) - direction = '1'; - g_free(attr_dir); - g_free(attributes); - } - - } - else - { - c++; - } - } - if (*c == '>') - c++; - } - else if (!g_ascii_strncasecmp(c + 1, "font", 4)) - { - c += 5; - - while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) - c++; - - if (!g_ascii_strncasecmp(c, "color=\"#", 7)) - { - c += 8; - - fontcolor[0] = *(c + 4); - fontcolor[1] = *(c + 5); - fontcolor[2] = *(c + 2); - fontcolor[3] = *(c + 3); - fontcolor[4] = *c; - fontcolor[5] = *(c + 1); - - c += 8; - } - else if (!g_ascii_strncasecmp(c, "face=\"", 6)) - { - const char *end = NULL; - const char *comma = NULL; - unsigned int namelen = 0; - - c += 6; - end = strchr(c, '\"'); - comma = strchr(c, ','); - - if (comma == NULL || comma > end) - namelen = (unsigned int)(end - c); - else - namelen = (unsigned int)(comma - c); - - fontface = g_strndup(c, namelen); - c = end + 2; - } - else - { - /* Drop all unrecognized/misparsed font tags */ - while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) - c++; - - if (*c != '\0') - c += 2; - } - } - else - { - while ((*c != '\0') && (*c != '>')) - c++; - if (*c != '\0') - c++; - } - } - else if (*c == '&') - { - if (!g_ascii_strncasecmp(c, "<", 4)) - { - msg[retcount++] = '<'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, ">", 4)) - { - msg[retcount++] = '>'; - c += 4; - } - else if (!g_ascii_strncasecmp(c, " ", 6)) - { - msg[retcount++] = ' '; - c += 6; - } - else if (!g_ascii_strncasecmp(c, """, 6)) - { - msg[retcount++] = '"'; - c += 6; - } - else if (!g_ascii_strncasecmp(c, "&", 5)) - { - msg[retcount++] = '&'; - c += 5; - } - else if (!g_ascii_strncasecmp(c, "'", 6)) - { - msg[retcount++] = '\''; - c += 6; - } - else - msg[retcount++] = *c++; - } - else - msg[retcount++] = *c++; - } - - if (fontface == NULL) - fontface = g_strdup("MS Sans Serif"); - - *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", - encode_spaces(fontface), - fonteffect, fontcolor, direction); - *message = g_strdup(msg); - - g_free(fontface); - g_free(msg); -} - -void -msn_parse_socket(const char *str, char **ret_host, int *ret_port) -{ - char *host; - char *c; - int port; - - host = g_strdup(str); - - if ((c = strchr(host, ':')) != NULL) - { - *c = '\0'; - port = atoi(c + 1); - } - else - port = 1863; - - *ret_host = host; - *ret_port = port; -} diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msn-utils.h --- a/libpurple/protocols/msn/msn-utils.h Thu Jun 21 18:08:48 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/** - * @file msn-utils.h Utility functions - * - * 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_UTILS_H_ -#define _MSN_UTILS_H_ - -/** - * Parses the MSN message formatting into a format compatible with Purple. - * - * @param mime The mime header with the formatting. - * @param pre_ret The returned prefix string. - * @param post_ret The returned postfix string. - * - * @return The new message. - */ -void msn_parse_format(const char *mime, char **pre_ret, char **post_ret); - -/** - * Parses the Purple message formatting (html) into the MSN format. - * - * @param html The html message to format. - * @param attributes The returned attributes string. - * @param message The returned message string. - * - * @return The new message. - */ -void msn_import_html(const char *html, char **attributes, char **message); - -void msn_parse_socket(const char *str, char **ret_host, int *ret_port); - -#endif /* _MSN_UTILS_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Fri Jun 22 03:55:10 2007 +0000 @@ -37,7 +37,7 @@ #include "cmds.h" #include "core.h" #include "prpl.h" -#include "msn-utils.h" +#include "msnutils.h" #include "version.h" #include "switchboard.h" @@ -123,7 +123,7 @@ return PURPLE_CMD_RET_OK; } -static void +void msn_act_id(PurpleConnection *gc, const char *entry) { MsnCmdProc *cmdproc; @@ -131,6 +131,9 @@ PurpleAccount *account; const char *alias; + char *soapbody; + MsnSoapReq *soap_request; + session = gc->proto_data; cmdproc = session->notification->cmdproc; account = purple_connection_get_account(gc); @@ -147,9 +150,27 @@ return; } - msn_cmdproc_send(cmdproc, "REA", "%s %s", - purple_account_get_username(account), - alias); + if (*alias == '\0') { + alias = purple_url_encode(purple_account_get_username(account)); + } + + msn_cmdproc_send(cmdproc, "PRP", "MFN %s", alias); + + soapbody = g_strdup_printf(MSN_CONTACT_UPDATE_TEMPLATE, alias); + /*build SOAP and POST it*/ + soap_request = msn_soap_request_new(MSN_CONTACT_SERVER, + MSN_ADDRESS_BOOK_POST_URL, + MSN_CONTACT_UPDATE_SOAP_ACTION, + soapbody, + NULL, + NULL); + + session->contact->soapconn->read_cb = NULL; + msn_soap_post(session->contact->soapconn, + soap_request, + msn_contact_connect_init); + + g_free(soapbody); } static void @@ -432,6 +453,7 @@ session = gc->proto_data; xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who); + if (xfer) { slplink = msn_session_get_slplink(session, who); @@ -483,18 +505,56 @@ return "msn"; } +/* + * Set the User status text + * Add the PSM String Using "Name - PSM String" format + */ static char * msn_status_text(PurpleBuddy *buddy) { PurplePresence *presence; PurpleStatus *status; + const char *msg, *name, *cmedia; + char *psm_str, *tmp2, *text; presence = purple_buddy_get_presence(buddy); status = purple_presence_get_active_status(presence); - if (!purple_presence_is_available(presence) && !purple_presence_is_idle(presence)) - { - return g_strdup(purple_status_get_name(status)); + msg = purple_status_get_attr_string(status, "message"); + cmedia=purple_status_get_attr_string(status, "currentmedia"); + + if (!purple_presence_is_available(presence) && !purple_presence_is_idle(presence)){ + name = purple_status_get_name(status); + }else{ + name = NULL; + } + + if (cmedia != NULL) { + if(name) { + tmp2 = g_strdup_printf("%s - %s", name, cmedia); + text = g_markup_escape_text(tmp2, -1); + } else { + text = g_markup_escape_text(cmedia, -1); + } + return text; + } else if (msg != NULL) { + tmp2 = purple_markup_strip_html(msg); + if (name){ + psm_str = g_strdup_printf("%s - %s", name, tmp2); + g_free(tmp2); + }else{ + psm_str = tmp2; + } + text = g_markup_escape_text(psm_str, -1); + g_free(psm_str); + return text; + } else { + if (!purple_presence_is_available(presence) && !purple_presence_is_idle(presence)){ + psm_str = g_strdup(purple_status_get_name(status)); + text = g_markup_escape_text(psm_str, -1); + g_free(psm_str); + return text; + } } return NULL; @@ -512,8 +572,24 @@ if (purple_presence_is_online(presence)) { + const char *psm, *currentmedia; + char *tmp; + + psm = purple_status_get_attr_string(status, "message"); + currentmedia = purple_status_get_attr_string(status, "currentmedia"); + purple_notify_user_info_add_pair(user_info, _("Status"), (purple_presence_is_idle(presence) ? _("Idle") : purple_status_get_name(status))); + if (psm) { + tmp = g_markup_escape_text(psm, -1); + purple_notify_user_info_add_pair(user_info, _("PSM"), tmp); + g_free(tmp); + } + if (currentmedia) { + tmp = g_markup_escape_text(currentmedia, -1); + purple_notify_user_info_add_pair(user_info, _("Current media"), tmp); + g_free(tmp); + } } if (full && user) @@ -538,29 +614,48 @@ { PurpleStatusType *status; GList *types = NULL; - +#if 0 status = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); +#endif + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - NULL, NULL, FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - "brb", _("Be Right Back"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, "brb", _("Be Right Back"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, - "busy", _("Busy"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_UNAVAILABLE, "busy", _("Busy"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, - "phone", _("On the Phone"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_UNAVAILABLE, "phone", _("On the Phone"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); - - status = purple_status_type_new_full(PURPLE_STATUS_AWAY, - "lunch", _("Out to Lunch"), FALSE, TRUE, FALSE); + status = purple_status_type_new_with_attrs( + PURPLE_STATUS_AWAY, "lunch", _("Out to Lunch"), TRUE, TRUE, FALSE, + "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "currentmedia", _("Current media"), purple_value_new(PURPLE_TYPE_STRING), + NULL); types = g_list_append(types, status); status = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, @@ -570,11 +665,11 @@ status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_append(types, status); - + status = purple_status_type_new_full(PURPLE_STATUS_MOBILE, "mobile", NULL, FALSE, FALSE, TRUE); types = g_list_append(types, status); - + return types; } @@ -757,6 +852,7 @@ char *msgformat; char *msgtext; + purple_debug_info("MaYuan","send IM {%s} to %s\n",message,who); account = purple_connection_get_account(gc); if (buddy) { @@ -770,62 +866,91 @@ } 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 (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564) - { + if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564) + { + g_free(msgformat); + g_free(msgtext); + + return -E2BIG; + } + + msg = msn_message_new_plain(msgtext); + msg->remote_user = g_strdup(who); + msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); + g_free(msgformat); g_free(msgtext); - return -E2BIG; - } + purple_debug_info("MaYuan","prepare to send online Message\n"); + if (g_ascii_strcasecmp(who, purple_account_get_username(account))) + { + MsnSession *session; + MsnSwitchBoard *swboard; - msg = msn_message_new_plain(msgtext); - msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat); - - g_free(msgformat); - g_free(msgtext); + 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("MaYuan","send to Yahoo User\n"); + uum_send_msg(session,msg); + }else{ + purple_debug_info("MaYuan","send via switchboard\n"); + swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM); + msn_switchboard_send_msg(swboard, msg, TRUE); + } + } + else + { + char *body_str, *body_enc, *pre, *post; + const char *format; + MsnIMData *imdata = g_new0(MsnIMData, 1); + /* + * In MSN, you can't send messages to yourself, so + * we'll fake like we received it ;) + */ + body_str = msn_message_to_string(msg); + body_enc = g_markup_escape_text(body_str, -1); + g_free(body_str); - if (g_ascii_strcasecmp(who, purple_account_get_username(account))) - { - MsnSession *session; - MsnSwitchBoard *swboard; + format = msn_message_get_attr(msg, "X-MMS-IM-Format"); + msn_parse_format(format, &pre, &post); + body_str = g_strdup_printf("%s%s%s", pre ? pre : "", + body_enc ? body_enc : "", post ? post : ""); + g_free(body_enc); + g_free(pre); + g_free(post); + + serv_got_typing_stopped(gc, who); + imdata->gc = gc; + imdata->who = who; + imdata->msg = body_str; + imdata->flags = flags; + imdata->when = time(NULL); + g_idle_add(msn_send_me_im, imdata); + } + msn_message_destroy(msg); + }else { + /*send Offline Instant Message,only to MSN Passport User*/ + MsnSession *session; + MsnOim *oim; + char *friendname; + + purple_debug_info("MaYuan","prepare to send offline Message\n"); session = gc->proto_data; - swboard = msn_session_get_swboard(session, who, MSN_SB_FLAG_IM); + /* XXX/khc: hack */ + if (!session->oim) + session->oim = msn_oim_new(session); - msn_switchboard_send_msg(swboard, msg, TRUE); + oim = session->oim; + friendname = msn_encode_mime(account->username); + msn_oim_prep_send_msg_info(oim, purple_account_get_username(account), + friendname, who, message); + msn_oim_send_msg(oim); } - else - { - char *body_str, *body_enc, *pre, *post; - const char *format; - MsnIMData *imdata = g_new0(MsnIMData, 1); - /* - * In MSN, you can't send messages to yourself, so - * we'll fake like we received it ;) - */ - body_str = msn_message_to_string(msg); - body_enc = g_markup_escape_text(body_str, -1); - g_free(body_str); - - format = msn_message_get_attr(msg, "X-MMS-IM-Format"); - msn_parse_format(format, &pre, &post); - body_str = g_strdup_printf("%s%s%s", pre ? pre : "", - body_enc ? body_enc : "", post ? post : ""); - g_free(body_enc); - g_free(pre); - g_free(post); - - serv_got_typing_stopped(gc, who); - imdata->gc = gc; - imdata->who = who; - imdata->msg = body_str; - imdata->flags = flags; - imdata->when = time(NULL); - g_idle_add(msn_send_me_im, imdata); - } - - msn_message_destroy(msg); return 1; } @@ -964,6 +1089,7 @@ userlist = session->userlist; who = msn_normalize(gc->account, buddy->name); + purple_debug_info("MaYuan","add user:{%s} to group:{%s}\n",who,group->name); if (!session->logged_in) { #if 0 @@ -1256,22 +1382,25 @@ { MsnSession *session; MsnCmdProc *cmdproc; - int old_gid; + const char *old_gid; const char *enc_new_group_name; session = gc->proto_data; cmdproc = session->notification->cmdproc; enc_new_group_name = purple_url_encode(group->name); + purple_debug_info("MaYuan","rename group:old{%s},new{%s}",old_name,enc_new_group_name); old_gid = msn_userlist_find_group_id(session->userlist, old_name); - if (old_gid >= 0) + if (old_gid != NULL) { + /*find a Group*/ msn_cmdproc_send(cmdproc, "REG", "%d %s 0", old_gid, enc_new_group_name); } else { + /*not found*/ msn_cmdproc_send(cmdproc, "ADG", "%s 0", enc_new_group_name); } } @@ -1332,14 +1461,21 @@ { MsnSession *session; MsnCmdProc *cmdproc; - int group_id; + const char *group_id; session = gc->proto_data; cmdproc = session->notification->cmdproc; - if ((group_id = msn_userlist_find_group_id(session->userlist, group->name)) >= 0) + /*we can't delete the default group*/ + if(!strcmp(group->name,MSN_INDIVIDUALS_GROUP_NAME)|| + !strcmp(group->name,MSN_NON_IM_GROUP_NAME)) { - msn_cmdproc_send(cmdproc, "RMG", "%d", group_id); + return ; + } + group_id = msn_userlist_find_group_id(session->userlist, group->name); + if (group_id != NULL) + { + msn_del_group(session,group_id); } } @@ -1390,12 +1526,11 @@ { char *p, *q; - if ((p = strstr(url_text, " contactparams:photopreauthurl=\"")) != NULL) + if ((p = strstr(url_text, PHOTO_URL)) != NULL) { - p += strlen(" contactparams:photopreauthurl=\""); + p += strlen(PHOTO_URL); } - - if (p && (strncmp(p, "http://", 8) == 0) && ((q = strchr(p, '"')) != NULL)) + if (p && (strncmp(p, "http://",strlen("http://")) == 0) && ((q = strchr(p, '"')) != NULL)) return g_strndup(p, q - p); return NULL; @@ -1460,7 +1595,7 @@ MsnGetInfoStepTwoData *info2_data = NULL; #endif - purple_debug_info("msn", "In msn_got_info\n"); + purple_debug_info("msn", "In msn_got_info,url_text:{%s}\n",url_text); /* Make sure the connection is still valid */ if (g_list_find(purple_connections_get_all(), info_data->gc) == NULL) @@ -1844,6 +1979,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("Ma Yuan","photo url:{%s}\n",photo_url_text); /* Marshall the existing state */ info2_data = g_malloc0(sizeof(MsnGetInfoStepTwoData)); @@ -2068,7 +2204,7 @@ msn_add_deny, /* add_deny */ msn_rem_permit, /* rem_permit */ msn_rem_deny, /* rem_deny */ - msn_set_permit_deny, /* set_permit_deny */ + msn_set_permit_deny, /* set_permit_deny */ NULL, /* join_chat */ NULL, /* reject chat invite */ NULL, /* get_chat_name */ @@ -2124,10 +2260,11 @@ "MSN", /**< name */ VERSION, /**< version */ /** summary */ - N_("MSN Protocol Plugin"), + N_("Windows Live Messenger Protocol Plugin"), /** description */ - N_("MSN Protocol Plugin"), - "Christian Hammond ", /**< author */ + N_("Windows Live Messenger Protocol Plugin"), + "Christian Hammond , " + "MaYuan ", /**< author */ PURPLE_WEBSITE, /**< homepage */ msn_load, /**< load */ @@ -2152,11 +2289,11 @@ PurpleAccountOption *option; option = purple_account_option_string_new(_("Server"), "server", - MSN_SERVER); + WLM_SERVER); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); - option = purple_account_option_int_new(_("Port"), "port", 1863); + option = purple_account_option_int_new(_("Port"), "port", WLM_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msn.h --- a/libpurple/protocols/msn/msn.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/msn.h Fri Jun 22 03:55:10 2007 +0000 @@ -62,12 +62,23 @@ #define USEROPT_MSNPORT 4 #define MSN_PORT 1863 +/* 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 MSN_TYPING_RECV_TIMEOUT 6 #define MSN_TYPING_SEND_TIMEOUT 4 -#define HOTMAIL_URL "http://www.hotmail.com/cgi-bin/folders" +#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 @@ -85,9 +96,11 @@ MSN_LIST_FL_OP = 0x01, MSN_LIST_AL_OP = 0x02, MSN_LIST_BL_OP = 0x04, - MSN_LIST_RL_OP = 0x08 + MSN_LIST_RL_OP = 0x08, + MSN_LIST_PL_OP = 0x10 } MsnListOp; +#define MSN_LIST_OP_MASK 0x07 typedef enum { @@ -128,4 +141,7 @@ (MSN_CLIENT_ID_RESERVED_2 << 8) | \ (MSN_CLIENT_ID_CAPABILITIES)) +void msn_act_id(PurpleConnection *gc, const char *entry); + + #endif /* _MSN_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msnutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.c Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,591 @@ +/** + * @file msnutils.c Utility functions + * + * 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 "msn.h" +#include "msnutils.h" +#include "time.h" +//#include + +char *rand_guid(void); + +/************************************************************************** + * Util + **************************************************************************/ +char * +rand_guid() +{ + return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111, + rand() % 0xAAFF + 0x1111); +} + +void +msn_parse_format(const char *mime, char **pre_ret, char **post_ret) +{ + char *cur; + GString *pre = g_string_new(NULL); + GString *post = g_string_new(NULL); + unsigned int colors[3]; + + if (pre_ret != NULL) *pre_ret = NULL; + if (post_ret != NULL) *post_ret = NULL; + + cur = strstr(mime, "FN="); + + if (cur && (*(cur = cur + 3) != ';')) + { + pre = g_string_append(pre, ""); + post = g_string_prepend(post, ""); + } + + cur = strstr(mime, "EF="); + + if (cur && (*(cur = cur + 3) != ';')) + { + while (*cur && *cur != ';') + { + pre = g_string_append_c(pre, '<'); + pre = g_string_append_c(pre, *cur); + pre = g_string_append_c(pre, '>'); + post = g_string_prepend_c(post, '>'); + post = g_string_prepend_c(post, *cur); + post = g_string_prepend_c(post, '/'); + post = g_string_prepend_c(post, '<'); + cur++; + } + } + + cur = strstr(mime, "CO="); + + if (cur && (*(cur = cur + 3) != ';')) + { + int i; + + i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); + + if (i > 0) + { + char tag[64]; + + if (i == 1) + { + colors[1] = 0; + colors[2] = 0; + } + else if (i == 2) + { + unsigned int temp = colors[0]; + + colors[0] = colors[1]; + colors[1] = temp; + colors[2] = 0; + } + else if (i == 3) + { + unsigned int temp = colors[2]; + + colors[2] = colors[0]; + colors[0] = temp; + } + + g_snprintf(tag, sizeof(tag), + "", + colors[0], colors[1], colors[2]); + + pre = g_string_append(pre, tag); + post = g_string_prepend(post, ""); + } + } + + cur = strstr(mime, "RL="); + + if (cur && (*(cur = cur + 3) != ';')) + { + if (*cur == '1') + { + /* RTL text was received */ + pre = g_string_append(pre, ""); + post = g_string_prepend(post, ""); + } + } + + cur = g_strdup(purple_url_decode(pre->str)); + g_string_free(pre, TRUE); + + if (pre_ret != NULL) + *pre_ret = cur; + else + g_free(cur); + + cur = g_strdup(purple_url_decode(post->str)); + g_string_free(post, TRUE); + + if (post_ret != NULL) + *post_ret = cur; + else + g_free(cur); +} + +/*encode the str to RFC2047 style + * Currently only support the UTF-8 and base64 encode + */ +char * +msn_encode_mime(const char *str) +{ + char *base64; + + base64 = purple_base64_encode((guchar *)str, strlen(str)); + return g_strdup_printf("=?utf-8?B?%s?=", base64); +} + +/* + * We need this because we're only supposed to encode spaces in the font + * names. purple_url_encode() isn't acceptable. + */ +static const char * +encode_spaces(const char *str) +{ + static char buf[BUF_LEN]; + const char *c; + char *d; + + g_return_val_if_fail(str != NULL, NULL); + + for (c = str, d = buf; *c != '\0'; c++) + { + if (*c == ' ') + { + *d++ = '%'; + *d++ = '2'; + *d++ = '0'; + } + else + *d++ = *c; + } + + return buf; +} + +/* + * Taken from the zephyr plugin. + * This parses HTML formatting (put out by one of the gtkimhtml widgets + * and converts it to msn formatting. It doesn't deal with the tag closing, + * but gtkimhtml widgets give valid html. + * It currently deals properly with , , , , + * , , . + * It ignores and + */ +void +msn_import_html(const char *html, char **attributes, char **message) +{ + int len, retcount = 0; + const char *c; + char *msg; + char *fontface = NULL; + char fonteffect[4]; + char fontcolor[7]; + char direction = '0'; + + gboolean has_bold = FALSE; + gboolean has_italic = FALSE; + gboolean has_underline = FALSE; + gboolean has_strikethrough = FALSE; + + g_return_if_fail(html != NULL); + g_return_if_fail(attributes != NULL); + g_return_if_fail(message != NULL); + + len = strlen(html); + msg = g_malloc0(len + 1); + + memset(fontcolor, 0, sizeof(fontcolor)); + strcat(fontcolor, "0"); + memset(fonteffect, 0, sizeof(fonteffect)); + + for (c = html; *c != '\0';) + { + if (*c == '<') + { + if (!g_ascii_strncasecmp(c + 1, "br>", 3)) + { + msg[retcount++] = '\r'; + msg[retcount++] = '\n'; + c += 4; + } + else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) + { + if (!has_italic) + { + strcat(fonteffect, "I"); + has_italic = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) + { + if (!has_bold) + { + strcat(fonteffect, "B"); + has_bold = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) + { + if (!has_underline) + { + strcat(fonteffect, "U"); + has_underline = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) + { + if (!has_strikethrough) + { + strcat(fonteffect, "S"); + has_strikethrough = TRUE; + } + c += 3; + } + else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) + { + c += 9; + + if (!g_ascii_strncasecmp(c, "mailto:", 7)) + c += 7; + + while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) + msg[retcount++] = *c++; + + if (*c != '\0') + c += 2; + + /* ignore descriptive string */ + while ((*c != '\0') && g_ascii_strncasecmp(c, "", 4)) + c++; + + if (*c != '\0') + c += 4; + } + else if (!g_ascii_strncasecmp(c + 1, "span", 4)) + { + /* Bi-directional text support using CSS properties in span tags */ + c += 5; + + while (*c != '\0' && *c != '>') + { + while (*c == ' ') + c++; + if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) + { + c += 9; + direction = '1'; + } + else if (!g_ascii_strncasecmp(c, "style=\"", 7)) + { + /* Parse inline CSS attributes */ + char *attributes; + int attr_len = 0; + c += 7; + while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') + attr_len++; + if (*(c + attr_len) == '"') + { + char *attr_dir; + attributes = g_strndup(c, attr_len); + attr_dir = purple_markup_get_css_property(attributes, "direction"); + if (attr_dir && (!strncasecmp(attr_dir, "RTL", 3))) + direction = '1'; + g_free(attr_dir); + g_free(attributes); + } + + } + else + { + c++; + } + } + if (*c == '>') + c++; + } + else if (!g_ascii_strncasecmp(c + 1, "font", 4)) + { + c += 5; + + while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) + c++; + + if (!g_ascii_strncasecmp(c, "color=\"#", 7)) + { + c += 8; + + fontcolor[0] = *(c + 4); + fontcolor[1] = *(c + 5); + fontcolor[2] = *(c + 2); + fontcolor[3] = *(c + 3); + fontcolor[4] = *c; + fontcolor[5] = *(c + 1); + + c += 8; + } + else if (!g_ascii_strncasecmp(c, "face=\"", 6)) + { + const char *end = NULL; + const char *comma = NULL; + unsigned int namelen = 0; + + c += 6; + end = strchr(c, '\"'); + comma = strchr(c, ','); + + if (comma == NULL || comma > end) + namelen = (unsigned int)(end - c); + else + namelen = (unsigned int)(comma - c); + + fontface = g_strndup(c, namelen); + c = end + 2; + } + else + { + /* Drop all unrecognized/misparsed font tags */ + while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) + c++; + + if (*c != '\0') + c += 2; + } + } + else + { + while ((*c != '\0') && (*c != '>')) + c++; + if (*c != '\0') + c++; + } + } + else if (*c == '&') + { + if (!g_ascii_strncasecmp(c, "<", 4)) + { + msg[retcount++] = '<'; + c += 4; + } + else if (!g_ascii_strncasecmp(c, ">", 4)) + { + msg[retcount++] = '>'; + c += 4; + } + else if (!g_ascii_strncasecmp(c, " ", 6)) + { + msg[retcount++] = ' '; + c += 6; + } + else if (!g_ascii_strncasecmp(c, """, 6)) + { + msg[retcount++] = '"'; + c += 6; + } + else if (!g_ascii_strncasecmp(c, "&", 5)) + { + msg[retcount++] = '&'; + c += 5; + } + else if (!g_ascii_strncasecmp(c, "'", 6)) + { + msg[retcount++] = '\''; + c += 6; + } + else + msg[retcount++] = *c++; + } + else + msg[retcount++] = *c++; + } + + if (fontface == NULL) + fontface = g_strdup("MS Sans Serif"); + + *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", + encode_spaces(fontface), + fonteffect, fontcolor, direction); + *message = g_strdup(msg); + + g_free(fontface); + g_free(msg); +} + +void +msn_parse_socket(const char *str, char **ret_host, int *ret_port) +{ + char *host; + char *c; + int port; + + host = g_strdup(str); + + if ((c = strchr(host, ':')) != NULL){ + *c = '\0'; + port = atoi(c + 1); + }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("MaYuan","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 + */ +#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]; + + long long nHigh=0, nLow=0; + + int i; + + /* 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, (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); + + /* 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; + } + + /* 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; + + /* this is magic */ + for (i=0; i<(strlen(buf)/4)-1; i+=2){ + long long temp; + + chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); + chlStringParts[i+1] = GUINT_TO_LE(chlStringParts[i+1]); + + 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; + + newHashParts[0]^=nHigh; + newHashParts[1]^=nLow; + newHashParts[2]^=nHigh; + newHashParts[3]^=nLow; + + /* 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; + + /* 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]; + } + + output[32]='\0'; + +// purple_debug_info("MaYuan","chl output{%s}\n",output); +} diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/msnutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.h Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,60 @@ +/** + * @file msnutils.h Utility functions + * + * 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_UTILS_H_ +#define _MSN_UTILS_H_ + +/*encode the str to RFC2047 style*/ +char * msn_encode_mime(const char *str); + +/** + * Generate the Random GUID + */ +char * rand_guid(void); + +/** + * Parses the MSN message formatting into a format compatible with Purple. + * + * @param mime The mime header with the formatting. + * @param pre_ret The returned prefix string. + * @param post_ret The returned postfix string. + * + * @return The new message. + */ +void msn_parse_format(const char *mime, char **pre_ret, char **post_ret); + +/** + * Parses the Purple message formatting (html) into the MSN format. + * + * @param html The html message to format. + * @param attributes The returned attributes string. + * @param message The returned message string. + * + * @return The new message. + */ +void msn_import_html(const char *html, char **attributes, char **message); + +void msn_parse_socket(const char *str, char **ret_host, int *ret_port); +void msn_handle_chl(char *input, char *output); + +#endif /* _MSN_UTILS_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/nexus.c --- a/libpurple/protocols/msn/nexus.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Fri Jun 22 03:55:10 2007 +0000 @@ -22,8 +22,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" +#include "soap.h" #include "nexus.h" #include "notification.h" +#undef NEXUS_LOGIN_TWN + +/*Local Function Prototype*/ +static void nexus_login_connect_cb(gpointer data, PurpleSslConnection *gsc,PurpleInputCondition cond); /************************************************************************** * Main @@ -36,6 +41,9 @@ nexus = g_new0(MsnNexus, 1); nexus->session = session; + /*we must use SSL connection to do Windows Live ID authentication*/ + nexus->soapconn = msn_soap_new(session,nexus,1); + nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); @@ -45,24 +53,14 @@ void msn_nexus_destroy(MsnNexus *nexus) { - if (nexus->gsc) - purple_ssl_close(nexus->gsc); - - g_free(nexus->login_host); - - g_free(nexus->login_path); - if (nexus->challenge_data != NULL) g_hash_table_destroy(nexus->challenge_data); - if (nexus->input_handler > 0) - purple_input_remove(nexus->input_handler); - g_free(nexus->write_buf); - g_free(nexus->read_buf); - + msn_soap_destroy(nexus->soapconn); g_free(nexus); } +#if 0 /* khc */ /************************************************************************** * Util **************************************************************************/ @@ -121,285 +119,242 @@ nexus->written_cb(nexus, source, 0); } +#endif /************************************************************************** * Login **************************************************************************/ - static void -login_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond); +nexus_login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +{ + MsnSoapConn * soapconn = data; + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + + soapconn->gsc = NULL; + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication:Unable to connect")); + /* the above line will result in nexus being destroyed, so we don't want + * to destroy it here, or we'd crash */ +} + +/*process the SOAP reply, get the Authentication Info*/ static void -login_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +nexus_login_read_cb(gpointer data, gint source, PurpleInputCondition cond) { + MsnSoapConn * soapconn = data; MsnNexus *nexus; MsnSession *session; - nexus = data; - g_return_if_fail(nexus != NULL); + char *base, *c; + char *msn_twn_t,*msn_twn_p; + char *login_params; + char **elems, **cur, **tokens; + char * cert_str; - nexus->gsc = NULL; - + nexus = soapconn->parent; + g_return_if_fail(nexus != NULL); session = nexus->session; g_return_if_fail(session != NULL); - msn_session_set_error(session, MSN_ERROR_AUTH, _("Unable to connect")); - /* the above line will result in nexus being destroyed, so we don't want - * to destroy it here, or we'd crash */ + purple_debug_misc("msn", "TWN Server Reply: {%s}\n", soapconn->read_buf); + + /*reply OK, we should process the SOAP body*/ + purple_debug_info("MaYuan","Windows Live ID Reply OK!\n"); + + //TODO: we should parse it using XML +#ifdef NEXUS_LOGIN_TWN + base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_START_TOKEN); + base += strlen(TWN_START_TOKEN); + c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_END_TOKEN); +#else + base = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_START_TOKEN); + base += strlen(TWN_LIVE_START_TOKEN); + c = g_strstr_len(soapconn->read_buf, soapconn->read_len, TWN_LIVE_END_TOKEN); +#endif + login_params = g_strndup(base, c - base); + + // purple_debug_info("msn", "TWN Cert: {%s}\n", login_params); + + /* Parse the challenge data. */ + elems = g_strsplit(login_params, "&", 0); + + for (cur = elems; *cur != NULL; cur++){ + tokens = g_strsplit(*cur, "=", 2); + g_hash_table_insert(nexus->challenge_data, tokens[0], tokens[1]); + /* Don't free each of the tokens, only the array. */ + g_free(tokens); + } + + g_strfreev(elems); + + msn_twn_t = (char *)g_hash_table_lookup(nexus->challenge_data, "t"); + msn_twn_p = (char *)g_hash_table_lookup(nexus->challenge_data, "p"); + + /*setup the t and p parameter for session*/ + if (session->passport_info.t != NULL){ + g_free(session->passport_info.t); + } + session->passport_info.t = g_strdup(msn_twn_t); + + if (session->passport_info.p != NULL) + g_free(session->passport_info.p); + session->passport_info.p = g_strdup(msn_twn_p); + + cert_str = g_strdup_printf("t=%s&p=%s",msn_twn_t,msn_twn_p); + msn_got_login_params(session, cert_str); + + purple_debug_info("MaYuan","close nexus connection! \n"); + g_free(cert_str); + g_free(login_params); + msn_nexus_destroy(nexus); + session->nexus = NULL; + + return; } static void nexus_login_written_cb(gpointer data, gint source, PurpleInputCondition cond) { - MsnNexus *nexus = data; - MsnSession *session; - int len; + MsnSoapConn * soapconn = data; - session = nexus->session; - g_return_if_fail(session != NULL); - - if (nexus->input_handler == 0) - /* TODO: Use purple_ssl_input_add()? */ - nexus->input_handler = purple_input_add(nexus->gsc->fd, - PURPLE_INPUT_READ, nexus_login_written_cb, nexus); + soapconn->read_cb = nexus_login_read_cb; +// msn_soap_read_cb(data,source,cond); +} - len = msn_ssl_read(nexus); - - if (len < 0 && errno == EAGAIN) - return; - else if (len < 0) { - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - /* TODO: error handling */ - return; - } - - if (g_strstr_len(nexus->read_buf, nexus->read_len, - "\r\n\r\n") == NULL) - return; - - purple_input_remove(nexus->input_handler); - nexus->input_handler = 0; - - purple_ssl_close(nexus->gsc); - nexus->gsc = NULL; - - purple_debug_misc("msn", "ssl buffer: {%s}", nexus->read_buf); - - if (strstr(nexus->read_buf, "HTTP/1.1 302") != NULL) - { - /* Redirect. */ - char *location, *c; - - location = strstr(nexus->read_buf, "Location: "); - if (location == NULL) - { - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - - return; - } - location = strchr(location, ' ') + 1; - - if ((c = strchr(location, '\r')) != NULL) - *c = '\0'; - - /* Skip the http:// */ - if ((c = strchr(location, '/')) != NULL) - location = c + 2; - - if ((c = strchr(location, '/')) != NULL) - { - g_free(nexus->login_path); - nexus->login_path = g_strdup(c); - - *c = '\0'; - } - - g_free(nexus->login_host); - nexus->login_host = g_strdup(location); - - nexus->gsc = purple_ssl_connect(session->account, - nexus->login_host, PURPLE_SSL_DEFAULT_PORT, - login_connect_cb, login_error_cb, nexus); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 401 Unauthorized") != NULL) - { - const char *error; - - if ((error = strstr(nexus->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); - if ((temp = strstr(error, " Do one of the following or try again:")) != NULL) - *temp = '\0'; - } - } - - msn_session_set_error(session, MSN_ERROR_AUTH, error); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 503 Service Unavailable")) - { - msn_session_set_error(session, MSN_ERROR_SERV_UNAVAILABLE, NULL); - } - else if (strstr(nexus->read_buf, "HTTP/1.1 200 OK")) - { - char *base, *c; - char *login_params; - -#if 0 - /* All your base are belong to us. */ - base = buffer; - - /* For great cookie! */ - while ((base = strstr(base, "Set-Cookie: ")) != NULL) - { - base += strlen("Set-Cookie: "); - - c = strchr(base, ';'); - - session->login_cookies = - g_list_append(session->login_cookies, - g_strndup(base, c - base)); - } +/*when connect, do the SOAP Style windows Live ID authentication */ +void +nexus_login_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn *soapconn; + MsnNexus * nexus; + MsnSession *session; + char *ru,*lc,*id,*tw,*ct,*kpp,*kv,*ver,*rn,*tpf; + char *fs0,*fs; + char *username, *password; + char *request_str, *head, *tail; +#ifdef NEXUS_LOGIN_TWN + char *challenge_str; +#else + char *rst1_str,*rst2_str,*rst3_str; #endif - base = strstr(nexus->read_buf, "Authentication-Info: "); + purple_debug_info("MaYuan","starting Windows Live ID authentication\n"); + + soapconn = data; + g_return_if_fail(soapconn != NULL); + + nexus = soapconn->parent; + g_return_if_fail(nexus != NULL); - g_return_if_fail(base != NULL); + session = soapconn->session; + g_return_if_fail(session != NULL); + + msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); + + /*prepare the Windows Live ID authentication token*/ + username = g_strdup(purple_account_get_username(session->account)); + password = g_strdup(purple_connection_get_password(session->account->gc)); - base = strstr(base, "from-PP='"); - base += strlen("from-PP='"); - c = strchr(base, '\''); + 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"); - login_params = g_strndup(base, c - base); - - msn_got_login_params(session, login_params); - - g_free(login_params); - + /* + * 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("MaYuan","WLM Authenticate Key Error!\n"); + msn_session_set_error(session, MSN_ERROR_AUTH, _("Windows Live ID authentication Failed")); + g_free(username); + g_free(password); + purple_ssl_close(gsc); msn_nexus_destroy(nexus); session->nexus = NULL; return; } - g_free(nexus->read_buf); - nexus->read_buf = NULL; - nexus->read_len = 0; - -} - -/* this guards against missing hash entries */ -static char * -nexus_challenge_data_lookup(GHashTable *challenge_data, const char *key) -{ - char *entry; - - return (entry = (char *)g_hash_table_lookup(challenge_data, key)) ? - entry : "(null)"; -} + /* + * 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"); + } -void -login_connect_cb(gpointer data, PurpleSslConnection *gsc, - PurpleInputCondition cond) -{ - MsnNexus *nexus; - MsnSession *session; - char *username, *password; - char *request_str, *head, *tail; - char *buffer = NULL; - guint32 ctint; - - nexus = data; - g_return_if_fail(nexus != NULL); - - session = nexus->session; - g_return_if_fail(session != NULL); - - msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE); +#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 + ); - username = - g_strdup(purple_url_encode(purple_account_get_username(session->account))); - - password = - g_strdup(purple_url_encode(purple_connection_get_password(session->account->gc))); - - ctint = strtoul((char *)g_hash_table_lookup(nexus->challenge_data, "ct"), NULL, 10) + 200; - - head = g_strdup_printf( - "GET %s HTTP/1.1\r\n" - "Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s", - nexus->login_path, - (char *)g_hash_table_lookup(nexus->challenge_data, "ru"), - username); + /*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); - tail = g_strdup_printf( - "lc=%s,id=%s,tw=%s,fs=%s,ru=%s,ct=%" G_GUINT32_FORMAT ",kpp=%s,kv=%s,ver=%s,tpf=%s\r\n" - "User-Agent: MSMSGS\r\n" - "Host: %s\r\n" - "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n", - nexus_challenge_data_lookup(nexus->challenge_data, "lc"), - nexus_challenge_data_lookup(nexus->challenge_data, "id"), - nexus_challenge_data_lookup(nexus->challenge_data, "tw"), - nexus_challenge_data_lookup(nexus->challenge_data, "fs"), - nexus_challenge_data_lookup(nexus->challenge_data, "ru"), - ctint, - nexus_challenge_data_lookup(nexus->challenge_data, "kpp"), - nexus_challenge_data_lookup(nexus->challenge_data, "kv"), - nexus_challenge_data_lookup(nexus->challenge_data, "ver"), - nexus_challenge_data_lookup(nexus->challenge_data, "tpf"), - nexus->login_host); + soapconn->login_path = g_strdup(TWN_POST_URL); + head = g_strdup_printf( + "POST %s HTTP/1.1\r\n" + "Accept: text/*\r\n" + "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n" + "Host: %s\r\n" + "Content-Length: %d\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n\r\n", + soapconn->login_path,soapconn->login_host,(int)strlen(tail)); - buffer = g_strdup_printf("%s,pwd=XXXXXXXX,%s\r\n", head, tail); - request_str = g_strdup_printf("%s,pwd=%s,%s\r\n", head, password, tail); + request_str = g_strdup_printf("%s%s", head,tail); + purple_debug_misc("msn", "TWN Sending: {%s}\n", request_str); - purple_debug_misc("msn", "Sending: {%s}\n", buffer); - - g_free(buffer); g_free(head); g_free(tail); g_free(username); g_free(password); - nexus->write_buf = request_str; - nexus->written_len = 0; - - nexus->read_len = 0; - - nexus->written_cb = nexus_login_written_cb; - - nexus->input_handler = purple_input_add(gsc->fd, PURPLE_INPUT_WRITE, - nexus_write_cb, nexus); - - nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); + /*prepare to send the SOAP request*/ + msn_soap_write(soapconn,request_str,nexus_login_written_cb); return; - - } +#if 0 /* khc */ static void nexus_connect_written_cb(gpointer data, gint source, PurpleInputCondition cond) { MsnNexus *nexus = data; int len; + char *da_login; char *base, *c; @@ -408,6 +363,7 @@ nexus->input_handler = purple_input_add(nexus->gsc->fd, PURPLE_INPUT_READ, nexus_connect_written_cb, nexus); + /* Get the PassportURLs line. */ len = msn_ssl_read(nexus); @@ -470,10 +426,13 @@ } +#endif + /************************************************************************** * Connect **************************************************************************/ +#if 0 /* khc */ static void nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) @@ -502,10 +461,13 @@ nexus_write_cb(nexus, gsc->fd, PURPLE_INPUT_WRITE); } +#endif + void msn_nexus_connect(MsnNexus *nexus) { - nexus->gsc = purple_ssl_connect(nexus->session->account, - "nexus.passport.com", PURPLE_SSL_DEFAULT_PORT, - nexus_connect_cb, login_error_cb, nexus); + /* Authenticate via Windows Live ID. */ + purple_debug_info("MaYuan","msn_nexus_connect...\n"); + msn_soap_init(nexus->soapconn,MSN_TWN_SERVER,1,nexus_login_connect_cb,nexus_login_error_cb); + msn_soap_connect(nexus->soapconn); } diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/nexus.h --- a/libpurple/protocols/msn/nexus.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Fri Jun 22 03:55:10 2007 +0000 @@ -24,25 +24,124 @@ #ifndef _MSN_NEXUS_H_ #define _MSN_NEXUS_H_ +#include "soap.h" + +/*#define MSN_TWN_SERVER "loginnet.passport.com"*/ +#define MSN_TWN_SERVER "login.live.com" + +#define TWN_START_TOKEN "" +#define TWN_END_TOKEN "" + +#define TWN_POST_URL "/RST.srf" +#define TWN_ENVELOP_TEMPLATE ""\ + ""\ + "
"\ + ""\ + "{3:B}"\ + "4"\ + "1"\ + ""\ + "AQAAAAIAAABsYwQAAAAzMDg0"\ + ""\ + ""\ + ""\ + "%s"\ + "%s"\ + ""\ + ""\ + "
"\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "http://Passport.NET/tb"\ + ""\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "messenger.msn.com"\ + ""\ + ""\ + ""\ + ""\ + ""\ + ""\ + ""\ + "
" + +#define TWN_LIVE_START_TOKEN "" +#define TWN_LIVE_END_TOKEN "" +#define TWN_LIVE_ENVELOP_TEMPLATE ""\ +""\ + "
"\ + ""\ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}"\ + "4"\ + "1"\ + ""\ + "AQAAAAIAAABsYwQAAAAyMDUy"\ + ""\ + ""\ + ""\ + "%s"\ + "%s"\ + ""\ + ""\ + "
"\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "http://Passport.NET/tb"\ + ""\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "messenger.msn.com"\ + ""\ + ""\ + ""\ + ""\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "contacts.msn.com"\ + ""\ + ""\ + ""\ + " "\ + ""\ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue"\ + ""\ + ""\ + "voice.messenger.msn.com"\ + ""\ + " "\ + ""\ + ""\ + ""\ + ""\ +"
" + typedef struct _MsnNexus MsnNexus; struct _MsnNexus { MsnSession *session; - - char *login_host; - char *login_path; + MsnSoapConn *soapconn; + char * challenge_data_str; GHashTable *challenge_data; - PurpleSslConnection *gsc; - - guint input_handler; - - char *write_buf; - gsize written_len; - PurpleInputFunction written_cb; - - char *read_buf; - gsize read_len; }; void msn_nexus_connect(MsnNexus *nexus); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Fri Jun 22 03:55:10 2007 +0000 @@ -25,7 +25,7 @@ #include "notification.h" #include "state.h" #include "error.h" -#include "msn-utils.h" +#include "msnutils.h" #include "page.h" #include "userlist.h" @@ -34,6 +34,14 @@ static MsnTable *cbs_table; +/**************************************************************************** + * Local Function Prototype + ****************************************************************************/ + +static void msn_notification_fqy_yahoo(MsnSession *session, const char *passport); +static void msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len); +static void msn_add_contact_xml(MsnSession *session, xmlnode *mlNode, const char *passport, int list_op, MsnUserType type); + /************************************************************************** * Main **************************************************************************/ @@ -102,9 +110,11 @@ account = session->account; /* Allocate an array for CVR0, NULL, and all the versions */ - a = c = g_new0(char *, session->protocol_ver - 8 + 3); +// a = c = g_new0(char *, session->protocol_ver - WLM_MIN_PROTOCOL + 3); + a = c = g_new0(char *, WLM_MAX_PROTOCOL - WLM_MIN_PROTOCOL + 3); - for (i = session->protocol_ver; i >= 8; i--) +// for (i = session->protocol_ver; i >= WLM_MIN_PROTOCOL; i--) + for (i = WLM_MAX_PROTOCOL; i >= WLM_MIN_PROTOCOL; i--) *c++ = g_strdup_printf("MSNP%d", i); *c++ = g_strdup("CVR0"); @@ -112,9 +122,13 @@ vers = g_strjoinv(" ", a); if (session->login_step == MSN_LOGIN_STEP_START) + { msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE); + } else + { msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2); + } msn_cmdproc_send(cmdproc, "VER", "%s", vers); @@ -153,7 +167,7 @@ **************************************************************************/ static void -group_error_helper(MsnSession *session, const char *msg, int group_id, int error) +group_error_helper(MsnSession *session, const char *msg, const char *group_id, int error) { PurpleAccount *account; PurpleConnection *gc; @@ -172,9 +186,7 @@ else { const char *group_name; - group_name = - msn_userlist_find_group_name(session->userlist, - group_id); + group_name = msn_userlist_find_group_name(session->userlist,group_id); reason = g_strdup_printf(_("%s is not a valid group."), group_name); } @@ -214,7 +226,6 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", purple_account_get_username(account)); } @@ -232,14 +243,17 @@ if (!g_ascii_strcasecmp(cmd->params[1], "OK")) { - /* 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"); +// 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")) { @@ -249,15 +263,20 @@ 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); + tokens = g_strsplit(*cur, "=", 2); + if(tokens[0]&&tokens[1]) + { + purple_debug_info("MaYuan","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); + } + /* Don't free each of the tokens, only the array. */ + g_free(tokens); } g_strfreev(elems); @@ -322,8 +341,15 @@ return; } + /* + * Windows Live Messenger 8.0 + * 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 MSNMSGR 6.0.0602 MSMSGS %s", +// "0x0409 winnt 5.1 i386 MSG80BETA 8.0.0689 msmsgs %s", + "0x0804 winnt 5.1 i386 MSNMSGR 8.0.0792 msmsgs %s", purple_account_get_username(account)); } @@ -366,7 +392,7 @@ msg = msn_message_new_from_cmd(cmdproc->session, cmd); - msn_message_parse_payload(msg, payload, len); + 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 @@ -379,9 +405,12 @@ static void msg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { + purple_debug_info("MaYuan","Processing MSG... \n"); + if(cmd->payload_len == 0){ + return; + } /* 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 = msg_cmd_post; @@ -391,32 +420,145 @@ { g_return_if_fail(cmd->payload_cb != NULL); + purple_debug_info("MaYuan","MSG payload:{%s}\n",cmd->payload); cmd->payload_cb(cmdproc, cmd, cmd->payload, cmd->payload_len); } } +/*send Message to Yahoo Messenger*/ +void +uum_send_msg(MsnSession *session,MsnMessage *msg) +{ + MsnCmdProc *cmdproc; + MsnTransaction *trans; + char *payload; + gsize payload_len; + int type; + + cmdproc = session->notification->cmdproc; + g_return_if_fail(msg != NULL); + payload = msn_message_gen_payload(msg, &payload_len); + purple_debug_info("MaYuan","send UUM,payload{%s},strlen:%d,len:%d\n", + payload,strlen(payload),payload_len); + type = msg->type; + trans = msn_transaction_new(cmdproc, "UUM","%s 32 %d %d",msg->remote_user,type,payload_len); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + +static void +ubm_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + MsnMessage *msg; + PurpleConnection *gc; + const char *passport; + const char *content_type; + + purple_debug_info("MaYuan","Process UBM payload:%s\n",payload); + msg = msn_message_new_from_cmd(cmdproc->session, cmd); + + 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 + + gc = cmdproc->session->account->gc; + passport = msg->remote_user; + + content_type = msn_message_get_content_type(msg); + purple_debug_info("MaYuan","type:%d\n",content_type); + if(!strcmp(content_type,"text/plain")){ + const char *value; + const char *body; + char *body_str; + char *body_enc; + char *body_final = NULL; + size_t body_len; + + body = msn_message_get_bin_data(msg, &body_len); + body_str = g_strndup(body, body_len); + body_enc = g_markup_escape_text(body_str, -1); + g_free(body_str); + + if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) { + char *pre, *post; + + msn_parse_format(value, &pre, &post); + body_final = g_strdup_printf("%s%s%s", pre ? pre : "", + body_enc ? body_enc : "", post ? post : ""); + g_free(pre); + g_free(post); + g_free(body_enc); + } + serv_got_im(gc, passport, body_final, 0, time(NULL)); + } + if(!strcmp(content_type,"text/x-msmsgscontrol")){ + if(msn_message_get_attr(msg, "TypingUser") != NULL){ + serv_got_typing(gc, passport, MSN_TYPING_RECV_TIMEOUT, + PURPLE_TYPING); + } + } + if(!strcmp(content_type,"text/x-msnmsgr-datacast")){ + char *username, *str; + PurpleAccount *account; + PurpleBuddy *buddy; + const char *user; + + account = cmdproc->session->account; + user = msg->remote_user; + + if ((buddy = purple_find_buddy(account, user)) != NULL){ + username = g_markup_escape_text(purple_buddy_get_alias(buddy), -1); + }else{ + username = g_markup_escape_text(user, -1); + } + + str = g_strdup_printf(_("%s just sent you a Nudge!"), username); + g_free(username); + msn_session_report_user(cmdproc->session,user,str,PURPLE_MESSAGE_SYSTEM); + g_free(str); + } + msn_message_destroy(msg); +} + +/*Yahoo msg process*/ +static void +ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Processing UBM... \n"); + if(cmd->payload_len == 0){ + return; + } + /* 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{ + g_return_if_fail(cmd->payload_cb != NULL); + + purple_debug_info("MaYuan","UBM payload:{%s}\n",cmd->payload); + ubm_cmd_post(cmdproc, cmd, cmd->payload, cmd->payload_len); + } +} + /************************************************************************** * Challenges + * we use MD5 to caculate the Challenges **************************************************************************/ - static void chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnTransaction *trans; char buf[33]; - const char *challenge_resp; - PurpleCipher *cipher; - PurpleCipherContext *context; - guchar digest[16]; - int i; +#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 = "VT6PX?UQTM4WM%YR"; + challenge_resp = MSNP13_WLM_PRODUCT_KEY; purple_cipher_context_append(context, (const guchar *)challenge_resp, strlen(challenge_resp)); @@ -424,9 +566,14 @@ purple_cipher_context_destroy(context); for (i = 0; i < 16; i++) + { g_snprintf(buf + (i*2), 3, "%02x", digest[i]); - - trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9"); + } +#else + msn_handle_chl(cmd->params[1], buf); +#endif +// purple_debug_info("MaYuan","<params[1],buf); + trans = msn_transaction_new(cmdproc, "QRY", "%s 32", MSNP13_WLM_PRODUCT_ID); msn_transaction_set_payload(trans, buf, 32); @@ -436,43 +583,219 @@ /************************************************************************** * Buddy Lists **************************************************************************/ +/* add contact to xmlnode */ +static void +msn_add_contact_xml(MsnSession *session, xmlnode *mlNode,const char *passport,int list_op, MsnUserType type) +{ + xmlnode *d_node,*c_node; + char **tokens; + char *email,*domain; + char *list_op_str,*type_str; + + purple_debug_info("MaYuan","passport:%s type: %d\n",passport, type); + tokens = g_strsplit(passport, "@", 2); + email = tokens[0]; + domain = tokens[1]; + + /*find a domain Node*/ + for(d_node = xmlnode_get_child(mlNode,"d"); d_node; d_node = xmlnode_get_next_twin(d_node)) + { + const char * attr = NULL; + purple_debug_info("MaYuan","d_node:%s\n",d_node->name); + attr = xmlnode_get_attrib(d_node,"n"); + if(attr == NULL){ + continue; + } + if(!strcmp(attr,domain)){ + break; + } + } + if(d_node == NULL) + { + /*domain not found, create a new domain Node*/ + purple_debug_info("MaYuan","get No d_node\n"); + d_node = xmlnode_new("d"); + xmlnode_set_attrib(d_node,"n",domain); + xmlnode_insert_child(mlNode,d_node); + } + + /*create contact node*/ + c_node = xmlnode_new("c"); + xmlnode_set_attrib(c_node,"n",email); + + list_op_str = g_strdup_printf("%d",list_op); + purple_debug_info("MaYuan","list_op:%d\n",list_op); + xmlnode_set_attrib(c_node,"l",list_op_str); + g_free(list_op_str); + + if (type != MSN_USER_TYPE_UNKNOWN) { + type_str = g_strdup_printf("%d", type); + } else { + if (msn_user_is_yahoo(session->account, passport)) + type_str = g_strdup_printf("%d", MSN_USER_TYPE_YAHOO); + else + type_str = g_strdup_printf("%d", MSN_USER_TYPE_PASSPORT); + } + /*mobile*/ + //type_str = g_strdup_printf("4"); + xmlnode_set_attrib(c_node,"t",type_str); + g_free(type_str); + + xmlnode_insert_child(d_node, c_node); + + g_strfreev(tokens); +} static void -add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +msn_notification_post_adl(MsnCmdProc *cmdproc, const char *payload, int payload_len) +{ + MsnTransaction *trans; + + purple_debug_info("MaYuan","Send ADL{%s}\n",payload); + trans = msn_transaction_new(cmdproc, "ADL","%d",strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + +/*dump contact info to NS*/ +void +msn_notification_dump_contact(MsnSession *session) +{ + MsnUser *user; + GList *l; + xmlnode *adl_node; + char *payload; + int payload_len; + int adl_count = 0; + const char *display_name; + + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + xmlnode_set_attrib(adl_node, "l", "1"); + + /*get the userlist*/ + for (l = session->userlist->users; l != NULL; l = l->next){ + user = l->data; + + /* skip RL & PL during initial dump */ + if (!(user->list_op & MSN_LIST_OP_MASK)) + continue; + + msn_add_contact_xml(session, adl_node, user->passport, + user->list_op & MSN_LIST_OP_MASK, user->type); + + /* each ADL command may contain up to 150 contacts */ + if (++adl_count % 150 == 0 || l->next == NULL) { + payload = xmlnode_to_str(adl_node,&payload_len); + + msn_notification_post_adl(session->notification->cmdproc, + payload, payload_len); + + g_free(payload); + xmlnode_free(adl_node); + + if (l->next) { + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + xmlnode_set_attrib(adl_node, "l", "1"); + } + } + } + + + display_name = purple_connection_get_display_name(session->account->gc); + if (display_name && strcmp(display_name, + purple_account_get_username(session->account))) { + msn_act_id(session->account->gc, display_name); + } + +} + +/*Post FQY to NS,Inform add a Yahoo User*/ +static void +msn_notification_fqy_yahoo(MsnSession *session, const char *passport) +{ + MsnTransaction *trans; + MsnCmdProc *cmdproc; + char* email,*domain,*payload; + char **tokens; + + cmdproc = session->notification->cmdproc; + + tokens = g_strsplit(passport, "@", 2); + email = tokens[0]; + domain = tokens[1]; + + payload = g_strdup_printf("",domain,email); + trans = msn_transaction_new(cmdproc, "FQY","%d",strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); + + g_free(payload); + g_free(tokens); +} + +static void +blp_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Process BLP\n"); +} + +static void +adl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Process ADL\n"); +} + +static void +adl_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { MsnSession *session; - MsnUser *user; - const char *list; - const char *passport; - const char *friendly; - MsnListId list_id; - int group_id; - - list = cmd->params[1]; - passport = cmd->params[3]; - friendly = purple_url_decode(cmd->params[4]); + PurpleAccount *account; + PurpleConnection *gc; + char *reason = NULL; session = cmdproc->session; + account = session->account; + gc = purple_account_get_connection(account); - user = msn_userlist_find_user(session->userlist, passport); + 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); +} + +static void +fqy_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + purple_debug_info("MaYuan","FQY payload{%s}\n",payload); + msn_notification_post_adl(cmdproc,payload,len); +} - if (user == NULL) - { - user = msn_user_new(session->userlist, passport, friendly); - msn_userlist_add_user(session->userlist, user); - } - else - msn_user_set_friendly_name(user, friendly); +static void +fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Process FQY\n"); + cmdproc->last_cmd->payload_cb = fqy_cmd_post; +} - list_id = msn_get_list_id(list); +static void +rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ +#if 0 + MsnTransaction *trans; + char * payload; +#endif - if (cmd->param_count >= 6) - group_id = atoi(cmd->params[5]); - else - group_id = -1; + purple_debug_info("MaYuan","Process RML\n"); +#if 0 + trans = msn_transaction_new(cmdproc, "RML",""); - msn_got_add_user(session, user, list_id, group_id); - msn_user_update(user); + msn_transaction_set_payload(trans, payload, strlen(payload)); + + msn_cmdproc_send_trans(cmdproc, trans); +#endif } static void @@ -567,7 +890,7 @@ group_name = purple_url_decode(cmd->params[2]); - msn_group_new(session->userlist, group_id, group_name); + msn_group_new(session->userlist, cmd->params[3], group_name); /* There is a user that must me moved to this group */ if (cmd->trans->data) @@ -642,6 +965,7 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; + int wlmclient; const char *state, *passport, *friendly; session = cmdproc->session; @@ -650,7 +974,9 @@ state = cmd->params[1]; passport = cmd->params[2]; - friendly = purple_url_decode(cmd->params[3]); + /*if a contact is actually on the WLM part or the yahoo part*/ + wlmclient = atoi(cmd->params[3]); + friendly = purple_url_decode(cmd->params[4]); user = msn_userlist_find_user(session->userlist, passport); @@ -658,9 +984,9 @@ msn_user_set_friendly_name(user, friendly); - if (session->protocol_ver >= 9 && cmd->param_count == 6) + if (session->protocol_ver >= 9 && cmd->param_count == 8) { - msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); + msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6])); msn_user_set_object(user, msnobj); } @@ -692,6 +1018,7 @@ MsnUser *user; MsnObject *msnobj; int clientid; + int wlmclient; const char *state, *passport, *friendly, *old_friendly; session = cmdproc->session; @@ -700,7 +1027,8 @@ state = cmd->params[0]; passport = cmd->params[1]; - friendly = purple_url_decode(cmd->params[2]); + wlmclient = atoi(cmd->params[2]); + friendly = purple_url_decode(cmd->params[3]); user = msn_userlist_find_user(session->userlist, passport); @@ -713,10 +1041,9 @@ if (session->protocol_ver >= 9) { - if (cmd->param_count == 5) + if (cmd->param_count == 7) { - msnobj = - msn_object_new_from_string(purple_url_decode(cmd->params[4])); + msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); msn_user_set_object(user, msnobj); } else @@ -725,7 +1052,7 @@ } } - clientid = atoi(cmd->params[3]); + clientid = atoi(cmd->params[4]); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE); msn_user_set_state(user, state); @@ -821,6 +1148,12 @@ msn_user_set_work_phone(session->user, NULL); else if (!strcmp(type, "PHM")) msn_user_set_mobile_phone(session->user, NULL); + else if (!strcmp(type, "MFM")) { + type = cmd->params[1]; + purple_connection_set_display_name( + purple_account_get_connection(session->account), + purple_url_decode(cmd->params[2])); + } } } @@ -828,11 +1161,10 @@ reg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - int group_id; - const char *group_name; + const char *group_id, *group_name; session = cmdproc->session; - group_id = atoi(cmd->params[2]); + group_id = cmd->params[2]; group_name = purple_url_decode(cmd->params[3]); msn_userlist_rename_group_id(session->userlist, group_id, group_name); @@ -841,12 +1173,12 @@ static void reg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { - int group_id; + const char * group_id; char **params; params = g_strsplit(trans->params, " ", 0); - group_id = atoi(params[0]); + group_id = params[0]; group_error_helper(cmdproc->session, _("Unable to rename group"), group_id, error); @@ -858,10 +1190,8 @@ { MsnSession *session; MsnUser *user; - const char *list; - const char *passport; + const char *group_id, *list, *passport; MsnListId list_id; - int group_id; session = cmdproc->session; list = cmd->params[1]; @@ -873,9 +1203,9 @@ list_id = msn_get_list_id(list); if (cmd->param_count == 5) - group_id = atoi(cmd->params[4]); + group_id = cmd->params[4]; else - group_id = -1; + group_id = NULL; msn_got_rem_user(session, user, list_id, group_id); msn_user_update(user); @@ -885,10 +1215,10 @@ rmg_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; - int group_id; + const char *group_id; session = cmdproc->session; - group_id = atoi(cmd->params[2]); + group_id = cmd->params[2]; msn_userlist_remove_group_id(session->userlist, group_id); } @@ -896,12 +1226,12 @@ static void rmg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { - int group_id; + const char *group_id; char **params; params = g_strsplit(trans->params, " ", 0); - group_id = atoi(params[0]); + group_id = params[0]; group_error_helper(cmdproc->session, _("Unable to delete group"), group_id, error); @@ -1146,6 +1476,86 @@ g_free(host); } +static void +gcf_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + /*get the payload content*/ + purple_debug_info("MaYuan","GCF{%s}\n",cmd->payload); +} + +static void +gcf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Processing GCF... \n"); + cmdproc->last_cmd->payload_cb = gcf_cmd_post; + return; +} + +static void +sbs_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Processing SBS... \n"); + if(cmd->payload_len == 0){ + return; + } + /*get the payload content*/ +} + +/* + * Get the UBX's PSM info + * Post it to the User status + * Thanks for Chris 's code + */ +static void +ubx_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + MsnSession *session; + PurpleAccount *account; + PurpleConnection *gc; + MsnUser *user; + const char *passport; + char *psm_str, *currentmedia_str; + + /*get the payload content*/ +// purple_debug_info("MaYuan","UBX {%s} payload{%s}\n",cmd->params[0], cmd->payload); + + session = cmdproc->session; + account = session->account; + gc = purple_account_get_connection(account); + + passport = cmd->params[0]; + user = msn_userlist_find_user(session->userlist, passport); + + psm_str = msn_get_psm(cmd->payload,len); + currentmedia_str = msn_parse_currentmedia( + msn_get_currentmedia(cmd->payload, len)); + + msn_user_set_statusline(user, psm_str); + msn_user_set_currentmedia(user, currentmedia_str); + msn_user_update(user); + + g_free(psm_str); + g_free(currentmedia_str); +} + +static void +ubx_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","UBX... \n"); + if(cmd->payload_len == 0){ + return; + } + cmdproc->last_cmd->payload_cb = ubx_cmd_post; +} + +static void +uux_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","UUX... \n"); +} + /************************************************************************** * Message Types **************************************************************************/ @@ -1155,7 +1565,9 @@ { MsnSession *session; const char *value; + const char *clLastChange; + purple_debug_info("MaYuan","profile_msg... \n"); session = cmdproc->session; if (strcmp(msg->remote_user, "Hotmail")) @@ -1187,10 +1599,27 @@ } if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL) + { session->passport_info.client_port = ntohs(atoi(value)); + } if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL) session->passport_info.sl = atol(value); + + /*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, clLastChange); +#else + /* always get the full list? */ + msn_get_contact_list(session->contact, NULL); +#endif +#if 0 + msn_contact_connect(session->contact); +#endif } static void @@ -1246,6 +1675,85 @@ g_hash_table_destroy(table); } +/*offline Message notification process*/ +static void +initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + MsnSession *session; + PurpleConnection *gc; + GHashTable *table; + const char *mdata, *unread; + + session = cmdproc->session; + gc = session->account->gc; + + if (strcmp(msg->remote_user, "Hotmail")) + /* 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"); + + if (mdata != NULL) + msn_parse_oim_msg(session->oim, mdata); + + if (g_hash_table_lookup(table, "Inbox-URL") == NULL) + { + g_hash_table_destroy(table); + return; + } + + if (session->passport_info.file == NULL) + { + MsnTransaction *trans; + trans = msn_transaction_new(cmdproc, "URL", "%s", "INBOX"); + msn_transaction_queue_cmd(trans, msg->cmd); + + msn_cmdproc_send_trans(cmdproc, trans); + + g_hash_table_destroy(table); + return; + } + + if (!purple_account_get_check_mail(session->account)) + { + g_hash_table_destroy(table); + return; + } + + unread = g_hash_table_lookup(table, "Inbox-Unread"); + + if (unread != NULL) + { + int count = atoi(unread); + + if (count > 0) + { + const char *passport; + const char *url; + + passport = msn_user_get_passport(session->user); + url = session->passport_info.file; + + purple_notify_emails(gc, atoi(unread), FALSE, NULL, NULL, + &passport, &url, NULL, NULL); + } + } + + g_hash_table_destroy(table); +} + +/*offline Message Notification*/ +static void +delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ +} + static void email_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { @@ -1349,46 +1857,62 @@ void msn_notification_add_buddy(MsnNotification *notification, const char *list, const char *who, const char *store_name, - int group_id) + const char *group_id) { MsnCmdProc *cmdproc; + xmlnode *adl_node; + char *payload; + int payload_len; + cmdproc = notification->servconn->cmdproc; - if (group_id < 0 && !strcmp(list, "FL")) - group_id = 0; + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + + msn_add_contact_xml(notification->session,adl_node,who,1,MSN_USER_TYPE_PASSPORT); - if (group_id >= 0) + payload = xmlnode_to_str(adl_node,&payload_len); + xmlnode_free(adl_node); + if (msn_user_is_yahoo(notification->session->account,who)) { - msn_cmdproc_send(cmdproc, "ADD", "%s %s %s %d", - list, who, store_name, group_id); + msn_notification_fqy_yahoo(notification->session, who); } else { - msn_cmdproc_send(cmdproc, "ADD", "%s %s %s", list, who, store_name); + msn_notification_post_adl(notification->servconn->cmdproc, + payload,payload_len); } } void msn_notification_rem_buddy(MsnNotification *notification, const char *list, - const char *who, int group_id) + const char *who, const char *group_id) { MsnCmdProc *cmdproc; + MsnTransaction *trans; + xmlnode *rml_node; + char *payload; + int payload_len; + cmdproc = notification->servconn->cmdproc; - if (group_id >= 0) - { - msn_cmdproc_send(cmdproc, "REM", "%s %s %d", list, who, group_id); - } - else - { - msn_cmdproc_send(cmdproc, "REM", "%s %s", list, who); - } + rml_node = xmlnode_new("ml"); + rml_node->child = NULL; + + msn_add_contact_xml(notification->session,rml_node,who,1,MSN_USER_TYPE_PASSPORT); + + payload = xmlnode_to_str(rml_node,&payload_len); + xmlnode_free(rml_node); + + purple_debug_info("MaYuan","RML{%s}\n",payload); + trans = msn_transaction_new(cmdproc, "RML","%d",strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); } /************************************************************************** * Init **************************************************************************/ - void msn_notification_init(void) { @@ -1399,18 +1923,18 @@ /* 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, "ADD", "ADD", add_cmd); - msn_table_add_cmd(cbs_table, "ADD", "ILN", iln_cmd); + msn_table_add_cmd(cbs_table, "ADL", "ILN", iln_cmd); msn_table_add_cmd(cbs_table, "REM", "REM", rem_cmd); 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); 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, "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); @@ -1419,11 +1943,15 @@ /* Asynchronous */ msn_table_add_cmd(cbs_table, NULL, "IPG", ipg_cmd); msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd); + msn_table_add_cmd(cbs_table, NULL, "GCF", gcf_cmd); + msn_table_add_cmd(cbs_table, NULL, "SBS", sbs_cmd); msn_table_add_cmd(cbs_table, NULL, "NOT", not_cmd); msn_table_add_cmd(cbs_table, NULL, "CHL", chl_cmd); - msn_table_add_cmd(cbs_table, NULL, "REM", rem_cmd); - msn_table_add_cmd(cbs_table, NULL, "ADD", add_cmd); + msn_table_add_cmd(cbs_table, NULL, "RML", rml_cmd); + msn_table_add_cmd(cbs_table, NULL, "ADL", adl_cmd); + msn_table_add_cmd(cbs_table, NULL, "FQY", fqy_cmd); msn_table_add_cmd(cbs_table, NULL, "QRY", NULL); msn_table_add_cmd(cbs_table, NULL, "QNG", qng_cmd); @@ -1433,11 +1961,15 @@ msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); msn_table_add_cmd(cbs_table, NULL, "RNG", rng_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBX", ubx_cmd); + msn_table_add_cmd(cbs_table, NULL, "UUX", uux_cmd); + msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd); msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd); msn_table_add_error(cbs_table, "ADD", add_error); + 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); */ @@ -1446,12 +1978,24 @@ msn_table_add_msg_type(cbs_table, "text/x-msmsgsprofile", profile_msg); + /*initial OIM notification*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsinitialmdatanotification", + initial_mdata_msg); + /*OIM notification when user online*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsoimnotification", + initial_mdata_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgsinitialemailnotification", initial_email_msg); msn_table_add_msg_type(cbs_table, "text/x-msmsgsemailnotification", email_msg); + /*delete an offline Message notification*/ + msn_table_add_msg_type(cbs_table, + "text/x-msmsgsactivemailnotification", + delete_oim_msg); msn_table_add_msg_type(cbs_table, "application/x-msmsgssystemmessage", system_msg); @@ -1462,3 +2006,4 @@ { msn_table_destroy(cbs_table); } + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/notification.h --- a/libpurple/protocols/msn/notification.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/notification.h Fri Jun 22 03:55:10 2007 +0000 @@ -24,6 +24,14 @@ #ifndef _MSN_NOTIFICATION_H_ #define _MSN_NOTIFICATION_H_ +/*MSN protocol challenge info*/ +/*MSNP13 challenge*/ +#define MSNP13_WLM_PRODUCT_KEY "O4BG@C7BWLYQX?5G" +#define MSNP13_WLM_PRODUCT_ID "PROD01065C%ZFN6F" + +#define MSNP10_PRODUCT_KEY "VT6PX?UQTM4WM%YR" +#define MSNP10_PRODUCT_ID "PROD0038W!61ZTF9" + typedef struct _MsnNotification MsnNotification; #include "session.h" @@ -40,21 +48,23 @@ }; #include "state.h" +void uum_send_msg(MsnSession *session,MsnMessage *msg); void msn_notification_end(void); void msn_notification_init(void); void msn_notification_add_buddy(MsnNotification *notification, const char *list, const char *who, - const char *store_name, int group_id); + const char *store_name, const char *group_id); void msn_notification_rem_buddy(MsnNotification *notification, const char *list, const char *who, - int group_id); + const char *group_id); MsnNotification *msn_notification_new(MsnSession *session); void msn_notification_destroy(MsnNotification *notification); gboolean msn_notification_connect(MsnNotification *notification, const char *host, int port); void msn_notification_disconnect(MsnNotification *notification); +void msn_notification_dump_contact(MsnSession *session); /** * Closes a notification. diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/oim.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.c Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,632 @@ +/** + * @file oim.c + * get and send MSN offline Instant Message via SOAP request + * Author + * MaYuan + * 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 "msn.h" +#include "soap.h" +#include "oim.h" +#include "msnutils.h" + +/*Local Function Prototype*/ +static void msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid); +static MsnOimSendReq *msn_oim_new_send_req(const char *from_member, + const char *friendname, + const char* to_member, + gint send_seq, + const char *msg); +static void msn_oim_retrieve_connect_init(MsnSoapConn *soapconn); +static void msn_oim_send_connect_init(MsnSoapConn *soapconn); +static void msn_oim_free_send_req(MsnOimSendReq *req); +static void msn_oim_report_to_user(MsnOim *oim, char *msg_str); +static void msn_oim_get_process(MsnOim *oim, char *oim_msg); +static char *msn_oim_msg_to_str(MsnOim *oim, const char *body); +static void msn_oim_send_process(MsnOim *oim, const char *body, int len); + +/*new a OIM object*/ +MsnOim * +msn_oim_new(MsnSession *session) +{ + MsnOim *oim; + + oim = g_new0(MsnOim, 1); + oim->session = session; + oim->retrieveconn = msn_soap_new(session,oim,1); + + oim->oim_list = NULL; + oim->sendconn = msn_soap_new(session,oim,1); + oim->run_id = rand_guid(); + oim->challenge = NULL; + oim->send_queue = g_queue_new(); + oim->send_seq = 1; + return oim; +} + +/*destroy the oim object*/ +void +msn_oim_destroy(MsnOim *oim) +{ + MsnOimSendReq *request; + + purple_debug_info("OIM","destroy the OIM \n"); + msn_soap_destroy(oim->retrieveconn); + msn_soap_destroy(oim->sendconn); + g_free(oim->run_id); + g_free(oim->challenge); + + while((request = g_queue_pop_head(oim->send_queue)) != NULL){ + msn_oim_free_send_req(request); + } + g_queue_free(oim->send_queue); + + g_free(oim); +} + +static MsnOimSendReq * +msn_oim_new_send_req(const char *from_member, const char*friendname, + const char* to_member, gint send_seq, + const char *msg) +{ + MsnOimSendReq *request; + + request = g_new0(MsnOimSendReq, 1); + request->from_member =g_strdup(from_member); + request->friendname = g_strdup(friendname); + request->to_member = g_strdup(to_member); + request->send_seq = send_seq; + request->oim_msg = g_strdup(msg); + return request; +} + +static void +msn_oim_free_send_req(MsnOimSendReq *req) +{ + g_return_if_fail(req != NULL); + + g_free(req->from_member); + g_free(req->friendname); + g_free(req->to_member); + g_free(req->oim_msg); + + g_free(req); +} + +/**************************************** + * OIM send SOAP request + * **************************************/ +/*encode the message to OIM Message Format*/ +static char * +msn_oim_msg_to_str(MsnOim *oim, const char *body) +{ + char *oim_body,*oim_base64; + + purple_debug_info("MaYuan","encode OIM Message...\n"); + oim_base64 = purple_base64_encode((const guchar *)body, strlen(body)); + purple_debug_info("MaYuan","encoded base64 body:{%s}\n",oim_base64); + oim_body = g_strdup_printf(MSN_OIM_MSG_TEMPLATE, + oim->run_id,oim->send_seq,oim_base64); + + return oim_body; +} + +/*oim SOAP server login error*/ +static void +msn_oim_send_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +{ + MsnSoapConn *soapconn = data; + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + + msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); +} + +/*msn oim SOAP server connect process*/ +static void +msn_oim_send_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnSession * session; + MsnOim *oim; + + oim = soapconn->parent; + g_return_if_fail(oim != NULL); + + session = oim->session; + g_return_if_fail(session != NULL); +} + +/* + * Process the send return SOAP string + * If got SOAP Fault,get the lock key,and resend it. + */ +static void +msn_oim_send_process(MsnOim *oim, const char *body, int len) +{ + xmlnode *responseNode, *bodyNode; + xmlnode *faultNode, *faultCodeNode, *faultstringNode; + xmlnode *detailNode, *challengeNode; + char *faultCodeStr, *faultstring; + + responseNode = xmlnode_from_str(body,len); + g_return_if_fail(responseNode != NULL); + bodyNode = xmlnode_get_child(responseNode,"Body"); + faultNode = xmlnode_get_child(bodyNode,"Fault"); + if(faultNode == NULL){ + /*Send OK! return*/ + MsnOimSendReq *request; + + purple_debug_info("MaYuan","send OIM OK!"); + xmlnode_free(responseNode); + request = g_queue_pop_head(oim->send_queue); + msn_oim_free_send_req(request); + /*send next buffered Offline Message*/ + msn_soap_post(oim->sendconn,NULL,msn_oim_send_connect_init); + return; + } + /*get the challenge,and repost it*/ + faultCodeNode = xmlnode_get_child(faultNode,"faultcode"); + if(faultCodeNode == NULL){ + purple_debug_info("MaYuan","faultcode Node is NULL\n"); + goto oim_send_process_fail; + } + faultCodeStr = xmlnode_get_data(faultCodeNode); + purple_debug_info("MaYuan","fault code:{%s}\n",faultCodeStr); + + if(!strcmp(faultCodeStr,"q0:AuthenticationFailed")){ + /*other Fault Reason?*/ + goto oim_send_process_fail; + } + + faultstringNode = xmlnode_get_child(faultNode,"faultstring"); + faultstring = xmlnode_get_data(faultstringNode); + purple_debug_info("MaYuan","fault string :{%s}\n",faultstring); + + /* lock key fault reason, + * compute the challenge and resend it + */ + detailNode = xmlnode_get_child(faultNode, "detail"); + if(detailNode == NULL){ + goto oim_send_process_fail; + } + challengeNode = xmlnode_get_child(detailNode,"LockKeyChallenge"); + if (challengeNode == NULL) { + goto oim_send_process_fail; + } + + g_free(oim->challenge); + oim->challenge = xmlnode_get_data(challengeNode); + purple_debug_info("MaYuan","lockkey:{%s}\n",oim->challenge); + + /*repost the send*/ + purple_debug_info("MaYuan","prepare to repost the send...\n"); + msn_oim_send_msg(oim); + +oim_send_process_fail: + xmlnode_free(responseNode); + return ; +} + +static void +msn_oim_send_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + MsnSession *session = soapconn->session; + MsnOim * oim; + + g_return_if_fail(session != NULL); + oim = soapconn->session->oim; + g_return_if_fail(oim != NULL); + + purple_debug_info("MaYuan","read buffer:{%s}\n",soapconn->body); + msn_oim_send_process(oim,soapconn->body,soapconn->body_len); +} + +static void +msn_oim_send_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + soapconn->read_cb = msn_oim_send_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +void +msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, + const char* friendname, const char *tomember, + const char * msg) +{ + MsnOimSendReq *request; + + g_return_if_fail(oim != NULL); + + request = msn_oim_new_send_req(membername,friendname,tomember,oim->send_seq,msg); + g_queue_push_tail(oim->send_queue,request); +} + +/*post send single message request to oim server*/ +void +msn_oim_send_msg(MsnOim *oim) +{ + MsnSoapReq *soap_request; + MsnOimSendReq *oim_request; + char *soap_body,*mspauth; + char *msg_body; + char buf[33]; + + g_return_if_fail(oim != NULL); + oim_request = g_queue_pop_head(oim->send_queue); + g_return_if_fail(oim_request != NULL); + + purple_debug_info("MaYuan","send single OIM Message\n"); + mspauth = g_strdup_printf("t=%s&p=%s", + oim->session->passport_info.t, + oim->session->passport_info.p + ); + g_queue_push_head(oim->send_queue,oim_request); + + /* if we got the challenge lock key, we compute it + * else we go for the SOAP fault and resend it. + */ + if(oim->challenge != NULL){ + msn_handle_chl(oim->challenge, buf); + }else{ + purple_debug_info("MaYuan","no lock key challenge,wait for SOAP Fault and Resend\n"); + buf[0]='\0'; + } + purple_debug_info("MaYuan","get the lock key challenge {%s}\n",buf); + + msg_body = msn_oim_msg_to_str(oim, oim_request->oim_msg); + soap_body = g_strdup_printf(MSN_OIM_SEND_TEMPLATE, + oim_request->from_member, + oim_request->friendname, + oim_request->to_member, + mspauth, + MSNP13_WLM_PRODUCT_ID, + buf, + oim_request->send_seq, + msg_body + ); + soap_request = msn_soap_request_new(MSN_OIM_SEND_HOST, + MSN_OIM_SEND_URL,MSN_OIM_SEND_SOAP_ACTION, + soap_body, + msn_oim_send_read_cb, + msn_oim_send_written_cb); + g_free(mspauth); + g_free(msg_body); + g_free(soap_body); + + /*increase the offline Sequence control*/ + if(oim->challenge != NULL){ + oim->send_seq++; + } + msn_soap_post(oim->sendconn,soap_request,msn_oim_send_connect_init); +} + +/**************************************** + * OIM delete SOAP request + * **************************************/ +static void +msn_oim_delete_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + purple_debug_info("MaYuan","OIM delete read buffer:{%s}\n",soapconn->body); + + msn_soap_free_read_buf(soapconn); + /*get next single Offline Message*/ + msn_soap_post(soapconn,NULL,msn_oim_retrieve_connect_init); +} + +static void +msn_oim_delete_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + soapconn->read_cb = msn_oim_delete_read_cb; +} + +/*Post to get the Offline Instant Message*/ +static void +msn_oim_post_delete_msg(MsnOim *oim,const char *msgid) +{ + MsnSoapReq *soap_request; + const char *soap_body,*t,*p; + + g_return_if_fail(oim != NULL); + g_return_if_fail(msgid != NULL); + + purple_debug_info("MaYuan","Delete single OIM Message {%s}\n",msgid); + t = oim->session->passport_info.t; + p = oim->session->passport_info.p; + + soap_body = g_strdup_printf(MSN_OIM_DEL_TEMPLATE, + t, + p, + msgid + ); + soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL,MSN_OIM_DEL_SOAP_ACTION, + soap_body, + msn_oim_delete_read_cb, + msn_oim_delete_written_cb); + msn_soap_post(oim->retrieveconn,soap_request,msn_oim_retrieve_connect_init); +} + +/**************************************** + * OIM get SOAP request + * **************************************/ +/*oim SOAP server login error*/ +static void +msn_oim_get_error_cb(PurpleSslConnection *gsc, PurpleSslErrorType error, void *data) +{ + MsnSoapConn *soapconn = data; + MsnSession *session; + + session = soapconn->session; + g_return_if_fail(session != NULL); + msn_soap_clean_unhandled_request(soapconn); + +// msn_session_set_error(session, MSN_ERROR_SERV_DOWN, _("Unable to connect to OIM server")); +} + +/*msn oim SOAP server connect process*/ +static void +msn_oim_get_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnSession * session; + MsnOim *oim; + + oim = soapconn->parent; + g_return_if_fail(oim != NULL); + + session = oim->session; + g_return_if_fail(session != NULL); + + purple_debug_info("MaYuan","oim get SOAP Server connected!\n"); +} + +/*Post the Offline Instant Message to User Conversation*/ +static void +msn_oim_report_to_user(MsnOim *oim, char *msg_str) +{ + MsnMessage *message; + char *date,*from,*decode_msg; + gsize body_len; + char **tokens; + char *start,*end; + int has_nick = 0; + char *passport_str, *passport; + char *msg_id; + time_t stamp; + + message = msn_message_new(MSN_MSG_UNKNOWN); + + msn_message_parse_payload(message, msg_str, strlen(msg_str), + MSG_OIM_LINE_DEM, MSG_OIM_BODY_DEM); + purple_debug_info("MaYuan","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," ")){ + has_nick = 1; + } + if(has_nick){ + tokens = g_strsplit(from , " " , 2); + passport_str = g_strdup(tokens[1]); + purple_debug_info("MaYuan","oim Date:{%s},nickname:{%s},tokens[1]:{%s} passport{%s}\n", + date,tokens[0],tokens[1],passport_str); + g_strfreev(tokens); + }else{ + passport_str = g_strdup(from); + purple_debug_info("MaYuan","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("MaYuan","oim Date:{%s},passport{%s}\n",date,passport); + + stamp = purple_str_to_time(date, TRUE, NULL, NULL, NULL); + + serv_got_im(oim->session->account->gc, passport, decode_msg, 0, stamp); + + /*Now get the oim message ID from the oim_list. + * and append to read list to prepare for deleting the Offline Message when sign out + */ + if(oim->oim_list != NULL){ + msg_id = oim->oim_list->data; + msn_oim_post_delete_msg(oim,msg_id); + oim->oim_list = g_list_remove(oim->oim_list, oim->oim_list->data); + g_free(msg_id); + } + + g_free(passport); +} + +/* Parse the XML data, + * prepare to report the OIM to user + */ +static void +msn_oim_get_process(MsnOim *oim, char *oim_msg) +{ + xmlnode *oimNode,*bodyNode,*responseNode,*msgNode; + char *msg_data,*msg_str; + + oimNode = xmlnode_from_str(oim_msg, strlen(oim_msg)); + bodyNode = xmlnode_get_child(oimNode,"Body"); + responseNode = xmlnode_get_child(bodyNode,"GetMessageResponse"); + msgNode = xmlnode_get_child(responseNode,"GetMessageResult"); + msg_data = xmlnode_get_data(msgNode); + msg_str = g_strdup(msg_data); + g_free(msg_data); + purple_debug_info("OIM","msg:{%s}\n",msg_str); + msn_oim_report_to_user(oim,msg_str); + + g_free(msg_str); +} + +static void +msn_oim_get_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + MsnOim * oim = soapconn->session->oim; + + purple_debug_info("MaYuan","OIM get read buffer:{%s}\n",soapconn->body); + + /*we need to process the read message!*/ + msn_oim_get_process(oim,soapconn->body); + msn_soap_free_read_buf(soapconn); + + /*get next single Offline Message*/ + msn_soap_post(soapconn,NULL,msn_oim_retrieve_connect_init); +} + +static void +msn_oim_get_written_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn * soapconn = data; + + soapconn->read_cb = msn_oim_get_read_cb; +// msn_soap_read_cb(data,source,cond); +} + +/* parse the oim XML data + * and post it to the soap server to get the Offline Message + * */ +void +msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg) +{ + xmlnode *node, *mdNode,*mNode,*ENode,*INode,*rtNode,*nNode; + char *passport,*msgid,*nickname, *unread, *rTime = NULL; + MsnSession *session = oim->session; + + node = xmlnode_from_str(xmlmsg, strlen(xmlmsg)); + + ENode = xmlnode_get_child(node, "E"); + INode = xmlnode_get_child(ENode, "IU"); + unread = xmlnode_get_data(INode); + + if (unread != NULL && purple_account_get_check_mail(session->account)) + { + int count = atoi(unread); + + if (count > 0) + { + const char *passport; + const char *url; + + passport = msn_user_get_passport(session->user); + url = session->passport_info.file; + + purple_notify_emails(session->account->gc, atoi(unread), FALSE, NULL, NULL, + &passport, &url, NULL, NULL); + } + } + + mdNode = xmlnode_get_child(node, "MD"); + if (mdNode == NULL) { + xmlnode_free(node); + return; + } + for(mNode = xmlnode_get_child(mdNode, "M"); mNode; + mNode = xmlnode_get_next_twin(mNode)){ + /*email Node*/ + ENode = xmlnode_get_child(mNode,"E"); + passport = xmlnode_get_data(ENode); + /*Index */ + INode = xmlnode_get_child(mNode,"I"); + msgid = xmlnode_get_data(INode); + /*Nickname*/ + nNode = xmlnode_get_child(mNode,"N"); + nickname = xmlnode_get_data(nNode); + /*receive time*/ + rtNode = xmlnode_get_child(mNode,"RT"); + if(rtNode != NULL) { + rTime = xmlnode_get_data(rtNode); + rtNode = NULL; + } +/* purple_debug_info("MaYuan","E:{%s},I:{%s},rTime:{%s}\n",passport,msgid,rTime); */ + + oim->oim_list = g_list_append(oim->oim_list,msgid); + msn_oim_post_single_get_msg(oim,msgid); + g_free(passport); + g_free(msgid); + g_free(rTime); + rTime = NULL; + g_free(nickname); + } + xmlnode_free(node); +} + +/*Post to get the Offline Instant Message*/ +static void +msn_oim_post_single_get_msg(MsnOim *oim,const char *msgid) +{ + MsnSoapReq *soap_request; + const char *soap_body,*t,*p; + + purple_debug_info("MaYuan","Get single OIM Message\n"); + t = oim->session->passport_info.t; + p = oim->session->passport_info.p; + + soap_body = g_strdup_printf(MSN_OIM_GET_TEMPLATE, + t, + p, + msgid + ); + soap_request = msn_soap_request_new(MSN_OIM_RETRIEVE_HOST, + MSN_OIM_RETRIEVE_URL,MSN_OIM_GET_SOAP_ACTION, + soap_body, + msn_oim_get_read_cb, + msn_oim_get_written_cb); + msn_soap_post(oim->retrieveconn,soap_request,msn_oim_retrieve_connect_init); +} + +/*msn oim retrieve server connect init */ +static void +msn_oim_retrieve_connect_init(MsnSoapConn *soapconn) +{ + purple_debug_info("MaYuan","msn_oim_connect...\n"); + msn_soap_init(soapconn,MSN_OIM_RETRIEVE_HOST,1, + msn_oim_get_connect_cb, + msn_oim_get_error_cb); +} + +/*Msn OIM Send Server Connect Init Function*/ +static void +msn_oim_send_connect_init(MsnSoapConn *sendconn) +{ + purple_debug_info("MaYuan","msn oim send connect init...\n"); + msn_soap_init(sendconn,MSN_OIM_SEND_HOST,1, + msn_oim_send_connect_cb, + msn_oim_send_error_cb); +} + +/*endof oim.c*/ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/oim.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.h Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,148 @@ +/** + * @file oim.h Header file for oim.c + * Author + * MaYuan + * 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_OIM_H_ +#define _MSN_OIM_H_ + +/*OIM Retrieve SOAP Template*/ +#define MSN_OIM_RETRIEVE_HOST "rsi.hotmail.com" +#define MSN_OIM_RETRIEVE_URL "/rsi/rsi.asmx" +#define MSN_OIM_GET_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage" + +#define MSN_OIM_GET_TEMPLATE ""\ +""\ + ""\ + ""\ + "%s"\ + "

%s

"\ + "
"\ + "
"\ + ""\ + ""\ + "%s"\ + "false"\ + ""\ + ""\ +"
" + +/*OIM Delete SOAP Template*/ +#define MSN_OIM_DEL_SOAP_ACTION "http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages" + +#define MSN_OIM_DEL_TEMPLATE ""\ +""\ + ""\ + ""\ + "%s"\ + "

%s

"\ + "
"\ + "
"\ + ""\ + ""\ + ""\ + "%s"\ + ""\ + ""\ + ""\ +"
" + +/*OIM Send SOAP Template*/ +#define MSN_OIM_MSG_TEMPLATE "MIME-Version: 1.0\n"\ + "Content-Type: text/plain; charset=UTF-8\n"\ + "Content-Transfer-Encoding: base64\n"\ + "X-OIM-Message-Type: OfflineMessage\n"\ + "X-OIM-Run-Id: {%s}\n"\ + "X-OIM-Sequence-Num: %d\n\n"\ + "%s" + +#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_TEMPLATE ""\ +""\ + ""\ + ""\ + ""\ + ""\ + ""\ + "http://messenger.msn.com"\ + "%d"\ + ""\ + ""\ + ""\ + "text"\ + "%s"\ + ""\ +"" + +typedef struct _MsnOimSendReq MsnOimSendReq; + +struct _MsnOimSendReq +{ + char *from_member; + char *friendname; + char *to_member; + char *oim_msg; + gint send_seq; +}; + +typedef struct _MsnOim MsnOim; + +struct _MsnOim +{ + MsnSession *session; + + MsnSoapConn *retrieveconn; + GList * oim_list; + + MsnSoapConn *sendconn; + char *challenge; + char *run_id; + gint send_seq; + GQueue *send_queue; +}; + +/**************************************************** + * function prototype + * **************************************************/ +MsnOim * msn_oim_new(MsnSession *session); +void msn_oim_destroy(MsnOim *oim); +void msn_oim_connect(MsnOim *oim); + +void msn_parse_oim_msg(MsnOim *oim,const char *xmlmsg); + +/*Send OIM Message*/ +void msn_oim_prep_send_msg_info(MsnOim *oim, const char *membername, + const char *friendname, const char *tomember, + const char * msg); + +void msn_oim_send_msg(MsnOim *oim); + +/*get the OIM message*/ +void msn_oim_get_msg(MsnOim *oim); + +/*report the oim message to the conversation*/ +void msn_oim_report_user(MsnOim *oim,const char *passport,char *msg); + +#endif/* _MSN_OIM_H_*/ +/*endof oim.h*/ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/servconn.c --- a/libpurple/protocols/msn/servconn.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Fri Jun 22 03:55:10 2007 +0000 @@ -166,7 +166,7 @@ **************************************************************************/ static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, const char *error_message) { MsnServConn *servconn; @@ -243,7 +243,9 @@ return TRUE; } else + { return FALSE; + } } void @@ -444,6 +446,7 @@ else { msn_cmdproc_process_cmd_text(servconn->cmdproc, cur); + servconn->payload_len = servconn->cmdproc->last_cmd->payload_len; } } while (servconn->connected && !servconn->wasted && servconn->rx_len > 0); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/session.c Fri Jun 22 03:55:10 2007 +0000 @@ -43,7 +43,9 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); - session->protocol_ver = 9; + /*if you want to chat with Yahoo Messenger*/ + //session->protocol_ver = WLM_YAHOO_PROT_VER; + session->protocol_ver = WLM_PROT_VER; session->conv_seq = 1; return session; @@ -70,6 +72,8 @@ msn_userlist_destroy(session->userlist); + g_free(session->passport_info.t); + g_free(session->passport_info.p); g_free(session->passport_info.kv); g_free(session->passport_info.sid); g_free(session->passport_info.mspauth); @@ -87,6 +91,11 @@ 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); @@ -154,6 +163,37 @@ return NULL; } +static PurpleConversation * +msn_session_get_conv(MsnSession *session,const char *passport) +{ + PurpleAccount *account; + PurpleConversation * conv; + + g_return_val_if_fail(session != NULL, NULL); + account = session->account; + + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, + passport, account); + if(conv == NULL){ + conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, passport); + } + return conv; +} + +/* put Message to User Conversation + * + * passport - the one want to talk to you + */ +void +msn_session_report_user(MsnSession *session,const char *passport,char *msg,PurpleMessageFlags flags) +{ + PurpleConversation * conv; + + if ((conv = msn_session_get_conv(session,passport)) != NULL){ + purple_conversation_write(conv, NULL, msg, flags, time(NULL)); + } +} + MsnSwitchBoard * msn_session_find_swboard_with_conv(MsnSession *session, PurpleConversation *conv) { @@ -229,13 +269,18 @@ /* The core used to use msn_add_buddy to add all buddies before * being logged in. This no longer happens, so we manually iterate - * over the whole buddy list to identify sync issues. */ - - for (gnode = purple_blist_get_root(); gnode; gnode = gnode->next) { + * over the whole buddy list to identify sync issues. + */ + for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) { PurpleGroup *group = (PurpleGroup *)gnode; - const char *group_name = group->name; + const char *group_name; if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue; + group_name = group->name; + if(!g_strcasecmp(group_name, MSN_INDIVIDUALS_GROUP_NAME) + || !g_strcasecmp(group_name,MSN_NON_IM_GROUP_NAME)){ + continue; + } for(cnode = gnode->child; cnode; cnode = cnode->next) { if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue; @@ -252,21 +297,26 @@ if ((remote_user != NULL) && (remote_user->list_op & MSN_LIST_FL_OP)) { - int group_id; + const char *group_id; GList *l; + purple_debug_info("MaYuan","remote user:{%s}\n",b->name); group_id = msn_userlist_find_group_id(remote_user->userlist, group_name); + if(group_id == NULL){ + continue; + } + purple_debug_info("MaYuan","group_id:{%s}\n",group_id); for (l = remote_user->group_ids; l != NULL; l = l->next) { - if (group_id == GPOINTER_TO_INT(l->data)) + purple_debug_info("MaYuan","l->data:{%s}\n",l->data); + if (!g_strcasecmp(group_id ,l->data)) { found = TRUE; break; } } - } if (!found) @@ -419,3 +469,4 @@ msn_cmdproc_send(session->notification->cmdproc, "URL", "%s", "INBOX"); } } + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/session.h --- a/libpurple/protocols/msn/session.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/session.h Fri Jun 22 03:55:10 2007 +0000 @@ -38,6 +38,8 @@ #include "cmdproc.h" #include "nexus.h" #include "httpconn.h" +#include "contact.h" +#include "oim.h" #include "userlist.h" #include "sync.h" @@ -94,6 +96,8 @@ MsnNotification *notification; MsnNexus *nexus; + MsnContact *contact; + MsnOim *oim; MsnSync *sync; MsnUserList *userlist; @@ -105,8 +109,15 @@ int conv_seq; /**< The current conversation sequence number. */ + /*psm info*/ + char *psm; + struct { + /*t and p, get via USR TWN*/ + char *t; + char *p; + char *kv; char *sid; char *mspauth; @@ -114,7 +125,6 @@ char *file; char *client_ip; int client_port; - } passport_info; }; @@ -224,4 +234,8 @@ */ void msn_session_finish_login(MsnSession *session); +/*post message to User*/ +void msn_session_report_user(MsnSession *session,const char *passport, + char *msg,PurpleMessageFlags flags); + #endif /* _MSN_SESSION_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Fri Jun 22 03:55:10 2007 +0000 @@ -33,6 +33,8 @@ /* ms to delay between sending buddy icon requests to the server. */ #define BUDDY_ICON_DELAY 20000 +/*debug SLP*/ +#define MSN_DEBUG_UD static void send_ok(MsnSlpCall *slpcall, const char *branch, const char *type, const char *content); @@ -777,11 +779,11 @@ if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) { /* 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 - */ + instead of all at once, calling write multiple times and + close once at the very end + */ purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); - purple_conv_custom_smiley_close(conv, slpcall->data_info); + purple_conv_custom_smiley_close(conv, slpcall->data_info ); } #ifdef MSN_DEBUG_UD purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/slpcall.c --- a/libpurple/protocols/msn/slpcall.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/slpcall.c Fri Jun 22 03:55:10 2007 +0000 @@ -22,6 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "msn.h" +#include "msnutils.h" #include "slpcall.h" #include "slpsession.h" @@ -30,24 +31,6 @@ /* #define MSN_DEBUG_SLPCALL */ /************************************************************************** - * Util - **************************************************************************/ - -static char * -rand_guid() -{ - return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111, - rand() % 0xAAFF + 0x1111); -} - -/************************************************************************** * Main **************************************************************************/ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Fri Jun 22 03:55:10 2007 +0000 @@ -112,8 +112,10 @@ if (slplink->remote_user != NULL) g_free(slplink->remote_user); +#if 0 if (slplink->directconn != NULL) msn_directconn_destroy(slplink->directconn); +#endif while (slplink->slp_calls != NULL) msn_slp_call_destroy(slplink->slp_calls->data); @@ -244,11 +246,13 @@ void msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg) { +#if 0 if (slplink->directconn != NULL) { msn_directconn_send_msg(slplink->directconn, msg); } else +#endif { if (slplink->swboard == NULL) { @@ -634,9 +638,10 @@ MsnDirectConn *directconn; directconn = slplink->directconn; - +#if 0 if (!directconn->acked) msn_directconn_send_handshake(directconn); +#endif } else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/soap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.c Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,634 @@ +/** + * @file soap.c + * SOAP connection related process + * Author + * MaYuan + * 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 "msn.h" +#include "soap.h" + +/*define this Macro to debug soap server action*/ +#undef MSN_SOAP_DEBUG + +/*local function prototype*/ +void msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step); + +/*setup the soap process step*/ +void +msn_soap_set_process_step(MsnSoapConn *soapconn, MsnSoapStep step) +{ + soapconn->step = step; +} + +//msn_soap_new(MsnSession *session,gpointer data,int sslconn) +/*new a soap connection*/ +MsnSoapConn * +msn_soap_new(MsnSession *session,gpointer data,int sslconn) +{ + MsnSoapConn *soapconn; + + soapconn = g_new0(MsnSoapConn, 1); + soapconn->session = session; + soapconn->parent = data; + soapconn->ssl_conn = sslconn; + + soapconn->gsc = NULL; + soapconn->input_handler = -1; + soapconn->output_handler = -1; + + msn_soap_set_process_step(soapconn,MSN_SOAP_UNCONNECTED); + soapconn->soap_queue = g_queue_new(); + return soapconn; +} + +/*ssl soap connect callback*/ +void +msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, + PurpleInputCondition cond) +{ + MsnSoapConn * soapconn; + MsnSession *session; + + purple_debug_info("MaYuan","Soap connection connected!\n"); + soapconn = data; + g_return_if_fail(soapconn != NULL); + + session = soapconn->session; + g_return_if_fail(session != NULL); + + soapconn->gsc = gsc; + + /*connection callback*/ + if(soapconn->connect_cb != NULL){ + soapconn->connect_cb(data,gsc,cond); + } + + msn_soap_set_process_step(soapconn,MSN_SOAP_CONNECTED); + /*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_info("MaYuan","Soap connection error!\n"); + msn_soap_set_process_step(soapconn, MSN_SOAP_UNCONNECTED); + + /*error callback*/ + if(soapconn->error_cb != NULL){ + soapconn->error_cb(gsc,error,data); + } +} + +/*init the soap connection*/ +void +msn_soap_init(MsnSoapConn *soapconn,char * host,int ssl, + PurpleSslInputFunction connect_cb, + PurpleSslErrorFunction error_cb) +{ + purple_debug_info("MaYuan","msn_soap_init...\n"); + soapconn->login_host = g_strdup(host); + soapconn->ssl_conn = ssl; + soapconn->connect_cb = connect_cb; + soapconn->error_cb = error_cb; +} + +/*connect the soap connection*/ +void +msn_soap_connect(MsnSoapConn *soapconn) +{ + 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{ + } + msn_soap_set_process_step(soapconn,MSN_SOAP_CONNECTING); +} + +/*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); +} + +/*clean the unhandled SOAP request*/ +void +msn_soap_clean_unhandled_request(MsnSoapConn *soapconn) +{ + MsnSoapReq *request; + + g_return_if_fail(soapconn != NULL); + + while ((request = g_queue_pop_head(soapconn->soap_queue)) != NULL){ + msn_soap_request_free(request); + } +} + +/*destroy the soap connection*/ +void +msn_soap_destroy(MsnSoapConn *soapconn) +{ + if(soapconn->login_host) + g_free(soapconn->login_host); + + if(soapconn->login_path) + g_free(soapconn->login_path); + + /*remove the write handler*/ + if (soapconn->output_handler > 0){ + purple_input_remove(soapconn->output_handler); + } + /*remove the read handler*/ + if (soapconn->input_handler > 0){ + purple_input_remove(soapconn->input_handler); + } + 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_request(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]; + +// requested_len = (soapconn->need_to_read > 0) ? soapconn->need_to_read : MSN_SOAP_READ_BUFF_SIZE; + requested_len = MSN_SOAP_READ_BUFF_SIZE; + if(soapconn->ssl_conn){ + len = purple_ssl_read(soapconn->gsc, temp_buf,requested_len); + }else{ + len = read(soapconn->fd, temp_buf,requested_len); + } + if(len >0){ + soapconn->read_buf = g_realloc(soapconn->read_buf, + soapconn->read_len + len + 1); + memcpy(soapconn->read_buf + soapconn->read_len, temp_buf, len); + soapconn->read_len += len; + soapconn->read_buf[soapconn->read_len] = '\0'; + } +#ifdef MSN_SOAP_DEBUG + purple_debug_info("MaYuan","++soap ssl read:{%d}\n",len); + purple_debug_info("MaYuan","nexus ssl read:{%s}\n",soapconn->read_buf); +#endif + return len; +} + +/*read the whole SOAP server response*/ +void +msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond) +{ + MsnSoapConn *soapconn = data; + MsnSession *session; + int len; + char * body_start,*body_len; + char *length_start,*length_end; + +// purple_debug_misc("MaYuan", "soap read cb\n"); + session = soapconn->session; + g_return_if_fail(session != NULL); + + if (soapconn->input_handler == -1){ + soapconn->input_handler = purple_input_add(soapconn->gsc->fd, + PURPLE_INPUT_READ, msn_soap_read_cb, soapconn); + } + + /*read the request header*/ + len = msn_soap_read(soapconn); + if (len < 0 && errno == EAGAIN){ + return; + }else if (len < 0) { + purple_debug_error("msn", "read Error!len:%d\n",len); + purple_input_remove(soapconn->input_handler); + soapconn->input_handler = -1; + g_free(soapconn->read_buf); + soapconn->read_buf = NULL; + soapconn->read_len = 0; + /* TODO: error handling */ + return; + } + + if(soapconn->read_buf == NULL){ + return; + } + + if (strstr(soapconn->read_buf, "HTTP/1.1 302") != NULL) + { + /* Redirect. */ + char *location, *c; + + purple_debug_error("MaYuan", "soap redirect\n"); + location = strstr(soapconn->read_buf, "Location: "); + if (location == NULL) + { + msn_soap_free_read_buf(soapconn); + + return; + } + location = strchr(location, ' ') + 1; + + if ((c = strchr(location, '\r')) != NULL) + *c = '\0'; + + /* 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); + + purple_ssl_connect(session->account, soapconn->login_host, + PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, + msn_soap_error_cb, soapconn); + } + /* Another case of redirection, active on May, 2007 + See http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener#Redirect + */ + else if (strstr(soapconn->read_buf, + "psf:Redirect") != NULL) + { + char *location, *c; + + location = strstr(soapconn->read_buf, ""); + /* Omit the tag preceding the URL */ + location += strlen(""); + location = strstr(location, ":/"); + if (location == NULL) + { + msn_soap_free_read_buf(soapconn); + return; + } + + location += strlen("://"); /* Skip http:// or https:// */ + + if ( (c = strstr(location, "")) != NULL ) + *c = '\0'; + + 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); + + purple_ssl_connect(session->account, soapconn->login_host, + PURPLE_SSL_DEFAULT_PORT, msn_soap_connect_cb, + msn_soap_error_cb, soapconn); + } + else if (strstr(soapconn->read_buf, "HTTP/1.1 401 Unauthorized") != NULL) + { + const char *error; + + purple_debug_error("MaYuan", "soap 401\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_SERV_UNAVAILABLE, error); + } + 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"))) + { + /*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; + + // purple_debug_misc("msn", "Soap Read: {%s}\n", soapconn->read_buf); + + /* we read the content-length*/ + length_start = strstr(soapconn->read_buf, "Content-Length: "); + length_start += strlen("Content-Length: "); + length_end = strstr(length_start, "\r\n"); + body_len = g_strndup(length_start,length_end - length_start); + + /*setup the conn body */ + soapconn->body = body_start; + soapconn->body_len = atoi(body_len); +#ifdef MSN_SOAP_DEBUG + purple_debug_misc("MaYuan","SOAP Read length :%d,body len:%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; + } + g_free(body_len); + + /*remove the read handler*/ + purple_input_remove(soapconn->input_handler); + soapconn->input_handler = -1; + /* + * 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->read_cb(soapconn,source,0); + } + } + return; +} + +void +msn_soap_free_read_buf(MsnSoapConn *soapconn) +{ + if(soapconn->read_buf){ + g_free(soapconn->read_buf); + } + soapconn->read_buf = NULL; + soapconn->read_len = 0; + soapconn->need_to_read = 0; +} + +void +msn_soap_free_write_buf(MsnSoapConn *soapconn) +{ + if(soapconn->write_buf){ + g_free(soapconn->write_buf); + } + soapconn->write_buf = NULL; + soapconn->written_len = 0; +} + +/*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("MaYuan","soap buffer is NULL\n"); + purple_input_remove(soapconn->output_handler); + soapconn->output_handler = -1; + return; + } + 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!*/ + purple_input_remove(soapconn->output_handler); + soapconn->output_handler = -1; + /* TODO: notify of the error */ + return; + } + soapconn->written_len += len; + + if (soapconn->written_len < total_len) + return; + + purple_input_remove(soapconn->output_handler); + soapconn->output_handler = -1; + + /*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, source, 0); + } + /*maybe we need to read the input?*/ + msn_soap_read_cb(soapconn,source,0); +} + +/*write the buffer to SOAP connection*/ +void +msn_soap_write(MsnSoapConn * soapconn, char *write_buf, PurpleInputFunction written_cb) +{ + soapconn->write_buf = write_buf; + soapconn->written_len = 0; + soapconn->written_cb = written_cb; + + /*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, + PurpleInputFunction read_cb,PurpleInputFunction written_cb) +{ + 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->read_cb = read_cb; + request->written_cb = written_cb; + + 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; + + g_free(request); +} + +/*post the soap request queue's head request*/ +void +msn_soap_post_head_request(MsnSoapConn *soapconn) +{ + g_return_if_fail(soapconn->soap_queue != NULL); + + 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); + } + } + msn_soap_set_process_step(soapconn,MSN_SOAP_CONNECTED_IDLE); +} + +/*post the soap request , + * if not connected, Connected first. + */ +void +msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request, + MsnSoapConnectInitFunction msn_soap_init_func) +{ + if(request != NULL){ + g_queue_push_tail(soapconn->soap_queue, request); + } + if(!msn_soap_connected(soapconn)&&(soapconn->step == MSN_SOAP_UNCONNECTED) + &&(!g_queue_is_empty(soapconn->soap_queue))){ + /*not connected?and we have something to process connect it first*/ + purple_debug_info("Ma Yuan","soap is not connected!\n"); + msn_soap_init_func(soapconn); + msn_soap_connect(soapconn); + return; + } + purple_debug_info("Ma Yuan","soap connected!\n"); + + /*if connected, what we only needed to do is to queue the request, + * when SOAP request in the queue processed done, will do this command. + * we just waiting... + * If we send the request this time,error may occure + */ +#if 0 + if(soapconn->step == MSN_SOAP_CONNECTED_IDLE){ + msn_soap_post_head_request(soapconn); + } +#endif +} + +/*Post the soap request action*/ +void +msn_soap_post_request(MsnSoapConn *soapconn,MsnSoapReq *request) +{ + char * soap_head = NULL; + char * request_str = NULL; + + purple_debug_info("MaYuan","msn_soap_post_request()...\n"); + msn_soap_set_process_step(soapconn,MSN_SOAP_PROCESSING); + soap_head = 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: %d\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n\r\n", + request->login_path, + request->soap_action, + soapconn->session->passport_info.mspauth, + request->login_host, + strlen(request->body) + ); + request_str = g_strdup_printf("%s%s", soap_head,request->body); + g_free(soap_head); + +#ifdef MSN_SOAP_DEBUG + purple_debug_info("MaYuan","send to server{%s}\n",request_str); +#endif + + /*free read buffer*/ + msn_soap_free_read_buf(soapconn); + /*post it to server*/ + msn_soap_write(soapconn,request_str,request->written_cb); +} + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/soap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.h Fri Jun 22 03:55:10 2007 +0000 @@ -0,0 +1,145 @@ +/** + * @file soap.h + * header file for SOAP connection related process + * Author + * MaYuan + * 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_SOAP_H_ +#define _MSN_SOAP_H_ + +#define MSN_SOAP_READ_BUFF_SIZE 8192 + +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; + +/*MSN Https connection structure*/ +typedef struct _MsnSoapConn MsnSoapConn; + +typedef void (*MsnSoapConnectInitFunction)(MsnSoapConn *); + +struct _MsnSoapReq{ + /*request sequence*/ + int id; + + char *login_host; + char *login_path; + char *soap_action; + + char *body; + + PurpleInputFunction read_cb; + PurpleInputFunction written_cb; +}; + +struct _MsnSoapConn{ + MsnSession *session; + gpointer parent; + + char *login_host; + char *login_path; + char *soap_action; + + MsnSoapStep step; + /*ssl connection?*/ + guint ssl_conn; + /*normal connection*/ + guint fd; + /*SSL connection*/ + PurpleSslConnection *gsc; + /*ssl connection callback*/ + PurpleSslInputFunction connect_cb; + /*ssl error callback*/ + PurpleSslErrorFunction error_cb; + + /*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; + PurpleInputFunction written_cb; + + /*read buffer*/ + char *read_buf; + gsize read_len; + gsize need_to_read; + PurpleInputFunction read_cb; + + /*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, + PurpleInputFunction read_cb, + PurpleInputFunction written_cb); + +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,int sslconn); + +/*destroy */ +void msn_soap_destroy(MsnSoapConn *soapconn); + +/*init a soap conneciton */ +void msn_soap_init(MsnSoapConn *soapconn,char * host,int ssl,PurpleSslInputFunction connect_cb,PurpleSslErrorFunction 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, PurpleInputFunction written_cb); +void msn_soap_post(MsnSoapConn *soapconn,MsnSoapReq *request,MsnSoapConnectInitFunction msn_soap_init_func); + +void msn_soap_free_read_buf(MsnSoapConn *soapconn); +void msn_soap_free_write_buf(MsnSoapConn *soapconn); +void msn_soap_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond); +void msn_soap_read_cb(gpointer data, gint source, PurpleInputCondition cond); + +/*clean the unhandled request*/ +void msn_soap_clean_unhandled_request(MsnSoapConn *soapconn); + +/*check if the soap connection is connected*/ +int msn_soap_connected(MsnSoapConn *soapconn); + +#endif/*_MSN_SOAP_H_*/ + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/state.c --- a/libpurple/protocols/msn/state.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/state.c Fri Jun 22 03:55:10 2007 +0000 @@ -38,6 +38,209 @@ N_("Available") }; +/* Local Function Prototype*/ +static char *msn_build_psm(const char *psmstr,const char *mediastr, + const char *guidstr); + +/* + * WLM media PSM info build prcedure + * + * Result can like: + * \0Music\01\0{0} - {1}\0 Song Title\0Song Artist\0Song Album\0\0\ + * \0Games\01\0Playing {0}\0Game Name\0\ + * \0Office\01\0Office Message\0Office App Name\0" + */ +static char * +msn_build_psm(const char *psmstr,const char *mediastr, const char *guidstr) +{ + xmlnode *dataNode,*psmNode,*mediaNode,*guidNode; + char *result; + int length; + + dataNode = xmlnode_new("Data"); + + psmNode = xmlnode_new("PSM"); + if(psmstr != NULL){ + xmlnode_insert_data(psmNode,psmstr,strlen(psmstr)); + } + xmlnode_insert_child(dataNode,psmNode); + + mediaNode = xmlnode_new("CurrentMedia"); + if(mediastr != NULL){ + xmlnode_insert_data(psmNode,mediastr,strlen(mediastr)); + } + xmlnode_insert_child(dataNode,mediaNode); + + guidNode = xmlnode_new("MachineGuid"); + if(guidstr != NULL){ + xmlnode_insert_data(guidNode,guidstr,strlen(guidstr)); + } + xmlnode_insert_child(dataNode,guidNode); + + result = xmlnode_to_str(dataNode,&length); + return result; +} + +/* parse CurrentMedia string */ +char * +msn_parse_currentmedia(const char *cmedia) +{ + char **cmedia_array; + char *buffer=NULL, *inptr, *outptr, *tmpptr; + int length, strings, tmp; + + if((cmedia == NULL) || (*cmedia == '\0')) { + purple_debug_info("msn", "No currentmedia string\n"); + return NULL; + } + + purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia); + + cmedia_array=g_strsplit(cmedia, "\\0", 0); + + strings=1; /* Skip first empty string */ + length=5; /* Space for '\0' (1 byte) and prefix (4 bytes) */ + while(strcmp(cmedia_array[strings], "")) { + length+= strlen(cmedia_array[strings]); + strings++; + } + + if((strings>3) && (!strcmp(cmedia_array[2], "1"))) { /* Check if enabled */ + + buffer=g_malloc(length); + + inptr=cmedia_array[3]; + outptr=buffer; + + if(!strcmp(cmedia_array[1], "Music")) { + strcpy(outptr, "np. "); + outptr+=4; + }/* else if(!strcmp(cmedia_array[1], "Games")) { + } else if(!strcmp(cmedia_array[1], "Office")) { + }*/ + + while(*inptr!='\0') { + if((*inptr == '{') && (strlen(inptr) > 2) && (*(inptr+2) == '}') ) { + errno = 0; + tmp = strtol(inptr+1,&tmpptr,10); + if( (errno!=0) || (tmpptr == (inptr+1)) || + ((tmp+5)>(strings)) ) { + *outptr = *inptr; /* Conversion not successful */ + outptr++; + } else { + /* Replace {?} tag with appropriate text */ + strcpy(outptr, cmedia_array[tmp+4]); + outptr+=strlen(cmedia_array[tmp+4]); + inptr+=2; + } + } else { + *outptr = *inptr; + outptr++; + } + inptr++; + } + *outptr='\0'; + purple_debug_info("msn", "Parsed currentmedia string, result: \"%s\"\n", + buffer); + } else { + purple_debug_info("msn", "Current media marked disabled, not parsing\n"); + } + + g_strfreev(cmedia_array); + return buffer; +} + +/* get the CurrentMedia info from the XML string */ +char * +msn_get_currentmedia(char *xml_str, gsize len) +{ + xmlnode *payloadNode, *currentmediaNode; + char *currentmedia_str, *currentmedia; + + purple_debug_info("msn","msn get CurrentMedia\n"); + payloadNode = xmlnode_from_str(xml_str, len); + 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"); + g_free(payloadNode); + return NULL; + } + currentmedia_str = xmlnode_get_data(currentmediaNode); + currentmedia = g_strdup(currentmedia_str); + + g_free(currentmediaNode); + g_free(payloadNode); + + return currentmedia; +} + +/*get the PSM info from the XML string*/ +char * +msn_get_psm(char *xml_str, gsize len) +{ + xmlnode *payloadNode, *psmNode; + char *psm_str, *psm; + + purple_debug_info("Ma Yuan","msn get PSM\n"); + payloadNode = xmlnode_from_str(xml_str, len); + if (!payloadNode){ + purple_debug_error("MaYuan","PSM XML parse Error!\n"); + return NULL; + } + psmNode = xmlnode_get_child(payloadNode, "PSM"); + if (psmNode == NULL){ + purple_debug_info("Ma Yuan","No PSM status Node"); + g_free(payloadNode); + return NULL; + } + psm_str = xmlnode_get_data(psmNode); + psm = g_strdup(psm_str); + + g_free(psmNode); + g_free(payloadNode); + + return psm; +} + +/* set the MSN's PSM info,Currently Read from the status Line + * Thanks for Cris Code + */ +void +msn_set_psm(MsnSession *session) +{ + PurpleAccount *account = session->account; + PurplePresence *presence; + PurpleStatus *status; + MsnCmdProc *cmdproc; + MsnTransaction *trans; + char *payload; + const char *statusline; + + g_return_if_fail(session != NULL); + g_return_if_fail(session->notification != NULL); + + cmdproc = session->notification->cmdproc; + /*prepare PSM info*/ + if(session->psm){ + g_free(session->psm); + } + /*Get the PSM string from Purple's Status Line*/ + presence = purple_account_get_presence(account); + status = purple_presence_get_active_status(presence); + statusline = purple_status_get_attr_string(status, "message"); + session->psm = msn_build_psm(statusline, NULL, NULL); + payload = session->psm; + + purple_debug_info("MaYuan","UUX{%s}\n",payload); + trans = msn_transaction_new(cmdproc, "UUX","%d",strlen(payload)); + msn_transaction_set_payload(trans, payload, strlen(payload)); + msn_cmdproc_send_trans(cmdproc, trans); +} + void msn_change_status(MsnSession *session) { @@ -79,6 +282,7 @@ g_free(msnobj_str); } + msn_set_psm(session); } const char * diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/state.h --- a/libpurple/protocols/msn/state.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/state.h Fri Jun 22 03:55:10 2007 +0000 @@ -59,6 +59,17 @@ const char *msn_state_get_text(MsnAwayType state); +void msn_set_psm(MsnSession *session); + +/* Parse CurrentMedia string */ +char * msn_parse_currentmedia(const char *cmedia); + +/* Get the CurrentMedia info from the XML string */ +char * msn_get_currentmedia(char *xml_str,gsize len); + +/*get the PSM info from the XML string*/ +char * msn_get_psm(char *xml_str,gsize len); + MsnAwayType msn_state_from_account(PurpleAccount *account); #endif /* _MSN_STATE_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Fri Jun 22 03:55:10 2007 +0000 @@ -25,7 +25,7 @@ #include "prefs.h" #include "switchboard.h" #include "notification.h" -#include "msn-utils.h" +#include "msnutils.h" #include "error.h" @@ -534,6 +534,7 @@ payload = msn_message_gen_payload(msg, &payload_len); #ifdef MSN_DEBUG_SB + purple_debug_info("MaYuan","SB length:{%d}",payload_len); msn_message_show_readable(msg, "SB SEND", FALSE); #endif @@ -621,6 +622,7 @@ g_return_if_fail(swboard != NULL); g_return_if_fail(msg != NULL); + purple_debug_info("Ma Yuan","switchboard send msg..\n"); if (msn_switchboard_can_send(swboard)) release_msg(swboard, msg); else if (queue) @@ -727,7 +729,8 @@ msg = msn_message_new_from_cmd(cmdproc->session, cmd); - msn_message_parse_payload(msg, payload, len); + msn_message_parse_payload(msg, payload, len, + MSG_LINE_DEM,MSG_BODY_DEM); #ifdef MSN_DEBUG_SB msn_message_show_readable(msg, "SB RECV", FALSE); #endif @@ -749,6 +752,14 @@ } static void +ubm_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_misc("MaYuan","get UBM...\n"); + cmdproc->servconn->payload_len = atoi(cmd->params[4]); + cmdproc->last_cmd->payload_cb = msg_cmd_post; +} + +static void nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnMessage *msg; @@ -962,7 +973,7 @@ str = g_strdup_printf(_("%s just sent you a Nudge!"), username); g_free(username); - msn_switchboard_report_user(swboard, PURPLE_MESSAGE_SYSTEM|PURPLE_MESSAGE_NOTIFY, str); + msn_switchboard_report_user(swboard, PURPLE_MESSAGE_SYSTEM, str); g_free(str); } @@ -1093,6 +1104,8 @@ cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { int reason = MSN_SB_ERROR_UNKNOWN; + MsnMessage *msg; + MsnSwitchBoard *swboard = trans->data; if (error == 215) { @@ -1105,7 +1118,19 @@ } 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("Ma Yuan","offline msg to send:{%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, + MSN_MSG_ERROR_SB); + msn_message_unref(msg); + } cal_error_helper(trans, reason); } @@ -1149,6 +1174,7 @@ /* The conversation window was closed. */ return; + purple_debug_info("MaYuan","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); @@ -1261,6 +1287,7 @@ msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd); msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd); + msn_table_add_cmd(cbs_table, NULL, "UBM", ubm_cmd); msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd); msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd); msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/sync.c --- a/libpurple/protocols/msn/sync.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/sync.c Fri Jun 22 03:55:10 2007 +0000 @@ -90,9 +90,9 @@ { MsnSession *session = cmdproc->session; const char *name; - int group_id; + const char *group_id; - group_id = atoi(cmd->params[0]); + group_id = cmd->params[0]; name = purple_url_decode(cmd->params[1]); msn_group_new(session->userlist, group_id, name); @@ -156,10 +156,10 @@ for (c = tokens; *c != NULL; c++) { - int id; + char *id; - id = atoi(*c); - group_ids = g_slist_append(group_ids, GINT_TO_POINTER(id)); + id = *c; + group_ids = g_slist_append(group_ids, g_strdup(id)); } g_strfreev(tokens); diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/user.c --- a/libpurple/protocols/msn/user.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/user.c Fri Jun 22 03:55:10 2007 +0000 @@ -25,6 +25,7 @@ #include "user.h" #include "slp.h" +/*new a user object*/ MsnUser * msn_user_new(MsnUserList *userlist, const char *passport, const char *store_name) @@ -50,6 +51,7 @@ return user; } +/*destroy a user object*/ void msn_user_destroy(MsnUser *user) { @@ -59,7 +61,14 @@ g_hash_table_destroy(user->clientcaps); if (user->group_ids != NULL) + { + GList *l; + for (l = user->group_ids; l != NULL; l = l->next) + { + g_free(l->data); + } g_list_free(user->group_ids); + } if (user->msnobj != NULL) msn_object_destroy(user->msnobj); @@ -67,6 +76,7 @@ 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); g_free(user->phone.mobile); @@ -81,7 +91,18 @@ account = user->userlist->session->account; - if (user->status != NULL) { + if (user->statusline != NULL && user->currentmedia != NULL) { + purple_prpl_got_user_status(account, user->passport, user->status, + "message", user->statusline, + "currentmedia", user->currentmedia, NULL); + } else if (user->currentmedia != NULL) { + purple_prpl_got_user_status(account, user->passport, user->status, "currentmedia", + user->currentmedia, NULL); + } else if (user->statusline != NULL) { + //char *status = g_strdup_printf("%s - %s", user->status, user->statusline); + purple_prpl_got_user_status(account, user->passport, user->status, + "message", user->statusline, NULL); + } else if (user->status != NULL) { if (!strcmp(user->status, "offline") && user->mobile) { purple_prpl_got_user_status(account, user->passport, "offline", NULL); purple_prpl_got_user_status(account, user->passport, "mobile", NULL); @@ -142,12 +163,58 @@ } void +msn_user_set_statusline(MsnUser *user, const char *statusline) +{ + g_return_if_fail(user != NULL); + + g_free(user->statusline); + user->statusline = g_strdup(statusline); +} + +void +msn_user_set_currentmedia(MsnUser *user, const char *currentmedia) +{ + g_return_if_fail(user != NULL); + + g_free(user->currentmedia); + user->currentmedia = g_strdup(currentmedia); +} + +void msn_user_set_store_name(MsnUser *user, const char *name) { g_return_if_fail(user != NULL); - g_free(user->store_name); - user->store_name = g_strdup(name); + 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); + + g_free(user->uid); + user->uid = g_strdup(uid); +} + +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); + + user->list_op |= list_op; } void @@ -218,54 +285,97 @@ } } +/*add group id to User object*/ void -msn_user_add_group_id(MsnUser *user, int id) +msn_user_add_group_id(MsnUser *user, const char* id) { MsnUserList *userlist; PurpleAccount *account; PurpleBuddy *b; PurpleGroup *g; const char *passport; + char *group_id; const char *group_name; g_return_if_fail(user != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); - user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id)); + group_id = g_strdup(id); + user->group_ids = g_list_append(user->group_ids, group_id); userlist = user->userlist; account = userlist->session->account; passport = msn_user_get_passport(user); - group_name = msn_userlist_find_group_name(userlist, id); + 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); g = purple_find_group(group_name); - if ((id == 0) && (g == NULL)) + if ((id == NULL) && (g == NULL)) { g = purple_group_new(group_name); purple_blist_add_group(g, NULL); } b = purple_find_buddy_in_group(account, passport, g); - if (b == NULL) { b = purple_buddy_new(account, passport, NULL); - purple_blist_add_buddy(b, NULL, g, NULL); } + b->proto_data = user; + /*Update the blist Node info*/ +// purple_blist_node_set_string(&(b->node), "", ""); +} - b->proto_data = user; +/*check if the msn user is online*/ +gboolean +msn_user_is_online(PurpleAccount *account, const char *name) +{ + PurpleBuddy *buddy; + + buddy =purple_find_buddy(account,name); + return PURPLE_BUDDY_IS_ONLINE(buddy); +} + +gboolean +msn_user_is_yahoo(PurpleAccount *account, const char *name) +{ + MsnSession *session = NULL; + MsnUser *user; + PurpleConnection *gc; + + gc = purple_account_get_connection(account); + 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 (strstr(name,"@yahoo.") != NULL); } void -msn_user_remove_group_id(MsnUser *user, int id) +msn_user_remove_group_id(MsnUser *user, const char *id) { + GList *l; + g_return_if_fail(user != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); + + l = g_list_find_custom(user->group_ids, id, (GCompareFunc)strcmp); - user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id)); + if (l == NULL) + return; + + g_free(l->data); + user->group_ids = g_list_remove_link(user->group_ids, l); } void diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/user.h --- a/libpurple/protocols/msn/user.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/user.h Fri Jun 22 03:55:10 2007 +0000 @@ -31,6 +31,17 @@ #include "userlist.h" +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; + /** * A user. */ @@ -45,7 +56,12 @@ char *store_name; /**< The name stored in the server. */ char *friendly_name; /**< The friendly name. */ + char * uid; /*< User Id */ + const char *status; /**< The state of the user. */ + char *statusline; /**< The state of the user. */ + char *currentmedia; /**< The current media of the user. */ + gboolean idle; /**< The idle state of the user. */ struct @@ -65,7 +81,8 @@ GHashTable *clientcaps; /**< The client's capabilities. */ - int list_op; + MsnUserType type; /**< The user type */ + int list_op; /**< Which lists the user is in */ }; /**************************************************************************/ @@ -102,6 +119,22 @@ */ void msn_user_update(MsnUser *user); + /** + * Sets the new statusline of user. + * + * @param user The user. + * @param state The statusline string. + */ +void msn_user_set_statusline(MsnUser *user, const char *statusline); + + /** + * Sets the current media of user. + * + * @param user The user. + * @param state The statusline string. + */ +void msn_user_set_currentmedia(MsnUser *user, const char *currentmedia); + /** * Sets the new state of user. * @@ -156,7 +189,7 @@ * @param user The user. * @param id The group ID. */ -void msn_user_add_group_id(MsnUser *user, int id); +void msn_user_add_group_id(MsnUser *user, const char * id); /** * Removes the group ID from a user. @@ -164,7 +197,7 @@ * @param user The user. * @param id The group ID. */ -void msn_user_remove_group_id(MsnUser *user, int id); +void msn_user_remove_group_id(MsnUser *user, const char * id); /** * Sets the home phone number for a user. @@ -182,6 +215,9 @@ */ 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 mobile phone number for a user. * @@ -279,6 +315,21 @@ */ GHashTable *msn_user_get_client_caps(const MsnUser *user); +/** + * check to see if user is online + */ +gboolean +msn_user_is_online(PurpleAccount *account, const char *name); + +/** + * check to see if user is Yahoo User + */ +gboolean +msn_user_is_yahoo(PurpleAccount *account ,const char *name); + +void msn_user_set_op(MsnUser *user,int list_op); + /*@}*/ + #endif /* _MSN_USER_H_ */ diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Fri Jun 22 03:55:10 2007 +0000 @@ -53,10 +53,13 @@ static void msn_cancel_add_cb(MsnPermitAdd *pa) { - MsnSession *session = pa->gc->proto_data; - MsnUserList *userlist = session->userlist; + if (g_list_find(purple_connections_get_all(), pa->gc) != NULL) + { + MsnSession *session = pa->gc->proto_data; + MsnUserList *userlist = session->userlist; - msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL); + msn_userlist_add_buddy(userlist, pa->who, MSN_LIST_BL, NULL); + } g_free(pa->who); g_free(pa->friendly); @@ -76,6 +79,7 @@ purple_account_request_authorization(purple_connection_get_account(gc), passport, NULL, friendly, NULL, purple_find_buddy(purple_connection_get_account(gc), passport) != NULL, G_CALLBACK(msn_accept_add_cb), G_CALLBACK(msn_cancel_add_cb), pa); + } /************************************************************************** @@ -83,22 +87,22 @@ **************************************************************************/ static gboolean -user_is_in_group(MsnUser *user, int group_id) +user_is_in_group(MsnUser *user, const char * group_id) { if (user == NULL) return FALSE; - if (group_id < 0) + if (group_id == NULL) return FALSE; - if (g_list_find(user->group_ids, GINT_TO_POINTER(group_id))) + if (g_list_find_custom(user->group_ids, group_id, (GCompareFunc)strcmp)) return TRUE; return FALSE; } static gboolean -user_is_there(MsnUser *user, int list_id, int group_id) +user_is_there(MsnUser *user, int list_id, const char * group_id) { int list_op; @@ -112,7 +116,7 @@ if (list_id == MSN_LIST_FL) { - if (group_id >= 0) + if (group_id != NULL) return user_is_in_group(user, group_id); } @@ -151,25 +155,26 @@ msn_request_add_group(MsnUserList *userlist, const char *who, const char *old_group_name, const char *new_group_name) { + MsnSession *session; MsnCmdProc *cmdproc; - MsnTransaction *trans; MsnMoveBuddy *data; - cmdproc = userlist->session->notification->cmdproc; + session = userlist->session; + cmdproc = session->notification->cmdproc; data = g_new0(MsnMoveBuddy, 1); data->who = g_strdup(who); if (old_group_name) + { data->old_group_name = g_strdup(old_group_name); + /*delete the old group via SOAP action*/ + msn_del_group(session,old_group_name); + } - trans = msn_transaction_new(cmdproc, "ADG", "%s %d", - purple_url_encode(new_group_name), - 0); + /*add new group via SOAP action*/ + msn_add_group(session, new_group_name); - msn_transaction_set_data(trans, data); - - msn_cmdproc_send_trans(cmdproc, trans); } /************************************************************************** @@ -193,12 +198,13 @@ void msn_got_add_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id) + MsnListId list_id, const char * group_id) { PurpleAccount *account; const char *passport; const char *friendly; + purple_debug_info("MaYuan","got add user...\n"); account = session->account; passport = msn_user_get_passport(user); @@ -212,7 +218,7 @@ serv_got_alias(gc, passport, friendly); - if (group_id >= 0) + if (group_id != NULL) { msn_user_add_group_id(user, group_id); } @@ -261,7 +267,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); } } @@ -271,7 +277,7 @@ void msn_got_rem_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id) + MsnListId list_id, const char * group_id) { PurpleAccount *account; const char *passport; @@ -283,7 +289,7 @@ if (list_id == MSN_LIST_FL) { /* TODO: When is the user totally removed? */ - if (group_id >= 0) + if (group_id != NULL) { msn_user_remove_group_id(user, group_id); return; @@ -331,7 +337,6 @@ { purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n", passport); - } } @@ -355,8 +360,8 @@ GSList *c; for (c = group_ids; c != NULL; c = g_slist_next(c)) { - int group_id; - group_id = GPOINTER_TO_INT(c->data); + char *group_id; + group_id = c->data; msn_user_add_group_id(user, group_id); } @@ -391,11 +396,11 @@ if (!(list_op & (MSN_LIST_AL_OP | MSN_LIST_BL_OP))) { - got_new_entry(gc, passport, store); +// got_new_entry(gc, passport, store); } } - user->list_op = list_op; + user->list_op |= list_op; } /************************************************************************** @@ -425,18 +430,18 @@ { GList *l; + /*destroy userlist*/ for (l = userlist->users; l != NULL; l = l->next) { msn_user_destroy(l->data); } - g_list_free(userlist->users); + /*destroy group list*/ for (l = userlist->groups; l != NULL; l = l->next) { msn_group_destroy(l->data); } - g_list_free(userlist->groups); g_queue_free(userlist->buddy_icon_requests); @@ -447,6 +452,21 @@ g_free(userlist); } +MsnUser * +msn_userlist_find_add_user(MsnUserList *userlist,const char *passport,const char *userName) +{ + MsnUser *user; + + user = msn_userlist_find_user(userlist, passport); + if (user == NULL) + { + user = msn_user_new(userlist, passport, userName); + msn_userlist_add_user(userlist, user); + } + msn_user_set_store_name(user, userName); + return user; +} + void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user) { @@ -469,11 +489,13 @@ for (l = userlist->users; l != NULL; l = l->next) { 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 (!strcmp(passport, user->passport)) + if (!g_strcasecmp(passport, user->passport)){ +// purple_debug_info("MsnUserList","return:%p\n",user); return user; + } } return NULL; @@ -492,18 +514,18 @@ } MsnGroup * -msn_userlist_find_group_with_id(MsnUserList *userlist, int id) +msn_userlist_find_group_with_id(MsnUserList *userlist, const char * id) { GList *l; g_return_val_if_fail(userlist != NULL, NULL); - g_return_val_if_fail(id >= 0, NULL); + g_return_val_if_fail(id != NULL, NULL); for (l = userlist->groups; l != NULL; l = l->next) { MsnGroup *group = l->data; - if (group->id == id) + if (!g_strcasecmp(group->id,id)) return group; } @@ -522,14 +544,14 @@ { MsnGroup *group = l->data; - if ((group->name != NULL) && !g_ascii_strcasecmp(name, group->name)) + if ((group->name != NULL) && !g_strcasecmp(name, group->name)) return group; } return NULL; } -int +const char * msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name) { MsnGroup *group; @@ -539,11 +561,11 @@ if (group != NULL) return msn_group_get_id(group); else - return -1; + return NULL; } const char * -msn_userlist_find_group_name(MsnUserList *userlist, int group_id) +msn_userlist_find_group_name(MsnUserList *userlist, const char * group_id) { MsnGroup *group; @@ -556,7 +578,7 @@ } void -msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, +msn_userlist_rename_group_id(MsnUserList *userlist, const char * group_id, const char *new_name) { MsnGroup *group; @@ -568,7 +590,7 @@ } void -msn_userlist_remove_group_id(MsnUserList *userlist, int group_id) +msn_userlist_remove_group_id(MsnUserList *userlist, const char * group_id) { MsnGroup *group; @@ -586,17 +608,23 @@ const char *who, int list_id, const char *group_name) { MsnUser *user; - int group_id; + const char *group_id; const char *list; user = msn_userlist_find_user(userlist, who); - group_id = -1; + + g_return_if_fail(user != NULL); + + /*delete the contact from address book via soap action*/ + msn_delete_contact(userlist->session->contact,user->uid); + + group_id = NULL; if (group_name != NULL) { group_id = msn_userlist_find_group_id(userlist, group_name); - if (group_id < 0) + if (group_id == NULL) { /* Whoa, there is no such group. */ purple_debug_error("msn", "Group doesn't exist: %s\n", group_name); @@ -619,17 +647,19 @@ msn_notification_rem_buddy(userlist->session->notification, list, who, group_id); } +/*add buddy*/ void msn_userlist_add_buddy(MsnUserList *userlist, const char *who, int list_id, const char *group_name) { MsnUser *user; - int group_id; + const char *group_id; const char *list; const char *store_name; - group_id = -1; + purple_debug_info("MaYuan", "userlist add buddy,name:{%s},group:{%s}\n",who ,group_name); + group_id = NULL; if (!purple_email_is_valid(who)) { @@ -651,7 +681,7 @@ { group_id = msn_userlist_find_group_id(userlist, group_name); - if (group_id < 0) + if (group_id == NULL) { /* Whoa, we must add that group first. */ msn_request_add_group(userlist, who, NULL, group_name); @@ -659,7 +689,11 @@ } } - user = msn_userlist_find_user(userlist, who); + /* XXX: using _add_user here may not be correct (should add them in the + ACK to the ADL command, and we might also want to make sure the user's groups + are correct. but for now we need to make sure they exist early enough that + the ILN command doesn't screw us up */ + user = msn_userlist_find_add_user(userlist, who, who); /* First we're going to check if it's already there. */ if (user_is_there(user, list_id, group_id)) @@ -671,9 +705,15 @@ store_name = (user != NULL) ? get_store_name(user) : who; + /* XXX: see XXX above, this should really be done when we get the response from + the server */ + msn_user_set_op(user, list_id); + /* Then request the add to the server. */ list = lists[list_id]; + purple_debug_info("MaYuan", "add user:{%s} to group id {%s}\n",store_name ,group_id); + msn_add_contact(userlist->session->contact,who,group_id); msn_notification_add_buddy(userlist->session->notification, list, who, store_name, group_id); } @@ -682,11 +722,11 @@ msn_userlist_move_buddy(MsnUserList *userlist, const char *who, const char *old_group_name, const char *new_group_name) { - int new_group_id; + const char *new_group_id; new_group_id = msn_userlist_find_group_id(userlist, new_group_name); - if (new_group_id < 0) + if (new_group_id == NULL) { msn_request_add_group(userlist, who, old_group_name, new_group_name); return; @@ -695,3 +735,54 @@ msn_userlist_add_buddy(userlist, who, MSN_LIST_FL, new_group_name); msn_userlist_rem_buddy(userlist, who, MSN_LIST_FL, old_group_name); } + +/*load userlist from the Blist file cache*/ +void +msn_userlist_load(MsnSession *session) +{ + PurpleBlistNode *gnode, *cnode, *bnode; + PurpleConnection *gc = purple_account_get_connection(session->account); + GSList *l; + MsnUser * user; + + g_return_if_fail(gc != NULL); + + for (gnode = purple_get_blist()->root; gnode; gnode = gnode->next) + { + if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) + continue; + for (cnode = gnode->child; cnode; cnode = cnode->next) + { + if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) + continue; + for (bnode = cnode->child; bnode; bnode = bnode->next) + { + PurpleBuddy *b; + if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) + continue; + b = (PurpleBuddy *)bnode; + if (b->account == gc->account) + { + user = msn_userlist_find_add_user(session->userlist, + b->name,NULL); + b->proto_data = user; + msn_user_set_op(user, MSN_LIST_FL_OP); + } + } + } + } + for (l = session->account->permit; l != NULL; l = l->next) + { + user = msn_userlist_find_add_user(session->userlist, + (char *)l->data,NULL); + msn_user_set_op(user, MSN_LIST_AL_OP); + } + for (l = session->account->deny; l != NULL; l = l->next) + { + user = msn_userlist_find_add_user(session->userlist, + (char *)l->data,NULL); + msn_user_set_op(user, MSN_LIST_BL_OP); + } + +} + diff -r a573a67c80a4 -r c9bcf4f11e30 libpurple/protocols/msn/userlist.h --- a/libpurple/protocols/msn/userlist.h Thu Jun 21 18:08:48 2007 +0000 +++ b/libpurple/protocols/msn/userlist.h Fri Jun 22 03:55:10 2007 +0000 @@ -35,7 +35,8 @@ MSN_LIST_FL, MSN_LIST_AL, MSN_LIST_BL, - MSN_LIST_RL + MSN_LIST_RL, + MSN_LIST_PL } MsnListId; @@ -67,30 +68,34 @@ MsnListId msn_get_list_id(const char *list); void msn_got_add_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id); + MsnListId list_id, const char *group_id); void msn_got_rem_user(MsnSession *session, MsnUser *user, - MsnListId list_id, int group_id); + MsnListId list_id, const char *group_id); void msn_got_lst_user(MsnSession *session, MsnUser *user, int list_op, GSList *group_ids); MsnUserList *msn_userlist_new(MsnSession *session); void msn_userlist_destroy(MsnUserList *userlist); + void msn_userlist_add_user(MsnUserList *userlist, MsnUser *user); void msn_userlist_remove_user(MsnUserList *userlist, MsnUser *user); MsnUser *msn_userlist_find_user(MsnUserList *userlist, - const char *passport); + const char *passport); +MsnUser *msn_userlist_find_add_user(MsnUserList *userlist, + const char *passport,const char *userName); + void msn_userlist_add_group(MsnUserList *userlist, MsnGroup *group); void msn_userlist_remove_group(MsnUserList *userlist, MsnGroup *group); -MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, int id); +MsnGroup *msn_userlist_find_group_with_id(MsnUserList *userlist, const char *id); MsnGroup *msn_userlist_find_group_with_name(MsnUserList *userlist, const char *name); -int msn_userlist_find_group_id(MsnUserList *userlist, +const char * msn_userlist_find_group_id(MsnUserList *userlist, const char *group_name); const char *msn_userlist_find_group_name(MsnUserList *userlist, - int group_id); -void msn_userlist_rename_group_id(MsnUserList *userlist, int group_id, + const char *group_id); +void msn_userlist_rename_group_id(MsnUserList *userlist, const char *group_id, const char *new_name); -void msn_userlist_remove_group_id(MsnUserList *userlist, int group_id); +void msn_userlist_remove_group_id(MsnUserList *userlist, const char *group_id); void msn_userlist_rem_buddy(MsnUserList *userlist, const char *who, int list_id, const char *group_name); @@ -99,5 +104,6 @@ void msn_userlist_move_buddy(MsnUserList *userlist, const char *who, const char *old_group_name, const char *new_group_name); +void msn_userlist_load(MsnSession *session); #endif /* _MSN_USERLIST_H_ */