/*
Plugin of Miranda IM for communicating with users of the AIM protocol.
Copyright (c) 2008-2009 Boris Krasnovskiy
Copyright (C) 2005-2006 Aaron Myles Landwehr
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.  If not, see .
*/
#include "aim.h"
HANDLE CAimProto::aim_connect(const char* server, unsigned short port, bool use_ssl, const char* host)
{
	NETLIBOPENCONNECTION ncon = { 0 };
	ncon.cbSize = sizeof(ncon);
	ncon.szHost = server;
	ncon.wPort = port;
	ncon.timeout = 6;
	ncon.flags = NLOCF_V2;
	debugLogA("%s:%u", server, port);
	HANDLE con = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)m_hNetlibUser, (LPARAM)&ncon);
	if (con && use_ssl) {
		NETLIBSSL ssl = {0};
		ssl.cbSize = sizeof(ssl);
		ssl.host = host;
		if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)con, (LPARAM)&ssl)) {
			Netlib_CloseHandle(con);
			con = NULL;
		}
	}
	return con;
}
HANDLE CAimProto::aim_peer_connect(const char* ip, unsigned short port)
{ 
	NETLIBOPENCONNECTION ncon = { 0 };
	ncon.cbSize = sizeof(ncon);
	ncon.flags = NLOCF_V2;
	ncon.szHost = ip;
	ncon.wPort = port;
	ncon.timeout = 3;
	return (HANDLE)CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlibPeer, (LPARAM)&ncon);
}
HANDLE CAimProto::aim_peer_connect(unsigned long ip, unsigned short port)
{
	char ips[20];
	long_ip_to_char_ip(ip, ips);
	return aim_peer_connect(ips, port);
}
void CAimProto::aim_connection_authorization(void)
{
	NETLIBPACKETRECVER packetRecv = {0};
	HANDLE hServerPacketRecver = NULL;
	if (m_iDesiredStatus == ID_STATUS_OFFLINE)
		goto exit;
	char *password = getStringA(AIM_KEY_PW);
	if (password == NULL)
		goto exit;
	mir_free(username);
	username = getStringA(AIM_KEY_SN);
	if (username == NULL)
		goto exit;
	hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 2048 * 4);
	packetRecv.cbSize = sizeof(packetRecv);
	packetRecv.dwTimeout = 5000;
	for (;;) {
		int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM) & packetRecv);
		if (recvResult == 0) {
			debugLogA("Connection Closed: No Error? during Connection Authorization");
			break;
		}
		else if (recvResult < 0) {
			debugLogA("Connection Closed: Socket Error during Connection Authorization %d", WSAGetLastError());
			break;
		}
		else {
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsed0)
		{
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsed0)
		{
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsed 0)
		{
			unsigned short flap_length=0;
			for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length)
			{
				if (!packetRecv.buffer)
					break;
				FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
				if (!flap.len())
					break;
				flap_length += FLAP_SIZE + flap.len();
				if (flap.cmp(0x01))
				{
					aim_send_cookie(hAvatarConn, avatar_seqno, AVATAR_COOKIE_LENGTH, AVATAR_COOKIE);//cookie challenge
					mir_free(AVATAR_COOKIE);
					AVATAR_COOKIE = NULL;
					AVATAR_COOKIE_LENGTH = 0;
				}
				else if (flap.cmp(0x02))
				{
					SNAC snac(flap.val(), flap.snaclen());
					if (snac.cmp(0x0001))
					{
						snac_supported_families(snac, hAvatarConn, avatar_seqno);
						snac_supported_family_versions(snac, hAvatarConn, avatar_seqno);
						snac_avatar_rate_limitations(snac, hAvatarConn, avatar_seqno);
						snac_error(snac);
					}
					if (snac.cmp(0x0010))
					{
						snac_retrieve_avatar(snac);
						snac_upload_reply_avatar(snac);
					}
				}
				else if (flap.cmp(0x04))
					goto exit;
			}
		}
	}
exit:
	Netlib_CloseHandle(hServerPacketRecver);
	Netlib_CloseHandle(hAvatarConn);
	hAvatarConn=NULL;
	ResetEvent(hAvatarEvent);
	debugLogA("Avatar Server Connection has ended");
}
void __cdecl CAimProto::aim_chatnav_negotiation( void* )
{
	unsigned idle_chat = 0;
	HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hChatNavConn, 2048 * 8);
	NETLIBPACKETRECVER packetRecv = {0};
	packetRecv.cbSize = sizeof(packetRecv);
	packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
	for (;;)
	{
		int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM)&packetRecv);
		if (recvResult == 0)
			break;
		if (recvResult == SOCKET_ERROR)
		{
			if (WSAGetLastError() == ERROR_TIMEOUT)
			{
				if (chat_rooms.getCount())
					idle_chat = 0;
				else if (++idle_chat >= 6)
					break;
				if (aim_keepalive(hChatNavConn, chatnav_seqno) < 0)
					break;
			}
			else
				break;
		}
		if (recvResult>0)
		{
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsedhconn, 2048 * 8);
	NETLIBPACKETRECVER packetRecv = {0};
	packetRecv.cbSize = sizeof(packetRecv);
	packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
	for (;;)
	{
		int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
		if (recvResult == 0)
			break;
		if (recvResult == SOCKET_ERROR)
		{
			if (WSAGetLastError() == ERROR_TIMEOUT)
			{
				if (aim_keepalive(item->hconn, item->seqno) < 0)
					break;
			}
			else
				break;
		}
		if (recvResult>0)
		{
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsedhconn,item->seqno,item->CHAT_COOKIE_LENGTH,item->CHAT_COOKIE);//cookie challenge
					mir_free(item->CHAT_COOKIE);
					item->CHAT_COOKIE=NULL;
					item->CHAT_COOKIE_LENGTH=0;
				}
				else if (flap.cmp(0x02))
				{
					SNAC snac(flap.val(),flap.snaclen());
					if (snac.cmp(0x0001))
					{
						snac_supported_families(snac,item->hconn,item->seqno);
						snac_supported_family_versions(snac,item->hconn,item->seqno);
						snac_chat_rate_limitations(snac,item->hconn,item->seqno);
						snac_error(snac);
					}
					if (snac.cmp(0x000E))
					{
						snac_chat_received_message(snac, item);
						snac_chat_joined_left_users(snac, item);
						snac_error(snac);
					}
				}
				else if (flap.cmp(0x04))
					goto exit;
			}
		}
	}
exit:
	Netlib_CloseHandle(hServerPacketRecver);
	Netlib_CloseHandle(item->hconn);
	chat_leave(item->id);
	remove_chat_by_ptr(item);
	debugLogA("Chat Server Connection has ended");
}
void __cdecl CAimProto::aim_admin_negotiation( void* )
{
	HANDLE hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hAdminConn, 2048 * 8);
	NETLIBPACKETRECVER packetRecv = {0};
	packetRecv.cbSize = sizeof(packetRecv);
	packetRecv.dwTimeout = 300000;//5 minutes connected
	for (;;)
	{
		int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM) & packetRecv);
		if (recvResult == 0)
			break;
		if (recvResult == SOCKET_ERROR)
			break;
		if (recvResult>0)
		{
			unsigned short flap_length=0;
			for (;packetRecv.bytesUsed