summaryrefslogtreecommitdiff
path: root/protocols/MSN/src/msn_commands.cpp
diff options
context:
space:
mode:
authorPiotr Piastucki <leech.miranda@gmail.com>2015-05-14 15:24:53 +0000
committerPiotr Piastucki <leech.miranda@gmail.com>2015-05-14 15:24:53 +0000
commitb7a1174511c3b7fad5b81a54bb4647662d94031c (patch)
tree91b3f36fd78ae9b481cb11d8602e61a79c388d04 /protocols/MSN/src/msn_commands.cpp
parent01b66588ca510b49be5a06d2bfb5bd28b4416030 (diff)
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
Diffstat (limited to 'protocols/MSN/src/msn_commands.cpp')
-rw-r--r--protocols/MSN/src/msn_commands.cpp942
1 files changed, 684 insertions, 258 deletions
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",
+ "<msgr><ver>%d</ver>%s<client><name>%s</name><ver>%s</ver></client>"
+ "<epid>%.*s</epid></msgr>\r\n",
+ msnP24Ver, (msnP24Ver>1?"<altVersions><ver>1</ver></altVersions>":""),
+ 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",
+ "<challenge><appId>%s</appId><response>%s</response></challenge>\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 = "<ssl-site-name>chatservice.live.com</ssl-site-name>"; break;
+ default:
+ m_iDesiredStatus = ID_STATUS_OFFLINE;
+ return 1;
+ }
+
+ info->sendPacketPayload("ATH", "CON\\USER",
+ "<user><ssl-compact-ticket>t=%s</ssl-compact-ticket>"
+ "<uic>%s</uic>%s"
+ "<id>%s</id><alias>%s</alias></user>\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",
+ "<user><uic>%s</uic><id>%s</id></user>\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",
+ "<threads><thread><id>%s</id></thread></threads>", 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",
+ "<messagesbyconversation><id>%s</id><start>%llu</start><pagesize>100</pagesize></messagesbyconversation>",
+ 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<ezxml> 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; i<msgs.getCount(); i++) {
+ ezxml_t msg = msgs[i];
+ ezxml_t arrtime = ezxml_child(msg, "originalarrivaltime"), from = ezxml_child(msg, "from"),
+ msgtype = ezxml_child(msg, "messagetype"), content = ezxml_child(msg, "content");
+ time_t ts;
+ char *netId, *email, *message;
+ bool sentMsg;
+
+ if (!arrtime || !from || !content) continue;
+ ts=IsoToUnixTime(arrtime->txt);
+ 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",
+ "<messagesbyconversation><id>%s</id><start>%llu</start><messagessyncstate>%s</messagessyncstate><pagesize>100</pagesize></messagesbyconversation>",
+ 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;