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::handleDirectGreetingMessage(directconnect* dc, PBYTE buf, WORD wLen, WORD wCommand, WORD wCookie, BYTE bMsgType, BYTE bMsgFlags, WORD wStatus, WORD wFlags, char* pszText) { DWORD dwLengthToEnd; DWORD dwDataLength; char* pszFileName = NULL; int typeId; WORD qt; #ifdef _DEBUG NetLog_Direct("Handling PEER_MSG_GREETING, command %u, cookie %u, messagetype %u, messageflags %u, status %u, flags %u", wCommand, wCookie, bMsgType, bMsgFlags, wStatus, wFlags); #endif NetLog_Direct("Parsing Greeting message through direct"); if (!unpackPluginTypeId(&buf, &wLen, &typeId, &qt, TRUE)) return; // Length of remaining data unpackLEDWord(&buf, &dwLengthToEnd); if (dwLengthToEnd < 4 || dwLengthToEnd > wLen) { NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 2, dwLengthToEnd, wLen); return; } // Length of message/reason unpackLEDWord(&buf, &dwDataLength); wLen -= 4; if (dwDataLength > wLen) { NetLog_Direct("Error: Sanity checking failed (%d) in handleDirectGreetingMessage, datalen %u wLen %u", 3, dwDataLength, wLen); return; } if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_MESSAGE) { char* szMsg; NetLog_Direct("This is file request"); szMsg = (char*)_alloca(dwDataLength+1); unpackString(&buf, szMsg, (WORD)dwDataLength); szMsg[dwDataLength] = '\0'; wLen = wLen - (WORD)dwDataLength; handleFileRequest(buf, wLen, dc->dwRemoteUin, wCookie, 0, 0, szMsg, 8, TRUE); } else if (typeId == MTYPE_FILEREQ && wCommand == DIRECT_ACK) { char* szMsg; NetLog_Direct("This is file ack"); szMsg = (char*)_alloca(dwDataLength+1); unpackString(&buf, szMsg, (WORD)dwDataLength); szMsg[dwDataLength] = '\0'; wLen = wLen - (WORD)dwDataLength; // 50 - file request granted/refused handleFileAck(buf, wLen, dc->dwRemoteUin, wCookie, wStatus, szMsg); } else if (typeId && wCommand == DIRECT_MESSAGE) { uid_str szUID; message_ack_params pMsgAck = {0}; pMsgAck.bType = MAT_DIRECT; pMsgAck.pDC = dc; pMsgAck.wCookie = wCookie; pMsgAck.msgType = typeId; handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, typeId, 0, 0, dwLengthToEnd, (WORD)dwDataLength, (char*)buf, MTF_PLUGIN | MTF_DIRECT, &pMsgAck); } else if (typeId == MTYPE_STATUSMSGEXT && wCommand == DIRECT_ACK) { // especially for icq2003b NetLog_Direct("This is extended status reply"); char *szMsg = (char*)_alloca(dwDataLength+1); uid_str szUID; unpackString(&buf, szMsg, (WORD)dwDataLength); szMsg[dwDataLength] = '\0'; handleMessageTypes(dc->dwRemoteUin, szUID, time(NULL), 0, 0, wCookie, dc->wVersion, (int)(qt + 0xE7), 3, 2, (DWORD)wLen, (WORD)dwDataLength, szMsg, MTF_PLUGIN | MTF_DIRECT, NULL); } else if (typeId && wCommand == DIRECT_ACK) { 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 { int ackType = -1; switch (typeId) { case MTYPE_MESSAGE: ackType = ACKTYPE_MESSAGE; break; case MTYPE_URL: ackType = ACKTYPE_URL; break; case MTYPE_CONTACTS: ackType = ACKTYPE_CONTACTS; break; case MTYPE_SCRIPT_NOTIFY: { char *szMsg; szMsg = (char*)_alloca(dwDataLength + 1); if (dwDataLength > 0) memcpy(szMsg, buf, dwDataLength); szMsg[dwDataLength] = '\0'; handleXtrazNotifyResponse(dc->dwRemoteUin, dc->hContact, wCookie, szMsg, dwDataLength); } 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); } // Release cookie ReleaseCookie(wCookie); } } else NetLog_Direct("Unsupported plugin message type %s", typeId); }
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); }
void CIcqProto::handleDirectCancel(directconnect *dc, PBYTE buf, WORD wLen, WORD wCommand, DWORD dwCookie, WORD wMessageType, WORD wStatus, WORD wFlags, char* pszText) { NetLog_Direct("handleDirectCancel: Unhandled cancel"); }
// 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; } }