From b7a1174511c3b7fad5b81a54bb4647662d94031c Mon Sep 17 00:00:00 2001 From: Piotr Piastucki Date: Thu, 14 May 2015 15:24:53 +0000 Subject: Updated for partial MSNP24 protocol support, for detailed changes see MSNP24 branch. git-svn-id: http://svn.miranda-ng.org/main/trunk@13589 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/MSN/src/msn_commands.cpp | 942 +++++++++++++++++++++++++++---------- 1 file changed, 684 insertions(+), 258 deletions(-) (limited to 'protocols/MSN/src/msn_commands.cpp') diff --git a/protocols/MSN/src/msn_commands.cpp b/protocols/MSN/src/msn_commands.cpp index ab9001d0c9..3c45f5d98d 100644 --- a/protocols/MSN/src/msn_commands.cpp +++ b/protocols/MSN/src/msn_commands.cpp @@ -193,9 +193,8 @@ void CMsnProto::MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, ShellExecuteA(NULL, "open", "conf.exe", NULL, NULL, SW_SHOW); Sleep(3000); - char command[1024]; - int nBytes = mir_snprintf(command, SIZEOF(command), - "MIME-Version: 1.0\r\n" + info->sendPacketPayload("MSG", "N", + "MIME-Version: 1.0\r\n" "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" "Invitation-Command: ACCEPT\r\n" "Invitation-Cookie: %s\r\n" @@ -203,22 +202,18 @@ void CMsnProto::MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, "Launch-Application: TRUE\r\n" "IP-Address: %s\r\n\r\n", Invcookie, MyConnection.GetMyExtIPStr()); - info->sendPacket("MSG", "N %d\r\n%s", nBytes, command); } return; } // netmeeting receive 1 if (Appname != NULL && !_stricmp(Appname, "NetMeeting")) { - char command[1024]; - int nBytes; - TCHAR text[512], *tszEmail = mir_a2t(email); mir_sntprintf(text, SIZEOF(text), TranslateT("Accept NetMeeting request from %s?"), tszEmail); mir_free(tszEmail); if (MessageBox(NULL, text, TranslateT("MSN Protocol"), MB_YESNO | MB_ICONQUESTION) == IDYES) { - nBytes = mir_snprintf(command, SIZEOF(command), + info->sendPacketPayload("MSG", "N", "MIME-Version: 1.0\r\n" "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" "Invitation-Command: ACCEPT\r\n" @@ -231,7 +226,7 @@ void CMsnProto::MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, Invcookie, MyConnection.GetMyExtIPStr()); } else { - nBytes = mir_snprintf(command, SIZEOF(command), + info->sendPacketPayload("MSG", "N", "MIME-Version: 1.0\r\n" "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n" "Invitation-Command: CANCEL\r\n" @@ -239,7 +234,6 @@ void CMsnProto::MSN_InviteMessage(ThreadData* info, char* msgBody, char* email, "Cancel-Code: REJECT\r\n\r\n", Invcookie); } - info->sendPacket("MSG", "N %d\r\n%s", nBytes, command); return; } @@ -320,31 +314,39 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para char* tWords[6]; struct { char *fromEmail, *fromNick, *strMsgBytes; } data; struct { char *fromEmail, *fromNetId, *toEmail, *toNetId, *typeId, *strMsgBytes; } datau; + struct { char *typeId, *strMsgBytes; } datas; }; - if (sttDivideWords(params, SIZEOF(tWords), tWords) < 3) { + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) { debugLogA("Invalid %.3s command, ignoring", cmdString); return; } int msgBytes; - char *nick, *email; + char *nick = NULL, *email; + TCHAR *mChatID = NULL; bool ubmMsg = strncmp(cmdString, "UBM", 3) == 0; + bool sdgMsg = strncmp(cmdString, "SDG", 3) == 0; bool sentMsg = false; - if (ubmMsg) { - msgBytes = atol(datau.strMsgBytes); - nick = datau.fromEmail; - email = datau.fromEmail; - } - else { - msgBytes = atol(data.strMsgBytes); - nick = data.fromNick; - email = data.fromEmail; - UrlDecode(nick); + if (sdgMsg) { + msgBytes = atol(datas.strMsgBytes); + if (stricmp(datas.typeId, "MSGR")) return; + } else { + if (ubmMsg) { + msgBytes = atol(datau.strMsgBytes); + nick = datau.fromEmail; + email = datau.fromEmail; + } + else { + msgBytes = atol(data.strMsgBytes); + nick = data.fromNick; + email = data.fromEmail; + UrlDecode(nick); + } + stripBBCode(nick); + stripColorCode(nick); } - stripBBCode(nick); - stripColorCode(nick); char* msg = (char*)alloca(msgBytes+1); @@ -360,11 +362,35 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para MimeHeaders tHeader; char* msgBody = tHeader.readFromBuffer(msg); + if (sdgMsg) { + if (tHeader["Ack-Id"]) { + CMStringA buf; + + buf.AppendFormat("Ack-Id: %s\r\n", tHeader["Ack-Id"]); + if (msnRegistration) buf.AppendFormat("Registration: %s\r\n", msnRegistration); + buf.AppendFormat("\r\n"); + msnNsThread->sendPacket("ACK", "MSGR %d\r\n%s", strlen(buf), buf); + } + msgBody = tHeader.readFromBuffer(msgBody); + if (!(email = NEWSTR_ALLOCA(tHeader["From"]))) return; + mChatID = mir_a2t(tHeader["To"]); + if (_tcsncmp(mChatID, _T("19:"), 3)) mChatID[0]=0; // NETID_THREAD + msgBody = tHeader.readFromBuffer(msgBody); + msgBody = tHeader.readFromBuffer(msgBody); + nick = NEWSTR_ALLOCA(tHeader["IM-Display-Name"]); + if (!strcmp(tHeader["Message-Type"], "RichText")) { + msgBody = NEWSTR_ALLOCA(msgBody); + stripHTML(msgBody); + HtmlDecode(msgBody); + } + } + else mChatID = info->mChatID; + const char* tMsgId = tHeader["Message-ID"]; // Chunked message char* newbody = NULL; - if (tMsgId) { + if (!sdgMsg && tMsgId) { int idx; const char* tChunks = tHeader["Chunks"]; if (tChunks) @@ -378,7 +404,7 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para } // message from the server (probably) - if (!ubmMsg && strchr(email, '@') == NULL && _stricmp(email, "Hotmail")) + if (!ubmMsg && !sdgMsg && strchr(email, '@') == NULL && _stricmp(email, "Hotmail")) return; const char* tContentType = tHeader["Content-Type"]; @@ -397,80 +423,80 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para delSetting(hContact, "StdMirVer"); } } - else if (!ubmMsg && !info->firstMsgRecv) { + else if (!ubmMsg && !sdgMsg && !info->firstMsgRecv) { info->firstMsgRecv = true; MsnContact *cont = Lists_Get(email); if (cont && cont->hContact != NULL) MSN_SetMirVer(cont->hContact, cont->cap1, true); } - if (!_strnicmp(tContentType, "text/plain", 10)) { - MCONTACT hContact = MSN_HContactFromEmail(email, nick, true, true); - - const char* p = tHeader["X-MMS-IM-Format"]; - bool isRtl = p != NULL && strstr(p, "RL=1") != NULL; - - if (info->mJoinedContactsWLID.getCount() > 1) - MSN_ChatStart(info); - else { - char *szEmail; - parseWLID(NEWSTR_ALLOCA(email), NULL, &szEmail, NULL); - sentMsg = _stricmp(szEmail, MyOptions.szEmail) == 0; - if (sentMsg) - hContact = ubmMsg ? MSN_HContactFromEmail(datau.toEmail, nick) : info->getContactHandle(); - } + if (!_strnicmp(tContentType, "text/plain", 10) || + (!_strnicmp(tContentType, "application/user+xml", 10) && tHeader["Message-Type"] && !strcmp(tHeader["Message-Type"], "RichText"))) { + MCONTACT hContact = strncmp(email, "19:", 3)?MSN_HContactFromEmail(email, nick, true, true):NULL; + + int iTyping = -1; + if (!_stricmp(tHeader["Message-Type"], "Control/Typing")) iTyping=7; else + if (!_stricmp(tHeader["Message-Type"], "Control/ClearTyping")) iTyping=0; + if (iTyping == -1) { + + const char* p = tHeader["X-MMS-IM-Format"]; + bool isRtl = p != NULL && strstr(p, "RL=1") != NULL; + + /*if (info->mJoinedContactsWLID.getCount() > 1) + MSN_ChatStart(info); + else */{ + char *szNet, *szEmail; + parseWLID(NEWSTR_ALLOCA(email), &szNet, &szEmail, NULL); + sentMsg = _stricmp(szEmail, GetMyUsername(atoi(szNet))) == 0; + if (sentMsg) + hContact = ubmMsg ? MSN_HContactFromEmail(datau.toEmail, nick) : info->getContactHandle(); + } - const char* tP4Context = tHeader["P4-Context"]; - if (tP4Context) { - size_t newlen = strlen(msgBody) + strlen(tP4Context) + 4; - char* newMsgBody = (char*)mir_alloc(newlen); - mir_snprintf(newMsgBody, newlen, "[%s] %s", tP4Context, msgBody); - mir_free(newbody); - msgBody = newbody = newMsgBody; - } + const char* tP4Context = tHeader["P4-Context"]; + if (tP4Context) { + size_t newlen = strlen(msgBody) + strlen(tP4Context) + 4; + char* newMsgBody = (char*)mir_alloc(newlen); + mir_snprintf(newMsgBody, newlen, "[%s] %s", tP4Context, msgBody); + mir_free(newbody); + msgBody = newbody = newMsgBody; + } - if (info->mChatID[0]) { - GCDEST gcd = { m_szModuleName, info->mChatID, GC_EVENT_MESSAGE }; - GCEVENT gce = { sizeof(gce), &gcd }; - gce.dwFlags = GCEF_ADDTOLOG; - gce.ptszUID = mir_a2t(email); - gce.ptszNick = GetContactNameT(hContact); - gce.time = time(NULL); - gce.bIsMe = FALSE; - - TCHAR* p = mir_utf8decodeT(msgBody); - gce.ptszText = EscapeChatTags(p); - mir_free(p); - - CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); - mir_free((void*)gce.ptszText); - mir_free((void*)gce.ptszUID); - } - else if (hContact) { - if (!sentMsg) { - CallService(MS_PROTO_CONTACTISTYPING, WPARAM(hContact), 0); - - PROTORECVEVENT pre = { 0 }; - pre.szMessage = (char*)msgBody; - pre.flags = PREF_UTF + (isRtl ? PREF_RTL : 0); - pre.timestamp = (DWORD)time(NULL); - pre.lParam = 0; - ProtoChainRecvMsg(hContact, &pre); + if (mChatID[0]) { + if (!_strnicmp(tHeader["Message-Type"], "ThreadActivity/", 15)) { + ezxml_t xmli = ezxml_parse_str(msgBody, strlen(msgBody)); + if (xmli) { + MSN_GCProcessThreadActivity(xmli, mChatID); + ezxml_free(xmli); + } + } + else MSN_GCAddMessage(mChatID, hContact, email, time(NULL), sentMsg, msgBody); } - else { - bool haveWnd = MSN_MsgWndExist(hContact); - - DBEVENTINFO dbei = { 0 }; - dbei.cbSize = sizeof(dbei); - dbei.eventType = EVENTTYPE_MESSAGE; - dbei.flags = DBEF_SENT | DBEF_UTF | (haveWnd ? 0 : DBEF_READ) | (isRtl ? DBEF_RTL : 0); - dbei.szModule = m_szModuleName; - dbei.timestamp = time(NULL); - dbei.cbBlob = (unsigned)strlen(msgBody) + 1; - dbei.pBlob = (PBYTE)msgBody; - db_event_add(hContact, &dbei); + else if (hContact) { + if (!sentMsg) { + CallService(MS_PROTO_CONTACTISTYPING, WPARAM(hContact), 0); + + PROTORECVEVENT pre = { 0 }; + pre.szMessage = (char*)msgBody; + pre.flags = PREF_UTF + (isRtl ? PREF_RTL : 0); + pre.timestamp = (DWORD)time(NULL); + pre.lParam = 0; + ProtoChainRecvMsg(hContact, &pre); + } + else { + bool haveWnd = MSN_MsgWndExist(hContact); + + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.flags = DBEF_SENT | DBEF_UTF | (haveWnd ? 0 : DBEF_READ) | (isRtl ? DBEF_RTL : 0); + dbei.szModule = m_szModuleName; + dbei.timestamp = time(NULL); + dbei.cbBlob = (unsigned)strlen(msgBody) + 1; + dbei.pBlob = (PBYTE)msgBody; + db_event_add(hContact, &dbei); + } } - } + } else CallService(MS_PROTO_CONTACTISTYPING, hContact, iTyping); } else if (!_strnicmp(tContentType, "text/x-msmsgsprofile", 20)) { replaceStr(msnExternalIP, tHeader["ClientIP"]); @@ -487,12 +513,14 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para MSN_EnableMenuItems(true); } } - else if (!_strnicmp(tContentType, "text/x-msmsgscontrol", 20)) { - const char* tTypingUser = tHeader["TypingUser"]; + else if (!_strnicmp(tContentType, "text/x-msmsgscontrol", 20) || + (sdgMsg && !_strnicmp(tContentType, "Application/Message", 19))) { + const char* tTypingUser = sdgMsg?email:tHeader["TypingUser"]; if (tTypingUser != NULL && info->mChatID[0] == 0 && _stricmp(email, MyOptions.szEmail)) { MCONTACT hContact = MSN_HContactFromEmail(tTypingUser, tTypingUser); - CallService(MS_PROTO_CONTACTISTYPING, hContact, 7); + CallService(MS_PROTO_CONTACTISTYPING, hContact, + sdgMsg && !_stricmp(tHeader["Message-Type"], "Control/ClearTyping")?0:7); } } else if (!_strnicmp(tContentType, "text/x-msnmsgr-datacast", 23)) { @@ -562,6 +590,7 @@ void CMsnProto::MSN_ReceiveMessage(ThreadData* info, char* cmdString, char* para else if (!_strnicmp(tContentType, "text/x-mms-animemoticon", 23)) MSN_CustomSmiley(msgBody, email, nick, MSN_APPID_CUSTOMANIMATEDSMILEY); + mir_free(mChatID); mir_free(newbody); } @@ -705,35 +734,145 @@ void CMsnProto::MSN_ProcessRemove(char* buf, size_t len) // MSN_HandleCommands - process commands from the server ///////////////////////////////////////////////////////////////////////////////////////// -void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wlid) +void CMsnProto::MSN_ProcessNLN(const char *userStatus, const char *wlid, char *userNick, const char *objid, char *cmdstring) { - MCONTACT hContact = MSN_HContactFromEmail(wlid); - if (hContact == NULL) return; + if (userNick) { + UrlDecode(userNick); + stripBBCode(userNick); + stripColorCode(userNick); + } - ezxml_t xmli = ezxml_parse_str(buf, len); + bool isMe = false; + char* szEmail, *szNet; + parseWLID(NEWSTR_ALLOCA(wlid), &szNet, &szEmail, NULL); + if (!stricmp(szEmail, GetMyUsername(atoi(szNet)))) { + isMe = true; + int newStatus = MSNStatusToMiranda(userStatus); + if (newStatus != m_iStatus && newStatus != ID_STATUS_IDLE) { + int oldMode = m_iStatus; + m_iDesiredStatus = m_iStatus = newStatus; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldMode, m_iStatus); + } + } - char* szEmail; - parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, NULL); + WORD lastStatus = ID_STATUS_OFFLINE; - // Add endpoints - for (ezxml_t endp = ezxml_child(xmli, "EndpointData"); endp; endp = ezxml_next(endp)) { - const char *id = ezxml_attr(endp, "id"); - const char *caps = ezxml_txt(ezxml_child(endp, "Capabilities")); - char* end = NULL; - unsigned cap1 = caps ? strtoul(caps, &end, 10) : 0; - unsigned cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0; - - Lists_AddPlace(szEmail, id, cap1, cap2); + MsnContact *cont = Lists_Get(szEmail); + + MCONTACT hContact = NULL; + if (!cont && !isMe) { + hContact = MSN_HContactFromEmail(wlid, userNick, true, true); + cont = Lists_Get(szEmail); } + if (cont) hContact = cont->hContact; - // Process status message info - const char* szStatMsg = ezxml_txt(ezxml_child(xmli, "PSM")); - if (*szStatMsg) { - stripBBCode((char*)szStatMsg); - stripColorCode((char*)szStatMsg); - db_set_utf(hContact, "CList", "StatusMsg", szStatMsg); + if (hContact != NULL) { + if (userNick) setStringUtf(hContact, "Nick", userNick); + lastStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE); + if (lastStatus == ID_STATUS_OFFLINE || lastStatus == ID_STATUS_INVISIBLE) + db_unset(hContact, "CList", "StatusMsg"); + + int newStatus = MSNStatusToMiranda(userStatus); + setWord(hContact, "Status", newStatus != ID_STATUS_IDLE ? newStatus : ID_STATUS_AWAY); + setDword(hContact, "IdleTS", newStatus != ID_STATUS_IDLE ? 0 : time(NULL)); + } + + if (cont) { + if (objid) { + char* end = NULL; + cont->cap1 = strtoul(objid, &end, 10); + cont->cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0; + } + + if (lastStatus == ID_STATUS_OFFLINE) { + DBVARIANT dbv; + bool always = getString(hContact, "MirVer", &dbv) != 0; + if (!always) db_free(&dbv); + MSN_SetMirVer(hContact, cont->cap1, always); + } + + char *pszUrl, *pszAvatarHash; + if (cmdstring && *cmdstring && strcmp(cmdstring, "0") && + (pszAvatarHash = MSN_GetAvatarHash(cmdstring, &pszUrl))) + { + setString(hContact, "PictContext", cmdstring); + setString(hContact, "AvatarHash", pszAvatarHash); + if (pszUrl) + setString(hContact, "AvatarUrl", pszUrl); + else + delSetting(hContact, "AvatarUrl"); + + if (hContact != NULL) { + char szSavedHash[64] = ""; + db_get_static(hContact, m_szModuleName, "AvatarSavedHash", szSavedHash, sizeof(szSavedHash)); + if (stricmp(szSavedHash, pszAvatarHash)) + pushAvatarRequest(hContact, pszUrl); + else { + char szSavedContext[64]; + int result = db_get_static(hContact, m_szModuleName, "PictSavedContext", szSavedContext, sizeof(szSavedContext)); + if (result || strcmp(szSavedContext, cmdstring)) + pushAvatarRequest(hContact, pszUrl); + } + } + mir_free(pszAvatarHash); + mir_free(pszUrl); + } + else { + delSetting(hContact, "AvatarHash"); + delSetting(hContact, "AvatarSavedHash"); + delSetting(hContact, "AvatarUrl"); + delSetting(hContact, "PictContext"); + delSetting(hContact, "PictSavedContext"); + + ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0); + } + } + else if (lastStatus == ID_STATUS_OFFLINE) + delSetting(hContact, "MirVer"); +} + +void CMsnProto::MSN_ProcessStatusMessage(ezxml_t xmli, const char* wlid) +{ + MCONTACT hContact = MSN_HContactFromEmail(wlid); + if (hContact == NULL) return; + + char* szEmail, *szNetId; + parseWLID(NEWSTR_ALLOCA(wlid), &szNetId, &szEmail, NULL); + + bool bHasPSM=false; + char* szStatMsg = NULL; + + for (ezxml_t s = ezxml_child(xmli, "s"); s; s = s->next) { + const char *n = ezxml_attr(s, "n"); + if (!strcmp(n, "SKP")) { + szStatMsg = ezxml_txt(ezxml_child(s, "Mood")); + if (*szStatMsg) db_set_utf(hContact, "CList", "StatusMsg", szStatMsg); + else if (!bHasPSM) db_unset(hContact, "CList", "StatusMsg"); + } else if (!strcmp(n, "PE")) { + szStatMsg = ezxml_txt(ezxml_child(s, "PSM")); + if (*szStatMsg) { + stripBBCode((char*)szStatMsg); + stripColorCode((char*)szStatMsg); + db_set_utf(hContact, "CList", "StatusMsg", szStatMsg); + bHasPSM = true; + } + else db_unset(hContact, "CList", "StatusMsg"); + } + } + + // Add endpoints + for (ezxml_t endp = ezxml_child(xmli, "sep"); endp; endp = ezxml_next(endp)) { + const char *n = ezxml_attr(endp, "n"); + if (!strcmp(n, "IM")) { + const char *id = ezxml_attr(endp, "epid"); + const char *caps = ezxml_txt(ezxml_child(endp, "Capabilities")); + char* end = NULL; + unsigned cap1 = caps ? strtoul(caps, &end, 10) : 0; + unsigned cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0; + + Lists_AddPlace(szEmail, id, cap1, cap2); + } } - else db_unset(hContact, "CList", "StatusMsg"); { ptrT tszStatus(mir_utf8decodeT(szStatMsg)); @@ -744,7 +883,6 @@ void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wl const char* szCrntMda = ezxml_txt(ezxml_child(xmli, "CurrentMedia")); if (!*szCrntMda) { delSetting(hContact, "ListeningTo"); - ezxml_free(xmli); return; } @@ -766,7 +904,6 @@ void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wl // Now let's mount the final string if (pCount <= 4) { delSetting(hContact, "ListeningTo"); - ezxml_free(xmli); return; } @@ -780,7 +917,6 @@ void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wl } if (!foundUsefullInfo) { delSetting(hContact, "ListeningTo"); - ezxml_free(xmli); return; } @@ -847,7 +983,6 @@ void CMsnProto::MSN_ProcessStatusMessage(char* buf, unsigned len, const char* wl mir_free(lti.ptszPlayer); mir_free(lti.ptszType); } - ezxml_free(xmli); } void CMsnProto::MSN_ProcessPage(char* buf, unsigned len) @@ -918,6 +1053,7 @@ void CMsnProto::MSN_ProcessNotificationMessage(char* buf, unsigned len) void CMsnProto::MSN_InitSB(ThreadData* info, const char* szEmail) { +/* MSNP21: No more switchboard, bye, bye ... MsnContact *cont = Lists_Get(szEmail); if (cont->netId == NETID_MSN) @@ -936,7 +1072,7 @@ void CMsnProto::MSN_InitSB(ThreadData* info, const char* szEmail) ProtoBroadcastAck(cont->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)E.seq, 0); } else { - if (E.msgType == 'D' && !info->mBridgeInit /*&& strchr(data.flags, ':')*/) { + if (E.msgType == 'D' && !info->mBridgeInit) { //&& strchr(data.flags, ':')) { info->mBridgeInit = true; // P2PV2_Header hdrdata(E.message); @@ -966,6 +1102,7 @@ void CMsnProto::MSN_InitSB(ThreadData* info, const char* szEmail) PROTO_AVATAR_INFORMATIONT ai = { sizeof(ai), cont->hContact }; GetAvatarInfo(GAIF_FORCE, (LPARAM)&ai); + */ } int CMsnProto::MSN_HandleCommands(ThreadData* info, char* cmdString) @@ -1029,12 +1166,77 @@ LBL_InvalidCommand: case ' SNA': //********* ANS: section 8.4 Getting Invited to a Switchboard Session break; + case ' HTA': //********* ATH: MSNP21+ Authentication + { + union { + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; + }; + + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) + goto LBL_InvalidCommand; + + HReadBuffer buf(info, 0); + char* msgBody = (char*)buf.surelyRead(atol(data.strMsgBytes)); + + if (!bSentBND) + { + info->sendPacketPayload("BND", "CON\\MSGR", + "%d%s%s%s" + "%.*s\r\n", + msnP24Ver, (msnP24Ver>1?"1":""), + msnStoreAppId, msnProductVer, + strlen(MyOptions.szMachineGuid)-2, MyOptions.szMachineGuid+1); + bSentBND = true; + } + else + { + msnLoggedIn = true; + MSN_SetServerStatus(m_iStatus); + MSN_EnableMenuItems(true); + MSN_RefreshContactList(); + MSN_FetchRecentMessages(); + } + } + break; + case ' PRP': break; case ' PLB': //********* BLP: section 7.6 List Retrieval And Property Management break; + case ' DNB': //********* BND: MSNP21+ bind request answer? + { + union { + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; + }; + + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) + goto LBL_InvalidCommand; + + MimeHeaders tHeader; + HReadBuffer buf(info, 0); + char* msgBody = tHeader.readFromBuffer((char*)buf.surelyRead(atol(data.strMsgBytes))); + + replaceStr(msnRegistration,tHeader["Set-Registration"]); + if (!strcmp(data.typeId, "CON")) { + ezxml_t xmlbnd = ezxml_parse_str(msgBody, strlen(msgBody)); + ezxml_t xmlbdy = ezxml_child(xmlbnd, "nonce"); + if (xmlbdy) + { + char dgst[64]; + MSN_MakeDigest(xmlbdy->txt, dgst); + info->sendPacketPayload("PUT", "MSGR\\CHALLENGE", + "%s%s\r\n", + msnProductID, dgst); + } + ezxml_free(xmlbnd); + } + } + break; + case ' EYB': //********* BYE: section 8.5 Session Participant Changes { union { @@ -1149,6 +1351,60 @@ LBL_InvalidCommand: info->sendPacket("QRY", "%s 32\r\n%s", msnProductID, dgst); } break; + case ' TNC': //********* CNT: Connect, MSNP21+ Authentication + { + union { + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; + }; + + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) + goto LBL_InvalidCommand; + + HReadBuffer buf(info, 0); + char* msgBody = (char*)buf.surelyRead(atol(data.strMsgBytes)); + if (strcmp(data.typeId, "CON")) break; + + if (GetMyNetID()!=NETID_SKYPE) { + /* MSN account login */ + char *pszSite = ""; + + switch (MSN_AuthOAuth()) + { + case 1: break; + case 2: pszSite = "chatservice.live.com"; break; + default: + m_iDesiredStatus = ID_STATUS_OFFLINE; + return 1; + } + + info->sendPacketPayload("ATH", "CON\\USER", + "t=%s" + "%s%s" + "%s%s\r\n", + authSSLToken ? ptrA(HtmlEncode(authSSLToken)) : "", + authUIC, pszSite, + GetMyUsername(NETID_MSN), GetMyUsername(NETID_SKYPE)); + } else { + /* Skype username/pass login */ + ezxml_t xmlcnt = ezxml_parse_str(msgBody, strlen(msgBody)); + ezxml_t xmlnonce = ezxml_child(xmlcnt, "nonce"); + if (xmlnonce) { + char szUIC[1024]={0}; + + MSN_SkypeAuth(xmlnonce->txt, szUIC); + info->sendPacketPayload("ATH", "CON\\USER", + "%s%s\r\n", + szUIC, MyOptions.szEmail); + } + ezxml_free(xmlcnt); + } + + bSentBND = false; + ForkThread(&CMsnProto::msn_keepAliveThread, NULL); + ForkThread(&CMsnProto::MSNConnDetectThread, NULL); + } + break; case ' RVC': //********* CVR: MSNP8 break; @@ -1171,115 +1427,184 @@ LBL_InvalidCommand: } } break; - case ' NLI': - case ' NLN': //********* ILN/NLN: section 7.9 Notification Messages + + case ' TEG': //********* GET: MSNP21+ GET reply { union { - char* tWords[5]; - struct { char *userStatus, *wlid, *userNick, *objid, *cmdstring; } data; + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; }; - int tArgs = sttDivideWords(params, 5, tWords); - if (tArgs < 3) + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) goto LBL_InvalidCommand; - UrlDecode(data.userNick); - stripBBCode(data.userNick); - stripColorCode(data.userNick); - - bool isMe = false; - char* szEmail, *szNet; - parseWLID(NEWSTR_ALLOCA(data.wlid), &szNet, &szEmail, NULL); - if (!stricmp(szEmail, MyOptions.szEmail) && !strcmp(szNet, "1")) { - isMe = true; - int newStatus = MSNStatusToMiranda(params); - if (newStatus != m_iStatus && newStatus != ID_STATUS_IDLE) { - int oldMode = m_iStatus; - m_iDesiredStatus = m_iStatus = newStatus; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldMode, m_iStatus); - } - } - - WORD lastStatus = ID_STATUS_OFFLINE; - - MsnContact *cont = Lists_Get(szEmail); - - MCONTACT hContact = NULL; - if (!cont && !isMe) { - hContact = MSN_HContactFromEmail(data.wlid, data.userNick, true, true); - cont = Lists_Get(szEmail); - } - if (cont) hContact = cont->hContact; - - if (hContact != NULL) { - setStringUtf(hContact, "Nick", data.userNick); - lastStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE); - if (lastStatus == ID_STATUS_OFFLINE || lastStatus == ID_STATUS_INVISIBLE) - db_unset(hContact, "CList", "StatusMsg"); - - int newStatus = MSNStatusToMiranda(params); - setWord(hContact, "Status", newStatus != ID_STATUS_IDLE ? newStatus : ID_STATUS_AWAY); - setDword(hContact, "IdleTS", newStatus != ID_STATUS_IDLE ? 0 : time(NULL)); - } - - if (tArgs > 3 && tArgs <= 5 && cont) { - UrlDecode(data.cmdstring); - - char* end = NULL; - cont->cap1 = strtoul(data.objid, &end, 10); - cont->cap2 = end && *end == ':' ? strtoul(end + 1, NULL, 10) : 0; + MimeHeaders tHeader; + HReadBuffer buf(info, 0); + char* msgBody = tHeader.readFromBuffer((char*)buf.surelyRead(atol(data.strMsgBytes))); + ezxml_t xmli; - if (lastStatus == ID_STATUS_OFFLINE) { - DBVARIANT dbv; - bool always = getString(hContact, "MirVer", &dbv) != 0; - if (!always) db_free(&dbv); - MSN_SetMirVer(hContact, cont->cap1, always); + if (tHeader["Set-Registration"]) replaceStr(msnRegistration,tHeader["Set-Registration"]); + if (xmli = ezxml_parse_str(msgBody, strlen(msgBody))) + { + if (!strcmp(xmli->name, "recentconversations-response")) + { + for (ezxml_t conv = ezxml_get(xmli, "conversations", 0, "conversation", -1); conv != NULL; conv = ezxml_next(conv)) { + ezxml_t id; + MCONTACT hContact; + MEVENT hDbEvent; + DWORD ts = 1; + + if (ezxml_get(conv, "messages", 0, "message", -1) && (id=ezxml_child(conv, "id"))) + { + if (strncmp(id->txt, "19:", 3) == 0) { + /* This is a thread (Groupchat) + * Find out about its current state on the server */ + hContact = MSN_HContactFromChatID(id->txt); + msnNsThread->sendPacketPayload("GET", "MSGR\\THREADS", + "%s", id->txt); + } else hContact = MSN_HContactFromEmail(id->txt, NULL, false, false); + + if (hContact) { + // There are messages to be fetched + if (hDbEvent = db_event_last(hContact)) { + DBEVENTINFO dbei = { sizeof(dbei) }; + db_event_get(hDbEvent, &dbei); + ts = dbei.timestamp; + } + db_set_dw(hContact, m_szModuleName, "syncTS", ts); + } + msnNsThread->sendPacketPayload("GET", "MSGR\\MESSAGESBYCONVERSATION", + "%s%llu100", + id->txt, ((unsigned __int64)ts)*1000); + } + } } - - if (data.cmdstring[0] && strcmp(data.cmdstring, "0")) { - char *pszUrl, *pszAvatarHash = MSN_GetAvatarHash(data.cmdstring, &pszUrl); - if (pszAvatarHash == NULL) - goto remove; - - setString(hContact, "PictContext", data.cmdstring); - setString(hContact, "AvatarHash", pszAvatarHash); - if (pszUrl) - setString(hContact, "AvatarUrl", pszUrl); - else - delSetting(hContact, "AvatarUrl"); - - if (hContact != NULL) { - char szSavedHash[64] = ""; - db_get_static(hContact, m_szModuleName, "AvatarSavedHash", szSavedHash, sizeof(szSavedHash)); - if (stricmp(szSavedHash, pszAvatarHash)) - pushAvatarRequest(hContact, pszUrl); - else { - char szSavedContext[64]; - int result = db_get_static(hContact, m_szModuleName, "PictSavedContext", szSavedContext, sizeof(szSavedContext)); - if (result || strcmp(szSavedContext, data.cmdstring)) - pushAvatarRequest(hContact, pszUrl); + else if (!strcmp(xmli->name, "messagesbyconversation-response")) { + ezxml_t id; + MCONTACT hContact; + + if ((id=ezxml_child(xmli, "id"))) + { + bool bIsChat = strncmp(id->txt, "19:", 3)==0; + bool bHasMore = stricmp(ezxml_txt(ezxml_child(xmli, "hasmore")), "true") == 0; + ezxml_t syncstate; + hContact = MSN_HContactFromEmail(id->txt, NULL, false, false); + if (!bHasMore && hContact) db_unset(hContact, m_szModuleName, "syncTS"); + + /* We have to traverse the list in reverse order as newest events are on top (which is the opposite direction of Groupchat) */ + LIST msgs(10,PtrKeySortT); + for (ezxml_t msg = ezxml_get(xmli, "messages", 0, "message", -1); msg != NULL; msg = ezxml_next(msg)) msgs.insert(msg, 0); + for (int i=0; itxt); + parseWLID(NEWSTR_ALLOCA(from->txt), &netId, &email, NULL); + message=content->txt; + sentMsg = stricmp(email, GetMyUsername(atoi(netId)))==0; + if (msgtype) { + if (!strcmp(msgtype->txt, "RichText")) { + message = NEWSTR_ALLOCA(message); + stripHTML(message); + HtmlDecode(message); + } else if (!strncmp(msgtype->txt, "ThreadActivity/", 15)) { + if (ezxml_t xmlact = ezxml_parse_str(content->txt, strlen(content->txt))) { + MSN_GCProcessThreadActivity(xmlact, _A2T(id->txt)); + ezxml_free(xmlact); + } + continue; + } else if (strcmp(msgtype->txt, "Text")) continue; + /* TODO: Implement i.e. RichText/Files for announcement of file transfers */ + } + + if (bIsChat) { + hContact = MSN_HContactFromEmail(from->txt, NULL, false, false); + if (hContact) db_unset(hContact, m_szModuleName, "syncTS"); + MSN_GCAddMessage(_A2T(id->txt), hContact, email, ts, sentMsg, message); + } + else if (hContact) { + /* Protect against double sync (Miranda MSGs only have granularity in seconds) */ + MEVENT hDbEvent; + bool bDuplicate = false; + DBEVENTINFO dbei = { sizeof(dbei) }; + DWORD cbBlob = strlen(message); + dbei.cbBlob = cbBlob; + BYTE *pszMsgBuf = (BYTE*)mir_calloc(cbBlob); + if (pszMsgBuf) { + dbei.pBlob = pszMsgBuf; + for((hDbEvent = db_event_last(hContact)); + !bDuplicate && hDbEvent; + hDbEvent=db_event_prev(hContact, hDbEvent)) + { + if (db_event_get(hDbEvent, &dbei) || dbei.timestamp > ts+1 || dbei.timestamp < ts) break; + if (!memcmp((char*)dbei.pBlob, message, cbBlob)) bDuplicate = true; + dbei.cbBlob = cbBlob; + } + mir_free(pszMsgBuf); + if (bDuplicate) continue; + } + + if (!sentMsg) { + PROTORECVEVENT pre = { 0 }; + pre.szMessage = (char*)message; + pre.flags = PREF_UTF; + pre.timestamp = (DWORD)ts; + ProtoChainRecvMsg(hContact, &pre); + } + else { + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.flags = DBEF_SENT | DBEF_UTF; + dbei.szModule = m_szModuleName; + dbei.timestamp = ts; + dbei.cbBlob = (unsigned)strlen(message) + 1; + dbei.pBlob = (PBYTE)message; + db_event_add(hContact, &dbei); + } + } + } + /* In groupchat it wouldn't make much sense to sync more as older messages are coming now and that would jumble our log */ + if (!bIsChat && bHasMore && (syncstate = ezxml_child(xmli, "messagessyncstate"))) { + msnNsThread->sendPacketPayload("GET", "MSGR\\MESSAGESBYCONVERSATION", + "%s%llu%s100", + id->txt, ((unsigned __int64)db_get_dw(hContact, m_szModuleName, "syncTS", 1000))*1000, syncstate->txt); } + msgs.destroy(); } - mir_free(pszAvatarHash); - mir_free(pszUrl); } - else { -remove: - delSetting(hContact, "AvatarHash"); - delSetting(hContact, "AvatarSavedHash"); - delSetting(hContact, "AvatarUrl"); - delSetting(hContact, "PictContext"); - delSetting(hContact, "PictSavedContext"); - - ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0); + else if (!strcmp(xmli->name, "threads-response")) { + for (ezxml_t thread = ezxml_get(xmli, "threads", 0, "thread", -1); thread != NULL; thread = ezxml_next(thread)) + MSN_ChatStart(thread); } - } - else if (lastStatus == ID_STATUS_OFFLINE) - delSetting(hContact, "MirVer"); + ezxml_free(xmli); + } } break; - case ' ORI': //********* IRO: section 8.4 Getting Invited to a Switchboard Session + + case ' NLI': + case ' NLN': //********* ILN/NLN: section 7.9 Notification Messages + { + union { + char* tWords[5]; + struct { char *userStatus, *wlid, *userNick, *objid, *cmdstring; } data; + }; + + int tArgs = sttDivideWords(params, 5, tWords); + if (tArgs < 3) + goto LBL_InvalidCommand; + + if (data.cmdstring) UrlDecode(data.cmdstring); + MSN_ProcessNLN(data.userStatus, data.wlid, data.userNick, data.objid, data.cmdstring); + } + break; + case ' ORI': /********* IRO: section 8.4 Getting Invited to a Switchboard Session { union { char* tWords[5]; @@ -1314,9 +1639,9 @@ remove: MSN_ChatStart(info); } } - break; + break;*/ - case ' IOJ': //********* JOI: section 8.5 Session Participant Changes + case ' IOJ': /********* JOI: section 8.5 Session Participant Changes { union { char* tWords[3]; @@ -1421,7 +1746,7 @@ remove: else MSN_ChatStart(info); } } - break; + break;*/ case ' GSM': //********* MSG: sections 8.7 Instant Messages, 8.8 Receiving an Instant Message MSN_ReceiveMessage(info, cmdString, params); @@ -1439,6 +1764,67 @@ remove: debugLogA("Message send failed (trid=%d)", trid); break; + case ' YFN': //********* NFY: MSNP21+ Notifications + { + union { + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; + }; + + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) + goto LBL_InvalidCommand; + + HReadBuffer buf(info, 0); + char* msgBody = (char*)buf.surelyRead(atol(data.strMsgBytes)); + if (msgBody == NULL) break; + + if (!strcmp(data.typeId, "MSGR\\PUT") || !strcmp(data.typeId, "MSGR\\DEL")) { + MimeHeaders tHeader; + + int i; + for (i=0; i<2; i++) msgBody = tHeader.readFromBuffer(msgBody); + char *pszTo = NULL, *pszToNet; + if (tHeader["To"]) parseWLID(NEWSTR_ALLOCA(tHeader["To"]), &pszToNet, &pszTo, NULL); + const char *pszFrom = tHeader["From"]; + for (i=0; i<2; i++) msgBody = tHeader.readFromBuffer(msgBody); + + if (pszFrom) + { + ezxml_t xmli; + if (xmli = ezxml_parse_str(msgBody, strlen(msgBody))) + { + if (!strcmp(xmli->name, "user")) + { + ezxml_t xmlstatus = ezxml_get(xmli, "s", 0, "Status", -1); + /* FIXME: MSGR\DEL: Instance of user with given EPID disconnected, not + * sure if this implies that contact is offline now... */ + if (xmlstatus || !strcmp(data.typeId, "MSGR\\DEL")) + { + // These capabilities seem to be something different than in previous MSNP versions? + //ezxml_t xmlcaps = ezxml_get(xmli, "sep", 0, "Capabilities", -1); + ezxml_t usertile = ezxml_get(xmli, "s", 1, "UserTileLocation", -1); + MSN_ProcessNLN(ezxml_txt(xmlstatus), pszFrom, NULL, NULL, usertile?usertile->txt:NULL); + } + MSN_ProcessStatusMessage(xmli, pszFrom); + } + ezxml_free(xmli); + } + } + } + else if (!strcmp(data.typeId, "MSGR\\THREAD")) { + MimeHeaders tHeader; + char *msgBody = tHeader.readFromBuffer(info->mData); + ezxml_t xmli; + + if (xmli = ezxml_parse_str(msgBody, strlen(msgBody))) + { + MSN_ChatStart(xmli); + ezxml_free(xmli); + } + } + } + break; + case ' TON': //********* NOT: notification message MSN_ProcessNotificationMessage((char*)HReadBuffer(info, 0).surelyRead(trid), trid); break; @@ -1462,6 +1848,54 @@ remove: return 1; + case ' TUP': //******** MSNP21+: PUT notifications + case ' GNP': //******** MSNP21+: PNG reply + { + union { + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; + }; + + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) + goto LBL_InvalidCommand; + + MimeHeaders tHeader; + HReadBuffer buf(info, 0); + char* msgBody = tHeader.readFromBuffer((char*)buf.surelyRead(atol(data.strMsgBytes))); + + if (tHeader["Set-Registration"]) replaceStr(msnRegistration,tHeader["Set-Registration"]); + if (cmdString[1]=='N') { // PNG + if (ezxml_t xmli = ezxml_parse_str(msgBody, strlen(msgBody))) { + if (ezxml_t wait = ezxml_child(xmli, "wait")) { + msnPingTimeout = atoi(ezxml_txt(wait)); + if (msnPingTimeout && hKeepAliveThreadEvt != NULL) + SetEvent(hKeepAliveThreadEvt); + } + ezxml_free(xmli); + } + } else { // PUT + ezxml_t xmli; + if (*msgBody && (xmli = ezxml_parse_str(msgBody, strlen(msgBody)))) { + if (!strcmp(xmli->name, "presence-response")) { + ezxml_t user, from; + if ((user = ezxml_child(xmli, "user")) && (from = ezxml_child(xmli, "from"))) { + if (ezxml_t xmlstatus = ezxml_get(user, "s", 0, "Status", -1)) { + ezxml_t usertile = ezxml_get(user, "s", 1, "UserTileLocation", -1); + MSN_ProcessNLN(ezxml_txt(xmlstatus), from->txt, NULL, NULL, usertile?usertile->txt:NULL); + } else { + int oldMode = m_iStatus; + m_iStatus = m_iDesiredStatus; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldMode, m_iStatus); + } + MSN_ProcessStatusMessage(user, from->txt); + } + } + ezxml_free(xmli); + } + } + } + break; + case ' YRQ': //********* QRY: break; @@ -1521,6 +1955,10 @@ remove: } break; + case ' GDS': // SDG: MSNP21+ Messaging + MSN_ReceiveMessage(info, cmdString, params); + break; + case ' XBU': // UBX : MSNP11+ User Status Message { union { @@ -1535,7 +1973,11 @@ remove: if (len < 0 || len > 4000) goto LBL_InvalidCommand; - MSN_ProcessStatusMessage((char*)HReadBuffer(info, 0).surelyRead(len), len, data.wlid); + ezxml_t xmli = ezxml_parse_str((char*)HReadBuffer(info, 0).surelyRead(len), len); + if (xmli) { + MSN_ProcessStatusMessage(xmli, data.wlid); + ezxml_free(xmli); + } } break; @@ -1693,52 +2135,36 @@ remove: case ' RFX': //******** XFR: sections 7.4 Referral, 8.1 Referral to Switchboard { union { - char* tWords[7]; - struct { char *type, *newServer, *security, *authChallengeInfo, - *type2, *srcUrl, *genGateway; } data; + char* tWords[2]; + struct { char *typeId, *strMsgBytes; } data; }; - int numWords = sttDivideWords(params, 7, tWords); - if (numWords < 3) + if (sttDivideWords(params, SIZEOF(tWords), tWords) < 2) goto LBL_InvalidCommand; - if (!strcmp(data.type, "NS")) { //notification server - UrlDecode(data.newServer); - ThreadData* newThread = new ThreadData; - strcpy(newThread->mServer, data.newServer); - newThread->mType = SERVER_NOTIFICATION; - newThread->mTrid = info->mTrid; - newThread->mIsMainThread = true; - usingGateway |= (*data.security == 'G'); - info->mIsMainThread = false; - - debugLogA("Switching to notification server '%s'...", data.newServer); - newThread->startThread(&CMsnProto::MSNServerThread, this); - return 1; //kill the old thread - } - - if (!strcmp(data.type, "SB")) { //switchboard server - UrlDecode(data.newServer); - - if (numWords < 4) - goto LBL_InvalidCommand; - - if (strcmp(data.security, "CKI")) { - debugLogA("Unknown XFR SB security package '%s'", data.security); - break; + MimeHeaders tHeader; + HReadBuffer buf(info, 0); + char* msgBody = tHeader.readFromBuffer((char*)buf.surelyRead(atol(data.strMsgBytes))); + if (!strcmp(data.typeId, "CON")) { + ezxml_t xmlxfr = ezxml_parse_str(msgBody, strlen(msgBody)); + ezxml_t xmltgt = ezxml_child(xmlxfr, "target"); + if (xmltgt) + { + ThreadData* newThread = new ThreadData; + strcpy(newThread->mServer, xmltgt->txt); + strcpy(newThread->mState, ezxml_txt(ezxml_child(xmlxfr, "state"))); + newThread->mType = SERVER_NOTIFICATION; + newThread->mTrid = info->mTrid; + newThread->mIsMainThread = true; + info->mIsMainThread = false; + + debugLogA("Switching to notification server '%s'...", xmltgt->txt); + newThread->startThread(&CMsnProto::MSNServerThread, this); + ezxml_free(xmlxfr); + return 1; //kill the old thread } - - ThreadData* newThread = new ThreadData; - strcpy(newThread->mServer, data.newServer); - newThread->gatewayType = data.genGateway && atol(data.genGateway) != 0; - newThread->mType = SERVER_SWITCHBOARD; - newThread->mCaller = 1; - strcpy(newThread->mCookie, data.authChallengeInfo); - - debugLogA("Opening switchboard server '%s'...", data.newServer); - newThread->startThread(&CMsnProto::MSNServerThread, this); + ezxml_free(xmlxfr); } - else debugLogA("Unknown referral server: %s", data.type); } break; -- cgit v1.2.3