void CIcqProto::handleExtensionServerInfo(BYTE *buf, WORD wPackLen, WORD wFlags) { oscar_tlv_chain *chain; oscar_tlv *dataTlv; // The entire packet is encapsulated in a TLV type 1 chain = readIntoTLVChain(&buf, wPackLen, 0); if (chain == NULL) { debugLogA("Error: Broken snac 15/3 %d", 1); return; } dataTlv = chain->getTLV(0x0001, 1); if (dataTlv == NULL) { disposeChain(&chain); debugLogA("Error: Broken snac 15/3 %d", 2); return; } BYTE *databuf = dataTlv->pData; wPackLen -= 4; _ASSERTE(dataTlv->wLen == wPackLen); _ASSERTE(wPackLen >= 10); if ((dataTlv->wLen == wPackLen) && (wPackLen >= 10)) { WORD wBytesRemaining; WORD wRequestType; WORD wCookie; DWORD dwMyUin; unpackLEWord(&databuf, &wBytesRemaining); unpackLEDWord(&databuf, &dwMyUin); unpackLEWord(&databuf, &wRequestType); unpackWord(&databuf, &wCookie); _ASSERTE(wBytesRemaining == (wPackLen - 2)); if (wBytesRemaining == (wPackLen - 2)) { wPackLen -= 10; switch (wRequestType) { case SRV_META_INFO_REPLY: // SRV_META request replies handleExtensionMetaResponse(databuf, wPackLen, wCookie, wFlags); break; default: debugLogA("Warning: Ignoring Meta response - Unknown type %d", wRequestType); break; } } } else debugLogA("Error: Broken snac 15/3 %d", 3); if (chain) disposeChain(&chain); }
void CIcqProto::handleDirectMessage(directconnect* dc, PBYTE buf, WORD wLen) { WORD wCommand; WORD wCookie; BYTE bMsgType,bMsgFlags; WORD wStatus; WORD wFlags; WORD wTextLen; char* pszText = NULL; // The first part of the packet should always be at least 31 bytes if (wLen < 31) { NetLog_Direct("Error during parsing of DC packet 2 PEER_MSG (too short)"); return; } // Skip packet checksum buf += 4; wLen -= 4; // Command: // 0x07d0 = 2000 - cancel given message. // 0x07da = 2010 - acknowledge message. // 0x07ee = 2030 - normal message/request. unpackLEWord(&buf, &wCommand); wLen -= 2; // Unknown, always 0xe (14) buf += 2; wLen -= 2; // Sequence number unpackLEWord(&buf, &wCookie); wLen -=2; // Unknown, always zeroes buf += 12; wLen -= 12; // Peer message type unpackByte(&buf, &bMsgType); // Peer message flags unpackByte(&buf, &bMsgFlags); wLen -= 2; // The current status of the user, or whether the message was accepted or not. // 0x00 - user is online, or message was receipt, or file transfer accepted // 0x01 - refused // 0x04 - auto-refused, because of away // 0x09 - auto-refused, because of occupied // 0x0a - auto-refused, because of dnd // 0x0e - auto-refused, because of na unpackLEWord(&buf, &wStatus); wLen -= 2; // Flags, or priority // Seen: 1 - Chat request // 0 - File auto accept (type 3) // 33 - priority ? unpackLEWord(&buf, &wFlags); wLen -= 2; // Messagetext. This is either the status message or the actual message // when this is a PEER_MSG_MSG packet unpackLEWord(&buf, &wTextLen); if (wTextLen > 0) { pszText = (char*)_alloca(wTextLen+1); unpackString(&buf, pszText, wTextLen); pszText[wTextLen] = '\0'; } wLen = (wLen - 2) - wTextLen; #ifdef _DEBUG NetLog_Direct("Handling PEER_MSG '%s', command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", pszText, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); #else NetLog_Direct("Message through direct - UID: %u", dc->dwRemoteUin); #endif // The remaining actual message is handled either as a status message request, // a greeting message, a acknowledge or a normal (text, url, file) message if (wCommand == DIRECT_MESSAGE) switch (bMsgType) { case MTYPE_FILEREQ: // File inits handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, pszText, 7, TRUE); break; case MTYPE_AUTOAWAY: case MTYPE_AUTOBUSY: case MTYPE_AUTONA: case MTYPE_AUTODND: case MTYPE_AUTOFFC: { char **szMsg = MirandaStatusToAwayMsg(AwayMsgTypeToStatus(bMsgType)); if (szMsg) icq_sendAwayMsgReplyDirect(dc, wCookie, bMsgType, ( const char** )szMsg); } break; case MTYPE_PLUGIN: // Greeting handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); break; default: { message_ack_params pMsgAck = {0}; uid_str szUID; buf -= wTextLen; wLen += wTextLen; pMsgAck.bType = MAT_DIRECT; pMsgAck.pDC = dc; pMsgAck.wCookie = wCookie; pMsgAck.msgType = bMsgType; pMsgAck.bFlags = bMsgFlags; handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 0, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, &pMsgAck); break; } } else if (wCommand == DIRECT_ACK) { if (bMsgFlags == 3) { // this is status reply uid_str szUID; buf -= wTextLen; wLen += wTextLen; handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)bMsgType, (int)bMsgFlags, 2, (DWORD)wLen, wTextLen, (char*)buf, MTF_DIRECT, NULL); } else { MCONTACT hCookieContact; cookie_message_data *pCookieData = NULL; if (!FindCookie(wCookie, &hCookieContact, (void**)&pCookieData)) { NetLog_Direct("Received an unexpected direct ack"); } else if (hCookieContact != dc->hContact) { NetLog_Direct("Direct Contact does not match Cookie Contact(0x%x != 0x%x)", dc->hContact, hCookieContact); ReleaseCookie(wCookie); // This could be a bad idea, but I think it is safe } else { // the ack is correct int ackType = -1; switch (bMsgType) { case MTYPE_PLAIN: ackType = ACKTYPE_MESSAGE; break; case MTYPE_URL: ackType = ACKTYPE_URL; break; case MTYPE_CONTACTS: ackType = ACKTYPE_CONTACTS; break; case MTYPE_FILEREQ: // File acks handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, pszText); break; case MTYPE_PLUGIN: // Greeting handleDirectGreetingMessage(dc, buf, wLen, wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags, pszText); break; default: NetLog_Direct("Skipped packet from direct connection"); break; } if (ackType != -1) { // was a good ack to broadcast ? ProtoBroadcastAck(dc->hContact, ackType, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); ReleaseCookie(wCookie); } } } } else if (wCommand == DIRECT_CANCEL) { NetLog_Direct("Cannot handle abort messages yet... :("); } else NetLog_Direct("Unknown wCommand, packet skipped"); }
void CIcqProto::handleFileAck(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, WORD wStatus, char* pszText) { char* pszFileName = NULL; DWORD dwFileSize; HANDLE hCookieContact; WORD wPort; WORD wFilenameLength; filetransfer* ft; // Find the filetransfer that belongs to this response if (!FindCookie(dwCookie, &hCookieContact, (void**)&ft)) { NetLog_Direct("Error: Received unexpected file transfer request response"); return; } FreeCookie(dwCookie); if (hCookieContact != HContactFromUIN(dwUin, NULL)) { NetLog_Direct("Error: UINs do not match in file transfer request response"); return; } // If status != 0, a request has been denied if (wStatus != 0) { NetLog_Direct("File transfer denied by %u.", dwUin); ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)ft, 0); FreeCookie(dwCookie); return; } if (wLen < 6) { // sanity check NetLog_Direct("Ignoring malformed file transfer request response"); return; } // Port to connect to unpackWord(&buf, &wPort); ft->dwRemotePort = wPort; wLen -= 2; // Unknown buf += 2; wLen -= 2; // Filename unpackLEWord(&buf, &wFilenameLength); if (wFilenameLength > 0) { if (wFilenameLength > wLen - 2) wFilenameLength = wLen - 2; pszFileName = (char*)_alloca(wFilenameLength+1); unpackString(&buf, pszFileName, wFilenameLength); pszFileName[wFilenameLength] = '\0'; } wLen = wLen - 2 - wFilenameLength; if (wLen >= 4) { // Total filesize unpackLEDWord(&buf, &dwFileSize); wLen -= 4; } else dwFileSize = 0; NetLog_Direct("File transfer ack from %u, port %u, name %s, size %u", dwUin, ft->dwRemotePort, pszFileName, dwFileSize); ProtoBroadcastAck(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)ft, 0); OpenDirectConnection(ft->hContact, DIRECTCONN_FILE, ft); }
// pszDescription points to a string with the reason // buf points to the first data after the string void CIcqProto::handleFileRequest(PBYTE buf, WORD wLen, DWORD dwUin, DWORD dwCookie, DWORD dwID1, DWORD dwID2, char* pszDescription, int nVersion, BOOL bDC) { BOOL bEmptyDesc = FALSE; if (strlennull(pszDescription) == 0) { pszDescription = Translate("No description given"); bEmptyDesc = TRUE; } // Empty port+pad buf += 4; wLen -= 4; // Filename WORD wFilenameLength; unpackLEWord(&buf, &wFilenameLength); if (!wFilenameLength) { NetLog_Direct("Ignoring malformed file send request"); return; } char *pszFileName = (char*)_alloca(wFilenameLength + 1); unpackString(&buf, pszFileName, wFilenameLength); pszFileName[wFilenameLength] = '\0'; wLen = wLen - 2 - wFilenameLength; // Total filesize DWORD dwFileSize; unpackLEDWord(&buf, &dwFileSize); wLen -= 4; int bAdded; HANDLE hContact = HContactFromUIN(dwUin, &bAdded); // Initialize a filetransfer struct filetransfer *ft = CreateFileTransfer(hContact, dwUin, nVersion); ft->dwCookie = dwCookie; ft->szFilename = mir_strdup(pszFileName); ft->szDescription = 0; ft->fileId = -1; ft->dwTotalSize = dwFileSize; ft->pMessage.dwMsgID1 = dwID1; ft->pMessage.dwMsgID2 = dwID2; ft->bDC = bDC; ft->bEmptyDesc = bEmptyDesc; // Send chain event TCHAR* ptszFileName = mir_utf8decodeT(pszFileName); PROTORECVFILET pre = {0}; pre.flags = PREF_TCHAR; pre.fileCount = 1; pre.timestamp = time(NULL); pre.tszDescription = mir_utf8decodeT(pszDescription); pre.ptszFiles = &ptszFileName; pre.lParam = (LPARAM)ft; ProtoChainRecvFile(hContact, &pre); mir_free(pre.tszDescription); mir_free(ptszFileName); }
void CIcqProto::handleFileTransferPacket(directconnect* dc, PBYTE buf, WORD wLen) { if (wLen < 1) return; NetLog_Direct("Handling file packet"); switch (buf[0]) { case PEER_FILE_INIT: /* first packet of a file transfer */ if (dc->initialised) return; if (wLen < 19) return; buf += 5; /* id, and unknown 0 */ dc->type = DIRECTCONN_FILE; { DWORD dwFileCount; DWORD dwTotalSize; DWORD dwTransferSpeed; WORD wNickLength; int bAdded; unpackLEDWord(&buf, &dwFileCount); unpackLEDWord(&buf, &dwTotalSize); unpackLEDWord(&buf, &dwTransferSpeed); unpackLEWord(&buf, &wNickLength); dc->ft = FindExpectedFileRecv(dc->dwRemoteUin, dwTotalSize); if (dc->ft == NULL) { NetLog_Direct("Unexpected file receive"); CloseDirectConnection(dc); return; } dc->ft->dwFileCount = dwFileCount; dc->ft->dwTransferSpeed = dwTransferSpeed; dc->ft->hContact = HContactFromUIN(dc->ft->dwUin, &bAdded); dc->ft->dwBytesDone = 0; dc->ft->iCurrentFile = -1; dc->ft->fileId = -1; dc->ft->hConnection = dc->hConnection; dc->ft->dwLastNotify = GetTickCount(); dc->initialised = 1; file_sendTransferSpeed(this, dc); file_sendNick(this, dc); } BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, dc->ft, 0); break; case PEER_FILE_INIT_ACK: if (wLen < 8) return; buf++; unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); /* followed by nick */ file_sendNextFile(this, dc); break; case PEER_FILE_NEXTFILE: if (wLen < 20) return; buf++; /* id */ { char *szAnsi; WORD wThisFilenameLen, wSubdirLen; BYTE isDirectory; unpackByte(&buf, &isDirectory); unpackLEWord(&buf, &wThisFilenameLen); if (wLen < 19 + wThisFilenameLen) return; SAFE_FREE(&dc->ft->szThisFile); szAnsi = (char *)_malloca(wThisFilenameLen + 1); memcpy(szAnsi, buf, wThisFilenameLen); szAnsi[wThisFilenameLen] = '\0'; dc->ft->szThisFile = ansi_to_utf8(szAnsi); buf += wThisFilenameLen; unpackLEWord(&buf, &wSubdirLen); if (wLen < 18 + wThisFilenameLen + wSubdirLen) return; SAFE_FREE(&dc->ft->szThisSubdir); szAnsi = (char *)_malloca(wSubdirLen + 1); memcpy(szAnsi, buf, wSubdirLen); szAnsi[wSubdirLen] = '\0'; dc->ft->szThisSubdir = ansi_to_utf8(szAnsi); buf += wSubdirLen; unpackLEDWord(&buf, &dc->ft->dwThisFileSize); unpackLEDWord(&buf, &dc->ft->dwThisFileDate); unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); /* no cheating with paths */ if (!IsValidRelativePath(dc->ft->szThisFile) || !IsValidRelativePath(dc->ft->szThisSubdir)) { NetLog_Direct("Invalid path information"); break; } char *szFullPath = (char*)SAFE_MALLOC(strlennull(dc->ft->szSavePath)+strlennull(dc->ft->szThisSubdir)+strlennull(dc->ft->szThisFile)+3); strcpy(szFullPath, dc->ft->szSavePath); NormalizeBackslash(szFullPath); strcat(szFullPath, dc->ft->szThisSubdir); NormalizeBackslash(szFullPath); // _chdir(szFullPath); // set current dir - not very useful strcat(szFullPath, dc->ft->szThisFile); // we joined the full path to dest file SAFE_FREE(&dc->ft->szThisFile); dc->ft->szThisFile = szFullPath; dc->ft->dwFileBytesDone = 0; dc->ft->iCurrentFile++; if (isDirectory) { MakeDirUtf(dc->ft->szThisFile); dc->ft->fileId = -1; } else { /* file resume */ PROTOFILETRANSFERSTATUS pfts = {0}; file_buildProtoFileTransferStatus(dc->ft, &pfts); if (BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, dc->ft, (LPARAM)&pfts)) break; /* UI supports resume: it will call PS_FILERESUME */ dc->ft->fileId = OpenFileUtf(dc->ft->szThisFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE); if (dc->ft->fileId == -1) { icq_LogMessage(LOG_ERROR, LPGEN("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder.")); CloseDirectConnection(dc); dc->ft->hConnection = NULL; break; } } } file_sendResume(this, dc); BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, dc->ft, 0); break; case PEER_FILE_RESUME: if (dc->ft->fileId == -1 && !dc->ft->currentIsDir) return; if (wLen < 13) return; if (wLen < 17) NetLog_Direct("Warning: Received short PEER_FILE_RESUME"); buf++; { DWORD dwRestartFrom; unpackLEDWord(&buf, &dwRestartFrom); if (dwRestartFrom > dc->ft->dwThisFileSize) return; buf += 4; /* unknown. 0 */ unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); buf += 4; /* unknown. 1 */ if (!dc->ft->currentIsDir) _lseek(dc->ft->fileId, dwRestartFrom, 0); dc->wantIdleTime = 1; dc->ft->dwBytesDone += dwRestartFrom; dc->ft->dwFileBytesDone += dwRestartFrom; } break; case PEER_FILE_SPEED: if (wLen < 5) return; buf++; unpackLEDWord(&buf, &dc->ft->dwTransferSpeed); dc->ft->dwLastNotify = GetTickCount(); break; case PEER_FILE_DATA: if (!dc->ft->currentIsDir) { if (dc->ft->fileId == -1) break; buf++; wLen--; _write(dc->ft->fileId, buf, wLen); } else wLen = 0; dc->ft->dwBytesDone += wLen; dc->ft->dwFileBytesDone += wLen; if (GetTickCount() > dc->ft->dwLastNotify + 500 || wLen < 2048) { PROTOFILETRANSFERSTATUS pfts; file_buildProtoFileTransferStatus(dc->ft, &pfts); BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, dc->ft, (LPARAM)&pfts); dc->ft->dwLastNotify = GetTickCount(); } if (wLen < 2048) { /* EOF */ if (!dc->ft->currentIsDir) _close(dc->ft->fileId); dc->ft->fileId = -1; if ((DWORD)dc->ft->iCurrentFile == dc->ft->dwFileCount - 1) { dc->type = DIRECTCONN_CLOSING; /* this guarantees that we won't accept any more data but that the sender is still free to closesocket() neatly */ BroadcastAck(dc->ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, dc->ft, 0); } } break; default: NetLog_Direct("Unknown file transfer packet ignored."); break; } }
void CIcqProto::handleDirectoryQueryResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, WORD wFlags) { WORD wBytesRemaining = 0; snac_header requestSnac = {0}; BYTE requestResult; #ifdef _DEBUG debugLogA("Received directory query response"); #endif if (wPacketLen >= 2) unpackLEWord(&databuf, &wBytesRemaining); wPacketLen -= 2; _ASSERTE(wPacketLen == wBytesRemaining); if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) { debugLogA("Error: Failed to parse directory response"); return; } cookie_directory_data *pCookieData; MCONTACT hContact; // check request cookie if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) { debugLogA("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); return; } /// FIXME: we should really check the snac contents according to cookie data here ?? // Check if this is the last packet for this request BOOL bMoreDataFollows = wFlags&0x0001 && requestSnac.wFlags&0x0001; if (wPacketLen >= 3) unpackByte(&databuf, &requestResult); else { debugLogA("Error: Malformed directory response"); if (!bMoreDataFollows) ReleaseCookie(wCookie); return; } if (requestResult != 1 && requestResult != 4) { debugLogA("Error: Directory request failed, status %u", requestResult); if (!bMoreDataFollows) { if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that ReleaseCookie(wCookie); } return; } WORD wLen; unpackWord(&databuf, &wLen); wPacketLen -= 3; if (wLen) debugLogA("Warning: Data in error message present!"); if (wPacketLen <= 0x16) { // sanity check debugLogA("Error: Malformed directory response"); if (!bMoreDataFollows) { if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that ReleaseCookie(wCookie); } return; } databuf += 0x10; // unknown stuff wPacketLen -= 0x10; DWORD dwItemCount; WORD wPageCount; /// FIXME: check itemcount, pagecount against the cookie data ??? unpackDWord(&databuf, &dwItemCount); unpackWord(&databuf, &wPageCount); wPacketLen -= 6; if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH && !bMoreDataFollows) debugLogA("Directory Search: %d contacts found (%u pages)", dwItemCount, wPageCount); if (wPacketLen <= 2) { // sanity check, block expected debugLogA("Error: Malformed directory response"); if (!bMoreDataFollows) { if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that ReleaseCookie(wCookie); } return; } WORD wData; unpackWord(&databuf, &wData); // This probably the count of items following (a block) wPacketLen -= 2; if (wPacketLen >= 2 && wData >= 1) { unpackWord(&databuf, &wLen); // This is the size of the first item wPacketLen -= 2; } if (wData == 0 && pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) { debugLogA("Directory Search: No contacts found"); ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); ReleaseCookie(wCookie); return; } _ASSERTE(wData == 1 && wPacketLen == wLen); if (wData != 1 || wPacketLen != wLen) { debugLogA("Error: Malformed directory response (missing data)"); if (!bMoreDataFollows) { if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER) ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); else if (pCookieData->bRequestType == DIRECTORYREQUEST_SEARCH) ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); // should report error here, but Find/Add module does not support that ReleaseCookie(wCookie); } return; } oscar_tlv_chain *pDirectoryData = readIntoTLVChain(&databuf, wLen, -1); if (pDirectoryData) { switch (pCookieData->bRequestType) { case DIRECTORYREQUEST_INFOOWNER: parseDirectoryUserDetailsData(NULL, pDirectoryData, wCookie, pCookieData, wReplySubtype); break; case DIRECTORYREQUEST_INFOUSER: { DWORD dwUin = 0; char *szUid = pDirectoryData->getString(0x32, 1); if (!szUid) { debugLogA("Error: Received unrecognized data from the directory"); break; } if (IsStringUIN(szUid)) dwUin = atoi(szUid); if (hContact != HContactFromUID(dwUin, szUid, NULL)) { debugLogA("Error: Received data does not match cookie contact, ignoring."); SAFE_FREE(&szUid); break; } else SAFE_FREE(&szUid); } case DIRECTORYREQUEST_INFOMULTI: parseDirectoryUserDetailsData(hContact, pDirectoryData, wCookie, pCookieData, wReplySubtype); break; case DIRECTORYREQUEST_SEARCH: parseDirectorySearchData(pDirectoryData, wCookie, pCookieData, wReplySubtype); break; default: debugLogA("Error: Unknown cookie type %x for directory response!", pCookieData->bRequestType); } disposeChain(&pDirectoryData); } else debugLogA("Error: Failed parsing directory response"); // Release Memory if (!bMoreDataFollows) ReleaseCookie(wCookie); }
void CIcqProto::handleExtensionError(BYTE *buf, WORD wPackLen) { WORD wErrorCode; if (wPackLen < 2) wErrorCode = 0; if (wPackLen >= 2 && wPackLen <= 6) unpackWord(&buf, &wErrorCode); else { // TODO: cookies need to be handled and freed here on error oscar_tlv_chain *chain = NULL; unpackWord(&buf, &wErrorCode); wPackLen -= 2; chain = readIntoTLVChain(&buf, wPackLen, 0); if (chain) { oscar_tlv* pTLV; pTLV = chain->getTLV(0x21, 1); // get meta error data if (pTLV && pTLV->wLen >= 8) { BYTE *pBuffer = pTLV->pData; WORD wData; pBuffer += 6; unpackLEWord(&pBuffer, &wData); // get request type switch (wData) { case CLI_META_INFO_REQ: if (pTLV->wLen >= 12) { WORD wSubType; WORD wCookie; unpackWord(&pBuffer, &wCookie); unpackLEWord(&pBuffer, &wSubType); // more sofisticated detection, send ack if (wSubType == META_REQUEST_FULL_INFO) { MCONTACT hContact; cookie_fam15_data *pCookieData = NULL; int foundCookie = FindCookie(wCookie, &hContact, (void**)&pCookieData); if (foundCookie && pCookieData) { ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); ReleaseCookie(wCookie); // we do not leak cookie and memory } debugLogA("Full info request error 0x%02x received", wErrorCode); } else if (wSubType == META_SET_PASSWORD_REQ) { // failed to change user password, report to UI ProtoBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); debugLogA("Meta change password request failed, error 0x%02x", wErrorCode); } else debugLogA("Meta request error 0x%02x received", wErrorCode); } else debugLogA("Meta request error 0x%02x received", wErrorCode); break; default: debugLogA("Unknown request 0x%02x error 0x%02x received", wData, wErrorCode); } disposeChain(&chain); return; } disposeChain(&chain); } } LogFamilyError(ICQ_EXTENSIONS_FAMILY, wErrorCode); }
void CIcqProto::parseSearchReplies(unsigned char *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype, BYTE bResultCode) { BYTE bParsingOK = FALSE; // For debugging purposes only BOOL bLastUser = FALSE; cookie_search *pCookie; if (!FindCookie(wCookie, NULL, (void**)&pCookie)) { debugLogA("Warning: Received unexpected search reply"); pCookie = NULL; } switch (wReplySubtype) { case SRV_LAST_USER_FOUND: // Search: last user found reply bLastUser = TRUE; case SRV_USER_FOUND: // Search: user found reply if (bLastUser) debugLogA("SNAC(0x15,0x3): Last search reply"); else debugLogA("SNAC(0x15,0x3): Search reply"); if (bResultCode == 0xA) { ICQSEARCHRESULT sr = {0}; DWORD dwUin; char szUin[UINMAXLEN]; WORD wLen; sr.hdr.cbSize = sizeof(sr); // Remaining bytes if (wPacketLen < 2) break; unpackLEWord(&databuf, &wLen); wPacketLen -= 2; _ASSERTE(wLen <= wPacketLen); if (wLen > wPacketLen) break; // Uin if (wPacketLen < 4) break; unpackLEDWord(&databuf, &dwUin); // Uin wPacketLen -= 4; sr.uin = dwUin; _itoa(dwUin, szUin, 10); sr.hdr.id = (FNAMECHAR*)szUin; // Nick if (wPacketLen < 2) break; unpackLEWord(&databuf, &wLen); wPacketLen -= 2; if (wLen > 0) { if (wPacketLen < wLen || (databuf[wLen-1] != 0)) break; sr.hdr.nick = (FNAMECHAR*)databuf; databuf += wLen; } else { sr.hdr.nick = NULL; } // First name if (wPacketLen < 2) break; unpackLEWord(&databuf, &wLen); wPacketLen -= 2; if (wLen > 0) { if (wPacketLen < wLen || (databuf[wLen-1] != 0)) break; sr.hdr.firstName = (FNAMECHAR*)databuf; databuf += wLen; } else { sr.hdr.firstName = NULL; } // Last name if (wPacketLen < 2) break; unpackLEWord(&databuf, &wLen); wPacketLen -= 2; if (wLen > 0) { if (wPacketLen < wLen || (databuf[wLen-1] != 0)) break; sr.hdr.lastName = (FNAMECHAR*)databuf; databuf += wLen; } else { sr.hdr.lastName = NULL; } // E-mail name if (wPacketLen < 2) break; unpackLEWord(&databuf, &wLen); wPacketLen -= 2; if (wLen > 0) { if (wPacketLen < wLen || (databuf[wLen-1] != 0)) break; sr.hdr.email = (FNAMECHAR*)databuf; databuf += wLen; } else { sr.hdr.email = NULL; } // Authentication needed flag if (wPacketLen < 1) break; unpackByte(&databuf, &sr.auth); // Finally, broadcast the result ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)wCookie, (LPARAM)&sr); // Broadcast "Last result" ack if this was the last user found if (wReplySubtype == SRV_LAST_USER_FOUND) { if (wPacketLen>=10) { DWORD dwLeft; databuf += 5; unpackLEDWord(&databuf, &dwLeft); if (dwLeft) debugLogA("Warning: %d search results omitted", dwLeft); } ReleaseSearchCookie(wCookie, pCookie); } bParsingOK = TRUE; } else { // Failed search debugLogA("SNAC(0x15,0x3): Search error %u", bResultCode); ReleaseSearchCookie(wCookie, pCookie); bParsingOK = TRUE; } break; case SRV_RANDOM_FOUND: // Random search server reply default: if (pCookie) ReleaseCookie(wCookie); break; } // For debugging purposes only if (!bParsingOK) { debugLogA("Warning: Parsing error in 15/03 search reply type x%x", wReplySubtype); _ASSERTE(!bParsingOK); } }
void CIcqProto::handleExtensionMetaResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wFlags) { WORD wReplySubtype; BYTE bResultCode; _ASSERTE(wPacketLen >= 3); if (wPacketLen >= 3) { // Reply subtype unpackLEWord(&databuf, &wReplySubtype); wPacketLen -= 2; // Success byte unpackByte(&databuf, &bResultCode); wPacketLen -= 1; switch (wReplySubtype) { case META_SET_PASSWORD_ACK: parseUserInfoUpdateAck(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); break; case SRV_RANDOM_FOUND: case SRV_USER_FOUND: case SRV_LAST_USER_FOUND: parseSearchReplies(databuf, wPacketLen, wCookie, wReplySubtype, bResultCode); break; case META_PROCESSING_ERROR: // Meta processing error server reply // Todo: We only use this as an SMS ack, that will have to change { // Terminate buffer char *pszInfo = (char *)_alloca(wPacketLen + 1); if (wPacketLen > 0) memcpy(pszInfo, databuf, wPacketLen); pszInfo[wPacketLen] = 0; ProtoBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_FAILED, (HANDLE)wCookie, (LPARAM)pszInfo); FreeCookie(wCookie); break; } break; case META_SMS_DELIVERY_RECEIPT: // Todo: This overlaps with META_SET_AFFINFO_ACK. // Todo: Check what happens if result != A if (wPacketLen > 8) { WORD wNetworkNameLen; WORD wAckLen; char *pszInfo; databuf += 6; // Some unknowns wPacketLen -= 6; unpackWord(&databuf, &wNetworkNameLen); if (wPacketLen >= (wNetworkNameLen + 2)) { databuf += wNetworkNameLen; wPacketLen -= wNetworkNameLen; unpackWord(&databuf, &wAckLen); if (pszInfo = (char *)_alloca(wAckLen + 1)) { // Terminate buffer if (wAckLen > 0) memcpy(pszInfo, databuf, wAckLen); pszInfo[wAckLen] = 0; ProtoBroadcastAck(NULL, ICQACKTYPE_SMS, ACKRESULT_SENTREQUEST, (HANDLE)wCookie, (LPARAM)pszInfo); FreeCookie(wCookie); // Parsing success break; } } } // Parsing failure debugLogA("Error: Failure parsing META_SMS_DELIVERY_RECEIPT"); break; case META_DIRECTORY_DATA: case META_DIRECTORY_RESPONSE: if (bResultCode == 0x0A) handleDirectoryQueryResponse(databuf, wPacketLen, wCookie, wReplySubtype, wFlags); else debugLogA("Error: Directory request failed, code %u", bResultCode); break; case META_DIRECTORY_UPDATE_ACK: if (bResultCode == 0x0A) handleDirectoryUpdateResponse(databuf, wPacketLen, wCookie, wReplySubtype); else debugLogA("Error: Directory request failed, code %u", bResultCode); break; case META_BASIC_USERINFO: case META_WORK_USERINFO: case META_MORE_USERINFO: case META_NOTES_USERINFO: case META_EMAIL_USERINFO: case META_INTERESTS_USERINFO: case META_AFFILATIONS_USERINFO: case META_SHORT_USERINFO: case META_HPAGECAT_USERINFO: debugLogA("Warning: Ignored 15/03 (legacy user info) replysubtype x%x", wReplySubtype); break; default: debugLogA("Warning: Ignored 15/03 replysubtype x%x", wReplySubtype); // _ASSERTE(0); break; } // Success return; } // Failure debugLogA("Warning: Broken 15/03 ExtensionMetaResponse"); }
void CIcqProto::handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype) { WORD wBytesRemaining = 0; snac_header requestSnac = {0}; BYTE requestResult; #ifdef _DEBUG debugLogA("Received directory update response"); #endif if (wPacketLen >= 2) unpackLEWord(&databuf, &wBytesRemaining); wPacketLen -= 2; _ASSERTE(wPacketLen == wBytesRemaining); if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid) { debugLogA("Error: Failed to parse directory response"); return; } cookie_directory_data *pCookieData; MCONTACT hContact; // check request cookie if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData) { debugLogA("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype); return; } /// FIXME: we should really check the snac contents according to cookie data here ?? if (wPacketLen >= 3) unpackByte(&databuf, &requestResult); else { debugLogA("Error: Malformed directory response"); ReleaseCookie(wCookie); return; } if (requestResult != 1 && requestResult != 4) { debugLogA("Error: Directory request failed, status %u", requestResult); if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) ProtoBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0); ReleaseCookie(wCookie); return; } WORD wLen; unpackWord(&databuf, &wLen); wPacketLen -= 3; if (wLen) debugLogA("Warning: Data in error message present!"); if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER) ProtoBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0); if (wPacketLen == 0x18) { DWORD64 qwMetaTime; BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; unpackQWord(&databuf, &qwMetaTime); setSettingBlob(NULL, DBSETTING_METAINFO_TIME, (BYTE*)&qwMetaTime, 8); if (memcmp(databuf, pbEmptyMetaToken, 0x10)) setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, databuf, 0x10); } ReleaseCookie(wCookie); }