# HG changeset patch # User Ka-Hing Cheung # Date 1178086016 0 # Node ID 14b8fb8d27b30e6e32d4bbf68b42f719f598be5c # Parent 6b4e778ee4b415ecff4b451319a966f63d9a107c# Parent 1122d47583a165378774acadf2deab68e7ff1250 merge of 790a91b1bb6c10ada984951cbd2485e95e5159fd and 05f7badcad9471084218e698a5c011908d17af90 diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/internal.h --- a/libpurple/internal.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/internal.h Wed May 02 06:06:56 2007 +0000 @@ -75,6 +75,7 @@ #ifndef _WIN32 #include #include +#include #endif #include #include diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/Makefile.am --- a/libpurple/protocols/msn/Makefile.am Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.am Wed May 02 06:06:56 2007 +0000 @@ -8,6 +8,8 @@ cmdproc.h \ command.c \ command.h \ + contact.c\ + contact.h\ dialog.c \ dialog.h \ directconn.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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/Makefile.mingw --- a/libpurple/protocols/msn/Makefile.mingw Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/Makefile.mingw Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/README Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/cmdproc.c --- a/libpurple/protocols/msn/cmdproc.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/cmdproc.c Wed May 02 06:06:56 2007 +0000 @@ -89,8 +89,7 @@ tmp = (incoming) ? 'S' : 'C'; - if ((show[len - 1] == '\n') && (show[len - 2] == '\r')) - { + if ((show[len - 1] == '\n') && (show[len - 2] == '\r')){ show[len - 2] = '\0'; } @@ -127,14 +126,14 @@ trans->callbacks = g_hash_table_lookup(cmdproc->cbs_table->cmds, trans->command); - if (trans->payload != NULL) - { + if (trans->payload != NULL){ data = g_realloc(data, len + trans->payload_len); memcpy(data + len, trans->payload, trans->payload_len); len += trans->payload_len; } msn_servconn_write(servconn, data, len); +// purple_debug_info("<<","%s\n",data); g_free(data); } @@ -228,8 +227,7 @@ { MsnMsgTypeCb cb; - if (msn_message_get_content_type(msg) == NULL) - { + if (msn_message_get_content_type(msg) == NULL){ purple_debug_misc("msn", "failed to find message content\n"); return; } @@ -237,8 +235,7 @@ cb = g_hash_table_lookup(cmdproc->cbs_table->msgs, msn_message_get_content_type(msg)); - if (cb == NULL) - { + if (cb == NULL){ purple_debug_warning("msn", "Unhandled content-type '%s'\n", msn_message_get_content_type(msg)); diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/command.c --- a/libpurple/protocols/msn/command.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/command.c Wed May 02 06:06:56 2007 +0000 @@ -24,6 +24,10 @@ #include "msn.h" #include "command.h" +/*local Function prototype*/ +int msn_get_payload_position(char *str); +int msn_set_payload_len(MsnCommand *cmd); + static gboolean is_num(char *str) { @@ -36,6 +40,72 @@ 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"))){ + return TRUE; + } + + return FALSE; +} + +/*get the payload positon*/ +int msn_get_payload_position(char *str) +{ + /*because MSG has "MSG hotmail hotmail [payload length]"*/ + if(!(strcmp(str,"MSG"))|| (!strcmp(str,"UBX")) ){ + return 2; + } + /*Yahoo User Message UBM + * Format UBM email@yahoo.com 32 1 [payload length]*/ + if(!(strcmp(str,"UBM"))|| (!strcmp(str,"UUM")) ){ + return 3; + } + + return 1; +} + +/* + * set command Payload length + */ +int +msn_set_payload_len(MsnCommand *cmd) +{ + char * param; + + if(msn_check_payload_cmd(cmd->command)){ + param = cmd->params[msn_get_payload_position(cmd->command)]; +#if 0 + if(!(strcmp(cmd->command,"MSG"))){ + param = cmd->params[2]; + }else{ + param = cmd->params[1]; + } +#endif + cmd->payload_len = is_num(param) ? atoi(param) : 0; + }else{ + cmd->payload_len = 0; + } + return 0; +} + MsnCommand * msn_command_from_string(const char *string) { @@ -70,7 +140,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/contact.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.c Wed May 02 06:06:56 2007 +0000 @@ -0,0 +1,879 @@ +/** + * @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; + } + return 0; +} + +/*get User Type*/ +static int +msn_get_user_type(char * type) +{ + if(!strcmp(type,"Regular")){ + return 1; + } + if(!strcmp(type,"Live")){ + return 1; + } + if(!strcmp(type,"LivePending")){ + return 1; + } + + return 0; +} + +/*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_blist_node_set_string(msn_session_get_bnode(contact->session),"CLLastChange",LastChangeStr); + purple_debug_misc("MSNCL","LastChangeNode %s\n",LastChangeStr); + + memberships =xmlnode_get_child(service,"Memberships"); + 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_blist_node_get_string(msn_session_get_bnode(contact->session),"ablastChange"); + dynamicItemLastChange = purple_blist_node_get_string(msn_session_get_bnode(contact->session),"dynamicItemLastChange"); + msn_get_address_book(contact, abLastChange, dynamicItemLastChange); +} + +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 gboolean +msn_parse_addressbook(MsnContact * contact) +{ + MsnSession * session; + xmlnode * node,*body,*response,*result; + xmlnode *groups,*group,*groupname,*groupId,*groupInfo; + xmlnode *contacts,*contactNode,*contactId,*contactInfo,*contactType,*passportName,*displayName,*groupIds,*guid; + xmlnode *abNode; + char *group_name,*group_id; + + 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"); + for(group = xmlnode_get_child(groups, "Group"); group; + group = xmlnode_get_next_twin(group)){ + 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_node_set_string(&(g->node),"groupId",group_id); + purple_blist_add_group(g, NULL); + } + g_free(group_id); + g_free(group_name); + } + /*add a default No group to set up the no group Membership*/ + group_id = g_strdup(MSN_INDIVIDUALS_GROUP_ID); + group_name = g_strdup(MSN_INDIVIDUALS_GROUP_NAME); + msn_group_new(session->userlist,group_id , group_name); + if (group_id != NULL){ + purple_debug_misc("MsnAB","group_id:%s name:%s,value:%d\n",group_id,group_name,*group_name=='\0'); + if ((purple_find_group(group_name)) == NULL){ + PurpleGroup *g = purple_group_new(group_name); + purple_blist_add_group(g, NULL); + } + } + g_free(group_name); + g_free(group_id); + + /*add a default No group to set up the no group Membership*/ + group_id = g_strdup(MSN_NON_IM_GROUP_ID); + group_name = g_strdup(MSN_NON_IM_GROUP_NAME); + msn_group_new(session->userlist,group_id , group_name); + if (group_id != NULL){ + purple_debug_misc("MsnAB","group_id:%s name:%s,value:%d\n",group_id,group_name,*group_name=='\0'); + if ((purple_find_group(group_name)) == NULL){ + PurpleGroup *g = purple_group_new(group_name); + purple_blist_add_group(g, NULL); + } + } + g_free(group_name); + g_free(group_id); + + /*Process contact List*/ + purple_debug_info("MSNAB","process contact list...\n"); + contacts =xmlnode_get_child(result,"contacts"); + for(contactNode = xmlnode_get_child(contacts, "Contact"); contactNode; + contactNode = xmlnode_get_next_twin(contactNode)){ + MsnUser *user; + 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 */ + } + + 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); + 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,msn_get_user_type(type)); + user->list_op |= MSN_LIST_FL_OP; + 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)){ + 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*/ + group_id = g_strdup(MSN_INDIVIDUALS_GROUP_ID); + msn_user_add_group_id(user,group_id); + g_free(group_id); + } + } + + 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_blist_node_set_string(msn_session_get_bnode(contact->session),"ablastChange",lastchange); + + DynamicItemLastChangedNode = xmlnode_get_child(abNode,"DynamicItemLastChanged"); + dynamicChange = xmlnode_get_data(DynamicItemLastChangedNode); + purple_debug_info("MsnAB"," DynamicItemLastChanged :{%s}\n",dynamicChange); + purple_blist_node_set_string(msn_session_get_bnode(contact->session),"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); +} + +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*/ +#if 0 +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); +} + +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); +} + +#if 0 +/*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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/contact.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/contact.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/dialog.c --- a/libpurple/protocols/msn/dialog.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/dialog.c Wed May 02 06:06:56 2007 +0000 @@ -34,38 +34,16 @@ } MsnAddRemData; -/* 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. */ -static void -msn_complete_sync_issue(MsnAddRemData *data) -{ - PurpleBuddy *buddy; - PurpleGroup *group = NULL; - - 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; - - msn_complete_sync_issue(data); + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - session = data->gc->proto_data; - 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 +53,13 @@ static void msn_rem_cb(MsnAddRemData *data) { - MsnSession *session; - MsnUserList *userlist; - - msn_complete_sync_issue(data); + if (g_list_find(purple_connections_get_all(), data->gc) != NULL) + { + MsnSession *session = data->gc->proto_data; + MsnUserList *userlist = session->userlist; - session = data->gc->proto_data; - 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); @@ -98,6 +74,8 @@ PurpleAccount *account; MsnAddRemData *data; char *msg, *reason; + PurpleBuddy *buddy; + PurpleGroup *group = NULL; account = session->account; gc = purple_account_get_connection(account); @@ -132,6 +110,17 @@ _("Yes"), G_CALLBACK(msn_add_cb), _("No"), G_CALLBACK(msn_rem_cb)); + if (group_name != NULL) + group = purple_find_group(group_name); + + if (group != NULL) + buddy = purple_find_buddy_in_group(account, passport, group); + else + buddy = purple_find_buddy(account, passport); + + if (buddy != NULL) + purple_blist_remove_buddy(buddy); + g_free(reason); g_free(msg); } diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/directconn.c --- a/libpurple/protocols/msn/directconn.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/directconn.c Wed May 02 06:06:56 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) @@ -476,6 +487,7 @@ void msn_directconn_destroy(MsnDirectConn *directconn) { + if (directconn->connect_data != NULL) purple_proxy_connect_cancel(directconn->connect_data); diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/directconn.h --- a/libpurple/protocols/msn/directconn.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/directconn.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/group.c --- a/libpurple/protocols/msn/group.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/group.c Wed May 02 06:06:56 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; } @@ -87,3 +88,4 @@ return group->name; } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/group.h --- a/libpurple/protocols/msn/group.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/group.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/history.c --- a/libpurple/protocols/msn/history.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/history.c Wed May 02 06:06:56 2007 +0000 @@ -84,3 +84,4 @@ msn_transaction_destroy(trans); } } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msg.c --- a/libpurple/protocols/msn/msg.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/msg.c Wed May 02 06:06:56 2007 +0000 @@ -23,6 +23,7 @@ */ #include "msn.h" #include "msg.h" +#define MSN_DEBUG_MSG MsnMessage * msn_message_new(MsnMsgType type) @@ -104,8 +105,7 @@ purple_debug_info("msn", "message unref (%p)[%d]\n", msg, msg->ref_count); #endif - if (msg->ref_count == 0) - { + if (msg->ref_count == 0){ msn_message_destroy(msg); return NULL; @@ -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,12 @@ char **elems, **cur, **tokens; g_return_if_fail(payload != NULL); - +// purple_debug_info("MaYuan","payload:{%s}\n",payload); 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,10 +230,9 @@ } *end = '\0'; - elems = g_strsplit(tmp, "\r\n", 0); + elems = g_strsplit(tmp, line_dem, 0); - for (cur = elems; *cur != NULL; cur++) - { + for (cur = elems; *cur != NULL; cur++){ const char *key, *value; tokens = g_strsplit(*cur, ": ", 2); @@ -240,20 +240,17 @@ key = tokens[0]; value = tokens[1]; - if (!strcmp(key, "MIME-Version")) - { + /*if not MIME content ,then return*/ + if (!strcmp(key, "MIME-Version")){ g_strfreev(tokens); continue; } - if (!strcmp(key, "Content-Type")) - { + if (!strcmp(key, "Content-Type")){ char *charset, *c; - if ((c = strchr(value, ';')) != NULL) - { - if ((charset = strchr(c, '=')) != NULL) - { + if ((c = strchr(value, ';')) != NULL){ + if ((charset = strchr(c, '=')) != NULL) { charset++; msn_message_set_charset(msg, charset); } @@ -262,9 +259,7 @@ } msn_message_set_content_type(msg, value); - } - else - { + }else{ msn_message_set_attr(msg, key, value); } @@ -274,14 +269,13 @@ 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); if (content_type != NULL && - !strcmp(content_type, "application/x-msnmsgrp2p")) - { + !strcmp(content_type, "application/x-msnmsgrp2p")){ MsnSlpHeader header; MsnSlpFooter footer; int body_len; @@ -323,9 +317,7 @@ tmp += sizeof(footer); msg->msnslp_footer.value = GUINT32_FROM_BE(footer.value); } - } - else - { + }else{ if (payload_len - (tmp - tmp_base) > 0) { msg->body_len = payload_len - (tmp - tmp_base); msg->body = g_malloc0(msg->body_len + 1); @@ -476,15 +468,14 @@ } else { - if (body != NULL) - { + if (body != NULL){ memcpy(n, body, body_len); n += body_len; + *n = '\0'; } } - if (ret_size != NULL) - { + if (ret_size != NULL){ *ret_size = n - base; if (*ret_size > 1664) @@ -523,14 +514,11 @@ if (msg->body != NULL) g_free(msg->body); - if (data != NULL && len > 0) - { + if (data != NULL && len > 0){ msg->body = g_malloc0(len + 1); memcpy(msg->body, data, len); msg->body_len = len; - } - else - { + }else{ msg->body = NULL; msg->body_len = 0; } @@ -785,3 +773,4 @@ g_string_free(str, TRUE); } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msg.h --- a/libpurple/protocols/msn/msg.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/msg.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msn-utils.c --- a/libpurple/protocols/msn/msn-utils.c Mon Apr 23 17:19:11 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msn-utils.h --- a/libpurple/protocols/msn/msn-utils.h Mon Apr 23 17:19:11 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msn.c --- a/libpurple/protocols/msn/msn.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/msn.c Wed May 02 06:06:56 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" @@ -114,7 +114,7 @@ return PURPLE_CMD_RET_OK; } -static void +void msn_act_id(PurpleConnection *gc, const char *entry) { MsnCmdProc *cmdproc; @@ -122,6 +122,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); @@ -138,9 +141,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 @@ -429,6 +450,7 @@ session = gc->proto_data; xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who); + if (xfer) { slplink = msn_session_get_slplink(session, who); @@ -480,18 +502,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; @@ -509,8 +569,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) @@ -535,29 +611,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_AWAY, "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_AWAY, "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, @@ -696,7 +791,8 @@ return; } - http_method = purple_account_get_bool(account, "http_method", FALSE); + if (purple_account_get_bool(account, "http_method", FALSE)) + http_method = TRUE; host = purple_account_get_string(account, "server", MSN_SERVER); port = purple_account_get_int(account, "port", MSN_PORT); @@ -743,6 +839,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) { @@ -756,58 +853,86 @@ } 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; + /* + * 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); + serv_got_im(gc, who, body_str, flags, time(NULL)); + g_free(body_str); + } + 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; - /* - * 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); - serv_got_im(gc, who, body_str, flags, time(NULL)); - g_free(body_str); - } - - msn_message_destroy(msg); - return 1; } @@ -867,8 +992,7 @@ gc = purple_account_get_connection(account); - if (gc != NULL) - { + if (gc != NULL){ session = gc->proto_data; msn_change_status(session); } @@ -945,6 +1069,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 @@ -1092,12 +1217,9 @@ cmdproc = session->notification->cmdproc; if (account->perm_deny == PURPLE_PRIVACY_ALLOW_ALL || - account->perm_deny == PURPLE_PRIVACY_DENY_USERS) - { + account->perm_deny == PURPLE_PRIVACY_DENY_USERS){ msn_cmdproc_send(cmdproc, "BLP", "%s", "AL"); - } - else - { + }else{ msn_cmdproc_send(cmdproc, "BLP", "%s", "BL"); } } @@ -1237,22 +1359,22 @@ { 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 - { + }else{ + /*not found*/ msn_cmdproc_send(cmdproc, "ADG", "%s 0", enc_new_group_name); } } @@ -1308,14 +1430,19 @@ { 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) - { - msn_cmdproc_send(cmdproc, "RMG", "%d", group_id); + /*we can't delete the default group*/ + if(!strcmp(group->name,MSN_INDIVIDUALS_GROUP_NAME)|| + !strcmp(group->name,MSN_NON_IM_GROUP_NAME)){ + return ; + } + group_id = msn_userlist_find_group_id(session->userlist, group->name); + if (group_id != NULL){ + msn_del_group(session,group_id); } } @@ -1330,19 +1457,16 @@ b = purple_find_buddy(purple_connection_get_account(info_data->gc), info_data->name); - if (b) - { + if (b){ char *tmp; - if (b->alias && b->alias[0]) - { + if (b->alias && b->alias[0]){ char *aliastext = g_markup_escape_text(b->alias, -1); purple_notify_user_info_add_pair(user_info, _("Alias"), aliastext); g_free(aliastext); } - if (b->server_alias) - { + if (b->server_alias){ char *nicktext = g_markup_escape_text(b->server_alias, -1); tmp = g_strdup_printf("%s
", nicktext); purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp); @@ -1366,12 +1490,10 @@ { char *p, *q; - if ((p = strstr(url_text, " contactparams:photopreauthurl=\"")) != NULL) - { - p += strlen(" contactparams:photopreauthurl=\""); + if ((p = strstr(url_text, PHOTO_URL)) != NULL){ + 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; @@ -1420,7 +1542,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) @@ -1801,6 +1923,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)); @@ -2025,7 +2148,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 */ @@ -2075,10 +2198,10 @@ "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"), + "MaYuan ", /**< author */ PURPLE_WEBSITE, /**< homepage */ msn_load, /**< load */ @@ -2097,11 +2220,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msn.h --- a/libpurple/protocols/msn/msn.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/msn.h Wed May 02 06:06:56 2007 +0000 @@ -62,12 +62,24 @@ #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 PASSPORT_URL "http://lc1.law13.hotmail.passport.com/cgi-bin/dologin?login=" -#define PROFILE_URL "http://spaces.msn.com/profile.aspx?mem=" +/*#define PROFILE_URL "http://spaces.msn.com/profile.aspx?mem="*/ +#define PROFILE_URL "http://spaces.live.com/profile.aspx?mem=" +#define PHOTO_URL " contactparams:photopreauthurl=\"" #define USEROPT_HOTMAIL 0 @@ -88,6 +100,7 @@ MSN_LIST_RL_OP = 0x08 } 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msnutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.c Wed May 02 06:06:56 2007 +0000 @@ -0,0 +1,1592 @@ +/** + * @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 + ***************************************************************************/ +/*check the edian of system*/ +int +isBigEndian(void) +{ + short int word = 0x0100; + char *byte = (char *)&word; + + return(byte[0]); +} + +/*swap utility*/ +unsigned int +swapInt(unsigned int dw) +{ + unsigned int tmp; + tmp = (dw & 0x000000FF); + tmp = ((dw & 0x0000FF00) >> 0x08) | (tmp << 0x08); + tmp = ((dw & 0x00FF0000) >> 0x10) | (tmp << 0x08); + tmp = ((dw & 0xFF000000) >> 0x18) | (tmp << 0x08); + return(tmp); +} + +/* + * 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, bigEndian; + + /* Determine our endianess */ + bigEndian = isBigEndian(); + + /* 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++){ + /* check for endianess */ + if(bigEndian) + md5Parts[i] = swapInt(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; + + if(bigEndian){ + chlStringParts[i] = swapInt(chlStringParts[i]); + chlStringParts[i+1] = swapInt(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; + + /* swap more bytes if big endian */ + for(i=0; i<4 && bigEndian; i++) + newHashParts[i] = swapInt(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); +} + +#if (!defined(_XOPEN_SOURCE))||defined(_WIN32) + +#ifndef __P +# if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +# define __P(args) args +# else +# define __P(args) () +# endif /* GCC. */ +#endif /* Not __P. */ + +#if defined(HAVE_LOCALTIME_R) && ! HAVE_LOCALTIME_R && ! defined localtime_r +# ifdef _LIBC +# define localtime_r __localtime_r +# else +/* Approximate localtime_r as best we can in its absence. */ +# define localtime_r my_localtime_r +static struct tm *localtime_r __P ((const time_t *, struct tm *)); +static struct tm * +localtime_r (t, tp) + const time_t *t; + struct tm *tp; +{ + struct tm *l = localtime (t); + if (! l) + return 0; + *tp = *l; + return tp; +} +# endif /* ! _LIBC */ +#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ + + +#define match_char(ch1, ch2) if (ch1 != ch2) return NULL + +#if defined __GNUC__ && __GNUC__ >= 2 +# define match_string(cs1, s2) \ + ({ size_t len = strlen (cs1); \ + int result = strncasecmp ((cs1), (s2), len) == 0; \ + if (result) (s2) += len; \ + result; }) +#else +/* Oh come on. Get a reasonable compiler. */ +# define match_string(cs1, s2) \ + (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) +#endif + +/* We intentionally do not use isdigit() for testing because this will + lead to problems with the wide character version. */ +#define get_number(from, to, n) \ + do { \ + int __n = n; \ + val = 0; \ + while (*rp == ' ') \ + ++rp; \ + if ((*rp < '0') || (*rp > '9')) \ + return NULL; \ + do { \ + val *= 10; \ + val += *rp++ - '0'; \ + } while ((--__n > 0) && (val * 10 <= to) && (*rp >= '0') && (*rp <= '9')); \ + if ((val < from) || (val > to)) \ + return NULL; \ + } while (0) + +#ifdef _NL_CURRENT +# define get_alt_number(from, to, n) \ + ({ \ + __label__ do_normal; \ + if (*decided != raw) \ + { \ + const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \ + int __n = n; \ + int any = 0; \ + while (*rp == ' ') \ + ++rp; \ + val = 0; \ + do { \ + val *= 10; \ + while (*alts != '\0') \ + { \ + size_t len = strlen (alts); \ + if (strncasecmp (alts, rp, len) == 0) \ + break; \ + alts += len + 1; \ + ++val; \ + } \ + if (*alts == '\0') \ + { \ + if (*decided == not && ! any) \ + goto do_normal; \ + /* If we haven't read anything it's an error. */ \ + if (! any) \ + return NULL; \ + /* Correct the premature multiplication. */ \ + val /= 10; \ + break; \ + } \ + else \ + *decided = loc; \ + } while (--__n > 0 && val * 10 <= to); \ + if (val < from || val > to) \ + return NULL; \ + } \ + else \ + { \ + do_normal: \ + get_number (from, to, n); \ + } \ + 0; \ + }) +#else +# define get_alt_number(from, to, n) \ + /* We don't have the alternate representation. */ \ + get_number(from, to, n) +#endif + +#define recursive(new_fmt) \ + (*(new_fmt) != '\0' \ + && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL) + + +#ifdef _LIBC +/* This is defined in locale/C-time.c in the GNU libc. */ +extern const struct locale_data _nl_C_LC_TIME; +extern const unsigned short int __mon_yday[2][13]; + +# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string) +# define ab_weekday_name \ + (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string) +# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string) +# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string) +# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string) +# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string) +# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string) +# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string) +# define HERE_T_FMT_AMPM \ + (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string) +# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string) + +# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n) +#else +static char const weekday_name[][10] = + { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }; +static char const ab_weekday_name[][4] = + { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; +static char const month_name[][10] = + { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }; +static char const ab_month_name[][4] = + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; +# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" +# define HERE_D_FMT "%m/%d/%y" +# define HERE_AM_STR "AM" +# define HERE_PM_STR "PM" +# define HERE_T_FMT_AMPM "%I:%M:%S %p" +# define HERE_T_FMT "%H:%M:%S" + +const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; +#endif + +/* Status of lookup: do we use the locale data or the raw data? */ +enum locale_status { not, loc, raw }; + + +#ifndef __isleap +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +# define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* Compute the day of the week. */ +static void +day_of_the_week (struct tm *tm) +{ + /* We know that January 1st 1970 was a Thursday (= 4). Compute the + the difference between this data in the one on TM and so determine + the weekday. */ + int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); + int wday = (-473 + + (365 * (tm->tm_year - 70)) + + (corr_year / 4) + - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) + + (((corr_year / 4) / 25) / 4) + + __mon_yday[0][tm->tm_mon] + + tm->tm_mday - 1); + tm->tm_wday = ((wday % 7) + 7) % 7; +} + +/* Compute the day of the year. */ +static void +day_of_the_year (struct tm *tm) +{ + tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] + + (tm->tm_mday - 1)); +} + +static char * +#ifdef _LIBC +internal_function +#endif +strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm, + enum locale_status *decided, int era_cnt)); + +static char * +#ifdef _LIBC +internal_function +#endif +strptime_internal (rp, fmt, tm, decided, era_cnt) + const char *rp; + const char *fmt; + struct tm *tm; + enum locale_status *decided; + int era_cnt; +{ + const char *rp_backup; + int cnt; + size_t val; + int have_I, is_pm; + int century, want_century; + int want_era; + int have_wday, want_xday; + int have_yday; + int have_mon, have_mday; +#ifdef _NL_CURRENT + size_t num_eras; +#endif + struct era_entry *era; + + have_I = is_pm = 0; + century = -1; + want_century = 0; + want_era = 0; + era = NULL; + + have_wday = want_xday = have_yday = have_mon = have_mday = 0; + + while (*fmt != '\0') + { + /* A white space in the format string matches 0 more or white + space in the input string. */ + if (isspace (*fmt)) + { + while (isspace (*rp)) + ++rp; + ++fmt; + continue; + } + + /* Any character but `%' must be matched by the same character + in the iput string. */ + if (*fmt != '%') + { + match_char (*fmt++, *rp++); + continue; + } + + ++fmt; +#ifndef _NL_CURRENT + /* We need this for handling the `E' modifier. */ + start_over: +#endif + + /* Make back up of current processing pointer. */ + rp_backup = rp; + + switch (*fmt++) + { + case '%': + /* Match the `%' character itself. */ + match_char ('%', *rp++); + break; + case 'a': + case 'A': + /* Match day of week. */ + for (cnt = 0; cnt < 7; ++cnt) + { +#ifdef _NL_CURRENT + if (*decided !=raw) + { + if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), + weekday_name[cnt])) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), + ab_weekday_name[cnt])) + *decided = loc; + break; + } + } +#endif + if (*decided != loc + && (match_string (weekday_name[cnt], rp) + || match_string (ab_weekday_name[cnt], rp))) + { + *decided = raw; + break; + } + } + if (cnt == 7) + /* Does not match a weekday name. */ + return NULL; + tm->tm_wday = cnt; + have_wday = 1; + break; + case 'b': + case 'B': + case 'h': + /* Match month name. */ + for (cnt = 0; cnt < 12; ++cnt) + { +#ifdef _NL_CURRENT + if (*decided !=raw) + { + if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), + month_name[cnt])) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), + ab_month_name[cnt])) + *decided = loc; + break; + } + } +#endif + if (match_string (month_name[cnt], rp) + || match_string (ab_month_name[cnt], rp)) + { + *decided = raw; + break; + } + } + if (cnt == 12) + /* Does not match a month name. */ + return NULL; + tm->tm_mon = cnt; + want_xday = 1; + break; + case 'c': + /* Match locale's date and time format. */ +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not && + strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } +#endif + if (!recursive (HERE_D_T_FMT)) + return NULL; + want_xday = 1; + break; + case 'C': + /* Match century number. */ +#ifdef _NL_CURRENT + match_century: +#endif + get_number (0, 99, 2); + century = val; + want_xday = 1; + break; + case 'd': + case 'e': + /* Match day of month. */ + get_number (1, 31, 2); + tm->tm_mday = val; + have_mday = 1; + want_xday = 1; + break; + case 'F': + if (!recursive ("%Y-%m-%d")) + return NULL; + want_xday = 1; + break; + case 'x': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } +#endif + /* Fall through. */ + case 'D': + /* Match standard day format. */ + if (!recursive (HERE_D_FMT)) + return NULL; + want_xday = 1; + break; + case 'k': + case 'H': + /* Match hour in 24-hour clock. */ + get_number (0, 23, 2); + tm->tm_hour = val; + have_I = 0; + break; + case 'I': + /* Match hour in 12-hour clock. */ + get_number (1, 12, 2); + tm->tm_hour = val % 12; + have_I = 1; + break; + case 'j': + /* Match day number of year. */ + get_number (1, 366, 3); + tm->tm_yday = val - 1; + have_yday = 1; + break; + case 'm': + /* Match number of month. */ + get_number (1, 12, 2); + tm->tm_mon = val - 1; + have_mon = 1; + want_xday = 1; + break; + case 'M': + /* Match minute. */ + get_number (0, 59, 2); + tm->tm_min = val; + break; + case 'n': + case 't': + /* Match any white space. */ + while (isspace (*rp)) + ++rp; + break; + case 'p': + /* Match locale's equivalent of AM/PM. */ +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) + { + if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) + { + if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) + *decided = loc; + is_pm = 1; + break; + } + *decided = raw; + } +#endif + if (!match_string (HERE_AM_STR, rp)) + if (match_string (HERE_PM_STR, rp)) + is_pm = 1; + else + return NULL; + break; + case 'r': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not && + strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), + HERE_T_FMT_AMPM)) + *decided = loc; + break; + } + *decided = raw; + } +#endif + if (!recursive (HERE_T_FMT_AMPM)) + return NULL; + break; + case 'R': + if (!recursive ("%H:%M")) + return NULL; + break; + case 's': + { + /* The number of seconds may be very high so we cannot use + the `get_number' macro. Instead read the number + character for character and construct the result while + doing this. */ + time_t secs = 0; + if (*rp < '0' || *rp > '9') + /* We need at least one digit. */ + return NULL; + + do + { + secs *= 10; + secs += *rp++ - '0'; + } + while (*rp >= '0' && *rp <= '9'); + + if (localtime_r (&secs, tm) == NULL) + /* Error in function. */ + return NULL; + } + break; + case 'S': + get_number (0, 61, 2); + tm->tm_sec = val; + break; + case 'X': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) + *decided = loc; + break; + } + *decided = raw; + } +#endif + /* Fall through. */ + case 'T': + if (!recursive (HERE_T_FMT)) + return NULL; + break; + case 'u': + get_number (1, 7, 1); + tm->tm_wday = val % 7; + have_wday = 1; + break; + case 'g': + get_number (0, 99, 2); + /* XXX This cannot determine any field in TM. */ + break; + case 'G': + if (*rp < '0' || *rp > '9') + return NULL; + /* XXX Ignore the number since we would need some more + information to compute a real date. */ + do + ++rp; + while (*rp >= '0' && *rp <= '9'); + break; + case 'U': + case 'V': + case 'W': + get_number (0, 53, 2); + /* XXX This cannot determine any field in TM without some + information. */ + break; + case 'w': + /* Match number of weekday. */ + get_number (0, 6, 1); + tm->tm_wday = val; + have_wday = 1; + break; + case 'y': +#ifdef _NL_CURRENT + match_year_in_century: +#endif + /* Match year within century. */ + get_number (0, 99, 2); + /* The "Year 2000: The Millennium Rollover" paper suggests that + values in the range 69-99 refer to the twentieth century. */ + tm->tm_year = val >= 69 ? val : val + 100; + /* Indicate that we want to use the century, if specified. */ + want_century = 1; + want_xday = 1; + break; + case 'Y': + /* Match year including century number. */ + get_number (0, 9999, 4); + tm->tm_year = val - 1900; + want_century = 0; + want_xday = 1; + break; + case 'Z': + /* XXX How to handle this? */ + break; + case 'E': +#ifdef _NL_CURRENT + switch (*fmt++) + { + case 'c': + /* Match locale's alternate date and time format. */ + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, D_T_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_D_T_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } + /* The C locale has no era information, so use the + normal representation. */ + if (!recursive (HERE_D_T_FMT)) + return NULL; + want_xday = 1; + break; + case 'C': + if (*decided != raw) + { + if (era_cnt >= 0) + { + era = _nl_select_era_entry (era_cnt); + if (match_string (era->era_name, rp)) + { + *decided = loc; + break; + } + else + return NULL; + } + else + { + num_eras = _NL_CURRENT_WORD (LC_TIME, + _NL_TIME_ERA_NUM_ENTRIES); + for (era_cnt = 0; era_cnt < (int) num_eras; + ++era_cnt, rp = rp_backup) + { + era = _nl_select_era_entry (era_cnt); + if (match_string (era->era_name, rp)) + { + *decided = loc; + break; + } + } + if (era_cnt == (int) num_eras) + { + era_cnt = -1; + if (*decided == loc) + return NULL; + } + else + break; + } + + *decided = raw; + } + /* The C locale has no era information, so use the + normal representation. */ + goto match_century; + case 'y': + if (*decided == raw) + goto match_year_in_century; + + get_number(0, 9999, 4); + tm->tm_year = val; + want_era = 1; + want_xday = 1; + break; + case 'Y': + if (*decided != raw) + { + num_eras = _NL_CURRENT_WORD (LC_TIME, + _NL_TIME_ERA_NUM_ENTRIES); + for (era_cnt = 0; era_cnt < (int) num_eras; + ++era_cnt, rp = rp_backup) + { + era = _nl_select_era_entry (era_cnt); + if (recursive (era->era_format)) + break; + } + if (era_cnt == (int) num_eras) + { + era_cnt = -1; + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + *decided = loc; + era_cnt = -1; + break; + } + + *decided = raw; + } + get_number (0, 9999, 4); + tm->tm_year = val - 1900; + want_century = 0; + want_xday = 1; + break; + case 'x': + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, D_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_D_FMT)) + *decided = loc; + break; + } + *decided = raw; + } + if (!recursive (HERE_D_FMT)) + return NULL; + break; + case 'X': + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, T_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_T_FMT)) + *decided = loc; + break; + } + *decided = raw; + } + if (!recursive (HERE_T_FMT)) + return NULL; + break; + default: + return NULL; + } + break; +#else + /* We have no information about the era format. Just use + the normal format. */ + if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' + && *fmt != 'x' && *fmt != 'X') + /* This is an illegal format. */ + return NULL; + + goto start_over; +#endif + case 'O': + switch (*fmt++) + { + case 'd': + case 'e': + /* Match day of month using alternate numeric symbols. */ + get_alt_number (1, 31, 2); + tm->tm_mday = val; + have_mday = 1; + want_xday = 1; + break; + case 'H': + /* Match hour in 24-hour clock using alternate numeric + symbols. */ + get_alt_number (0, 23, 2); + tm->tm_hour = val; + have_I = 0; + break; + case 'I': + /* Match hour in 12-hour clock using alternate numeric + symbols. */ + get_alt_number (1, 12, 2); + tm->tm_hour = val - 1; + have_I = 1; + break; + case 'm': + /* Match month using alternate numeric symbols. */ + get_alt_number (1, 12, 2); + tm->tm_mon = val - 1; + have_mon = 1; + want_xday = 1; + break; + case 'M': + /* Match minutes using alternate numeric symbols. */ + get_alt_number (0, 59, 2); + tm->tm_min = val; + break; + case 'S': + /* Match seconds using alternate numeric symbols. */ + get_alt_number (0, 61, 2); + tm->tm_sec = val; + break; + case 'U': + case 'V': + case 'W': + get_alt_number (0, 53, 2); + /* XXX This cannot determine any field in TM without + further information. */ + break; + case 'w': + /* Match number of weekday using alternate numeric symbols. */ + get_alt_number (0, 6, 1); + tm->tm_wday = val; + have_wday = 1; + break; + case 'y': + /* Match year within century using alternate numeric symbols. */ + get_alt_number (0, 99, 2); + tm->tm_year = val >= 69 ? val : val + 100; + want_xday = 1; + break; + default: + return NULL; + } + break; + default: + return NULL; + } + } + + if (have_I && is_pm) + tm->tm_hour += 12; + + if (century != -1) + { + if (want_century) + tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; + else + /* Only the century, but not the year. Strange, but so be it. */ + tm->tm_year = (century - 19) * 100; + } + +#ifdef _NL_CURRENT + if (era_cnt != -1) + { + era = _nl_select_era_entry(era_cnt); + if (want_era) + tm->tm_year = (era->start_date[0] + + ((tm->tm_year - era->offset) + * era->absolute_direction)); + else + /* Era start year assumed. */ + tm->tm_year = era->start_date[0]; + } + else +#endif + if (want_era) + return NULL; + + if (want_xday && !have_wday) + { + if ( !(have_mon && have_mday) && have_yday) + { + /* We don't have tm_mon and/or tm_mday, compute them. */ + int t_mon = 0; + while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) + t_mon++; + if (!have_mon) + tm->tm_mon = t_mon - 1; + if (!have_mday) + tm->tm_mday = + (tm->tm_yday + - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); + } + day_of_the_week (tm); + } + if (want_xday && !have_yday) + day_of_the_year (tm); + + return (char *) rp; +} + + +char * +msn_strptime (buf, format, tm) + const char *buf; + const char *format; + struct tm *tm; +{ + enum locale_status decided; + +#ifdef _NL_CURRENT + decided = not; +#else + decided = raw; +#endif + return strptime_internal (buf, format, tm, &decided, -1); +} +#else +#define msn_strptime strptime +#endif diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/msnutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/msnutils.h Wed May 02 06:06:56 2007 +0000 @@ -0,0 +1,64 @@ +/** + * @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); +int isBigEndian(void); +unsigned int swapInt(unsigned int dw); +char * msn_strptime (const char *buf,const char *format,struct tm *tm); + + +#endif /* _MSN_UTILS_H_ */ diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/nexus.c --- a/libpurple/protocols/msn/nexus.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/nexus.c Wed May 02 06:06:56 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,283 +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); - } - } - - 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; @@ -406,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); @@ -468,10 +426,13 @@ } +#endif + /************************************************************************** * Connect **************************************************************************/ +#if 0 /* khc */ static void nexus_connect_cb(gpointer data, PurpleSslConnection *gsc, PurpleInputCondition cond) @@ -500,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/nexus.h --- a/libpurple/protocols/msn/nexus.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/nexus.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/notification.c --- a/libpurple/protocols/msn/notification.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/notification.c Wed May 02 06:06:56 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, char *payload, int payload_len); +static void msn_add_contact_xml(xmlnode *mlNode, const char *passport, int list_op, int type); + /************************************************************************** * Main **************************************************************************/ @@ -102,19 +110,22 @@ 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"); vers = g_strjoinv(" ", a); - if (session->login_step == MSN_LOGIN_STEP_START) + if (session->login_step == MSN_LOGIN_STEP_START){ msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE); - else + }else{ msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE2); + } msn_cmdproc_send(cmdproc, "VER", "%s", vers); @@ -153,7 +164,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; @@ -163,24 +174,16 @@ account = session->account; gc = purple_account_get_connection(account); - if (error == 224) - { - if (group_id == 0) - { + if (error == 224){ + if (group_id == 0){ return; - } - else - { + }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); } - } - else - { + }else{ reason = g_strdup(_("Unknown error.")); } @@ -214,7 +217,6 @@ PurpleAccount *account; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "TWN I %s", purple_account_get_username(account)); } @@ -230,34 +232,37 @@ account = session->account; gc = purple_account_get_connection(account); - if (!g_ascii_strcasecmp(cmd->params[1], "OK")) - { - /* OK */ + if (!g_ascii_strcasecmp(cmd->params[1], "OK")){ + /* authenticate OK */ + /* friendly name part no longer true in msnp11 */ +#if 0 const char *friendly = purple_url_decode(cmd->params[3]); purple_connection_set_display_name(gc, friendly); - +#endif msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN); - msn_cmdproc_send(cmdproc, "SYN", "%s", "0"); - } - else if (!g_ascii_strcasecmp(cmd->params[1], "TWN")) - { +// 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")){ /* Passport authentication */ char **elems, **cur, **tokens; 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); + for (cur = elems; *cur != NULL; cur++){ + 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); @@ -306,24 +311,31 @@ g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver); - for (i = 1; i < cmd->param_count; i++) + for (i = 1; i < cmd->param_count -1; i++) { - if (!strcmp(cmd->params[i], proto_str)) + purple_debug_info("MaYuan","%s,proto_str:%s\n",cmd->params[i],proto_str); + if (strcmp(cmd->params[i], proto_str) >= 0) { protocol_supported = TRUE; break; } } - if (!protocol_supported) - { + if (!protocol_supported){ msn_session_set_error(session, MSN_ERROR_UNSUPPORTED_PROTOCOL, NULL); 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 +378,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 +391,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,42 +406,159 @@ { 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 Chanllenges **************************************************************************/ - 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)); purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); - for (i = 0; i < 16; i++) + 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 +568,182 @@ /************************************************************************** * Buddy Lists **************************************************************************/ +/* add contact to xmlnode */ +static void +msn_add_contact_xml(xmlnode *mlNode,const char *passport,int list_op,int type) +{ + xmlnode *d_node,*c_node; + char **tokens; + char *email,*domain; + char *list_op_str,*type_str; + + purple_debug_info("MaYuan","passport:%s\n",passport); + 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_str); + xmlnode_set_attrib(c_node,"l",list_op_str); + g_free(list_op_str); +#if 0 + type_str = g_strdup_printf("%d",type); + xmlnode_set_attrib(c_node,"t",type_str); +#else + if(g_strrstr(domain,"yahoo") != NULL){ + type_str = g_strdup_printf("32"); + }else{ + /*passport*/ + type_str = g_strdup_printf("1"); + } + /*mobile*/ + //type_str = g_strdup_printf("4"); + xmlnode_set_attrib(c_node,"t",type_str); + g_free(type_str); +#endif + xmlnode_insert_child(d_node, c_node); + + g_free(tokens); +} static void -add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +msn_notification_post_adl(MsnCmdProc *cmdproc, char *payload, int payload_len) { - MsnSession *session; + 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) +{ + MsnUserList *userlist; MsnUser *user; - const char *list; - const char *passport; - const char *friendly; - MsnListId list_id; - int group_id; + GList *l; + xmlnode *adl_node; + char *payload; + int payload_len; + const char *display_name; + + userlist = session->userlist; + adl_node = xmlnode_new("ml"); + adl_node->child = NULL; + xmlnode_set_attrib(adl_node, "l", "1"); + + /*get the userlist*/ + for (l = userlist->users; l != NULL; l = l->next){ + user = l->data; + msn_add_contact_xml(adl_node,user->passport,user->list_op&MSN_LIST_OP_MASK,user->type); + } + + payload = xmlnode_to_str(adl_node,&payload_len); + xmlnode_free(adl_node); - list = cmd->params[1]; - passport = cmd->params[3]; - friendly = purple_url_decode(cmd->params[4]); + msn_notification_post_adl(session->notification->cmdproc,payload,payload_len); + + 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); + } + +} - session = cmdproc->session; +/*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; - user = msn_userlist_find_user(session->userlist, passport); + cmdproc = session->notification->cmdproc; - 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); + 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"); +} - list_id = msn_get_list_id(list); +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); +} + +static void +fqy_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_info("MaYuan","Process FQY\n"); + cmdproc->last_cmd->payload_cb = fqy_cmd_post; +} - if (cmd->param_count >= 6) - group_id = atoi(cmd->params[5]); - else - group_id = -1; +static void +rml_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ +#if 0 + MsnTransaction *trans; + char * payload; +#endif - msn_got_add_user(session, user, list_id, group_id); - msn_user_update(user); + purple_debug_info("MaYuan","Process ADL\n"); +#if 0 + trans = msn_transaction_new(cmdproc, "RML",""); + + msn_transaction_set_payload(trans, payload, strlen(payload)); + + msn_cmdproc_send_trans(cmdproc, trans); +#endif } static void @@ -567,7 +838,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) @@ -614,6 +885,7 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; + int wlmclient; const char *state, *passport, *friendly; session = cmdproc->session; @@ -622,7 +894,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); @@ -630,9 +904,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); } @@ -664,6 +938,7 @@ MsnUser *user; MsnObject *msnobj; int clientid; + int wlmclient; const char *state, *passport, *friendly, *old_friendly; session = cmdproc->session; @@ -672,7 +947,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); @@ -685,10 +961,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 @@ -697,7 +972,7 @@ } } - clientid = atoi(cmd->params[3]); + clientid = atoi(cmd->params[4]); user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE); msn_user_set_state(user, state); @@ -793,6 +1068,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])); + } } } @@ -800,11 +1081,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); @@ -813,12 +1093,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); @@ -830,10 +1110,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]; @@ -845,9 +1123,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); @@ -857,10 +1135,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); } @@ -868,7 +1146,7 @@ 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); @@ -1124,6 +1402,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 **************************************************************************/ @@ -1133,23 +1491,23 @@ { MsnSession *session; const char *value; + const char *clLastChange; + purple_debug_info("MaYuan","profile_msg... \n"); session = cmdproc->session; if (strcmp(msg->remote_user, "Hotmail")) /* This isn't an official message. */ return; - if ((value = msn_message_get_attr(msg, "kv")) != NULL) - { + if ((value = msn_message_get_attr(msg, "kv")) != NULL){ if (session->passport_info.kv != NULL) g_free(session->passport_info.kv); session->passport_info.kv = g_strdup(value); } - if ((value = msn_message_get_attr(msg, "sid")) != NULL) - { + if ((value = msn_message_get_attr(msg, "sid")) != NULL){ if (session->passport_info.sid != NULL) g_free(session->passport_info.sid); @@ -1161,6 +1519,7 @@ if (session->passport_info.mspauth != NULL) g_free(session->passport_info.mspauth); + purple_debug_info("MaYuan","MSPAuth:%s\n",value); session->passport_info.mspauth = g_strdup(value); } @@ -1173,10 +1532,21 @@ } 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*/ + msn_userlist_load(session); + + msn_session_set_bnode(session); + session->contact = msn_contact_new(session); + clLastChange = purple_blist_node_get_string(msn_session_get_bnode(session),"CLLastChange"); + msn_get_contact_list(session->contact, clLastChange); +// msn_contact_connect(session->contact); } static void @@ -1232,6 +1602,71 @@ g_hash_table_destroy(table); } +/*offline Message notification process*/ +static void +initial_mdata_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ + MsnSession *session; + char **elems, **cur, **tokens; + +// purple_debug_info("MaYuan","mdata...{%s} \n",msg->body); + +// /*time debug*/ + { + const char *timestr; + time_t t; + struct tm *tm; + char datestr[]="2006-07-15T07:21:26+0700"; + GDate *date; + time(&t); + tm = gmtime(&t); + timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm); +// strftime(datestr,strlen(datestr),"%a",tm); + date = g_date_new(); + g_date_set_parse(date,datestr); + purple_debug_info("MaYuan","date is NULL?date valid%d\n",g_date_valid(date)); + g_date_free(date); + purple_debug_info("MaYuan","utf8 time:{%s}\n",timestr); + } + + /*new a oim session*/ + session = cmdproc->session; + session->oim = msn_oim_new(session); +// msn_oim_connect(session->oim); + + /*parse offline message data*/ + elems = g_strsplit(msg->body, "\r\n", 0); + for (cur = elems; *cur != NULL; cur++){ + const char *key, *value; + +// purple_debug_info("MaYuan","cur:{%s}\n",*cur); + tokens = g_strsplit(*cur, ": ", 2); + + key = tokens[0]; + value = tokens[1]; + + /*if not MIME content ,then return*/ + if ((key != NULL) && (!strcmp(key, "Mail-Data")) ){ +// purple_debug_info("MaYuan","data:{%s}\n",value); + msn_parse_oim_msg(session->oim,value); + g_strfreev(tokens); + break; + } + + g_strfreev(tokens); + } + + g_strfreev(elems); +/* test code for add group*/ +// msn_add_group(session,"hello"); +} + +/*offline Message Notification*/ +static void +delete_oim_msg(MsnCmdProc *cmdproc, MsnMessage *msg) +{ +} + static void email_msg(MsnCmdProc *cmdproc, MsnMessage *msg) { @@ -1338,46 +1773,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(adl_node,who,1,1); - 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(rml_node,who,1,1); + + 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) { @@ -1388,18 +1839,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); @@ -1408,11 +1859,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", NULL); @@ -1422,6 +1877,9 @@ 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); @@ -1435,12 +1893,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); @@ -1451,3 +1921,4 @@ { msn_table_destroy(cbs_table); } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/notification.h --- a/libpurple/protocols/msn/notification.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/notification.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/object.c --- a/libpurple/protocols/msn/object.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/object.c Wed May 02 06:06:56 2007 +0000 @@ -294,8 +294,7 @@ g_return_val_if_fail(sha1 != NULL, NULL); - for (l = local_objs; l != NULL; l = l->next) - { + for (l = local_objs; l != NULL; l = l->next){ MsnObject *local_obj = l->data; if (!strcmp(msn_object_get_sha1(local_obj), sha1)) @@ -344,3 +343,4 @@ return NULL; } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/oim.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.c Wed May 02 06:06:56 2007 +0000 @@ -0,0 +1,597 @@ +/** + * @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); +const 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. + */ +const 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"); + + 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, PurpleSslConnection *gsc, + 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, PurpleSslConnection *gsc, + 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; + + 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 = 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); + + msn_session_report_user(oim->session,passport,decode_msg,PURPLE_MESSAGE_SYSTEM); + + /*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, PurpleSslConnection *gsc, + 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 *mdNode,*mNode,*ENode,*INode,*rtNode,*nNode; + char *passport,*rTime,*msgid,*nickname; + + mdNode = xmlnode_from_str(xmlmsg, strlen(xmlmsg)); + 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); +/* 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); + g_free(nickname); + } +} + +/*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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/oim.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/oim.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/servconn.c --- a/libpurple/protocols/msn/servconn.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/servconn.c Wed May 02 06:06:56 2007 +0000 @@ -166,9 +166,9 @@ **************************************************************************/ static void -connect_cb(gpointer data, gint source, const gchar *error_message) +connect_cb(gpointer data, gint source, PurpleInputCondition cond) { - MsnServConn *servconn; + MsnServConn *servconn = data; servconn = data; servconn->connect_data = NULL; @@ -242,7 +242,9 @@ return TRUE; } else + { return FALSE; + } } void @@ -443,6 +445,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/session.c --- a/libpurple/protocols/msn/session.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/session.c Wed May 02 06:06:56 2007 +0000 @@ -42,8 +42,11 @@ session->user = msn_user_new(session->userlist, purple_account_get_username(account), NULL); - - session->protocol_ver = 9; + session->bnode = NULL; + + /*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 +73,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 +92,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 +164,38 @@ return NULL; } +/*get the conversation*/ +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) { @@ -219,6 +261,51 @@ return swboard; } +/*setup the bnode, for MSN SOAP contact/address book op*/ +void +msn_session_set_bnode(MsnSession *session) +{ + PurpleBlistNode *gnode, *cnode, *bnode; + PurpleConnection *gc = purple_account_get_connection(session->account); + + g_return_if_fail(gc != NULL); + + /* 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_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){ + session->bnode = bnode; + return; + } + } + } + } + session->bnode = NULL; +} + +/*get bnode*/ +PurpleBlistNode * +msn_session_get_bnode(MsnSession *session) +{ +#if 1 + return session->bnode; +#else + return purple_get_blist()->root; +#endif +} + static void msn_session_sync_users(MsnSession *session) { @@ -229,13 +316,17 @@ /* 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; if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue; + 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,28 +343,33 @@ 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) { /* The user was not on the server list or not in that group * on the server list */ - msn_show_sync_issue(session, purple_buddy_get_name(b), group_name); + msn_show_sync_issue(session, b->name, group_name); } } } @@ -405,3 +501,4 @@ /* Sync users */ msn_session_sync_users(session); } + diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/session.h --- a/libpurple/protocols/msn/session.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/session.h Wed May 02 06:06:56 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,18 @@ int conv_seq; /**< The current conversation sequence number. */ + /*psm info*/ + char *psm; + + /*first blist contact node*/ + PurpleBlistNode *bnode; + struct { + /*t and p, get via USR TWN*/ + char *t; + char *p; + char *kv; char *sid; char *mspauth; @@ -114,7 +128,6 @@ char *file; char *client_ip; int client_port; - } passport_info; }; @@ -224,4 +237,17 @@ */ void msn_session_finish_login(MsnSession *session); +/*get conversation via session, + * If has one, return that,else create a new one; + */ +PurpleConversation *msn_session_get_conv(MsnSession *session,const char *passport); + +/*post message to User*/ +void msn_session_report_user(MsnSession *session,const char *passport, + char *msg,PurpleMessageFlags flags); + +void msn_session_set_bnode(MsnSession *session); + +PurpleBlistNode *msn_session_get_bnode(MsnSession *session); + #endif /* _MSN_SESSION_H_ */ diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/slp.c --- a/libpurple/protocols/msn/slp.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/slp.c Wed May 02 06:06:56 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); @@ -751,7 +753,7 @@ * reporting bugs. Hopefully this doesn't cause more crashes. Stu. */ if (slplink->swboard != NULL) - slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); + slplink->swboard->slplink = slplink; else purple_debug_error("msn", "msn_p2p_msg, swboard is NULL, ouch!\n"); } @@ -771,15 +773,14 @@ gc = slpcall->slplink->session->account->gc; who = slpcall->slplink->remote_user; - if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, gc->account))) { + 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 - */ - purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); - purple_conv_custom_smiley_close(conv, slpcall->data_info); - } + /* 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 + */ + purple_conv_custom_smiley_write(conv, slpcall->data_info, data, size); + purple_conv_custom_smiley_close(conv, slpcall->data_info ); #ifdef MSN_DEBUG_UD purple_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); #endif diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/slpcall.c --- a/libpurple/protocols/msn/slpcall.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/slpcall.c Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/slplink.c --- a/libpurple/protocols/msn/slplink.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/slplink.c Wed May 02 06:06:56 2007 +0000 @@ -102,7 +102,7 @@ g_return_if_fail(slplink != NULL); if (slplink->swboard != NULL) - slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); + slplink->swboard->slplink = NULL; session = slplink->session; @@ -259,7 +259,7 @@ return; /* If swboard is destroyed we will be too */ - slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); + slplink->swboard->slplink = slplink; } msn_switchboard_send_msg(slplink->swboard, msg, TRUE); diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/soap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.c Wed May 02 06:06:56 2007 +0000 @@ -0,0 +1,597 @@ +/** + * @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); + } + 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/soap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/msn/soap.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/state.c --- a/libpurple/protocols/msn/state.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/state.c Wed May 02 06:06:56 2007 +0000 @@ -38,6 +38,208 @@ 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; + + purple_debug_info("msn", "Parsing currentmedia string: \"%s\"\n", cmedia); + if( (cmedia == NULL) || (!strcmp(cmedia, ""))) { + purple_debug_info("msn", "No currentmedia string\n"); + return NULL; + } + + 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) { @@ -63,13 +265,10 @@ msnobj = msn_user_get_object(user); - if (msnobj == NULL) - { + if (msnobj == NULL){ msn_cmdproc_send(cmdproc, "CHG", "%s %d", state_text, MSN_CLIENT_ID); - } - else - { + }else{ char *msnobj_str; msnobj_str = msn_object_to_string(msnobj); @@ -79,6 +278,7 @@ g_free(msnobj_str); } + msn_set_psm(session); } const char * diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/state.h --- a/libpurple/protocols/msn/state.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/state.h Wed May 02 06:06:56 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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/switchboard.c --- a/libpurple/protocols/msn/switchboard.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.c Wed May 02 06:06:56 2007 +0000 @@ -25,10 +25,12 @@ #include "prefs.h" #include "switchboard.h" #include "notification.h" -#include "msn-utils.h" +#include "msnutils.h" #include "error.h" +#define MSN_DEBUG_SB + static MsnTable *cbs_table; static void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, @@ -82,8 +84,8 @@ swboard->destroying = TRUE; /* If it linked us is because its looking for trouble */ - while (swboard->slplinks != NULL) - msn_slplink_destroy(swboard->slplinks->data); + if (swboard->slplink != NULL) + msn_slplink_destroy(swboard->slplink); /* Destroy the message queue */ while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL) @@ -527,6 +529,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 @@ -614,6 +617,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) @@ -720,7 +724,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 @@ -742,6 +747,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; @@ -955,7 +968,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); } @@ -976,16 +989,13 @@ swboard = cmdproc->data; g_return_if_fail(swboard != NULL); - if (msn_switchboard_is_invited(swboard)) - { + if (msn_switchboard_is_invited(swboard)){ swboard->empty = FALSE; msn_cmdproc_send(cmdproc, "ANS", "%s %s %s", purple_account_get_username(account), swboard->auth_key, swboard->session_id); - } - else - { + }else{ msn_cmdproc_send(cmdproc, "USR", "%s %s", purple_account_get_username(account), swboard->auth_key); @@ -1054,6 +1064,8 @@ cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error) { int reason = MSN_SB_ERROR_UNKNOWN; + MsnMessage *msg; + MsnSwitchBoard *swboard = trans->data; if (error == 215) { @@ -1066,7 +1078,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); } @@ -1110,6 +1134,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); @@ -1222,6 +1247,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/switchboard.h --- a/libpurple/protocols/msn/switchboard.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/switchboard.h Wed May 02 06:06:56 2007 +0000 @@ -102,7 +102,7 @@ MsnSBErrorType error; /**< The error that occurred in this switchboard (if applicable). */ - GList *slplinks; /**< The list of slplinks that are using this switchboard. */ + MsnSlpLink *slplink; /**< The slplink that is using this switchboard. */ }; /** diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/sync.c --- a/libpurple/protocols/msn/sync.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/sync.c Wed May 02 06:06:56 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); diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/table.c --- a/libpurple/protocols/msn/table.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/table.c Wed May 02 06:06:56 2007 +0000 @@ -77,20 +77,14 @@ cbs = NULL; - if (command == NULL) - { + if (command == NULL){ cbs = table->async; - } - else if (strcmp(command, "fallback") == 0) - { + }else if (strcmp(command, "fallback") == 0) { cbs = table->fallback; - } - else - { + }else{ cbs = g_hash_table_lookup(table->cmds, command); - if (cbs == NULL) - { + if (cbs == NULL){ cbs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert(table->cmds, command, cbs); } diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/transaction.c --- a/libpurple/protocols/msn/transaction.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/transaction.c Wed May 02 06:06:56 2007 +0000 @@ -205,8 +205,7 @@ void msn_transaction_set_timeout_cb(MsnTransaction *trans, MsnTimeoutCb cb) { - if (trans->timer) - { + if (trans->timer){ purple_debug_error("msn", "This shouldn't be happening\n"); purple_timeout_remove(trans->timer); } diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/user.c --- a/libpurple/protocols/msn/user.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/user.c Wed May 02 06:06:56 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) { @@ -58,8 +60,13 @@ if (user->clientcaps != NULL) g_hash_table_destroy(user->clientcaps); - if (user->group_ids != NULL) + 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 +74,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 +89,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, "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, "available", NULL); purple_prpl_got_user_status(account, user->passport, "mobile", NULL); @@ -142,12 +161,56 @@ } 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,int type) +{ + g_return_if_fail(user != NULL); + + user->type = type; +} + +void +msn_user_set_op(MsnUser *user,int list_op) +{ + g_return_if_fail(list_op != 0); + user->list_op |= list_op; } void @@ -232,54 +295,79 @@ } } +/*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); +} + +/*check to see if user is yahoo user? + * TODO: we need to identify it via contact parse + */ +gboolean +msn_user_is_yahoo(PurpleAccount *account ,const char *name) +{ + 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) { g_return_if_fail(user != NULL); - g_return_if_fail(id >= 0); + g_return_if_fail(id != NULL); - user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id)); + user->group_ids = g_list_remove(user->group_ids, id); + /* khc need to use g_list_find_custom here to find the right link */ + //g_free(id); } void diff -r 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/user.h --- a/libpurple/protocols/msn/user.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/user.h Wed May 02 06:06:56 2007 +0000 @@ -45,7 +45,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,6 +70,7 @@ GHashTable *clientcaps; /**< The client's capabilities. */ + int type; int list_op; }; @@ -102,6 +108,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 +178,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 +186,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 +204,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,int type); + /** * Sets the mobile phone number for a user. * @@ -279,6 +304,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/userlist.c --- a/libpurple/protocols/msn/userlist.c Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/userlist.c Wed May 02 06:06:56 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(user->group_ids, group_id)) 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; @@ -110,9 +114,8 @@ if (!(user->list_op & list_op)) return FALSE; - if (list_id == MSN_LIST_FL) - { - if (group_id >= 0) + if (list_id == MSN_LIST_FL){ + if (group_id != NULL) return user_is_in_group(user, group_id); } @@ -151,25 +154,25 @@ 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) + 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 +196,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 +216,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 +265,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 +275,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 +287,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 +335,6 @@ { purple_debug_info("msn", "Buddy '%s' shall be deleted?.\n", passport); - } } @@ -353,10 +356,9 @@ if (list_op & MSN_LIST_FL_OP) { GSList *c; - for (c = group_ids; c != NULL; c = g_slist_next(c)) - { - int group_id; - group_id = GPOINTER_TO_INT(c->data); + for (c = group_ids; c != NULL; c = g_slist_next(c)) { + char *group_id; + group_id = c->data; msn_user_add_group_id(user, group_id); } @@ -391,11 +393,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 +427,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 +449,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 +486,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 +511,17 @@ } 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) - { + 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 +540,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 +557,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 +574,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 +586,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,18 +604,22 @@ 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); - if (group_name != 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); return; @@ -619,25 +641,26 @@ 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)) { /* only notify the user about problems adding to the friends list * maybe we should do something else for other lists, but it probably * won't cause too many problems if we just ignore it */ - if (list_id == MSN_LIST_FL) - { + if (list_id == MSN_LIST_FL) { char *str = g_strdup_printf(_("Unable to add \"%s\"."), who); purple_notify_error(NULL, NULL, str, _("The screen name specified is invalid.")); @@ -651,7 +674,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); @@ -674,6 +697,8 @@ /* 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 +707,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 +720,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 6b4e778ee4b4 -r 14b8fb8d27b3 libpurple/protocols/msn/userlist.h --- a/libpurple/protocols/msn/userlist.h Mon Apr 23 17:19:11 2007 +0000 +++ b/libpurple/protocols/msn/userlist.h Wed May 02 06:06:56 2007 +0000 @@ -67,30 +67,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 +103,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_ */