/*
Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.

Copyright (c) 2012-2017 Miranda NG Team
Copyright (c) 2006-2012 Boris Krasnovskiy.
Copyright (c) 2003-2005 George Hazan.
Copyright (c) 2002-2003 Richard Hughes (original version).

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 <http://www.gnu.org/licenses/>.
*/

#include "stdafx.h"
#include "msn_proto.h"

//=======================================================================================

int ThreadData::send(const char data[], size_t datalen)
{
	resetTimeout();

	if (proto->usingGateway && !(mType == SERVER_FILETRANS || mType == SERVER_P2P_DIRECT)) {
		mGatewayTimeout = 2;
		Netlib_SetPollingTimeout(s, mGatewayTimeout);
	}

	int rlen = Netlib_Send(s, data, (int)datalen);
	if (rlen == SOCKET_ERROR) {
		// should really also check if sendlen is the same as datalen
		proto->debugLogA("Send failed: %d", WSAGetLastError());
		return FALSE;
	}

	return TRUE;
}

void ThreadData::resetTimeout(bool term)
{
	int timeout = term ? 10 : mIsMainThread ? 65 : 120;
	mWaitPeriod = clock() + timeout * CLOCKS_PER_SEC;
}

bool ThreadData::isTimeout(void)
{
	bool res = false;

	if (mWaitPeriod >= clock()) return false;

	if (mIsMainThread) {
		res = !proto->usingGateway;
	}
	else if (mJoinedContactsWLID.getCount() <= 1 || mChatID[0] == 0) {
#ifdef OBSOLETE
		MCONTACT hContact = getContactHandle();
#endif
		if (mJoinedContactsWLID.getCount() == 0 || termPending)
			res = true;
#ifdef OBSOLETE
		else if (proto->p2p_getThreadSession(hContact, mType) != NULL)
			res = false;
		else if (mType == SERVER_SWITCHBOARD) {
			res = MSN_MsgWndExist(hContact);
			if (res) {
				WORD status = proto->getWord(hContact, "Status", ID_STATUS_OFFLINE);
				if ((status == ID_STATUS_OFFLINE || status == ID_STATUS_INVISIBLE || proto->m_iStatus == ID_STATUS_INVISIBLE))
					res = false;
			}
		}
#endif
		else
			res = true;
	}

	if (res) {
		bool sbsess = mType == SERVER_SWITCHBOARD;

		proto->debugLogA("Dropping the idle %s due to inactivity", sbsess ? "switchboard" : "p2p");
		if (!sbsess || termPending) return true;

#ifdef OBSOLETE
		if (proto->getByte("EnableSessionPopup", 0)) {
			MCONTACT hContact = NULL;
			if (mJoinedContactsWLID.getCount())
				hContact = proto->MSN_HContactFromEmail(mJoinedContactsWLID[0]);
			else if (mInitialContactWLID)
				hContact = proto->MSN_HContactFromEmail(mInitialContactWLID);

			if (hContact)
				proto->MSN_ShowPopup(hContact, TranslateT("Chat session dropped due to inactivity"), 0);
		}

		sendTerminate();
		resetTimeout(true);
#endif
	}
	else
		resetTimeout();

	return false;
}

int ThreadData::recv(char* data, size_t datalen)
{
	if (!proto->usingGateway) {
		resetTimeout();

		NETLIBSELECT nls = {};
		nls.dwTimeout = 1000;
		nls.hReadConns[0] = s;

		for (;;) {
			int ret = Netlib_Select(&nls);
			if (ret < 0) {
				proto->debugLogA("Connection abortively closed, error %d", WSAGetLastError());
				return ret;
			}
			else if (ret == 0) {
				if (isTimeout()) return 0;
			}
			else
				break;
		}
	}

LBL_RecvAgain:
	int ret = Netlib_Recv(s, data, (int)datalen);
	if (ret == 0) {
		proto->debugLogA("Connection closed gracefully");
		return 0;
	}

	if (ret < 0) {
		proto->debugLogA("Connection abortively closed, error %d", WSAGetLastError());
		return ret;
	}

	if (proto->usingGateway) {
		if (ret == 1 && *data == 0) {
			if (sessionClosed || isTimeout()) return 0;
			if ((mGatewayTimeout += 2) > 20) mGatewayTimeout = 20;

			Netlib_SetPollingTimeout(s, mGatewayTimeout);
			goto LBL_RecvAgain;
		}
		else {
			resetTimeout();
			mGatewayTimeout = 1;
			Netlib_SetPollingTimeout(s, mGatewayTimeout);
		}
	}

	return ret;
}