/*

Jabber Protocol Plugin for Miranda IM
Tlen Protocol Plugin for Miranda NG
Copyright (C) 2002-2004  Santithorn Bunchua
Copyright (C) 2004-2007  Piotr Piastucki

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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "tlen.h"

BOOL TlenWsInit(TlenProtocol *proto)
{
	NETLIBUSER nlu = {0};
	NETLIBUSERSETTINGS nlus = {0};
	TCHAR name[128];


	nlu.cbSize = sizeof(nlu);
	nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_TCHAR;	// | NUF_HTTPGATEWAY;
	mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), proto->m_tszUserName);
	nlu.ptszDescriptiveName = name;
	nlu.szSettingsModule = proto->m_szModuleName;
	proto->m_hNetlibUser = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM) &nlu);

	nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_NOOPTIONS | NUF_TCHAR;
	mir_sntprintf(name, SIZEOF(name), TranslateT("%s SOCKS connection"), proto->m_tszUserName);
	nlu.ptszDescriptiveName = name;
	proto->hFileNetlibUser = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM) &nlu);
	nlus.cbSize = sizeof(nlus);
	nlus.useProxy = 0;
	CallService(MS_NETLIB_SETUSERSETTINGS, (WPARAM) proto->hFileNetlibUser, (LPARAM) &nlus);

	return (proto->m_hNetlibUser != NULL)?TRUE:FALSE;
}

void TlenWsUninit(TlenProtocol *proto)
{
	if (proto->m_hNetlibUser != NULL) Netlib_CloseHandle(proto->m_hNetlibUser);
	if (proto->hFileNetlibUser != NULL) Netlib_CloseHandle(proto->hFileNetlibUser);
	proto->m_hNetlibUser = NULL;
	proto->hFileNetlibUser = NULL;
}

HANDLE TlenWsConnect(TlenProtocol *proto, char *host, WORD port)
{
	NETLIBOPENCONNECTION nloc = {0};

	nloc.cbSize = sizeof(NETLIBOPENCONNECTION); //NETLIBOPENCONNECTION_V1_SIZE;
	nloc.szHost = host;
	nloc.wPort = port;
	nloc.flags = 0;
	nloc.timeout = 6;
	return (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) proto->m_hNetlibUser, (LPARAM) &nloc);
}


int TlenWsSend(TlenProtocol *proto, HANDLE s, char *data, int datalen)
{
	int len;
	if ((len=Netlib_Send(s, data, datalen, /*MSG_NODUMP|*/MSG_DUMPASTEXT)) == SOCKET_ERROR || len != datalen) {
	proto->debugLogA("Netlib_Send() failed, error=%d", WSAGetLastError());
		return FALSE;
	}
	return TRUE;
}

int TlenWsRecv(TlenProtocol *proto, HANDLE s, char *data, long datalen)
{
	int ret;
	ret = Netlib_Recv(s, data, datalen, /*MSG_NODUMP|*/MSG_DUMPASTEXT);
	if (ret == SOCKET_ERROR) {
		proto->debugLogA("Netlib_Recv() failed, error=%d", WSAGetLastError());
		return 0;
	}
	if (ret == 0) {
		proto->debugLogA("Connection closed gracefully");
		return 0;
	}
	return ret;
}


int TlenWsSendAES(TlenProtocol *proto, char *data, int datalen, aes_context *aes_ctx, unsigned char *aes_iv)
{
	int len, sendlen;
	unsigned char aes_input[16];
	unsigned char aes_output[256];
	if (proto->threadData == NULL) {
		return FALSE;
	}
	while (datalen > 0) {
		len = 0;
		while (datalen > 0 && len < 256) {
			int pad = datalen < 16 ? 16 - datalen : 0;
			memcpy(aes_input, data, datalen < 16 ? datalen : 16);
			memset(aes_input + 16 - pad, ' ', pad);
			aes_crypt_cbc(aes_ctx, AES_ENCRYPT, 16, aes_iv, aes_input, aes_output + len);
			datalen -= 16;
			data += 16;
			len += 16;
		}
		if (len > 0) {
			proto->debugLogA("Sending %d bytes", len);
			if ((sendlen=Netlib_Send(proto->threadData->s, (char *)aes_output, len, MSG_NODUMP)) == SOCKET_ERROR || len != sendlen) {
				proto->debugLogA("Netlib_Send() failed, error=%d", WSAGetLastError());
				return FALSE;
			}
		}
	}
	return TRUE;
}

int TlenWsRecvAES(TlenProtocol *proto, char *data, long datalen, aes_context *aes_ctx, unsigned char *aes_iv)
{
	int ret, len = 0, maxlen = datalen;
	unsigned char aes_input[16];
	unsigned char *aes_output = (unsigned char *)data;
	if (proto->threadData == NULL) {
		return 0;
	}
	for (maxlen = maxlen & ~0xF; maxlen != 0; maxlen = maxlen & 0xF) {
		ret = Netlib_Recv(proto->threadData->s, data, maxlen, MSG_NODUMP);
		if (ret == SOCKET_ERROR) {
			proto->debugLogA("Netlib_Recv() failed, error=%d", WSAGetLastError());
			return 0;
		}
		if (ret == 0) {
			proto->debugLogA("Connection closed gracefully");
			return 0;
		}
		data += ret;
		len += ret;
		maxlen -= ret;
	}

	ret = len;
	while (len > 15) {
		memcpy(aes_input, aes_output, 16);
		aes_crypt_cbc(aes_ctx, AES_DECRYPT, 16, aes_iv, aes_input, aes_output);
		aes_output += 16;
		len -= 16;
	}
	return ret;
}