From 3b55a62fdcb1f8222de3c2c8fbed530792c419a0 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 12 Oct 2012 14:53:57 +0000 Subject: GTalkExt, ICQ, IRC, Jabber: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1890 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/IcqOscarJ/fam_04message.cpp | 3043 --------------------------------- 1 file changed, 3043 deletions(-) delete mode 100644 protocols/IcqOscarJ/fam_04message.cpp (limited to 'protocols/IcqOscarJ/fam_04message.cpp') diff --git a/protocols/IcqOscarJ/fam_04message.cpp b/protocols/IcqOscarJ/fam_04message.cpp deleted file mode 100644 index 7d1bc6a829..0000000000 --- a/protocols/IcqOscarJ/fam_04message.cpp +++ /dev/null @@ -1,3043 +0,0 @@ -// ---------------------------------------------------------------------------80 -// ICQ plugin for Miranda Instant Messenger -// ________________________________________ -// -// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede -// Copyright © 2001-2002 Jon Keating, Richard Hughes -// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater -// Copyright © 2004-2010 Joe Kucera -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// -// ----------------------------------------------------------------------------- -// DESCRIPTION: -// -// Handles packets from Family 4 ICBM Messages -// -// ----------------------------------------------------------------------------- -#include "icqoscar.h" - - -void CIcqProto::handleMsgFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) -{ - switch (pSnacHeader->wSubtype) { - - case ICQ_MSG_SRV_ERROR: // SNAC(4, 0x01) - handleRecvServMsgError(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_REPLYICBM: // SNAC(4, 0x05) SRV_REPLYICBM - handleReplyICBM(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_RECV: // SNAC(4, 0x07) - handleRecvServMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_MISSED_MESSAGE: // SNAC(4, 0x0A) - handleMissedMsg(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_RESPONSE: // SNAC(4, 0x0B) - handleRecvMsgResponse(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_ACK: // SNAC(4, 0x0C) Server acknowledgements - handleServerAck(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_MTN: // SNAC(4, 0x14) Typing notifications - handleTypingNotification(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - case ICQ_MSG_SRV_OFFLINE_REPLY: // SNAC(4, 0x17) Offline Messages response - handleOffineMessagesReply(pBuffer, wBufferLength, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - - default: - NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_MSG_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); - break; - } -} - - -static void setMsgChannelParams(CIcqProto *ppro, WORD wChan, DWORD dwFlags) -{ - icq_packet packet; - - // Set message parameters for channel wChan (CLI_SET_ICBM_PARAMS) - serverPacketInit(&packet, 26); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_SETPARAMS); - packWord(&packet, wChan); // Channel - packDWord(&packet, dwFlags); // Flags - packWord(&packet, MAX_MESSAGESNACSIZE); // Max message snac size - packWord(&packet, 0x03E7); // Max sender warning level - packWord(&packet, 0x03E7); // Max receiver warning level - packWord(&packet, CLIENTRATELIMIT); // Minimum message interval in seconds - packWord(&packet, 0x0000); // Unknown - ppro->sendServPacket(&packet); -} - - -void CIcqProto::handleReplyICBM(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ // we don't care about the stuff, just change the params - DWORD dwFlags = 0x00000303; - -#ifdef DBG_CAPHTML - dwFlags |= 0x00000400; -#endif -#ifdef DBG_CAPMTN - dwFlags |= 0x00000008; -#endif - // Set message parameters for all channels (imitate ICQ 6) - setMsgChannelParams(this, 0x0000, dwFlags); -} - - -void CIcqProto::handleRecvServMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD wTLVCount; - WORD wMessageFormat; - uid_str szUID; - - if (wLen < 11) - { // just do some basic packet checking - NetLog_Server("Error: Malformed message thru server"); - return; - } - - // These two values are some kind of reference, we need to save - // them to send file request responses for example - unpackLEDWord(&buf, &dwMsgID1); // TODO: msg cookies should be main - wLen -= 4; - unpackLEDWord(&buf, &dwMsgID2); - wLen -= 4; - - // The message type used: - unpackWord(&buf, &wMessageFormat); // 0x0001: Simple message format - wLen -= 2; // 0x0002: Advanced message format - // 0x0004: 'New' message format - // Sender UIN - if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; - - if (dwUin && IsOnSpammerList(dwUin)) - { - NetLog_Server("Ignored Message from known Spammer"); - return; - } - - if (wLen < 4) - { // just do some basic packet checking - NetLog_Server("Error: Malformed message thru server"); - return; - } - - // Warning level? - buf += 2; - wLen -= 2; - - // Number of following TLVs, until msg-format dependant TLVs - unpackWord(&buf, &wTLVCount); - wLen -= 2; - if (wTLVCount > 0) - { - // Save current buffer pointer so we can calculate - // how much data we have left after the chain read. - BYTE *pBufStart = buf; - oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, wTLVCount); - - // This chain contains info that is filled in by the server. - // TLV(1): unknown - // TLV(2): date: on since - // TLV(3): date: on since - // TLV(4): unknown, usually 0000. Not in file-req or auto-msg-req - // TLV(6): sender's status - // TLV(F): a time in seconds, unknown - - disposeChain(&chain); - - // Update wLen - wLen -= buf - pBufStart; - } - - - // This is where the format specific data begins - - switch (wMessageFormat) { - - case 1: // Simple message format - handleRecvServMsgType1(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - case 2: // Encapsulated messages - handleRecvServMsgType2(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - case 4: // Typed messages - handleRecvServMsgType4(buf, wLen, dwUin, szUID, dwMsgID1, dwMsgID2, dwRef); - break; - - default: - NetLog_Server("Unknown format message thru server - Ref %u, Type: %u, UID: %s", dwRef, wMessageFormat, strUID(dwUin, szUID)); - break; - - } -} - - -char* CIcqProto::convertMsgToUserSpecificUtf(HANDLE hContact, const char *szMsg) -{ - WORD wCP = getSettingWord(hContact, "CodePage", m_wAnsiCodepage); - char *usMsg = NULL; - - if (wCP != CP_ACP) - usMsg = ansi_to_utf8_codepage(szMsg, wCP); - - return usMsg; -} - - -void CIcqProto::handleRecvServMsgType1(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE* pMsgTLV; - - if (wLen < 4) - { // just perform basic structure check - NetLog_Server("Message (format %u) - Ignoring empty message", 1); - return; - } - - // Unpack the first TLV(2) - unpackTypedTLV(buf, wLen, 2, &wTLVType, &wTLVLen, &pMsgTLV); - NetLog_Server("Message (format %u) - UID: %s", 1, strUID(dwUin, szUID)); - - // It must be TLV(2) - if (wTLVType == 2) - { - BYTE *pDataBuf = pMsgTLV; - oscar_tlv_chain *pChain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - - // TLV(2) contains yet another TLV chain with the following TLVs: - // TLV(1281): Capability - // TLV(257): This TLV contains the actual message (can be fragmented) - - if (pChain) - { - oscar_tlv* pMessageTLV; - oscar_tlv* pCapabilityTLV; - WORD wMsgPart = 1; - - // Find the capability TLV - pCapabilityTLV = pChain->getTLV(0x0501, 1); - if (pCapabilityTLV && (pCapabilityTLV->wLen > 0)) - { - WORD wDataLen; - BYTE *pDataBuf; - - wDataLen = pCapabilityTLV->wLen; - pDataBuf = pCapabilityTLV->pData; - - if (wDataLen > 0) - NetLog_Server("Message (format 1) - Message has %d caps.", wDataLen); - } - else - NetLog_Server("Message (format 1) - No message cap."); - - { // Parse the message parts, usually only one 0x0101 TLV containing the message, - // but in some cases there can be more 0x0101 TLVs containing message parts in - // different encodings (just like the new format of Offline Messages). - DWORD dwRecvTime; - char* szMsg = NULL; - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - int bAdded; - - HANDLE hContact = HContactFromUID(dwUin, szUID, &bAdded); - - while (pMessageTLV = pChain->getTLV(0x0101, wMsgPart)) - { // Loop thru all message parts - if (pMessageTLV->wLen > 4) - { - WORD wMsgLen; - BYTE *pMsgBuf; - WORD wEncoding; - WORD wCodePage; - char *szMsgPart = NULL; - int bMsgPartUnicode = FALSE; - - // The message begins with a encoding specification - // The first WORD is believed to have the following meaning: - // 0x00: US-ASCII - // 0x02: Unicode UCS-2 Big Endian encoding - // 0x03: local 8bit encoding - pMsgBuf = pMessageTLV->pData; - unpackWord(&pMsgBuf, &wEncoding); - unpackWord(&pMsgBuf, &wCodePage); - - wMsgLen = pMessageTLV->wLen - 4; - NetLog_Server("Message (format 1) - Part %d: Encoding is 0x%X, page is 0x%X", wMsgPart, wEncoding, wCodePage); - - switch (wEncoding) { - - case 2: // UCS-2 - { - WCHAR* usMsgPart = (WCHAR*)SAFE_MALLOC(wMsgLen + 2); - - unpackWideString(&pMsgBuf, usMsgPart, wMsgLen); - usMsgPart[wMsgLen/sizeof(WCHAR)] = 0; - - szMsgPart = make_utf8_string(usMsgPart); - if (!IsUSASCII(szMsgPart, strlennull(szMsgPart))) - bMsgPartUnicode = TRUE; - SAFE_FREE(&usMsgPart); - - break; - } - - case 0: // us-ascii - case 3: // ANSI - default: - { - // Copy the message text into a new proper string. - szMsgPart = (char*)SAFE_MALLOC(wMsgLen + 1); - memcpy(szMsgPart, pMsgBuf, wMsgLen); - szMsgPart[wMsgLen] = '\0'; - - break; - } - } - // Check if the new part is compatible with the message - if (!pre.flags && bMsgPartUnicode) - { // make the resulting message utf-8 encoded - need to append utf-8 encoded part - if (szMsg) - { // not necessary to convert - appending first part, only set flags - char *szUtfMsg = ansi_to_utf8_codepage(szMsg, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); - - SAFE_FREE(&szMsg); - szMsg = szUtfMsg; - } - pre.flags = PREF_UTF; - } - if (!bMsgPartUnicode && pre.flags == PREF_UTF) - { // convert message part to utf-8 and append - char *szUtfPart = ansi_to_utf8_codepage((char*)szMsgPart, getSettingWord(hContact, "CodePage", m_wAnsiCodepage)); - - SAFE_FREE(&szMsgPart); - szMsgPart = szUtfPart; - } - // Append the new message part - szMsg = (char*)SAFE_REALLOC(szMsg, strlennull(szMsg) + strlennull(szMsgPart) + 1); - - strcat(szMsg, szMsgPart); - SAFE_FREE(&szMsgPart); - } - wMsgPart++; - } - if (strlennull(szMsg)) - { - if (_strnicmp(szMsg, "", 6) == 0) - { // strip HTML formating from AIM message - szMsg = EliminateHtml(szMsg, strlennull(szMsg)); - } - - if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) - { // message is Ansi and contains national characters, create Unicode part by codepage - char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); - if (usMsg) - { - SAFE_FREE(&szMsg); - szMsg = usMsg; - pre.flags = PREF_UTF; - } - } - - dwRecvTime = (DWORD)time(NULL); - - { // Check if the message was received as offline - cookie_offline_messages *cookie; - - if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) - { - WORD wTimeTLVType, wTimeTLVLen; - BYTE *pTimeTLV; - - cookie->nMessages++; - - unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); - if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) - { // found Offline timestamp - BYTE *pBuf = pTimeTLV; - - unpackDWord(&pBuf, &dwRecvTime); - NetLog_Server("Message (format %u) - Offline timestamp is %s", 1, time2text(dwRecvTime)); - } - SAFE_FREE((void**)&pTimeTLV); - } - } - // Create and send the message event - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwRecvTime; - pre.szMessage = (char *)szMsg; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - NetLog_Server("Message (format 1) received"); - - // Save tick value - setSettingDword(ccs.hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); - } - else - NetLog_Server("Message (format %u) - Ignoring empty message", 1); - - SAFE_FREE(&szMsg); - } - - // Free the chain memory - disposeChain(&pChain); - } - else - NetLog_Server("Failed to read TLV chain in message (format 1)"); - } - else - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 1); - - SAFE_FREE((void**)&pMsgTLV); -} - - -void CIcqProto::handleRecvServMsgType2(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE *pDataBuf = NULL; - BYTE *pBuf; - - if (wLen < 4) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - // Unpack the first TLV(5) - unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); - NetLog_Server("Message (format %u) - UID: %s", 2, strUID(dwUin, szUID)); - pBuf = pDataBuf; - - // It must be TLV(5) - if (wTLVType == 5) - { - WORD wCommand; - oscar_tlv_chain* chain; - oscar_tlv* tlv; - DWORD q1,q2,q3,q4; - - if (wTLVLen < 26) - { // just check if all basic data is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - unpackWord(&pDataBuf, &wCommand); - wTLVLen -= 2; // Command 0x0000 - Normal message/file send request -#ifdef _DEBUG // 0x0001 - Abort request - NetLog_Server("Command is %u", wCommand); // 0x0002 - Acknowledge request -#endif - - // Some stuff we don't use - pDataBuf += 8; // dwID1 and dwID2 again - wTLVLen -= 8; - unpackDWord(&pDataBuf, &q1); - unpackDWord(&pDataBuf, &q2); - unpackDWord(&pDataBuf, &q3); - unpackDWord(&pDataBuf, &q4); // Message Capability - wTLVLen -= 16; - - if (CompareGUIDs(q1,q2,q3,q4, MCAP_SRV_RELAY_FMT)) - { // we surely have at least 4 bytes for TLV chain - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - SAFE_FREE((void**)&pBuf); - return; - } - - if (wTLVLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - // This TLV chain may contain the following TLVs: - // TLV(A): Acktype 0x0000 - normal message - // 0x0001 - file request / abort request - // 0x0002 - file ack - // TLV(F): Unknown - // TLV(3): External IP - // TLV(5): DC port (not to use for filetransfers) - // TLV(0x2711): The next message level - - chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - if (!chain) - { // sanity check - NetLog_Server("Message (format %u) - Invalid data", 2); - SAFE_FREE((void**)&pBuf); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - - // Update the saved DC info (if contact already exists) - if (hContact != INVALID_HANDLE_VALUE) - { - DWORD dwIP, dwExternalIP; - WORD wPort; - - if (dwExternalIP = chain->getDWord(0x03, 1)) - setSettingDword(hContact, "RealIP", dwExternalIP); - if (dwIP = chain->getDWord(0x04, 1)) - setSettingDword(hContact, "IP", dwIP); - if (wPort = chain->getWord(0x05, 1)) - setSettingWord(hContact, "UserPort", wPort); - - // Save tick value - BYTE bClientID = getSettingByte(hContact, "ClientID", 0); - if (bClientID == CLID_GENERIC || bClientID == CLID_ICQ6) - setSettingDword(hContact, "TickTS", time(NULL) - (dwMsgID1/1000)); - else - setSettingDword(hContact, "TickTS", 0); - } - - // Parse the next message level - if (tlv = chain->getTLV(0x2711, 1)) - { - parseServRelayData(tlv->pData, tlv->wLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType); - } - else - { - NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); - } - // Clean up - disposeChain(&chain); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_REVERSE_DC_REQ)) - { // Handle reverse DC request - if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - SAFE_FREE((void**)&pBuf); - return; - } - if (wTLVLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - SAFE_FREE((void**)&pBuf); - return; - } - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - SAFE_FREE((void**)&pBuf); - return; - } - chain = readIntoTLVChain(&pDataBuf, wTLVLen, 0); - if (!chain) - { // Malformed packet - NetLog_Server("Error: Malformed data in packet"); - SAFE_FREE((void**)&pBuf); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - // Parse the next message level - if (tlv = chain->getTLV(0x2711, 1)) - { - if (tlv->wLen == 0x1B) - { - BYTE *buf = tlv->pData; - DWORD dwUin; - - unpackLEDWord(&buf, &dwUin); - - HANDLE hContact = HContactFromUIN(dwUin, NULL); - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("Error: %s from unknown contact %u", "Reverse Connect Request", dwUin); - } - else - { - DWORD dwIp, dwPort; - WORD wVersion; - BYTE bMode; - - unpackDWord(&buf, &dwIp); - unpackLEDWord(&buf, &dwPort); - unpackByte(&buf, &bMode); - buf += 4; // unknown - if (dwPort) - buf += 4; // port, again? - else - unpackLEDWord(&buf, &dwPort); - unpackLEWord(&buf, &wVersion); - - setSettingDword(hContact, "IP", dwIp); - setSettingWord(hContact, "UserPort", (WORD)dwPort); - setSettingByte(hContact, "DCType", bMode); - setSettingWord(hContact, "Version", wVersion); - if (wVersion > 6) - { - cookie_reverse_connect *pCookie = (cookie_reverse_connect*)SAFE_MALLOC(sizeof(cookie_reverse_connect)); - - unpackLEDWord(&buf, (DWORD*)&pCookie->ft); - pCookie->dwMsgID1 = dwMsgID1; - pCookie->dwMsgID2 = dwMsgID2; - - OpenDirectConnection(hContact, DIRECTCONN_REVERSE, (void*)pCookie); - } - else - NetLog_Server("Warning: Unsupported direct protocol version in %s", "Reverse Connect Request"); - } - } - else - { - NetLog_Server("Malformed %s", "Reverse Connect Request"); - } - } - else - { - NetLog_Server("Warning, no 0x2711 TLV in message (format 2)"); - } - // Clean up - disposeChain(&chain); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_FILE_TRANSFER)) - { // this is an OFT packet - handleRecvServMsgOFT(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); - } - else if (CompareGUIDs(q1,q2,q3,q4, MCAP_CONTACTS)) - { // this is Contacts Transfer - handleRecvServMsgContacts(pDataBuf, wTLVLen, dwUin, szUID, dwMsgID1, dwMsgID2, wCommand); - } - else // here should be detection of extra data streams (Xtraz) - { - NetLog_Server("Unknown Message Format Capability"); - } - } - else - { - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 2); - } - - SAFE_FREE((void**)&pBuf); -} - - -void CIcqProto::parseServRelayData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType) -{ - WORD wId; - - if (wLen < 2) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - unpackLEWord(&pDataBuf, &wId); // Incorrect identification, but working - wLen -= 2; - - // Only 0x1B are real messages - if (wId == 0x001B) - { - WORD wVersion; - WORD wCookie; - DWORD dwGuid1,dwGuid2,dwGuid3,dwGuid4; - - if (wLen < 31) - { // just check if we have data to work with - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - unpackLEWord(&pDataBuf, &wVersion); - wLen -= 2; - - if (hContact != INVALID_HANDLE_VALUE) - setSettingWord(hContact, "Version", wVersion); - - unpackDWord(&pDataBuf, &dwGuid1); // plugin type GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - // Skip lots of unused stuff - pDataBuf += 9; - wLen -= 9; - - unpackLEWord(&pDataBuf, &wId); - wLen -= 2; - - unpackLEWord(&pDataBuf, &wCookie); - wLen -= 2; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) - { // is this a normal message ? - BYTE bMsgType; - BYTE bFlags; - WORD wStatus, wPritority; - WORD wMsgLen; - - if (wLen < 20) - { // check if there is everything that should be there - NetLog_Server("Message (format %u) - Ignoring empty message", 2); - return; - } - - pDataBuf += 12; /* all zeroes */ - wLen -= 12; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - unpackByte(&pDataBuf, &bFlags); - wLen -= 1; - - // Status - unpackLEWord(&pDataBuf, &wStatus); - wLen -= 2; - - // Priority - unpackLEWord(&pDataBuf, &wPritority); - wLen -= 2; - NetLog_Server("Priority: %u", wPritority); - - // Message - unpackLEWord(&pDataBuf, &wMsgLen); - wLen -= 2; - - // HANDLERS - switch (bMsgType) - { - // File messages, handled by the file module - case MTYPE_FILEREQ: - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - char* szMsg = (char *)_alloca(wMsgLen + 1); - memcpy(szMsg, pDataBuf, wMsgLen); - szMsg[wMsgLen] = '\0'; - pDataBuf += wMsgLen; - wLen -= wMsgLen; - - if (wAckType == 0 || wAckType == 1) - { - // File requests 7 - handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 7, FALSE); - } - else if (wAckType == 2) - { - // File reply 7 - handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); - } - else - { - NetLog_Server("Ignored strange file message"); - } - - break; - } - - // Chat messages, handled by the chat module - case MTYPE_CHAT: - { // TODO: this type is deprecated - break; - } - - // Plugin messages, need further parsing - case MTYPE_PLUGIN: - { - if (wLen < wMsgLen) - { // sanity check - NetLog_Server("Error: Malformed server Greeting message"); - return; - } - - parseServRelayPluginData(pDataBuf + wMsgLen, wLen - wMsgLen, hContact, dwUin, szUID, dwMsgID1, dwMsgID2, wAckType, bFlags, wStatus, wCookie, wVersion); - break; - } - - // Everything else - default: - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - message_ack_params pMsgAck = {0}; - - pMsgAck.bType = MAT_SERVER_ADVANCED; - pMsgAck.dwUin = dwUin; - pMsgAck.dwMsgID1 = dwMsgID1; - pMsgAck.dwMsgID2 = dwMsgID2; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = bMsgType; - pMsgAck.bFlags = bFlags; - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, bMsgType, bFlags, wAckType, wLen, wMsgLen, (char*)pDataBuf, 0, &pMsgAck); - break; - } - } - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_INFO_PLUGIN)) - { // info manager plugin - obsolete - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - BYTE bMsgType; - BYTE bLevel; - - pDataBuf += 16; /* unused stuff */ - wLen -= 16; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - - pDataBuf += 3; // unknown - wLen -= 3; - unpackByte(&pDataBuf, &bLevel); - if (bLevel != 0 || wLen < 16) - { - NetLog_Server("Invalid %s Manager Plugin message from %u", "Info", dwUin); - return; - } - unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_INFO)) - { - NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "info"); - } - else - NetLog_Server("Unknown %s Manager message from %u", "Info", dwUin); - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_STATUS_PLUGIN)) - { // status manager plugin - obsolete - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - - BYTE bMsgType; - BYTE bLevel; - - pDataBuf += 16; /* unused stuff */ - wLen -= 16; - unpackByte(&pDataBuf, &bMsgType); - wLen -= 1; - - pDataBuf += 3; // unknown - wLen -= 3; - unpackByte(&pDataBuf, &bLevel); - if (bLevel != 0 || wLen < 16) - { - NetLog_Server("Invalid %s Manager Plugin message from %u", "Status", dwUin); - return; - } - unpackDWord(&pDataBuf, &dwGuid1); // plugin request GUID - unpackDWord(&pDataBuf, &dwGuid2); - unpackDWord(&pDataBuf, &dwGuid3); - unpackDWord(&pDataBuf, &dwGuid4); - wLen -= 16; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PMSG_QUERY_STATUS)) - NetLog_Server("User %u requests our %s plugin list. NOT SUPPORTED", dwUin, "status"); - else - NetLog_Server("Unknown %s Manager message from %u", "Status", dwUin); - } - else - NetLog_Server("Unknown signature (%08x-%08x-%08x-%08x) in message (format 2)", dwGuid1, dwGuid2, dwGuid3, dwGuid4); - } - else - NetLog_Server("Unknown wId1 (%u) in message (format 2)", wId); -} - - -void CIcqProto::parseServRelayPluginData(BYTE *pDataBuf, WORD wLen, HANDLE hContact, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, WORD wAckType, BYTE bFlags, WORD wStatus, WORD wCookie, WORD wVersion) -{ - int nTypeId; - WORD wFunction; - - NetLog_Server("Parsing Greeting message through server"); - - // Message plugin identification - if (!unpackPluginTypeId(&pDataBuf, &wLen, &nTypeId, &wFunction, FALSE)) return; - - if (wLen > 8) - { - DWORD dwLengthToEnd; - DWORD dwDataLen; - - // Length of remaining data - unpackLEDWord(&pDataBuf, &dwLengthToEnd); - - // Length of message - unpackLEDWord(&pDataBuf, &dwDataLen); - wLen -= 8; - - if (dwDataLen > wLen) - dwDataLen = wLen; - - if (nTypeId == MTYPE_FILEREQ && wAckType == 2) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is file ack"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileAck(pDataBuf, wLen, dwUin, wCookie, wStatus, szMsg); - } - else if (nTypeId == MTYPE_FILEREQ && wAckType == 1) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is a file request"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8, FALSE); - } - else if (nTypeId == MTYPE_CHAT && wAckType == 1) - { // TODO: this is deprecated - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - NetLog_Server("This is a chat request"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - memcpy(szMsg, pDataBuf, dwDataLen); - szMsg[dwDataLen] = '\0'; - pDataBuf += dwDataLen; - wLen -= (WORD)dwDataLen; - - // handleChatRequest(pDataBuf, wLen, dwUin, wCookie, dwMsgID1, dwMsgID2, szMsg, 8); - } - else if (nTypeId == MTYPE_STATUSMSGEXT && wFunction >= 1 && wFunction <= 3) - { // handle extended status message request - int nMsgType = 0; - - switch (wFunction) - { - case 1: // Away - if (m_iStatus == ID_STATUS_ONLINE || m_iStatus == ID_STATUS_INVISIBLE) - nMsgType = MTYPE_AUTOONLINE; - else if (m_iStatus == ID_STATUS_AWAY) - nMsgType = MTYPE_AUTOAWAY; - else if (m_iStatus == ID_STATUS_FREECHAT) - nMsgType = MTYPE_AUTOFFC; - break; - - case 2: // Busy - if (m_iStatus == ID_STATUS_OCCUPIED) - nMsgType = MTYPE_AUTOBUSY; - else if (m_iStatus == ID_STATUS_DND) - nMsgType = MTYPE_AUTODND; - break; - - case 3: // N/A - if (m_iStatus == ID_STATUS_NA) - nMsgType = MTYPE_AUTONA; - } - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, bFlags, wAckType, dwLengthToEnd, 0, (char*)pDataBuf, MTF_PLUGIN | MTF_STATUS_EXTENDED, NULL); - } - else if (nTypeId) - { - if (!dwUin) - { // AIM cannot send this, just sanity - NetLog_Server("Error: Malformed UIN in packet"); - return; - } - message_ack_params pMsgAck = {0}; - - pMsgAck.bType = MAT_SERVER_ADVANCED; - pMsgAck.dwUin = dwUin; - pMsgAck.dwMsgID1 = dwMsgID1; - pMsgAck.dwMsgID2 = dwMsgID2; - pMsgAck.wCookie = wCookie; - pMsgAck.msgType = nTypeId; - pMsgAck.bFlags = bFlags; - handleMessageTypes(dwUin, szUID, time(NULL), dwMsgID1, dwMsgID2, wCookie, wVersion, nTypeId, bFlags, wAckType, dwLengthToEnd, (WORD)dwDataLen, (char*)pDataBuf, MTF_PLUGIN, &pMsgAck); - } - else - { - NetLog_Server("Unsupported plugin message type %d", nTypeId); - } - } - else - NetLog_Server("Error: Malformed server plugin message"); -} - - -void CIcqProto::handleRecvServMsgContacts(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwID1, DWORD dwID2, WORD wCommand) -{ - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (wCommand == 0) - { // received contacts - if (wLen < 4) - { // just check if at least one tlv is there - NetLog_Server("Message (format %u) - Ignoring empty contacts message", 2); - return; - } - oscar_tlv_chain *chain = readIntoTLVChain(&buf, wLen, 0); - if (!chain) - { // sanity check - NetLog_Server("Message (format %u) - Invalid data", 2); - return; - } - - WORD wAckType = chain->getWord(0x0A, 1); - - if (wAckType == 1) - { // it is really message containing contacts, parse them - oscar_tlv *tlvUins = chain->getTLV(0x2711, 1); - oscar_tlv *tlvNames = chain->getTLV(0x2712, 1); - - if (!tlvUins || tlvUins->wLen < 4) - { - NetLog_Server("Malformed '%s' message", "contacts"); - disposeChain(&chain); - return; - } - int nContacts = 0x10, iContact = 0; - ICQSEARCHRESULT **contacts = (ICQSEARCHRESULT**)SAFE_MALLOC(nContacts * sizeof(ICQSEARCHRESULT*)); - WORD wContactsGroup = 0; - int valid = 1; - BYTE *pBuffer = tlvUins->pData; - int nLen = tlvUins->wLen; - - while (nLen > 2) - { // parse UIDs - if (!wContactsGroup) - { - WORD wGroupLen; - - unpackWord(&pBuffer, &wGroupLen); - nLen -= 2; - if (nLen >= wGroupLen + 2) - { - pBuffer += wGroupLen; - unpackWord(&pBuffer, &wContactsGroup); - nLen -= wGroupLen + 2; - } - else - break; - } - else - { // group parsed, UIDs waiting - WORD wUidLen; - - unpackWord(&pBuffer, &wUidLen); - nLen -= 2; - if (nLen >= wUidLen) - { - char *szUid = (char*)SAFE_MALLOC(wUidLen + 1); - unpackString(&pBuffer, szUid, wUidLen); - nLen -= wUidLen; - - if (iContact >= nContacts) - { // the list is too small, resize it - nContacts += 0x10; - contacts = (ICQSEARCHRESULT**)SAFE_REALLOC(contacts, nContacts * sizeof(ICQSEARCHRESULT*)); - } - contacts[iContact] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); - contacts[iContact]->hdr.cbSize = sizeof(ICQSEARCHRESULT); - contacts[iContact]->hdr.flags = PSR_TCHAR; - contacts[iContact]->hdr.nick = null_strdup(_T("")); - contacts[iContact]->hdr.id = ansi_to_tchar(szUid); - - if (IsStringUIN(szUid)) - { // icq contact - contacts[iContact]->uin = atoi(szUid); - if (contacts[iContact]->uin == 0) - valid = 0; - } - else - { // aim contact - if (!strlennull(szUid)) - valid = 0; - } - iContact++; - - SAFE_FREE(&szUid); - } - else - { - if (wContactsGroup) valid = 0; - break; - } - - wContactsGroup--; - } - } - if (!iContact || !valid) - { - NetLog_Server("Malformed '%s' message", "contacts"); - disposeChain(&chain); - for (int i = 0; i < iContact; i++) - { - SAFE_FREE(&contacts[i]->hdr.id); - SAFE_FREE(&contacts[i]->hdr.nick); - SAFE_FREE((void**)&contacts[i]); - } - SAFE_FREE((void**)&contacts); - return; - } - nContacts = iContact; - if (tlvNames && tlvNames->wLen >= 4) - { // parse names, if available - pBuffer = tlvNames->pData; - nLen = tlvNames->wLen; - iContact = 0; - - while (nLen > 2) - { // parse Names - if (!wContactsGroup) - { - WORD wGroupLen; - - unpackWord(&pBuffer, &wGroupLen); - nLen -= 2; - if (nLen >= wGroupLen + 2) - { - pBuffer += wGroupLen; - unpackWord(&pBuffer, &wContactsGroup); - nLen -= wGroupLen + 2; - } - else - break; - } - else - { // group parsed, Names waiting - WORD wNickLen; - - unpackWord(&pBuffer, &wNickLen); - nLen -= 2; - if (nLen >= wNickLen) - { - WORD wNickTLV, wNickTLVLen; - char *pNick = NULL; - - unpackTypedTLV(pBuffer, wNickLen, 0x01, &wNickTLV, &wNickTLVLen, (LPBYTE*)&pNick); - if (wNickTLV == 0x01) - { - SAFE_FREE(&contacts[iContact]->hdr.nick); - contacts[iContact]->hdr.nick = utf8_to_tchar(pNick); - } - else - SAFE_FREE(&pNick); - pBuffer += wNickLen; - nLen -= wNickLen; - - iContact++; - if (iContact >= nContacts) break; - } - else - break; - - wContactsGroup--; - } - } - } - - if (!valid) - { - NetLog_Server("Malformed '%s' message", "contacts"); - } - else - { - int bAdded; - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - hContact = HContactFromUID(dwUin, szUID, &bAdded); - - // ack the message - icq_sendContactsAck(dwUin, szUID, dwID1, dwID2); - - ccs.szProtoService = PSR_CONTACTS; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = (DWORD)time(NULL); - pre.szMessage = (char *)contacts; - pre.lParam = nContacts; - pre.flags = PREF_TCHAR; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - - for (int i = 0; i < iContact; i++) - { - SAFE_FREE(&contacts[i]->hdr.id); - SAFE_FREE(&contacts[i]->hdr.nick); - SAFE_FREE((void**)&contacts[i]); - } - SAFE_FREE((void**)&contacts); - } - else - NetLog_Server("Error: Received unknown contacts message, ignoring."); - // Clean up - disposeChain(&chain); - } - else if (wCommand == 1) - { - NetLog_Server("Cannot handle abort messages yet... :("); - return; - } - else if (wCommand == 2) - { // acknowledgement - DWORD dwCookie; - HANDLE hCookieContact; - - if (FindMessageCookie(dwID1, dwID2, &dwCookie, &hCookieContact, NULL)) - { - if (hCookieContact != hContact) - NetLog_Server("Warning: Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); - - BroadcastAck(hContact, ACKTYPE_CONTACTS, ACKRESULT_SUCCESS, (HANDLE)dwCookie, 0); - - ReleaseCookie(dwCookie); - } - else - NetLog_Server("Warning: Unexpected Contact Transfer ack from %s", strUID(dwUin, szUID)); - } -} - - -void CIcqProto::handleRecvServMsgType4(BYTE *buf, WORD wLen, DWORD dwUin, char *szUID, DWORD dwMsgID1, DWORD dwMsgID2, DWORD dwRef) -{ - WORD wTLVType; - WORD wTLVLen; - BYTE* pDataBuf; - DWORD dwUin2; - - if (wLen < 2) - { - NetLog_Server("Message (format %u) - Ignoring empty message", 4); - return; - } - - // Unpack the first TLV(5) - unpackTypedTLV(buf, wLen, 5, &wTLVType, &wTLVLen, &pDataBuf); - NetLog_Server("Message (format %u) - UID: %s", 4, strUID(dwUin, szUID)); - - // It must be TLV(5) - if (wTLVType == 5) - { - BYTE bMsgType; - BYTE bFlags; - BYTE* pmsg = pDataBuf; - WORD wMsgLen; - - - unpackLEDWord(&pmsg, &dwUin2); - - if (dwUin2 == dwUin) - { - unpackByte(&pmsg, &bMsgType); - unpackByte(&pmsg, &bFlags); - unpackLEWord(&pmsg, &wMsgLen); - - if (bMsgType == 0 && wMsgLen == 1) - { - NetLog_Server("User %u probably checks his ignore state.", dwUin); - } - else - { - cookie_offline_messages *cookie; - DWORD dwRecvTime = (DWORD)time(NULL); - - if (!(dwRef & 0x80000000) && FindCookie(dwRef, NULL, (void**)&cookie)) - { - WORD wTimeTLVType, wTimeTLVLen; - BYTE *pTimeTLV = NULL; - - cookie->nMessages++; - - unpackTypedTLV(buf, wLen, 0x16, &wTimeTLVType, &wTimeTLVLen, &pTimeTLV); - if (pTimeTLV && wTimeTLVType == 0x16 && wTimeTLVLen == 4) - { // found Offline timestamp - BYTE *pBuf = pTimeTLV; - - unpackDWord(&pBuf, &dwRecvTime); - NetLog_Server("Message (format %u) - Offline timestamp is %s", 4, time2text(dwRecvTime)); - } - SAFE_FREE((void**)&pTimeTLV); - } - - if (bMsgType == MTYPE_PLUGIN) - { - WORD wLen = wTLVLen - 8; - int typeId; - - NetLog_Server("Parsing Greeting message through server"); - - pmsg += wMsgLen; - wLen -= wMsgLen; - - if (unpackPluginTypeId(&pmsg, &wLen, &typeId, NULL, FALSE) && wLen > 8) - { - DWORD dwLengthToEnd; - DWORD dwDataLen; - - // Length of remaining data - unpackLEDWord(&pmsg, &dwLengthToEnd); - - // Length of message - unpackLEDWord(&pmsg, &dwDataLen); - wLen -= 8; - - if (dwDataLen > wLen) - dwDataLen = wLen; - - if (typeId) - { - uid_str szUID; - handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, typeId, bFlags, 0, dwLengthToEnd, (WORD)dwDataLen, (char*)pmsg, MTF_PLUGIN, NULL); - } - else - { - NetLog_Server("Unsupported plugin message type %d", typeId); - } - } - } - else - { - uid_str szUID; - handleMessageTypes(dwUin, szUID, dwRecvTime, dwMsgID1, dwMsgID2, 0, 0, bMsgType, bFlags, 0, wTLVLen - 8, wMsgLen, (char*)pmsg, 0, NULL); - } - } - } - else - { - NetLog_Server("Ignoring spoofed TYPE4 message thru server from %d", dwUin); - } - } - else - { - NetLog_Server("Unsupported TLV (%u) in message (format %u)", wTLVType, 4); - } - - SAFE_FREE((void**)&pDataBuf); -} - - -// -// Helper functions -// - -static int TypeGUIDToTypeId(DWORD dwGuid1, DWORD dwGuid2, DWORD dwGuid3, DWORD dwGuid4, WORD wType) -{ - int nTypeID = MTYPE_UNKNOWN; - - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_STATUSMSGEXT)) - { - nTypeID = MTYPE_STATUSMSGEXT; - } - else if (wType==MGTYPE_UNDEFINED) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, PSIG_MESSAGE)) - { // icq6 message ack - nTypeID = MTYPE_PLAIN; - } - } - else if (wType==MGTYPE_STANDARD_SEND) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_WEBURL)) - { - nTypeID = MTYPE_URL; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) - { - nTypeID = MTYPE_CONTACTS; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CHAT)) - { - nTypeID = MTYPE_CHAT; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_FILE)) - { - nTypeID = MTYPE_FILEREQ; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_GREETING_CARD)) - { - nTypeID = MTYPE_GREETINGCARD; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_MESSAGE)) - { - nTypeID = MTYPE_MESSAGE; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_SMS_MESSAGE)) - { - nTypeID = MTYPE_SMS_MESSAGE; - } - } - else if (wType==MGTYPE_CONTACTS_REQUEST) - { - if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_CONTACTS)) - { - nTypeID = MTYPE_REQUESTCONTACTS; - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) - { - nTypeID = MTYPE_SCRIPT_DATA; - } - } - else if (CompareGUIDs(dwGuid1, dwGuid2, dwGuid3, dwGuid4, MGTYPE_XTRAZ_SCRIPT)) - { - if (wType==MGTYPE_SCRIPT_INVITATION) - { - nTypeID = MTYPE_SCRIPT_INVITATION; - } - else if (wType==MGTYPE_SCRIPT_NOTIFY) - { - nTypeID = MTYPE_SCRIPT_NOTIFY; - } - } - - return nTypeID; -} - - -int CIcqProto::unpackPluginTypeId(BYTE **pBuffer, WORD *pwLen, int *pTypeId, WORD *pFunctionId, BOOL bThruDC) -{ - WORD wLen = *pwLen; - WORD wInfoLen; - DWORD dwPluginNameLen; - DWORD q1,q2,q3,q4; - WORD qt; - - if (wLen < 24) - return 0; // Failure - - unpackLEWord(pBuffer, &wInfoLen); - - unpackDWord(pBuffer, &q1); // get data GUID & function id - unpackDWord(pBuffer, &q2); - unpackDWord(pBuffer, &q3); - unpackDWord(pBuffer, &q4); - unpackLEWord(pBuffer, &qt); - wLen -= 20; - - if (pFunctionId) *pFunctionId = qt; - - unpackLEDWord(pBuffer, &dwPluginNameLen); - wLen -= 4; - - if (dwPluginNameLen > wLen) - { // check for malformed plugin name - dwPluginNameLen = wLen; - NetLog_Uni(bThruDC, "Warning: malformed size of plugin name."); - } - char *szPluginName = (char *)_alloca(dwPluginNameLen + 1); - memcpy(szPluginName, *pBuffer, dwPluginNameLen); - szPluginName[dwPluginNameLen] = '\0'; - wLen -= (WORD)dwPluginNameLen; - - *pBuffer += dwPluginNameLen; - - int typeId = TypeGUIDToTypeId(q1, q2, q3, q4, qt); - if (!typeId) - NetLog_Uni(bThruDC, "Error: Unknown type {%08x-%08x-%08x-%08x:%04x}: %s", q1,q2,q3,q4,qt, szPluginName); - - if (wInfoLen >= 22 + dwPluginNameLen) - { // sanity checking - wInfoLen -= (WORD)(22 + dwPluginNameLen); - - // check if enough data is available - skip remaining bytes of info block - if (wLen >= wInfoLen) - { - *pBuffer += wInfoLen; - wLen -= wInfoLen; - } - } - - *pwLen = wLen; - *pTypeId = typeId; - - return 1; // Success -} - - -int getPluginTypeIdLen(int nTypeID) -{ - switch (nTypeID) - { - case MTYPE_SCRIPT_NOTIFY: - return 0x51; - - case MTYPE_FILEREQ: - return 0x2B; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOBUSY: - case MTYPE_AUTODND: - case MTYPE_AUTOFFC: - return 0x3C; - - case MTYPE_AUTONA: - return 0x3B; - - default: - return 0; - } -} - - -void packPluginTypeId(icq_packet *packet, int nTypeID) -{ - switch (nTypeID) - { - case MTYPE_SCRIPT_NOTIFY: - packLEWord(packet, 0x04f); // Length - - packGUID(packet, MGTYPE_XTRAZ_SCRIPT); // Message Type GUID - packLEWord(packet, MGTYPE_SCRIPT_NOTIFY); // Function ID - packLEDWord(packet, 0x002a); // Request type string - packBuffer(packet, (LPBYTE)"Script Plug-in: Remote Notification Arrive", 0x002a); - - packDWord(packet, 0x00000100); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packWord(packet, 0x0000); - packByte(packet, 0x00); - - break; - - case MTYPE_FILEREQ: - packLEWord(packet, 0x029); // Length - - packGUID(packet, MGTYPE_FILE); // Message Type GUID - packWord(packet, 0x0000); // Unknown - packLEDWord(packet, 0x0004); // Request type string - packBuffer(packet, (LPBYTE)"File", 0x0004); - - packDWord(packet, 0x00000100); // More unknown binary stuff - packDWord(packet, 0x00010000); - packDWord(packet, 0x00000000); - packWord(packet, 0x0000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOFFC: - packLEWord(packet, 0x03A); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 1); // Function ID - packLEDWord(packet, 0x13); // Request type string - packBuffer(packet, (LPBYTE)"Away Status Message", 0x13); - - packDWord(packet, 0x01000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTOBUSY: - case MTYPE_AUTODND: - packLEWord(packet, 0x03A); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 2); // Function ID - packLEDWord(packet, 0x13); // Request type string - packBuffer(packet, (LPBYTE)"Busy Status Message", 0x13); - - packDWord(packet, 0x02000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - - case MTYPE_AUTONA: - packLEWord(packet, 0x039); // Length - - packGUID(packet, MGTYPE_STATUSMSGEXT); // Message Type GUID - - packLEWord(packet, 3); // Function ID - packLEDWord(packet, 0x12); // Request type string - packBuffer(packet, (LPBYTE)"N/A Status Message", 0x12); - - packDWord(packet, 0x03000000); // Unknown binary stuff - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packDWord(packet, 0x00000000); - packByte(packet, 0x00); - - break; - } -} - - -void CIcqProto::handleStatusMsgReply(const char *szPrefix, HANDLE hContact, DWORD dwUin, WORD wVersion, int bMsgType, WORD wCookie, const char *szMsg, int nMsgFlags) -{ - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - if (hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("%sIgnoring status message from unknown contact %u", szPrefix, dwUin); - return; - } - - int status = AwayMsgTypeToStatus(bMsgType); - if (status == ID_STATUS_OFFLINE) - { - NetLog_Server("%sIgnoring unknown status message from %u", szPrefix, dwUin); - return; - } - - // it is probably UTF-8 status reply - if (wVersion == 9 || (nMsgFlags & MTF_PLUGIN) && wVersion == 10) - { - if (UTF8_IsValid(szMsg)) pre.flags |= PREF_UTF; - } - - ccs.szProtoService = PSR_AWAYMSG; - ccs.hContact = hContact; - ccs.wParam = status; - ccs.lParam = (LPARAM)⪯ - pre.szMessage = (char*)szMsg; - pre.timestamp = time(NULL); - pre.lParam = wCookie; - - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); -} - - -HANDLE CIcqProto::handleMessageAck(DWORD dwUin, char *szUID, WORD wCookie, WORD wVersion, int type, WORD wMsgLen, PBYTE buf, BYTE bFlags, int nMsgFlags) -{ - if (bFlags == 3) - { - HANDLE hCookieContact; - cookie_message_data *pCookieData = NULL; - - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { - NetLog_Server("%sIgnoring unrequested status message from %u", "handleMessageAck: ", dwUin); - - ReleaseCookie(wCookie); - return INVALID_HANDLE_VALUE; - } - - if (hContact != hCookieContact) - { - NetLog_Server("%sAck Contact does not match Cookie Contact(0x%x != 0x%x)", "handleMessageAck: ", hContact, hCookieContact); - - ReleaseCookie(wCookie); - return INVALID_HANDLE_VALUE; - } - ReleaseCookie(wCookie); - - handleStatusMsgReply("handleMessageAck: ", hContact, dwUin, wVersion, type, wCookie, (char*)buf, nMsgFlags); - } - else - { - // Should not happen - NetLog_Server("%sIgnored type %u ack message (this should not happen)", "handleMessageAck: ", type); - } - - return INVALID_HANDLE_VALUE; -} - - -/* this function send all acks from handleMessageTypes */ -void CIcqProto::sendMessageTypesAck(HANDLE hContact, int bUnicode, message_ack_params *pArgs) -{ - if (pArgs) - { - if ((pArgs->msgType == MTYPE_PLAIN && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_MESSAGE)) - || (pArgs->msgType == MTYPE_URL && !CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_URL)) - || pArgs->msgType == MTYPE_CONTACTS) - { - if (pArgs->bType == MAT_SERVER_ADVANCED) - { // Only ack message packets - icq_sendAdvancedMsgAck(pArgs->dwUin, pArgs->dwMsgID1, pArgs->dwMsgID2, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags); - } - else if (pArgs->bType == MAT_DIRECT) - { // Send acknowledgement - icq_sendDirectMsgAck(pArgs->pDC, pArgs->wCookie, (BYTE)pArgs->msgType, pArgs->bFlags, bUnicode ? (char *)CAP_UTF8MSGS : NULL); - } - } - } -} - - -/* this function also processes direct packets, so it should be bulletproof */ -/* pMsg points to the beginning of the message */ -void CIcqProto::handleMessageTypes(DWORD dwUin, char *szUID, DWORD dwTimestamp, DWORD dwMsgID, DWORD dwMsgID2, WORD wCookie, WORD wVersion, int type, int flags, WORD wAckType, DWORD dwDataLen, WORD wMsgLen, char *pMsg, int nMsgFlags, message_ack_params *pAckParams) -{ - HANDLE hContact = INVALID_HANDLE_VALUE; - BOOL bThruDC = (nMsgFlags & MTF_DIRECT) == MTF_DIRECT; - int bAdded; - - - if (dwDataLen < wMsgLen) - { - NetLog_Uni(bThruDC, "Ignoring overflowed message"); - return; - } - - if (wAckType == 2) - { - handleMessageAck(dwUin, szUID, wCookie, wVersion, type, wMsgLen, (LPBYTE)pMsg, (BYTE)flags, nMsgFlags); - return; - } - - char *szMsg = (char *)SAFE_MALLOC(wMsgLen + 1); - if (wMsgLen > 0) - { - memcpy(szMsg, pMsg, wMsgLen); - pMsg += wMsgLen; - dwDataLen -= wMsgLen; - } - szMsg[wMsgLen] = '\0'; - - - char* pszMsgField[2*MAX_CONTACTSSEND+1]; - int nMsgFields = 0; - - pszMsgField[0] = szMsg; - if (type == MTYPE_URL || type == MTYPE_AUTHREQ || type == MTYPE_ADDED || type == MTYPE_CONTACTS || type == MTYPE_EEXPRESS || type == MTYPE_WWP) - { - for (char *pszMsg=szMsg, nMsgFields=1; *pszMsg; pszMsg++) - { - if ((BYTE)*pszMsg == 0xFE) - { - *pszMsg = '\0'; - pszMsgField[nMsgFields++] = pszMsg + 1; - if (nMsgFields >= SIZEOF(pszMsgField)) - break; - } - } - } - - switch (type) { - - case MTYPE_PLAIN: /* plain message */ - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - // Check if this message is marked as UTF8 encoded - if (dwDataLen > 12) - { - DWORD dwGuidLen = 0; - int bDoubleMsg = 0; - - if (bThruDC) - { - DWORD dwExtraLen = *(DWORD*)pMsg; - - if (dwExtraLen < dwDataLen && !strncmp(szMsg, "{\\rtf", 5)) - { // it is icq5 sending us crap, get real message from it - WCHAR* usMsg = (WCHAR*)_alloca((dwExtraLen + 1)*sizeof(WCHAR)); - // make sure it is null-terminated - wcsncpy(usMsg, (WCHAR*)(pMsg + 4), dwExtraLen); - usMsg[dwExtraLen] = '\0'; - SAFE_FREE(&szMsg); - szMsg = (char*)make_utf8_string(usMsg); - - if (!IsUnicodeAscii(usMsg, dwExtraLen)) - pre.flags = PREF_UTF; // only mark real non-ascii messages as unicode - - bDoubleMsg = 1; - } - } - - if (!bDoubleMsg) - { - dwGuidLen = *(DWORD*)(pMsg+8); - dwDataLen -= 12; - pMsg += 12; - } - - while ((dwGuidLen >= 38) && (dwDataLen >= dwGuidLen)) - { - if (!strncmp(pMsg, CAP_UTF8MSGS, 38)) - { // Found UTF8 cap, convert message to ansi - pre.flags = PREF_UTF; - break; - } - else if (!strncmp(pMsg, CAP_RTFMSGS, 38)) - { // Found RichText cap - NetLog_Uni(bThruDC, "Warning: User %u sends us RichText.", dwUin); - break; - } - - dwGuidLen -= 38; - dwDataLen -= 38; - pMsg += 38; - } - } - - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, pre.flags & PREF_UTF, pAckParams); - - if (!pre.flags && !IsUSASCII(szMsg, strlennull(szMsg))) - { // message is Ansi and contains national characters, create Unicode part by codepage - char *usMsg = convertMsgToUserSpecificUtf(hContact, szMsg); - if (usMsg) - { - SAFE_FREE(&szMsg); - szMsg = (char*)usMsg; - pre.flags = PREF_UTF; - } - } - - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)szMsg; - - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - break; - - case MTYPE_URL: - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - - if (nMsgFields < 2) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "URL"); - break; - } - - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, 0, pAckParams); - - char *szTitle = ICQTranslateUtf(LPGEN("Incoming URL:")); - char *szDataDescr = ansi_to_utf8(pszMsgField[0]); - char *szDataUrl = ansi_to_utf8(pszMsgField[1]); - char *szBlob = (char *)SAFE_MALLOC(strlennull(szTitle) + strlennull(szDataDescr) + strlennull(szDataUrl) + 8); - strcpy(szBlob, szTitle); - strcat(szBlob, " "); - strcat(szBlob, szDataDescr); // Description - strcat(szBlob, "\r\n"); - strcat(szBlob, szDataUrl); // URL - SAFE_FREE(&szTitle); - SAFE_FREE(&szDataDescr); - SAFE_FREE(&szDataUrl); - - ccs.szProtoService = PSR_MESSAGE; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)szBlob; - pre.flags = PREF_UTF; - - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - - SAFE_FREE(&szBlob); - } - break; - - case MTYPE_AUTHREQ: /* auth request */ - /* format: nick FE first FE last FE email FE unk-char FE msg 00 */ - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - char* szBlob; - char* pCurBlob; - - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "auth req"); - break; - } - - ccs.szProtoService=PSR_AUTH; - ccs.hContact=hContact=HContactFromUIN(dwUin, &bAdded); - ccs.wParam=0; - ccs.lParam=(LPARAM)⪯ - pre.timestamp=dwTimestamp; - pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+5; - - /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/ - pCurBlob=szBlob=(char *)_alloca(pre.lParam); - memcpy(pCurBlob,&dwUin,sizeof(DWORD)); pCurBlob+=sizeof(DWORD); - memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE); - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[5]); - pre.szMessage=(char *)szBlob; - - CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); - } - break; - - case MTYPE_ADDED: /* 'you were added' */ - /* format: nick FE first FE last FE email 00 */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 4) - { - NetLog_Server("Malformed '%s' message", "you were added"); - break; - } - - hContact = HContactFromUIN(dwUin, &bAdded); - - /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) */ - cbBlob=sizeof(DWORD)*2+strlennull(pszMsgField[0])+strlennull(pszMsgField[1])+strlennull(pszMsgField[2])+strlennull(pszMsgField[3])+4; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - *(DWORD*)pCurBlob = dwUin; pCurBlob += sizeof(DWORD); - *(DWORD*)pCurBlob = DWORD(hContact); pCurBlob += sizeof(DWORD); - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[1]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[2]); pCurBlob += strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, EVENTTYPE_ADDED, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_CONTACTS: - { - CCSDATA ccs; - PROTORECVEVENT pre = {0}; - char* pszNContactsEnd; - int nContacts; - int i; - - - if (nMsgFields < 3 - || (nContacts = strtol(pszMsgField[0], &pszNContactsEnd, 10)) == 0 - || pszNContactsEnd - pszMsgField[0] != (int)strlennull(pszMsgField[0]) - || nMsgFields < nContacts * 2 + 1) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); - break; - } - - int valid = 1; - ICQSEARCHRESULT** isrList = (ICQSEARCHRESULT**)_alloca(nContacts * sizeof(ICQSEARCHRESULT*)); - for (i = 0; i < nContacts; i++) - { - isrList[i] = (ICQSEARCHRESULT*)SAFE_MALLOC(sizeof(ICQSEARCHRESULT)); - isrList[i]->hdr.cbSize = sizeof(ICQSEARCHRESULT); - isrList[i]->hdr.flags = PSR_TCHAR; - if (IsStringUIN(pszMsgField[1 + i * 2])) - { // icq contact - isrList[i]->uin = atoi(pszMsgField[1 + i * 2]); - if (isrList[i]->uin == 0) - valid = 0; - } - else - { // aim contact - if (!strlennull(pszMsgField[1 + i * 2])) - valid = 0; - } - isrList[i]->hdr.id = ansi_to_tchar(pszMsgField[1 + i * 2]); - isrList[i]->hdr.nick = ansi_to_tchar(pszMsgField[2 + i * 2]); - } - - if (!valid) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "contacts"); - } - else - { - hContact = HContactFromUIN(dwUin, &bAdded); - sendMessageTypesAck(hContact, 0, pAckParams); - - ccs.szProtoService = PSR_CONTACTS; - ccs.hContact = hContact; - ccs.wParam = 0; - ccs.lParam = (LPARAM)⪯ - pre.timestamp = dwTimestamp; - pre.szMessage = (char *)isrList; - pre.lParam = nContacts; - pre.flags = PREF_TCHAR; - CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); - } - - for (i = 0; i < nContacts; i++) - { - SAFE_FREE(&isrList[i]->hdr.id); - SAFE_FREE(&isrList[i]->hdr.nick); - SAFE_FREE((void**)&isrList[i]); - } - } - break; - - case MTYPE_PLUGIN: // FIXME: this should be removed - it is never called - hContact = NULL; - - switch(dwUin) - { - case 1111: /* icqmail 'you've got mail' - not processed */ - break; - } - break; - - case MTYPE_SMS_MESSAGE: - /* it's a SMS message from a mobile - broadcast to SMS plugin */ - if (dwUin != 1002) - { - NetLog_Uni(bThruDC, "Malformed '%s' message", "SMS Mobile"); - break; - } - NetLog_Server("Received SMS Mobile message"); - - BroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SUCCESS, NULL, (LPARAM)szMsg); - break; - - case MTYPE_STATUSMSGEXT: - /* it's either extended StatusMsg reply from icq2003b or a IcqWebMessage */ - if (dwUin == 1003) - { - NetLog_Server("Received ICQWebMessage - NOT SUPPORTED"); - } - break; - - case MTYPE_WWP: - /* format: fromname FE FE FE fromemail FE unknownbyte FE 'Sender IP: xxx.xxx.xxx.xxx' 0D 0A body */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "web pager"); - break; - } - - /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ - cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, ICQEVENTTYPE_WEBPAGER, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_EEXPRESS: - /* format: fromname FE FE FE fromemail FE unknownbyte FE body */ - { - DWORD cbBlob; - PBYTE pBlob, pCurBlob; - - if (nMsgFields < 6) - { - NetLog_Server("Malformed '%s' message", "e-mail express"); - break; - } - - /*blob is: body(ASCIIZ), name(ASCIIZ), email(ASCIIZ) */ - cbBlob=strlennull(pszMsgField[0])+strlennull(pszMsgField[3])+strlennull(pszMsgField[5])+3; - pCurBlob=pBlob=(PBYTE)_alloca(cbBlob); - strcpy((char *)pCurBlob,pszMsgField[5]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[0]); pCurBlob+=strlennull((char *)pCurBlob)+1; - strcpy((char *)pCurBlob,pszMsgField[3]); - - AddEvent(NULL, ICQEVENTTYPE_EMAILEXPRESS, dwTimestamp, 0, cbBlob, pBlob); - } - break; - - case MTYPE_REQUESTCONTACTS: - /* it's a contacts-request */ - NetLog_Uni(bThruDC, "Received %s from %u", "Request for Contacts", dwUin); - break; - - case MTYPE_GREETINGCARD: - /* it's a greeting card */ - NetLog_Uni(bThruDC, "Received %s from %u", "Greeting Card", dwUin); - break; - - case MTYPE_SCRIPT_NOTIFY: - /* it's a xtraz notify request */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Notify Request", dwUin); - handleXtrazNotify(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_SCRIPT_INVITATION: - /* it's a xtraz invitation to session */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz Invitation", dwUin); - handleXtrazInvitation(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_SCRIPT_DATA: - /* it's a xtraz data packet */ - NetLog_Uni(bThruDC, "Received %s from %u", "Xtraz data packet", dwUin); - handleXtrazData(dwUin, dwMsgID, dwMsgID2, wCookie, szMsg, wMsgLen, bThruDC); - break; - - case MTYPE_AUTOONLINE: - case MTYPE_AUTOAWAY: - case MTYPE_AUTOBUSY: - case MTYPE_AUTONA: - case MTYPE_AUTODND: - case MTYPE_AUTOFFC: - { - char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(type)); - if (szMsg) - { - struct rates_status_message_response: public rates_queue_item - { - protected: - virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) - { - rates_status_message_response *pDest = (rates_status_message_response*)aDest; - if (!pDest) - pDest = new rates_status_message_response(ppro, wGroup); - - pDest->bExtended = bExtended; - pDest->dwMsgID1 = dwMsgID1; - pDest->dwMsgID2 = dwMsgID2; - pDest->wCookie = wCookie; - pDest->wVersion = wVersion; - pDest->nMsgType = nMsgType; - - return rates_queue_item::copyItem(pDest); - }; - public: - rates_status_message_response(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { }; - virtual ~rates_status_message_response() { }; - - virtual void execute() - { - char **pszMsg = ppro->MirandaStatusToAwayMsg(AwayMsgTypeToStatus(nMsgType)); - if (bExtended) - ppro->icq_sendAwayMsgReplyServExt(dwUin, szUid, dwMsgID1, dwMsgID2, wCookie, wVersion, nMsgType, pszMsg); - else if (dwUin) - ppro->icq_sendAwayMsgReplyServ(dwUin, dwMsgID1, dwMsgID2, wCookie, wVersion, (BYTE)nMsgType, pszMsg); - else - ppro->NetLog_Server("Error: Malformed UIN in packet"); - }; - - BOOL bExtended; - DWORD dwMsgID1; - DWORD dwMsgID2; - WORD wCookie; - WORD wVersion; - int nMsgType; - }; - - m_ratesMutex->Enter(); - WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); - m_ratesMutex->Leave(); - - rates_status_message_response rr(this, wGroup); - rr.bExtended = (nMsgFlags & MTF_STATUS_EXTENDED) == MTF_STATUS_EXTENDED; - rr.hContact = hContact; - rr.dwUin = dwUin; - rr.szUid = szUID; - rr.dwMsgID1 = dwMsgID; - rr.dwMsgID2 = dwMsgID2; - rr.wCookie = wCookie; - rr.wVersion = wVersion; - rr.nMsgType = type; - - handleRateItem(&rr, RQT_RESPONSE); - } - - break; - } - - case MTYPE_FILEREQ: // Never happens - default: - NetLog_Uni(bThruDC, "Unprocessed message type %d", type); - break; - - } - - SAFE_FREE(&szMsg); -} - - -void CIcqProto::handleRecvMsgResponse(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - DWORD dwCookie; - WORD wMessageFormat; - WORD wStatus; - WORD bMsgType = 0; - BYTE bFlags; - WORD wLength; - HANDLE hCookieContact; - DWORD dwMsgID1, dwMsgID2; - WORD wVersion = 0; - cookie_message_data *pCookieData = NULL; - - - unpackLEDWord(&buf, &dwMsgID1); // Message ID - unpackLEDWord(&buf, &dwMsgID2); - wLen -= 8; - - unpackWord(&buf, &wMessageFormat); - wLen -= 2; - if (wMessageFormat != 2) - { - NetLog_Server("SNAC(4.B) Unknown type"); - return; - } - - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); - - buf += 2; // 3. unknown - wLen -= 2; - - if (!FindMessageCookie(dwMsgID1, dwMsgID2, &dwCookie, &hCookieContact, &pCookieData)) - { - NetLog_Server("SNAC(4.B) Received an ack that I did not ask for from (%u)", dwUin); - return; - } - - if (IsValidOscarTransfer(pCookieData)) - { // it is OFT response - handleRecvServResponseOFT(buf, wLen, dwUin, szUid, pCookieData); - return; - } - - if (!dwUin) - { // AIM cannot send this - just sanity - NetLog_Server("Error: Invalid UID in message response."); - return; - } - - // Length of sub chunk? - if (wLen >= 2) - { - unpackLEWord(&buf, &wLength); - wLen -= 2; - } - else - wLength = 0; - - if (wLength == 0x1b && pCookieData->bMessageType != MTYPE_REVERSE_REQUEST) - { // this can be v8 greeting message reply - WORD wCookie; - - unpackLEWord(&buf, &wVersion); - buf += 27; /* unknowns from the msg we sent */ - wLen -= 29; - - // Message sequence (SEQ2) - unpackLEWord(&buf, &wCookie); - wLen -= 2; - - // Unknown (12 bytes) - buf += 12; - wLen -= 12; - - // Message type - unpackByte(&buf, (BYTE*)&bMsgType); - unpackByte(&buf, &bFlags); - wLen -= 2; - - // Status - unpackLEWord(&buf, &wStatus); - wLen -= 2; - - // Priority? - buf += 2; - wLen -= 2; - - if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) - { // use old reliable method - NetLog_Server("Warning: Invalid cookie in %s from (%u)", "message response", dwUin); - - if (pCookieData->bMessageType != MTYPE_AUTOAWAY && bFlags == 3) - { // most probably a broken ack of some kind (e.g. from R&Q), try to fix that - bMsgType = pCookieData->bMessageType; - bFlags = 0; - - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - } - } - else if (bMsgType != MTYPE_PLUGIN && pCookieData->bMessageType != MTYPE_AUTOAWAY) - { // just because some clients break it... - dwCookie = wCookie; - - if (bMsgType != pCookieData->bMessageType) - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - - bMsgType = pCookieData->bMessageType; - } - else if (pCookieData->bMessageType == MTYPE_AUTOAWAY && bMsgType != MTYPE_PLUGIN) - { - if (bMsgType != pCookieData->nAckType) - NetLog_Server("Warning: Invalid message type in %s from (%u)", "message response", dwUin); - } - } - else - { - bMsgType = pCookieData->bMessageType; - bFlags = 0; - } - - if (hCookieContact != hContact) - { - NetLog_Server("SNAC(4.B) Ack Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact); - - ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe - return; - } - - if (bFlags == 3) // A status message reply - { - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, bMsgType, (WORD)dwCookie, (char*)(buf + 2), 0); - } - else - { // An ack of some kind - int ackType; - - - if (hContact == NULL || hContact == INVALID_HANDLE_VALUE) - { - NetLog_Server("SNAC(4.B) Message from unknown contact (%u)", dwUin); - - ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe - return; - } - - switch (bMsgType) { - - case MTYPE_FILEREQ: - { - char* szMsg; - WORD wMsgLen; - - // Message length - unpackLEWord(&buf, &wMsgLen); - wLen -= 2; - szMsg = (char *)_alloca(wMsgLen + 1); - szMsg[wMsgLen] = '\0'; - if (wMsgLen > 0) - { - memcpy(szMsg, buf, wMsgLen); - buf += wMsgLen; - wLen -= wMsgLen; - } - handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); - // No success protoack will be sent here, since all file requests - // will have been 'sent' when the server returns its ack - return; - } - - case MTYPE_PLUGIN: - { - WORD wMsgLen; - DWORD dwLengthToEnd; - DWORD dwDataLen; - int typeId; - WORD wFunctionId; - - - if (wLength != 0x1B) - { - NetLog_Server("Invalid Greeting %s", "message response"); - - ReleaseCookie(dwCookie); - return; - } - - NetLog_Server("Parsing Greeting %s", "message response"); - - // Message - unpackLEWord(&buf, &wMsgLen); - wLen -= 2; - buf += wMsgLen; - wLen -= wMsgLen; - - // This packet is malformed. Possibly a file accept from Miranda IM 0.1.2.1 - if (wLen < 20) - { - ReleaseCookie(dwCookie); - return; - } - - if (!unpackPluginTypeId(&buf, &wLen, &typeId, &wFunctionId, FALSE)) - { - ReleaseCookie(dwCookie); - return; - } - - if (wLen < 4) - { - NetLog_Server("Error: Invalid greeting %s", "message response"); - - ReleaseCookie(dwCookie); - return; - } - - // Length of remaining data - unpackLEDWord(&buf, &dwLengthToEnd); - wLen -= 4; - - if (wLen >= 4 && dwLengthToEnd > 0) - unpackLEDWord(&buf, &dwDataLen); // Length of message - else - dwDataLen = 0; - - - switch (typeId) - { - case MTYPE_PLAIN: - if (pCookieData && pCookieData->bMessageType == MTYPE_AUTOAWAY && dwLengthToEnd >= 4) - { // ICQ 6 invented this - char *szMsg = (char*)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, 0); - - ReleaseCookie(dwCookie); - return; - } - else - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_FILEREQ: - { - NetLog_Server("This is file ack"); - - char *szMsg = (char *)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - buf += dwDataLen; - wLen -= (WORD)dwDataLen; - - handleFileAck(buf, wLen, dwUin, dwCookie, wStatus, szMsg); - // No success protoack will be sent here, since all file requests - // will have been 'sent' when the server returns its ack - } - return; - - case MTYPE_SCRIPT_NOTIFY: - { - char *szMsg = (char*)_alloca(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - - handleXtrazNotifyResponse(dwUin, hContact, (WORD)dwCookie, szMsg, dwDataLen); - - ReleaseCookie(dwCookie); - } - return; - - case MTYPE_STATUSMSGEXT: - { // handle Away Message response (ICQ 6) - char *szMsg = (char*)SAFE_MALLOC(dwDataLen + 1); - - if (dwDataLen > 0) - memcpy(szMsg, buf, dwDataLen); - szMsg[dwDataLen] = '\0'; - szMsg = EliminateHtml(szMsg, dwDataLen); - - handleStatusMsgReply("SNAC(4.B) ", hContact, dwUin, wVersion, pCookieData->nAckType, (WORD)dwCookie, szMsg, MTF_PLUGIN | MTF_STATUS_EXTENDED); - - SAFE_FREE(&szMsg); - - ReleaseCookie(dwCookie); - } - return; - - default: - NetLog_Server("Error: Unknown plugin message response, type %d.", typeId); - return; - } - } - break; - - case MTYPE_PLAIN: - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_AUTHOK: - case MTYPE_AUTHDENY: - ackType = ACKTYPE_AUTHREQ; - break; - - case MTYPE_ADDED: - ackType = ACKTYPE_ADDED; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_REVERSE_REQUEST: - { - cookie_reverse_connect *pReverse = (cookie_reverse_connect*)pCookieData; - - if (pReverse->ft) - { - filetransfer *ft = (filetransfer*)pReverse->ft; - - BroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0); - } - NetLog_Server("Reverse Connect request failed"); - // Set DC status to failed - setSettingByte(hContact, "DCStatus", 2); - - ReleaseCookie(dwCookie); - } - return; - - case MTYPE_CHAT: - default: - NetLog_Server("SNAC(4.B) Unknown message type (%u) in switch", bMsgType); - return; - } - - if ((ackType == MTYPE_PLAIN && pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) || ackType != MTYPE_PLAIN) - { - BroadcastAck(hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)(WORD)dwCookie, 0); - } - } - - ReleaseCookie(dwCookie); -} - - -// A response to a CLI_SENDMSG -void CIcqProto::handleRecvServMsgError(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) -{ - WORD wError; - char *pszErrorMessage; - HANDLE hContact; - cookie_message_data *pCookieData = NULL; - int nMessageType; - - - if (wLen < 2) - return; - - if (FindCookie((WORD)dwSequence, &hContact, (void**)&pCookieData)) - { // all packet cookies from msg family has command 0 in the queue - DWORD dwUin; - uid_str szUid; - - if (getContactUid(hContact, &dwUin, &szUid)) - { // Invalid contact - FreeCookie((WORD)dwSequence); - return; - } - - // Error code - unpackWord(&buf, &wError); - - if (wError == 9 && pCookieData->bMessageType == MTYPE_AUTOAWAY) - { // we failed to request away message the normal way, try it AIM way - icq_packet packet; - - serverPacketInit(&packet, (WORD)(13 + getUINLen(dwUin))); - packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_REQ_USER_INFO, 0, (WORD)dwSequence); - packWord(&packet, 0x03); - packUIN(&packet, dwUin); - - sendServPacket(&packet); - return; - } - - // Not all of these are actually used in family 4 - // This will be moved into a special error handling function later - switch (wError) { - - case 0x0002: // Server rate limit exceeded - pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x02"); - break; - - case 0x0003: // Client rate limit exceeded - pszErrorMessage = Translate("You are sending too fast. Wait a while and try again.\r\nSNAC(4.1) Error x03"); - break; - - case 0x0004: // Recipient is not logged in (resend in a offline message) - if (pCookieData->bMessageType == MTYPE_PLAIN) - { - if (pCookieData->isOffline) - { // offline failed - most probably to AIM contact - pszErrorMessage = Translate("The contact does not support receiving offline messages."); - break; - } - // TODO: this needs better solution - setSettingWord(hContact, "Status", ID_STATUS_OFFLINE); - } - pszErrorMessage = Translate("The user has logged off. Select 'Retry' to send an offline message.\r\nSNAC(4.1) Error x04"); - break; - - case 0x0005: // Requested service unavailable - pszErrorMessage = Translate("The messaging service is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x05"); - break; - - case 0x0009: // Not supported by client (resend in a simpler format) - pszErrorMessage = Translate("The receiving client does not support this type of message.\r\nSNAC(4.1) Error x09"); - break; - - case 0x000A: // Refused by client - pszErrorMessage = Translate("You sent too long message. The receiving client does not support it.\r\nSNAC(4.1) Error x0A"); - break; - - case 0x000E: // Incorrect SNAC format - pszErrorMessage = Translate("The SNAC format was rejected by the server.\nSNAC(4.1) Error x0E"); - break; - - case 0x0013: // User temporarily unavailable - pszErrorMessage = Translate("The user is temporarily unavailable. Wait a while and try again.\r\nSNAC(4.1) Error x13"); - break; - - case 0x0001: // Invalid SNAC header - case 0x0006: // Requested service not defined - case 0x0007: // You sent obsolete SNAC - case 0x0008: // Not supported by server - case 0x000B: // Reply too big - case 0x000C: // Responses lost - case 0x000D: // Request denied - case 0x000F: // Insufficient rights - case 0x0010: // In local permit/deny (recipient blocked) - case 0x0011: // Sender too evil - case 0x0012: // Receiver too evil - case 0x0014: // No match - case 0x0015: // List overflow - case 0x0016: // Request ambiguous - case 0x0017: // Server queue full - case 0x0018: // Not while on AOL - default: - if (pszErrorMessage = (char*)_alloca(256)) - null_snprintf(pszErrorMessage, 256, Translate("SNAC(4.1) SENDMSG Error (x%02x)"), wError); - break; - } - - - switch (pCookieData->bMessageType) { - - case MTYPE_PLAIN: - nMessageType = ACKTYPE_MESSAGE; - break; - - case MTYPE_CHAT: - nMessageType = ACKTYPE_CHAT; - break; - - case MTYPE_FILEREQ: - nMessageType = ACKTYPE_FILE; - break; - - case MTYPE_URL: - nMessageType = ACKTYPE_URL; - break; - - case MTYPE_CONTACTS: - nMessageType = ACKTYPE_CONTACTS; - break; - - default: - nMessageType = -1; - break; - } - - if (nMessageType != -1) - { - BroadcastAck(hContact, nMessageType, ACKRESULT_FAILED, (HANDLE)(WORD)dwSequence, (LPARAM)pszErrorMessage); - } - else - { - NetLog_Server("Error: Message delivery to %u failed: %s", dwUin, pszErrorMessage); - } - - FreeCookie((WORD)dwSequence); - - if (pCookieData->bMessageType != MTYPE_FILEREQ) - SAFE_FREE((void**)&pCookieData); - } - else - { - unpackWord(&buf, &wError); - - LogFamilyError(ICQ_MSG_FAMILY, wError); - } -} - - -void CIcqProto::handleServerAck(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwSequence) -{ - DWORD dwUin; - uid_str szUID; - WORD wChannel; - cookie_message_data *pCookieData; - - - if (wLen < 13) - { - NetLog_Server("Ignoring SNAC(4,C) Packet to short"); - return; - } - - buf += 8; // Skip first 8 bytes - wLen -= 8; - - // Message channel - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUID)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUID, NULL); - - if (FindCookie((WORD)dwSequence, NULL, (void**)&pCookieData)) - { - // If the user requested a full ack, the - // server ack should be ignored here. - if (pCookieData && (pCookieData->nAckType == ACKTYPE_SERVER)) - { - if ((hContact != NULL) && (hContact != INVALID_HANDLE_VALUE)) - { - int ackType; - int ackRes = ACKRESULT_SUCCESS; - - switch (pCookieData->bMessageType) { - case MTYPE_PLAIN: - ackType = ACKTYPE_MESSAGE; - break; - - case MTYPE_CONTACTS: - ackType = ACKTYPE_CONTACTS; - break; - - case MTYPE_URL: - ackType = ACKTYPE_URL; - break; - - case MTYPE_FILEREQ: - ackType = ACKTYPE_FILE; - ackRes = ACKRESULT_SENTREQUEST; - // Note 1: We are not allowed to free the cookie here because it - // contains the filetransfer struct that we will need later - // Note 2: The cookiedata is NOT a message_cookie_data*, it is a - // filetransfer*. IMPORTANT! (it's one of those silly things) - break; - - default: - ackType = -1; - NetLog_Server("Error: Unknown message type %d in ack", pCookieData->bMessageType); - break; - } - if (ackType != -1) - BroadcastAck(hContact, ackType, ackRes, (HANDLE)(WORD)dwSequence, 0); - - if (pCookieData->bMessageType != MTYPE_FILEREQ) - SAFE_FREE((void**)&pCookieData); // this could be a bad idea, but I think it is safe - } - FreeCookie((WORD)dwSequence); - } - else if (pCookieData && (pCookieData->nAckType == ACKTYPE_CLIENT)) - NetLog_Server("Received a server ack, waiting for client ack."); - else - NetLog_Server("Ignored a server ack I did not ask for"); - } -} - - -void CIcqProto::handleMissedMsg(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - WORD wChannel; - WORD wWarningLevel; - WORD wCount; - WORD wError; - WORD wTLVCount; - - if (wLen < 14) - return; // Too short - - // Message channel? - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - if (wLen < 8) - return; // Too short - - // Warning level? - unpackWord(&buf, &wWarningLevel); - wLen -= 2; - - // TLV count - unpackWord(&buf, &wTLVCount); - wLen -= 2; - - // Read past user info TLVs - oscar_tlv_chain *pChain = readIntoTLVChain(&buf, (WORD)(wLen-4), wTLVCount); - if (pChain) - disposeChain(&pChain); - - if (wLen < 4) - return; // Too short - - // Number of missed messages - unpackWord(&buf, &wCount); - wLen -= 2; - - // Error code - unpackWord(&buf, &wError); - wLen -= 2; - - { // offline retrieval process in progress, note that we received missed message notification - cookie_offline_messages *cookie; - - if (FindCookieByType(CKT_OFFLINEMESSAGE, NULL, NULL, (void**)&cookie)) - cookie->nMissed++; - } - - switch (wError) { - - case 0: // The message was invalid - case 1: // The message was too long - case 2: // The sender has flooded the server - case 4: // You are too evil - break; - - default: - // 3 = Sender too evil (sender warn level > your max_msg_sevil) - return; - break; - } - - // Create event to notify user - int bAdded; - - AddEvent(HContactFromUID(dwUin, szUid, &bAdded), ICQEVENTTYPE_MISSEDMESSAGE, time(NULL), 0, sizeof(wError), (PBYTE)&wError); -} - - -void CIcqProto::handleOffineMessagesReply(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - cookie_offline_messages *cookie; - - if (FindCookie(dwRef, NULL, (void**)&cookie)) - { - NetLog_Server("End of offline msgs, %u received", cookie->nMessages); - if (cookie->nMissed) - { // NASTY WORKAROUND!! - // The ICQ server has a bug that causes offline messages to be received again and again when some - // missed message notification is present (most probably it is not processed correctly and causes - // the server to fail the purging process); try to purge them using the old offline messages - // protocol. 2008/05/21 - NetLog_Server("Warning: Received %u missed message notifications, trying to fix the server.", cookie->nMissed); - - icq_packet packet; - // This will delete the messages stored on server - serverPacketInit(&packet, 24); - packFNACHeader(&packet, ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST); - packWord(&packet, 1); // TLV Type - packWord(&packet, 10); // TLV Length - packLEWord(&packet, 8); // Data length - packLEDWord(&packet, m_dwLocalUIN); // My UIN - packLEWord(&packet, CLI_DELETE_OFFLINE_MSGS_REQ); // Ack offline msgs - packLEWord(&packet, 0x0000); // Request sequence number (we dont use this for now) - - // Send it - sendServPacket(&packet); - } - - ReleaseCookie(dwRef); - } - else - NetLog_Server("Error: Received unexpected end of offline msgs."); -} - - -void CIcqProto::handleTypingNotification(BYTE *buf, WORD wLen, WORD wFlags, DWORD dwRef) -{ - DWORD dwUin; - uid_str szUid; - WORD wChannel; - WORD wNotification; - - if (wLen < 14) - { - NetLog_Server("Ignoring SNAC(4.x11) Packet to short"); - return; - } - -#ifndef DBG_CAPMTN - { - NetLog_Server("Ignoring unexpected typing notification"); - return; - } -#endif - - // The message ID, unused? - buf += 8; - wLen -= 8; - - // Message channel, unused? - unpackWord(&buf, &wChannel); - wLen -= 2; - - // Sender - if (!unpackUID(&buf, &wLen, &dwUin, &szUid)) return; - - HANDLE hContact = HContactFromUID(dwUin, szUid, NULL); - - if (hContact == INVALID_HANDLE_VALUE) return; - - // Typing notification code - unpackWord(&buf, &wNotification); - wLen -= 2; - - SetContactCapabilities(hContact, CAPF_TYPING); - - // Notify user - switch (wNotification) { - - case MTN_FINISHED: - case MTN_TYPED: - CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); - NetLog_Server("%s has stopped typing (ch %u).", strUID(dwUin, szUid), wChannel); - break; - - case MTN_BEGUN: - CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)60); - NetLog_Server("%s is typing a message (ch %u).", strUID(dwUin, szUid), wChannel); - break; - - case MTN_WINDOW_CLOSED: - { - char szFormat[MAX_PATH]; - char szMsg[MAX_PATH]; - char *nick = NickFromHandleUtf(hContact); - - null_snprintf(szMsg, MAX_PATH, ICQTranslateUtfStatic(LPGEN("Contact \"%s\" has closed the message window."), szFormat, MAX_PATH), nick); - ShowPopUpMsg(hContact, ICQTranslateUtfStatic(LPGEN("ICQ Note"), szFormat, MAX_PATH), szMsg, LOG_NOTE); - SAFE_FREE((void**)&nick); - - NetLog_Server("%s has closed the message window.", strUID(dwUin, szUid)); - } - break; - - default: - NetLog_Server("Unknown typing notification from %s, type %u (ch %u)", strUID(dwUin, szUid), wNotification, wChannel); - break; - } -} - - -void CIcqProto::sendTypingNotification(HANDLE hContact, WORD wMTNCode) -{ - _ASSERTE((wMTNCode == MTN_FINISHED) || (wMTNCode == MTN_TYPED) || (wMTNCode == MTN_BEGUN) || (wMTNCode == MTN_WINDOW_CLOSED)); - - DWORD dwUin; - uid_str szUid; - if (getContactUid(hContact, &dwUin, &szUid)) - return; // Invalid contact - - WORD wLen = getUIDLen(dwUin, szUid); - - icq_packet packet; - serverPacketInit(&packet, 23 + wLen); - packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_MTN); - packLEDWord(&packet, 0x0000); // Msg ID - packLEDWord(&packet, 0x0000); // Msg ID - packWord(&packet, 0x01); // Channel - packUID(&packet, dwUin, szUid); // User ID - packWord(&packet, wMTNCode); // Notification type - - sendServPacketAsync(&packet); -} -- cgit v1.2.3