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::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"); }