void CIcqProto::handleLocationFam(BYTE *pBuffer, WORD wBufferLength, snac_header *pSnacHeader) { switch (pSnacHeader->wSubtype) { case ICQ_LOCATION_RIGHTS_REPLY: // Reply to CLI_REQLOCATION NetLog_Server("Server sent SNAC(x02,x03) - SRV_LOCATION_RIGHTS_REPLY"); break; case ICQ_LOCATION_USR_INFO_REPLY: // AIM user info reply handleLocationUserInfoReply(pBuffer, wBufferLength, pSnacHeader->dwRef); break; case ICQ_ERROR: { WORD wError; HANDLE hCookieContact; cookie_fam15_data *pCookieData; if (wBufferLength >= 2) unpackWord(&pBuffer, &wError); else wError = 0; if (wError == 4) { if (FindCookie(pSnacHeader->dwRef, &hCookieContact, (void**)&pCookieData) && !getContactUin(hCookieContact) && pCookieData->bRequestType == REQUESTTYPE_PROFILE) { BroadcastAck(hCookieContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, (HANDLE)1 ,0); ReleaseCookie(pSnacHeader->dwRef); } } LogFamilyError(ICQ_LOCATION_FAMILY, wError); break; } default: NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_LOCATION_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef); break; } }
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::handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie) { HANDLE hContact; DWORD dwUIN; uid_str szUID; WORD wTLVCount; WORD wWarningLevel; HANDLE hCookieContact; WORD status; cookie_message_data *pCookieData; // Unpack the sender's user ID if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return; // Syntax check if (wLen < 4) return; // Warning level? unpackWord(&buf, &wWarningLevel); wLen -= 2; // TLV count unpackWord(&buf, &wTLVCount); wLen -= 2; // Determine contact hContact = HContactFromUID(dwUIN, szUID, NULL); // Ignore away status if the user is not already on our list if (hContact == INVALID_HANDLE_VALUE) { #ifdef _DEBUG NetLog_Server("Ignoring away reply (%s)", strUID(dwUIN, szUID)); #endif return; } if (!FindCookie(dwCookie, &hCookieContact, (void**)&pCookieData)) { NetLog_Server("Error: Received unexpected away reply from %s", strUID(dwUIN, szUID)); return; } if (hContact != hCookieContact) { NetLog_Server("Error: Away reply 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; } switch (GetCookieType(dwCookie)) { case CKT_FAMILYSPECIAL: { ReleaseCookie(dwCookie); // Read user info TLVs { oscar_tlv_chain* pChain; BYTE *tmp; char *szMsg = NULL; // Syntax check if (wLen < 4) return; tmp = buf; // Get general chain if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) return; disposeChain(&pChain); wLen -= (buf - tmp); // Get extra chain if (pChain = readIntoTLVChain(&buf, wLen, 2)) { oscar_tlv *pTLV; char *szEncoding = NULL; // Get Profile encoding TLV pTLV = pChain->getTLV(0x01, 1); if (pTLV && (pTLV->wLen >= 1)) { szEncoding = (char*)_alloca(pTLV->wLen + 1); memcpy(szEncoding, pTLV->pData, pTLV->wLen); szEncoding[pTLV->wLen] = '\0'; } // Get Profile info TLV pTLV = pChain->getTLV(0x02, 1); if (pTLV && (pTLV->wLen >= 1)) { szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); memcpy(szMsg, pTLV->pData, pTLV->wLen); szMsg[pTLV->wLen] = '\0'; szMsg[pTLV->wLen + 1] = '\0'; szMsg = AimApplyEncoding(szMsg, szEncoding); szMsg = EliminateHtml(szMsg, pTLV->wLen); } // Free TLV chain disposeChain(&pChain); } setSettingString(hContact, "About", szMsg); BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0); SAFE_FREE((void**)&szMsg); } break; } default: // away message { status = AwayMsgTypeToStatus(pCookieData->nAckType); if (status == ID_STATUS_OFFLINE) { NetLog_Server("SNAC(2.6) Ignoring unknown status message from %s", strUID(dwUIN, szUID)); ReleaseCookie(dwCookie); return; } ReleaseCookie(dwCookie); // Read user info TLVs { oscar_tlv_chain* pChain; oscar_tlv* pTLV; BYTE *tmp; char *szMsg = NULL; CCSDATA ccs; PROTORECVEVENT pre; // Syntax check if (wLen < 4) return; tmp = buf; // Get general chain if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount))) return; disposeChain(&pChain); wLen -= (buf - tmp); // Get extra chain if (pChain = readIntoTLVChain(&buf, wLen, 2)) { char* szEncoding = NULL; // Get Away encoding TLV pTLV = pChain->getTLV(0x03, 1); if (pTLV && (pTLV->wLen >= 1)) { szEncoding = (char*)_alloca(pTLV->wLen + 1); memcpy(szEncoding, pTLV->pData, pTLV->wLen); szEncoding[pTLV->wLen] = '\0'; } // Get Away info TLV pTLV = pChain->getTLV(0x04, 1); if (pTLV && (pTLV->wLen >= 1)) { szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2); memcpy(szMsg, pTLV->pData, pTLV->wLen); szMsg[pTLV->wLen] = '\0'; szMsg[pTLV->wLen + 1] = '\0'; szMsg = AimApplyEncoding(szMsg, szEncoding); szMsg = EliminateHtml(szMsg, pTLV->wLen); } // Free TLV chain disposeChain(&pChain); } ccs.szProtoService = PSR_AWAYMSG; ccs.hContact = hContact; ccs.wParam = status; ccs.lParam = (LPARAM)⪯ pre.flags = 0; pre.szMessage = szMsg?szMsg:(char *)""; pre.timestamp = time(NULL); pre.lParam = dwCookie; CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); SAFE_FREE((void**)&szMsg); } break; } } }
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::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::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); }