Mercurial > pidgin.yaz
diff libpurple/protocols/msn/notification.c @ 31292:47b6eda87723
propagate from branch 'im.pidgin.pidgin' (head 07d0765c444a097af45c2650f54323afb900a07b)
to branch 'im.pidgin.soc.2010.msn-tlc' (head f3998422a4724ab424e4e2328f58fc0504856557)
author | masca@cpw.pidgin.im |
---|---|
date | Mon, 19 Jul 2010 21:11:32 +0000 |
parents | 88a047f92c39 c7fa7c7aca7d |
children | 23be655cc688 |
line wrap: on
line diff
--- a/libpurple/protocols/msn/notification.c Mon Jul 19 18:25:47 2010 +0000 +++ b/libpurple/protocols/msn/notification.c Mon Jul 19 21:11:32 2010 +0000 @@ -21,17 +21,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include "msn.h" + +#include "internal.h" +#include "cipher.h" +#include "core.h" +#include "debug.h" + #include "notification.h" + #include "contact.h" -#include "state.h" #include "error.h" #include "msnutils.h" -#include "page.h" - +#include "state.h" #include "userlist.h" -#include "sync.h" -#include "slplink.h" static MsnTable *cbs_table; @@ -92,6 +94,7 @@ { MsnCmdProc *cmdproc; MsnSession *session; + MsnTransaction *trans; PurpleAccount *account; GString *vers; const char *ver_str; @@ -117,7 +120,8 @@ /* Skip the initial space */ ver_str = (vers->str + 1); - msn_cmdproc_send(cmdproc, "VER", "%s", ver_str); + trans = msn_transaction_new(cmdproc, "VER", "%s", ver_str); + msn_cmdproc_send_trans(cmdproc, trans); g_string_free(vers, TRUE); } @@ -156,22 +160,30 @@ msn_got_login_params(MsnSession *session, const char *ticket, const char *response) { MsnCmdProc *cmdproc; + MsnTransaction *trans; cmdproc = session->notification->cmdproc; msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END); - msn_cmdproc_send(cmdproc, "USR", "SSO S %s %s", ticket, response); + if (session->protocol_ver >= 16) + trans = msn_transaction_new(cmdproc, "USR", "SSO S %s %s %s", ticket, response, session->guid); + else + trans = msn_transaction_new(cmdproc, "USR", "SSO S %s %s", ticket, response); + + msn_cmdproc_send_trans(cmdproc, trans); } static void cvr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { PurpleAccount *account; + MsnTransaction *trans; account = cmdproc->session->account; - msn_cmdproc_send(cmdproc, "USR", "SSO I %s", purple_account_get_username(account)); + trans = msn_transaction_new(cmdproc, "USR", "SSO I %s", purple_account_get_username(account)); + msn_cmdproc_send_trans(cmdproc, trans); } static void @@ -231,22 +243,25 @@ ver_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; + MsnTransaction *trans; PurpleAccount *account; gboolean protocol_supported = FALSE; - char proto_str[8]; + int proto_ver; size_t i; session = cmdproc->session; account = session->account; - g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver); - + session->protocol_ver = 0; for (i = 1; i < cmd->param_count; i++) { - if (!strcmp(cmd->params[i], proto_str)) - { - protocol_supported = TRUE; - break; + if (sscanf(cmd->params[i], "MSNP%d", &proto_ver) == 1) { + if (proto_ver >= WLM_MIN_PROTOCOL + && proto_ver <= WLM_MAX_PROTOCOL + && proto_ver > session->protocol_ver) { + protocol_supported = TRUE; + session->protocol_ver = proto_ver; + } } } @@ -257,15 +272,18 @@ return; } + purple_debug_info("msn", "Negotiated protocol version %d with the server.\n", session->protocol_ver); + /* * Windows Live Messenger 8.5 * Notice :CVR String discriminate! * reference of http://www.microsoft.com/globaldev/reference/oslocversion.mspx * to see the Local ID */ - msn_cmdproc_send(cmdproc, "CVR", + trans = msn_transaction_new(cmdproc, "CVR", "0x0409 winnt 5.1 i386 MSNMSGR 8.5.1302 BC01 %s", purple_account_get_username(account)); + msn_cmdproc_send_trans(cmdproc, trans); } /************************************************************************** @@ -287,12 +305,16 @@ void msn_notification_close(MsnNotification *notification) { + MsnTransaction *trans; + g_return_if_fail(notification != NULL); if (!notification->in_use) return; - msn_cmdproc_send_quick(notification->cmdproc, "OUT", NULL, NULL); + trans = msn_transaction_new(notification->cmdproc, "OUT", NULL); + msn_transaction_set_saveable(trans, FALSE); + msn_cmdproc_send_trans(notification->cmdproc, trans); msn_notification_disconnect(notification); } @@ -1003,7 +1025,8 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj = NULL; - unsigned long clientid; + unsigned long clientid, extcaps; + char *extcap_str; int networkid = 0; const char *state, *passport; char *friendly; @@ -1024,7 +1047,11 @@ /* Yahoo! Buddy, looks like */ networkid = atoi(cmd->params[3]); friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], NULL, 10); + clientid = strtoul(cmd->params[5], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; /* cmd->params[7] seems to be a URL to a Yahoo! icon: https://sec.yimg.com/i/us/nt/b/purpley.1.0.png @@ -1034,7 +1061,11 @@ /* MSNP14+ with Display Picture object */ networkid = atoi(cmd->params[3]); friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], NULL, 10); + clientid = strtoul(cmd->params[5], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[6])); } else if (cmd->param_count == 6) { /* Yes, this is 5. The friendly name could start with a number, @@ -1043,17 +1074,29 @@ /* MSNP14 without Display Picture object */ networkid = atoi(cmd->params[3]); friendly = g_strdup(purple_url_decode(cmd->params[4])); - clientid = strtoul(cmd->params[5], NULL, 10); + clientid = strtoul(cmd->params[5], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; } else { /* MSNP8+ with Display Picture object */ friendly = g_strdup(purple_url_decode(cmd->params[3])); - clientid = strtoul(cmd->params[4], NULL, 10); + clientid = strtoul(cmd->params[4], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; msnobj = msn_object_new_from_string(purple_url_decode(cmd->params[5])); } } else if (cmd->param_count == 5) { /* MSNP8+ without Display Picture object */ friendly = g_strdup(purple_url_decode(cmd->params[3])); - clientid = strtoul(cmd->params[4], NULL, 10); + clientid = strtoul(cmd->params[4], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; } else { purple_debug_warning("msn", "Received ILN with unknown number of parameters.\n"); return; @@ -1068,6 +1111,7 @@ user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); msn_user_set_clientid(user, clientid); + msn_user_set_extcaps(user, extcaps); msn_user_set_network(user, networkid); msn_user_set_state(user, state); @@ -1206,7 +1250,8 @@ PurpleConnection *gc; MsnUser *user; MsnObject *msnobj; - unsigned long clientid; + unsigned long clientid, extcaps; + char *extcap_str; int networkid; const char *state, *passport, *friendly; @@ -1219,7 +1264,10 @@ networkid = atoi(cmd->params[2]); friendly = purple_url_decode(cmd->params[3]); - user = msn_userlist_find_user(session->userlist, passport); + if (g_str_equal(passport, session->user->passport)) + user = session->user; + else + user = msn_userlist_find_user(session->userlist, passport); if (user == NULL) return; if (msn_user_set_friendly_name(user, friendly)) @@ -1237,10 +1285,16 @@ msn_user_set_object(user, NULL); } - clientid = strtoul(cmd->params[4], NULL, 10); + clientid = strtoul(cmd->params[4], &extcap_str, 10); + if (session->protocol_ver >= 16 && extcap_str && *extcap_str) + extcaps = strtoul(extcap_str+1, NULL, 10); + else + extcaps = 0; + user->mobile = (clientid & MSN_CLIENT_CAP_MSNMOBILE) || (user->extinfo && user->extinfo->phone_mobile && user->extinfo->phone_mobile[0] == '+'); msn_user_set_clientid(user, clientid); + msn_user_set_extcaps(user, extcaps); msn_user_set_network(user, networkid); msn_user_set_state(user, state); @@ -1508,6 +1562,77 @@ /*get the payload content*/ } +static void +parse_user_endpoints(MsnUser *user, xmlnode *payloadNode) +{ + xmlnode *epNode, *capsNode; + MsnUserEndpoint data; + const char *id; + char *caps, *tmp; + + purple_debug_info("msn", "Get EndpointData\n"); + + for (epNode = xmlnode_get_child(payloadNode, "EndpointData"); + epNode; + epNode = xmlnode_get_next_twin(epNode)) { + id = xmlnode_get_attrib(epNode, "id"); + capsNode = xmlnode_get_child(epNode, "Capabilities"); + + if (capsNode != NULL) { + caps = xmlnode_get_data(capsNode); + + data.clientid = strtoul(caps, &tmp, 10); + if (tmp && *tmp) + data.extcaps = strtoul(tmp + 1, NULL, 10); + else + data.extcaps = 0; + + g_free(caps); + + } else { + data.clientid = 0; + data.extcaps = 0; + } + + msn_user_set_endpoint_data(user, id, &data); + } + + /* Need to shortcut this check, probably... */ + if (user == user->userlist->session->user) { + for (epNode = xmlnode_get_child(payloadNode, "PrivateEndpointData"); + epNode; + epNode = xmlnode_get_next_twin(epNode)) { + MsnUserEndpoint *ep; + xmlnode *nameNode, *clientNode; + + /* <PrivateEndpointData id='{GUID}'> + <EpName>Endpoint Name</EpName> + <Idle>true/false</Idle> + <ClientType>1</ClientType> + <State>NLN</State> + </PrivateEndpointData> + */ + id = xmlnode_get_attrib(epNode, "id"); + ep = msn_user_get_endpoint_data(user, id); + + if (ep != NULL) { + nameNode = xmlnode_get_child(epNode, "EpName"); + if (nameNode != NULL) { + g_free(ep->name); + ep->name = xmlnode_get_data(nameNode); + } + + clientNode = xmlnode_get_child(epNode, "ClientType"); + if (clientNode != NULL) { + tmp = xmlnode_get_data(clientNode); + ep->type = strtoul(tmp, NULL, 10); + g_free(tmp); + } + } + } + } +} + static void parse_currentmedia(MsnUser *user, const char *cmedia) { char **cmedia_array; @@ -1574,15 +1699,19 @@ PurpleAccount *account; MsnUser *user; const char *passport; - char *str; + xmlnode *payloadNode; + char *psm_str, *str; session = cmdproc->session; account = session->account; passport = cmd->params[0]; - user = msn_userlist_find_user(session->userlist, passport); + if (g_str_equal(passport, session->user->passport)) + user = session->user; + else + user = msn_userlist_find_user(session->userlist, passport); if (user == NULL) { - str = g_strndup(payload, len); + char *str = g_strndup(payload, len); purple_debug_info("msn", "unknown user %s, payload is %s\n", passport, str); g_free(str); @@ -1601,13 +1730,28 @@ } if (len != 0) { - str = msn_get_psm(cmd->payload,len); - msn_user_set_statusline(user, str); - g_free(str); - - str = msn_get_currentmedia(cmd->payload, len); + payloadNode = xmlnode_from_str(payload, len); + if (!payloadNode) { + purple_debug_error("msn", "UBX XML parse Error!\n"); + + msn_user_set_statusline(user, NULL); + + msn_user_update(user); + return; + } + + psm_str = msn_get_psm(payloadNode); + msn_user_set_statusline(user, psm_str); + g_free(psm_str); + + str = msn_get_currentmedia(payloadNode); parse_currentmedia(user, str); g_free(str); + + parse_user_endpoints(user, payloadNode); + + xmlnode_free(payloadNode); + } else { msn_user_set_statusline(user, NULL); } @@ -1640,6 +1784,161 @@ cmd->payload_len = atoi(cmd->params[1]); } +void +msn_notification_send_uux(MsnSession *session, const char *payload) +{ + MsnTransaction *trans; + MsnCmdProc *cmdproc; + size_t len = strlen(payload); + + cmdproc = session->notification->cmdproc; + purple_debug_misc("msn", "Sending UUX command with payload: %s\n", payload); + trans = msn_transaction_new(cmdproc, "UUX", "%" G_GSIZE_FORMAT, len); + msn_transaction_set_payload(trans, payload, len); + msn_cmdproc_send_trans(cmdproc, trans); +} + +void msn_notification_send_uux_endpointdata(MsnSession *session) +{ + xmlnode *epDataNode; + xmlnode *capNode; + char *caps; + char *payload; + int length; + + epDataNode = xmlnode_new("EndpointData"); + + capNode = xmlnode_new_child(epDataNode, "Capabilities"); + if (session->protocol_ver >= 16) + caps = g_strdup_printf("%d:%02d", MSN_CLIENT_ID_CAPABILITIES, MSN_CLIENT_ID_EXT_CAPS); + else + caps = g_strdup_printf("%d", MSN_CLIENT_ID_CAPABILITIES); + xmlnode_insert_data(capNode, caps, -1); + g_free(caps); + + payload = xmlnode_to_str(epDataNode, &length); + + msn_notification_send_uux(session, payload); + + xmlnode_free(epDataNode); + g_free(payload); +} + +void msn_notification_send_uux_private_endpointdata(MsnSession *session) +{ + xmlnode *private; + const char *name; + xmlnode *epname; + xmlnode *idle; + GHashTable *ui_info; + const gchar *ui_type; + xmlnode *client_type; + xmlnode *state; + char *payload; + int length; + + private = xmlnode_new("PrivateEndpointData"); + + name = purple_account_get_string(session->account, "endpoint-name", NULL); + epname = xmlnode_new_child(private, "EpName"); + xmlnode_insert_data(epname, name, -1); + + idle = xmlnode_new_child(private, "Idle"); + xmlnode_insert_data(idle, "false", -1); + + /* ClientType info (from amsn guys): + 0: None + 1: Computer + 2: Website + 3: Mobile / none + 4: Xbox / phone /mobile + 9: MsnGroup + 32: Email member, currently Yahoo! + */ + client_type = xmlnode_new_child(private, "ClientType"); + ui_info = purple_core_get_ui_info(); + ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL; + if (ui_type) { + if (strcmp(ui_type, "pc") == 0) + xmlnode_insert_data(client_type, "1", -1); + else if (strcmp(ui_type, "web") == 0) + xmlnode_insert_data(client_type, "2", -1); + else if (strcmp(ui_type, "phone") == 0) + xmlnode_insert_data(client_type, "3", -1); + else if (strcmp(ui_type, "handheld") == 0) + xmlnode_insert_data(client_type, "3", -1); + else + xmlnode_insert_data(client_type, "1", -1); + } + else + xmlnode_insert_data(client_type, "1", -1); + + state = xmlnode_new_child(private, "State"); + xmlnode_insert_data(state, msn_state_get_text(msn_state_from_account(session->account)), -1); + + payload = xmlnode_to_str(private, &length); + + msn_notification_send_uux(session, payload); + + xmlnode_free(private); + g_free(payload); +} + +static void +ubn_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + /* Do Nothing, right now. */ + if (payload != NULL) + purple_debug_info("msn", "UBN payload:\n%s\n", payload); +} + +static void +ubn_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + purple_debug_misc("msn", "UBN received from %s.\n", cmd->params[0]); + cmdproc->last_cmd->payload_cb = ubn_cmd_post; + cmd->payload_len = atoi(cmd->params[2]); +} + +static void +uun_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload, + size_t len) +{ + /* Do Nothing, right now. */ + if (payload != NULL) + purple_debug_info("msn", "UUN payload:\n%s\n", payload); +} + +static void +uun_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) +{ + if (strcmp(cmd->params[1], "OK") != 0) { + purple_debug_misc("msn", "UUN received.\n"); + cmdproc->last_cmd->payload_cb = uun_cmd_post; + cmd->payload_len = atoi(cmd->params[1]); + } + else + purple_debug_misc("msn", "UUN OK received.\n"); +} + +void +msn_notification_send_uun(MsnSession *session, const char *user, + MsnUnifiedNotificationType type, const char *payload) +{ + MsnTransaction *trans; + MsnCmdProc *cmdproc; + size_t len = strlen(payload); + + cmdproc = session->notification->cmdproc; + purple_debug_misc("msn", "Sending UUN command %d to %s with payload: %s\n", + type, user, payload); + trans = msn_transaction_new(cmdproc, "UUN", "%s %d %" G_GSIZE_FORMAT, + user, type, len); + msn_transaction_set_payload(trans, payload, len); + msn_cmdproc_send_trans(cmdproc, trans); +} + /************************************************************************** * Message Types **************************************************************************/ @@ -1657,39 +1956,39 @@ /* This isn't an official message. */ return; - if ((value = msn_message_get_attr(msg, "kv")) != NULL) + if ((value = msn_message_get_header_value(msg, "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_header_value(msg, "sid")) != NULL) { g_free(session->passport_info.sid); session->passport_info.sid = g_strdup(value); } - if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL) + if ((value = msn_message_get_header_value(msg, "MSPAuth")) != NULL) { g_free(session->passport_info.mspauth); session->passport_info.mspauth = g_strdup(value); } - if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL) + if ((value = msn_message_get_header_value(msg, "ClientIP")) != NULL) { g_free(session->passport_info.client_ip); session->passport_info.client_ip = g_strdup(value); } - if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL) + if ((value = msn_message_get_header_value(msg, "ClientPort")) != NULL) { session->passport_info.client_port = ntohs(atoi(value)); } - if ((value = msn_message_get_attr(msg, "LoginTime")) != NULL) + if ((value = msn_message_get_header_value(msg, "LoginTime")) != NULL) session->passport_info.sl = atol(value); - if ((value = msn_message_get_attr(msg, "EmailEnabled")) != NULL) + if ((value = msn_message_get_header_value(msg, "EmailEnabled")) != NULL) session->passport_info.email_enabled = (gboolean)atol(value); /*starting retrieve the contact list*/ @@ -2093,6 +2392,9 @@ 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, "UBN", ubn_cmd); + msn_table_add_cmd(cbs_table, NULL, "UUN", uun_cmd); + msn_table_add_cmd(cbs_table, NULL, "URL", url_cmd); msn_table_add_cmd(cbs_table, "fallback", "XFR", xfr_cmd);