void CIcqProto::handleXtrazData(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) { MCONTACT hContact; char* szPluginID; hContact = HContactFromUIN(dwUin, NULL); if (hContact) // user sent us xtraz, he supports it SetContactCapabilities(hContact, CAPF_XTRAZ); szPluginID = getXmlPidItem(szMsg, nMsgLen); if (!strcmpnull(szPluginID, "viewCard")) { // it is a greeting card char *szWork, *szEnd, *szUrl, *szNum; szWork = strstrnull(szMsg, "<InD>"); szEnd = strstrnull(szMsg, "</InD>"); if (szWork && szEnd) { int nDataLen = szEnd - szWork; szUrl = (char*)_alloca(nDataLen); memcpy(szUrl, szWork + 5, nDataLen); szUrl[nDataLen - 5] = '\0'; if (!_strnicmp(szUrl, "view_", 5)) { szNum = szUrl + 5; szWork = strstrnull(szUrl, ".html"); if (szWork) { strcpy(szWork, ".php"); strcat(szWork, szWork + 5); } while (szWork = strstrnull(szUrl, "&")) // unescape & code strcpy(szWork + 1, szWork + 5); szWork = (char*)SAFE_MALLOC(nDataLen + MAX_PATH); ICQTranslateUtfStatic(LPGEN("Greeting card:"), szWork, MAX_PATH); strcat(szWork, "\r\nhttp://www.icq.com/friendship/pages/view_page_"); strcat(szWork, szNum); // Create message to notify user PROTORECVEVENT pre = { 0 }; pre.timestamp = time(NULL); pre.szMessage = szWork; pre.flags = PREF_UTF; int bAdded; ProtoChainRecvMsg(HContactFromUIN(dwUin, &bAdded), &pre); SAFE_FREE(&szWork); } else NetLog_Uni(bThruDC, "Error: Non-standard greeting card message"); } else NetLog_Uni(bThruDC, "Error: Malformed greeting card message"); } else NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); SAFE_FREE(&szPluginID); }
static void MessageIcqUser(ICQFILEINFO *info) { MCONTACT hContact; if (ServiceExists(MS_MSG_SENDMESSAGE)) { hContact = HContactFromUIN(atoi(info->uin), NULL); /* adds the contact if needed */ if (hContact != NULL) CallService(MS_MSG_SENDMESSAGE, hContact, 0); } }
void CIcqProto::handleXtrazInvitation(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) { MCONTACT hContact = HContactFromUIN(dwUin, NULL); if (hContact) // user sent us xtraz, he supports it SetContactCapabilities(hContact, CAPF_XTRAZ); char *szPluginID = getXmlPidItem(szMsg, nMsgLen); if (!strcmpnull(szPluginID, "ICQChatRecv")) // it is a invitation to multi-user chat ; else NetLog_Uni(bThruDC, "Error: Unknown plugin \"%s\" in Xtraz message", szPluginID); SAFE_FREE(&szPluginID); }
void CIcqProto::SendXtrazNotifyResponse(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szResponse, int nResponseLen, BOOL bThruDC) { char *szResBody = MangleXml(szResponse, nResponseLen); int nBodyLen = strlennull(szResBody) + 21; char *szBody = (char*)_alloca(nBodyLen); MCONTACT hContact = HContactFromUIN(dwUin, NULL); if (hContact != INVALID_CONTACT_ID && !CheckContactCapabilities(hContact, CAPF_XTRAZ)) { SAFE_FREE(&szResBody); return; // Contact does not support xtraz, do not send anything } nBodyLen = mir_snprintf(szBody, nBodyLen, "<NR><RES>%s</RES></NR>", szResBody); SAFE_FREE(&szResBody); // Was request received thru DC and have we a open DC, send through that if (bThruDC && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD, 0)) icq_sendXtrazResponseDirect(hContact, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); else icq_sendXtrazResponseServ(dwUin, dwMID, dwMID2, wCookie, szBody, nBodyLen, MTYPE_SCRIPT_NOTIFY); }
void CIcqProto::handleXtrazNotify(DWORD dwUin, DWORD dwMID, DWORD dwMID2, WORD wCookie, char* szMsg, int nMsgLen, BOOL bThruDC) { char *szNotify = strstrnull(szMsg, "<NOTIFY>"); char *szQuery = strstrnull(szMsg, "<QUERY>"); MCONTACT hContact = HContactFromUIN(dwUin, NULL); if (hContact) // user sent us xtraz, he supports it SetContactCapabilities(hContact, CAPF_XTRAZ); if (szNotify && szQuery) { // valid request char *szWork, *szEnd; int nNotifyLen, nQueryLen; szNotify += 8; szQuery += 7; szEnd = strstrnull(szMsg, "</NOTIFY>"); if (!szEnd) szEnd = szMsg + nMsgLen; nNotifyLen = (szEnd - szNotify); szEnd = strstrnull(szMsg, "</QUERY>"); if (!szEnd) szEnd = szNotify; szNotify = DemangleXml(szNotify, nNotifyLen); nQueryLen = (szEnd - szQuery); szQuery = DemangleXml(szQuery, nQueryLen); szWork = strstrnull(szQuery, "<PluginID>"); szEnd = strstrnull(szQuery, "</PluginID>"); #ifdef _DEBUG debugLogA("Query: %s", szQuery); debugLogA("Notify: %s", szNotify); #endif if (szWork && szEnd) { // this is our plugin szWork += 10; *szEnd = '\0'; if (!stricmpnull(szWork, "srvMng") && strstrnull(szNotify, "AwayStat")) { char *szSender = strstrnull(szNotify, "<senderId>"); char *szEndSend = strstrnull(szNotify, "</senderId>"); if (szSender && szEndSend) { szSender += 10; *szEndSend = '\0'; if ((DWORD)atoi(szSender) == dwUin) { BYTE dwXId = m_bXStatusEnabled ? getContactXStatus(NULL) : 0; if (dwXId && validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY)) { // apply privacy rules NotifyEventHooks(m_modeMsgsEvent, (WPARAM)MTYPE_SCRIPT_NOTIFY, (LPARAM)dwUin); char *tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, ""); char *szXName = MangleXml(tmp, strlennull(tmp)); SAFE_FREE(&tmp); tmp = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, ""); char *szXMsg = MangleXml(tmp, strlennull(tmp)); SAFE_FREE(&tmp); int nResponseLen = 212 + strlennull(szXName) + strlennull(szXMsg) + UINMAXLEN + 2; char *szResponse = (char*)_alloca(nResponseLen + 1); // send response mir_snprintf(szResponse, nResponseLen, "<ret event=\"OnRemoteNotification\">" "<srv><id>cAwaySrv</id>" "<val srv_id=\"cAwaySrv\"><Root>" "<CASXtraSetAwayMessage></CASXtraSetAwayMessage>" "<uin>%d</uin>" "<index>%d</index>" "<title>%s</title>" "<desc>%s</desc></Root></val></srv></ret>", m_dwLocalUIN, dwXId, szXName, szXMsg); SAFE_FREE(&szXName); SAFE_FREE(&szXMsg); struct rates_xstatus_response : public rates_queue_item { protected: virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) { rates_xstatus_response *pDest = (rates_xstatus_response*)aDest; if (!pDest) pDest = new rates_xstatus_response(ppro, wGroup); pDest->bThruDC = bThruDC; pDest->dwMsgID1 = dwMsgID1; pDest->dwMsgID2 = dwMsgID2; pDest->wCookie = wCookie; pDest->szResponse = null_strdup(szResponse); return rates_queue_item::copyItem(pDest); }; public: rates_xstatus_response(CIcqProto *ppro, WORD wGroup) : rates_queue_item(ppro, wGroup), szResponse(NULL) {}; virtual ~rates_xstatus_response() { if (bCreated) SAFE_FREE(&szResponse); }; virtual void execute() { ppro->SendXtrazNotifyResponse(dwUin, dwMsgID1, dwMsgID2, wCookie, szResponse, strlennull(szResponse), bThruDC); }; BOOL bThruDC; DWORD dwMsgID1; DWORD dwMsgID2; WORD wCookie; char *szResponse; }; m_ratesMutex->Enter(); WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_RESPONSE); m_ratesMutex->Leave(); rates_xstatus_response rr(this, wGroup); rr.hContact = hContact; rr.dwUin = dwUin; rr.bThruDC = bThruDC; rr.dwMsgID1 = dwMID; rr.dwMsgID2 = dwMID2; rr.wCookie = wCookie; rr.szResponse = szResponse; handleRateItem(&rr, RQT_RESPONSE, 0, !bThruDC); } else if (dwXId) debugLogA("Privacy: Ignoring XStatus request"); else debugLogA("Error: We are not in XStatus, skipping"); } else debugLogA("Error: Invalid sender information"); } else debugLogA("Error: Missing sender information"); } else debugLogA("Error: Unknown plugin \"%s\" in Xtraz message", szWork); } else debugLogA("Error: Missing PluginID in Xtraz message"); SAFE_FREE(&szNotify); SAFE_FREE(&szQuery); } else debugLogA("Error: Invalid Xtraz Notify message"); }
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; } }