Пример #1
0
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);
}
Пример #2
0
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");
}
Пример #3
0
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);
}
Пример #4
0
// 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);
}
Пример #5
0
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;
	}
}
Пример #6
0
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);
}
Пример #7
0
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);
}
Пример #8
0
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);
	}
}
Пример #9
0
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");
}
Пример #10
0
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);
}