//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//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., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "DebugHelpers.h"
#include "emule.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "opcodes.h"
#include "UpDownClient.h"
#include "ClientList.h"
#include "OtherFunctions.h"
#include "DownloadQueue.h"
#include "Statistics.h"
#include "IPFilter.h"
#include "SharedFileList.h"
#include "PartFile.h"
#include "SafeFile.h"
#include "Packets.h"
#include "UploadQueue.h"
#include "ServerList.h"
#include "Server.h"
#include "ServerConnect.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "ClientListCtrl.h"
#include "ChatWnd.h"
#include "PeerCacheFinder.h"
#include "Exceptions.h"
#include "Kademlia/Utils/uint128.h"
#include "Kademlia/Kademlia/kademlia.h"
#include "Kademlia/Kademlia/prefs.h"
#include "ClientUDPSocket.h"
#include "SHAHashSet.h"
#include "Log.h"
#include "Neo/Functions.h"// NEO: MOD <-- Xanatos --
#include "Neo/NeoOpCodes.h"// NEO: NXI - [NeoExtraInfo] <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
#include "Neo/SourceList.h"
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
#include "Neo/BandwidthControl/DownloadBandwidthThrottler.h"
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
#include "Neo/BandwidthControl/UploadBandwidthThrottler.h"
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
#include "Neo/BandwidthControl/BandwidthControl.h"
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
#include "Neo/Lancast.h"
#endif //LANCAST // NEO: NLC END <-- Xanatos --
#include "Neo/ClientFileStatus.h"// NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
#include "Neo/WebCache/WebCacheSocket.h"
#include "Neo/WebCache/WebCachedBlock.h"
#include "Neo/WebCache/WebCacheProxyClient.h"
#include "Neo/WebCache/WebCachedBlockList.h"
#include "Neo/WebCache/WebCacheOHCBManager.h"
#endif // NEO: WC END <-- Xanatos --
#include "FirewallOpener.h" // NEO: IFWS - [ICSFirewall] <-- Xanatos --
#include "Neo/UPnP.h" // NEO: UPNP - [UPnPNat] <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
#include "Neo/NatSocket.h"
#include "Neo/AbstractSocket.h"
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
#pragma warning(disable:4516) // access-declarations are deprecated; member using-declarations provide a better alternative
#pragma warning(disable:4244) // conversion from 'type1' to 'type2', possible loss of data
#pragma warning(disable:4100) // unreferenced formal parameter
#include <crypto51/osrng.h>
#pragma warning(default:4100) // unreferenced formal parameter
#pragma warning(default:4244) // conversion from 'type1' to 'type2', possible loss of data
#pragma warning(default:4516) // access-declarations are deprecated; member using-declarations provide a better alternative

#include "Neo/SocketEncryption.h"
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


// CClientReqSocket

IMPLEMENT_DYNCREATE(CClientReqSocket, CEMSocket)

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
CClientReqSocket::CClientReqSocket(CUpDownClient* in_client, bool bNatSocket)
: CEMSocket(bNatSocket)
#else
CClientReqSocket::CClientReqSocket(CUpDownClient* in_client)
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
{
	SetClient(in_client);
	theApp.listensocket->AddSocket(this);
	ResetTimeOutTimer();
	deletethis = false;
	deltimer = 0;
	m_bPortTestCon=false;
	m_nOnConnect=SS_Other;
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	isLanSocket = false;
#endif //LANCAST // NEO: NLC END <-- Xanatos --
}

// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
void CClientReqSocket::SetOnLan() 
{ 
	bool bUpdate = (isLanSocket == false);
	isLanSocket = true; 
	if(bUpdate){
		theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this);
		theApp.downloadBandwidthThrottler->RemoveFromAllQueues(this);

		if(!thePrefs.IsDirectLanUpload())
			theApp.uploadBandwidthThrottler->QueueForLanPacket(this);

		if(!thePrefs.IsDirectLanDownload()){
			theApp.downloadBandwidthThrottler->QueueForLanPacket(this);
			theApp.downloadqueue->AddToProcessQueue(this);
		}
	}
}
#endif //LANCAST // NEO: NLC END
// NEO: NBC END <-- Xanatos --

void CClientReqSocket::SetConState( SocketState val )
{
	//If no change, do nothing..
	if( (UINT)val == m_nOnConnect )
		return;
	//Decrease count of old state..
	switch( m_nOnConnect )
	{
		case SS_Half:
			theApp.listensocket->m_nHalfOpen--;
			break;
		case SS_Complete:
			theApp.listensocket->m_nComp--;
	}
	//Set state to new state..
	m_nOnConnect = val;
	//Increase count of new state..
	switch( m_nOnConnect )
	{
		case SS_Half:
			theApp.listensocket->m_nHalfOpen++;
			break;
		case SS_Complete:
			theApp.listensocket->m_nComp++;
	}
}

void CClientReqSocket::WaitForOnConnect()
{
	SetConState(SS_Half);
}
	
CClientReqSocket::~CClientReqSocket()
{
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	theApp.uploadBandwidthThrottler->RemoveFromStandardList(this);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	theApp.downloadBandwidthThrottler->RemoveFromStandardList(this);
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(isLanSocket){
		theApp.uploadBandwidthThrottler->RemoveFromLanPacketQueue(this);
		theApp.downloadBandwidthThrottler->RemoveFromLanPacketQueue(this);
		theApp.downloadqueue->RemoveFromProcessQueue(this);
	}
#endif //LANCAST // NEO: NLC END  <-- Xanatos --
	//This will update our statistics.
	SetConState(SS_Other);
	// NEO: FIX - [MaellaCodeFix] -- Xanatos -->
	if(client){
		if(client->socket == this)
			client->socket = 0;
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
		else if(client->oldsocket == this)
			client->oldsocket = 0;
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	}
	client = 0;
	// NEO: FIX END <-- Xanatos --
	theApp.listensocket->RemoveSocket(this);

	DEBUG_ONLY (theApp.clientlist->Debug_SocketDeleted(this));
}

void CClientReqSocket::SetClient(CUpDownClient* pClient)
{
	client = pClient;
	if (client)
		client->socket = this;
}

void CClientReqSocket::ResetTimeOutTimer(){
	timeout_timer = ::GetTickCount();
}

UINT CClientReqSocket::GetTimeOut()
{
	// PC-TODO
	// the PC socket may even already be disconnected and deleted and we still need to keep the
	// ed2k socket open because remote client may still be downloading from cache.
	if (client && client->IsUploadingToPeerCache() && (client->m_pPCUpSocket == NULL || !client->m_pPCUpSocket->IsConnected()))
	{
		// we are uploading (or at least allow uploading) but currently no socket
		return max(CEMSocket::GetTimeOut(), GetPeerCacheSocketUploadTimeout());
	}
	else if (client && client->m_pPCUpSocket && client->m_pPCUpSocket->IsConnected())
	{
		// we have an uploading PC socket, but that socket is not used (nor can it be closed)
		return max(CEMSocket::GetTimeOut(), client->m_pPCUpSocket->GetTimeOut());
	}
	else if (client && client->m_pPCDownSocket && client->m_pPCDownSocket->IsConnected())
	{
		// we have a downloading PC socket
		return max(CEMSocket::GetTimeOut(), client->m_pPCDownSocket->GetTimeOut());
	}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	// WC-TODO
	// the WC socket may even already be disconnected and deleted and we still need to keep the
	// ed2k socket open because remote client may still be downloading from cache.
	else if (client && client->IsUploadingToWebCache() && (client->m_pWCUpSocket == NULL || !client->m_pWCUpSocket->IsConnected()))
	{
		// we are uploading (or at least allow uploading) but currently no socket
		return max(CEMSocket::GetTimeOut(), GetWebCacheSocketUploadTimeout());
	}
	else if (client && client->m_pWCUpSocket && client->m_pWCUpSocket->IsConnected())
	{
		// we have an uploading WC socket, but that socket is not used (nor can it be closed)
		return max(CEMSocket::GetTimeOut(), client->m_pWCUpSocket->GetTimeOut());
	}
	else if (client && client->m_pWCDownSocket && client->m_pWCDownSocket->IsConnected())
	{
		// we have a downloading WC socket
		return max(CEMSocket::GetTimeOut(), client->m_pWCDownSocket->GetTimeOut());
	}
#endif // NEO: WC END <-- Xanatos --
	else
		return CEMSocket::GetTimeOut();
}

bool CClientReqSocket::CheckTimeOut()
{
	if(m_nOnConnect == SS_Half)
	{
		//This socket is still in a half connection state.. Because of SP2, we don't know
		//if this socket is actually failing, or if this socket is just queued in SP2's new
		//protection queue. Therefore we give the socket a chance to either finally report
		//the connection error, or finally make it through SP2's new queued socket system..
		if (::GetTickCount() - timeout_timer > CEMSocket::GetTimeOut()*4){
			timeout_timer = ::GetTickCount();
			CString str;
			str.Format(_T("Timeout: State:%u"), m_nOnConnect);
			Disconnect(str);
			return true;
		}
		return false;
	}
	UINT uTimeout = GetTimeOut();

	if(client)
	{
		if (client->GetKadState() == KS_CONNECTED_BUDDY)
		{
			//We originally ignored the timeout here for buddies.
			//This was a stupid idea on my part. There is now a ping/pong system
			//for buddies. This ping/pong system now prevents timeouts.
			//This release will allow lowID clients with KadVersion 0 to remain connected.
			//But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
			//JOHNTODO: Don't forget to remove backward support in a future release.
			if( client->GetKadVersion() == 0 )
				return false;
			uTimeout += MIN2MS(15);
		}
		if (client->GetChatState()!=MS_NONE)
		{
			//We extend the timeout time here to avoid people chatting from disconnecting to fast.
			uTimeout += CONNECTION_TIMEOUT;
		}
		// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
		if (thePrefs.UseLowID2HighIDAutoCallback() 
		 && (client->HasLowID() || theApp.serverconnect->IsLowID())){
			uTimeout += CONNECTION_TIMEOUT_L;
		}
		// NEO: L2H END <-- Xanatos --
	}
	if (::GetTickCount() - timeout_timer > uTimeout){
		timeout_timer = ::GetTickCount();
		CString str;
		str.Format(_T("Timeout: State:%u"), m_nOnConnect);
		Disconnect(str);
		return true;
	}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	//Xman there are some clients which are uploading to us.. and also get an uploadslot from us..
	//but they don't send a blockrequest. the socket won't timeout and we have a 0-uploadsocket
	if(client && client->GetUploadState()==US_UPLOADING && m_IsReady==false && client->HasCacheState()==false && client->GetUpStartTimeDelay()>=MIN2MS(1))
	{
		//timeout_timer = ::GetTickCount();
		theApp.uploadqueue->RemoveFromUploadQueue(client, _T("0-Uploadsocket"));
	}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	return false;
}

void CClientReqSocket::OnClose(int nErrorCode){
	ASSERT (theApp.listensocket->IsValidSocket(this));
	CEMSocket::OnClose(nErrorCode);

	LPCTSTR pszReason;
	CString* pstrReason = NULL;
	if (nErrorCode == 0)
		pszReason = _T("Close");
	else if (thePrefs.GetVerbose()){
		pstrReason = new CString;
		*pstrReason = GetErrorMessage(nErrorCode, 1);
		pszReason = *pstrReason;
	}
	else
		pszReason = NULL;
	Disconnect(pszReason);
	delete pstrReason;
}

void CClientReqSocket::Disconnect(LPCTSTR pszReason){
	AsyncSelect(0);
	byConnected = ES_DISCONNECTED;
	if (!client)
		Safe_Delete();
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
	else if(client->socket != this){ // is this a droped socket
		ASSERT(client->oldsocket == this);
		client->oldsocket = NULL;
		client = NULL;
		Safe_Delete();
	}
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	else if(client->Disconnected(pszReason, true)){
		CUpDownClient* temp = client;
		client->socket = NULL;
		client = NULL;
		delete temp;
		Safe_Delete();
	}
	else{
		client = NULL;
		Safe_Delete();
	}
};

void CClientReqSocket::Delete_Timed(){
// it seems that MFC Sockets call socketfunctions after they are deleted, even if the socket is closed
// and select(0) is set. So we need to wait some time to make sure this doesn't happens
	if (::GetTickCount() - deltimer > 10000)
		delete this;
}

void CClientReqSocket::Safe_Delete()
{
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
	SetPriorityReceive(false);
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	SetPrioritySend(false);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	ASSERT (theApp.listensocket->IsValidSocket(this));
	AsyncSelect(0);
	deltimer = ::GetTickCount();
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	if(m_Socket->IsNatSocket() ? ((CNATSocket*)m_Socket)->IsShutDown() != true : ((CTCPSocket*)m_Socket)->m_SocketData.hSocket != INVALID_SOCKET)
		m_Socket->ShutDown(SD_BOTH);
#else
	if (m_SocketData.hSocket != INVALID_SOCKET) // deadlake PROXYSUPPORT - changed to AsyncSocketEx
		ShutDown(SD_BOTH);
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
	if (client)
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
		if(client->socket == this)
			client->socket = 0;
		else if(client->oldsocket == this)
			client->oldsocket = 0;
#else
		client->socket = 0;
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	client = 0;
	byConnected = ES_DISCONNECTED;
	deletethis = true;
}

bool CClientReqSocket::ProcessPacket(const BYTE* packet, uint32 size, UINT opcode)
{
	try
	{
		try
		{
			if (!client && opcode != OP_HELLO)
			{
				theStats.AddDownDataOverheadOther(size);
				throw GetResString(IDS_ERR_NOHELLO);
			}
			else if (client && opcode != OP_HELLO && opcode != OP_HELLOANSWER)
				client->CheckHandshakeFinished();
			switch(opcode)
			{
				case OP_HELLOANSWER:
				{
					theStats.AddDownDataOverheadOther(size);
					client->ProcessHelloAnswer(packet,size);
					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_HelloAnswer", client);
						Debug(_T("  %s\n"), client->DbgGetHelloInfo());
					}

					// NEO: NMPi - [NeoModProtInfo] -- Xanatos -->
					if(client->GetNeoModProtVersion())
						client->SendModInfoPacket();
					else // we will start the SUI when we recieve the mod info packet
					// NEO: NMPi END <-- Xanatos --

					// start secure identification, if
					//  - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
					//	- we have received eMule-OP_HELLOANSWER (new eMule)
					if (client->GetInfoPacketsReceived() == IP_BOTH)
						client->InfoPacketsReceived();

					// NEO: FIX - [BetterClientAttaching] -- Xanatos -->
					// now we check if we know this client already. if yes this socket will
					// be attached to the known client, the new client will be deleted
					// and the var. "client" will point to the known client.
					// if not we keep our new-constructed client ;)
					//if(thePrefs.EnableSourceKeeper()) // even when NSK is disabled this function ist very usefull
					if(
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
					 !(client->IsLanClient() && thePrefs.UseLanMultiTransfer()) &&
#endif //LANCAST // NEO: NLC END <-- Xanatos --
					 theApp.clientlist->AttachToAlreadyKnown(&client,this,ATTACH_ANSWER))
					{
						// update the old client informations
						client->ProcessHelloAnswer(packet,size);
					}
					// NEO: FIX END <-- Xanatos --

					if (client) 
					{
						// NEO: NMPi - [NeoModProtInfo] -- Xanatos -->
						if(client->GetNeoModProtVersion() == 0) // we will call ConnectionEstablished when we recieve the Mod Info
						// NEO: NMPi END <-- Xanatos --
						{
							client->ConnectionEstablished();
							theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(client);
						}
					}
					break;
				}
				case OP_HELLO:
				{
					theStats.AddDownDataOverheadOther(size);

					// NEO: FIX - [MaellaCodeFix] -- Xanatos -->
					if(client && client->GetUserName().IsEmpty() == false)
					{
						CString oldHash;
						CString newHash;
						if(size > 17 && md4cmp(client->GetUploadFileID(), (const uchar*)&packet[1]) != 0)
							AddDebugLogLine(true,  _T("User %s (client=%s) try to send multiple OP_HELLO, old hash=%s, new has=%s"), client->GetUserName(), client->GetClientSoftVer(), EncodeBase16(client->GetUserHash(), 16), EncodeBase16((const uchar*)&packet[1], 16));
						else 
							AddDebugLogLine(true, _T("User %s (client=%s) try to send multiple OP_HELLO"), client->GetUserName(), client->GetClientSoftVer());
						throw CString(_T("Invalid request received"));
					}
					// NEO: FIX END <-- Xanatos --

					bool bNewClient = !client;
					if (bNewClient)
					{
						// create new client to save standart informations
						client = new CUpDownClient(this);
					}

					bool bIsMuleHello = false;
					try
					{
						bIsMuleHello = client->ProcessHelloPacket(packet,size);
					}
					catch(...)
					{
						if (bNewClient)
						{
							// Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
							delete client;
							client = NULL;
						}
						throw;
					}

					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_Hello", client);
						Debug(_T("  %s\n"), client->DbgGetHelloInfo());
					}

					// now we check if we know this client already. if yes this socket will
					// be attached to the known client, the new client will be deleted
					// and the var. "client" will point to the known client.
					// if not we keep our new-constructed client ;)

					if (
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
					 !(client->IsLanClient() && thePrefs.UseLanMultiTransfer()) &&
#endif //LANCAST // NEO: NLC END <-- Xanatos --
					theApp.clientlist->AttachToAlreadyKnown(&client,this,ATTACH_HALLO)) // NEO: FIX - [BetterClientAttaching] <-- Xanatos --
					{
						// update the old client informations
						bIsMuleHello = client->ProcessHelloPacket(packet,size);

						// lowid side
						client->DisableL2HAC(); // NEO: L2H - [LowID2HighIDAutoCallback] <-- Xanatos --
					}
					else 
					{
						theApp.clientlist->AddClient(client, bNewClient); // NEO: MOD - [CodeImprovement] <-- Xanatos -- //Xman: don't search new generated clients in lists
						client->SetCommentDirty();
					}

					theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(client);

					// send a response packet with standart informations
					if (client->GetHashType() == SO_EMULE && !bIsMuleHello)
						client->SendMuleInfoPacket(false);

					client->SendHelloAnswer();

					if (client)
					{
						// NEO: NMPi - [NeoModProtInfo] -- Xanatos -->
						if(client->GetNeoModProtVersion())
							client->SendModInfoPacket();
						else // we will call ConnectionEstablished when we recieve the Mod Info
						// NEO: NMPi END <-- Xanatos --
							client->ConnectionEstablished();
					}

					// TODO: How does ConnectionEstablished() delete this client object????
					ASSERT( client );
					if(client)
					{
						// NEO: NMPi - [NeoModProtInfo] -- Xanatos -->
						if(client->GetNeoModProtVersion() == 0) // we will start the SUI when we recieve the mod info packet
						// NEO: NMPi END <-- Xanatos --

						// start secure identification, if
						//	- we have received eMule-OP_HELLO (new eMule)
						if (client->GetInfoPacketsReceived() == IP_BOTH)
							client->InfoPacketsReceived();

						if( client->GetKadPort() )
							Kademlia::CKademlia::Bootstrap(ntohl(client->GetIP()), client->GetKadPort());
					}
					break;
				}
				case OP_REQUESTFILENAME:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_FileRequest", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					if (size >= 16)
					{
						if (!client->GetWaitStartTime())
							client->SetWaitStartTime();

						CSafeMemFile data_in(packet, size);
						uchar reqfilehash[16];
						data_in.ReadHash16(reqfilehash);

						CKnownFile* reqfile;
						if ( (reqfile = theApp.sharedfiles->GetFileByID(reqfilehash)) == NULL ){
							if ( !((reqfile = theApp.downloadqueue->GetFileByID(reqfilehash)) != NULL
						    && reqfile->GetFileSize() > (uint64)PARTSIZE) )
							{
								client->CheckFailedFileIdReqs(reqfilehash);
								break;
							}
						}

						if (reqfile->IsLargeFile() && !client->SupportsLargeFiles()){
							DebugLogWarning(_T("Client without 64bit file support requested large file; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
							break;
						}

						// check to see if this is a new file they are asking for
						if (md4cmp(client->GetUploadFileID(), reqfilehash) != 0)
							client->SetCommentDirty();
						client->SetUploadFileID(reqfile);
						client->SetActiveUpReqFlag(2/*OP_REQUESTFILENAME*/); // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --

						// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
						CClientFileStatus* status = client->GetFileStatus(reqfile, true); 
						if (!client->ProcessExtendedInfo(&data_in, status, reqfile))
						// NEO: SCFS END <-- Xanatos --
						{
							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__FileReqAnsNoFil", client, packet);
							client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
							Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
							md4cpy(replypacket->pBuffer, reqfile->GetFileHash());
							theStats.AddUpDataOverheadFileRequest(replypacket->size);
							SendPacket(replypacket, true);
							DebugLogWarning(_T("PartcountMismatch on requested file, sending FNF; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
							break;
						}

						// if we are downloading this file, this could be a new source
						// no passive adding of files with only one part
						if (reqfile->IsPartFile() && reqfile->GetFileSize() > (uint64)PARTSIZE)
						{
							if ((UINT)((CPartFile*)reqfile)->PartPrefs.GetHardLimit() > ((CPartFile*)reqfile)->GetSourceCount()) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
								theApp.downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, client, true);
						}
						// send filename etc
						CSafeMemFile data_out(128);
						data_out.WriteHash16(reqfile->GetFileHash());
						data_out.WriteString(reqfile->GetFileName(true), client->GetUnicodeSupport()); // NEO: PP - [PasswordProtection] <-- Xanatos --
						Packet* packet = new Packet(&data_out);
						packet->opcode = OP_REQFILENAMEANSWER;
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__FileReqAnswer", client, reqfile->GetFileHash());
						theStats.AddUpDataOverheadFileRequest(packet->size);
						SendPacket(packet, true);
						
						client->SendCommentInfo(reqfile);
						break;
					}
					throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
					break;
				}
				case OP_SETREQFILEID:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_SetReqFileID", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					if (size == 16)
					{
						if (!client->GetWaitStartTime())
							client->SetWaitStartTime();

						CKnownFile* reqfile;
						if ( (reqfile = theApp.sharedfiles->GetFileByID(packet)) == NULL ){
							if ( !((reqfile = theApp.downloadqueue->GetFileByID(packet)) != NULL
							 && reqfile->GetFileSize() > (uint64)PARTSIZE) 
							 || (reqfile->IsUnshared(md4cmp(client->GetUploadFileID(), packet) == 0  && client->GetUploadState() == US_ONUPLOADQUEUE )) // NEO: USC - [UnShareCommand] <-- Xanatos --
							){
								// send file request no such file packet (0x48)
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugSend("OP__FileReqAnsNoFil", client, packet);
								client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
								Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
								md4cpy(replypacket->pBuffer, packet);
								theStats.AddUpDataOverheadFileRequest(replypacket->size);
								SendPacket(replypacket, true);
								if(!reqfile) // NEO: USC - [UnShareCommand] <-- Xanatos --
									client->CheckFailedFileIdReqs(packet);
								break;
							}
						}
						if (reqfile->IsLargeFile() && !client->SupportsLargeFiles()){
							if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugSend("OP__FileReqAnsNoFil", client, packet);
							client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
							Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
							md4cpy(replypacket->pBuffer, packet);
							theStats.AddUpDataOverheadFileRequest(replypacket->size);
							SendPacket(replypacket, true);
							DebugLogWarning(_T("Client without 64bit file support requested large file; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
							break;
						}

						// check to see if this is a new file they are asking for
						if (md4cmp(client->GetUploadFileID(), packet) != 0)
							client->SetCommentDirty();

						client->SetUploadFileID(reqfile);
						client->SetActiveUpReqFlag(3/*OP_SETREQFILEID*/); // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --

						CClientFileStatus* status = client->GetFileStatus(reqfile); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --

						// send filestatus
						CSafeMemFile data(16+16);
						data.WriteHash16(reqfile->GetFileHash());
						// NEO: IPS - [InteligentPartSharing] -- Xanatos -->
						if (reqfile->IsPartFile())
							((CPartFile*)reqfile)->WritePartStatus(&data, status);
						else if(!reqfile->WritePartSelection(&data, status)) 
							data.WriteUInt16(0);
						// NEO: IPS END <-- Xanatos --
						Packet* packet = new Packet(&data);
						packet->opcode = OP_FILESTATUS;
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__FileStatus", client, reqfile->GetFileHash());
						theStats.AddUpDataOverheadFileRequest(packet->size);
						SendPacket(packet, true);
					
						// NEO: SCT - [SubChunkTransfer] -- Xanatos -->
						if (thePrefs.UseSubChunkTransfer() && client->GetSubChunksVer() 
						 && reqfile->IsPartFile() && client->GetUploadState() == US_NONEEDEDPARTS)
						{
							CSafeMemFile data(16+16);
							data.WriteHash16(reqfile->GetFileHash());
							((CPartFile*)reqfile)->WriteSubChunkMaps(&data, status);
							Packet* packet = new Packet(&data, client->GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
							packet->opcode = OP_SUBCHUNKMAPS;
							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__FileSubChunkMaps", client, reqfile->GetFileHash());
							theStats.AddUpDataOverheadFileRequest(packet->size);
							SendPacket(packet,true);
						}
						// NEO: SCT END<-- Xanatos --

						client->SendExtendedFileStatus(reqfile,false); // NEO: XCFS - [ExtendedClientFileStatus] <-- Xanatos --
						
						break;
					}
					throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
					break;
				}
				case OP_FILEREQANSNOFIL:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_FileReqAnsNoFil", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);
					if (size == 16)
					{
						CPartFile* reqfile = theApp.downloadqueue->GetFileByID(packet);
						if (!reqfile){
							client->CheckFailedFileIdReqs(packet);
							break;
						}
						else
								reqfile->m_DeadSourceList.AddDeadSource(client);
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
						if(thePrefs.IsFileFakerDetection())
							client->CheckFileNotFound();
#endif //ARGOS // NEO: NA END <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
						if(thePrefs.SaveSourceFileList() && client->Source())
							client->Source()->RemoveFile(reqfile->GetFileHash());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
						// if that client does not have my file maybe has another different
						// we try to swap to another file ignoring no needed parts files
						switch (client->GetDownloadState())
						{
							case DS_CONNECTED:
							case DS_ONQUEUE:
							case DS_NONEEDEDPARTS:
                                client->DontSwapTo(client->GetRequestFile()); // ZZ:DownloadManager
                                if (!client->SwapToAnotherFile(_T("Source says it doesn't have the file. CClientReqSocket::ProcessPacket()"), true, true, true, NULL, false, false)) { // ZZ:DownloadManager
    								theApp.downloadqueue->RemoveSource(client);
                                }
							break;
						}
						break;
					}
					throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
					break;
				}
				case OP_REQFILENAMEANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_FileReqAnswer", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar cfilehash[16];
					data.ReadHash16(cfilehash);
					CPartFile* file = theApp.downloadqueue->GetFileByID(cfilehash);
					if (file == NULL){
						// NEO: ASP - [ActiveSpreading] -- Xanatos -->
						if(theApp.sharedfiles->GetFileByID(cfilehash))
							break;
						// NEO: ASP END <-- Xanatos --
						client->CheckFailedFileIdReqs(cfilehash);
					}
				
					client->ProcessFileInfo(&data, file);
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
					if(thePrefs.SaveSourceFileList() && client->Source() && file)
						client->Source()->AddSeenFile(file->GetFileHash(),file->GetFileSize());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
					break;
				}
				case OP_FILESTATUS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_FileStatus", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar cfilehash[16];
					data.ReadHash16(cfilehash);
					CPartFile* file = theApp.downloadqueue->GetFileByID(cfilehash);
					if (file == NULL){
						if(theApp.sharedfiles->GetFileByID(cfilehash) == NULL) // NEO: ASP - [ActiveSpreading] <-- Xanatos --
							client->CheckFailedFileIdReqs(cfilehash);
						break;
					}
					// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
					CClientFileStatus* status = client->GetFileStatus(file, true);
					client->ProcessFileStatus(false, &data, status, file);
					// NEO: SCFS END <-- Xanatos --
					break;
				}
				case OP_STARTUPLOADREQ:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_StartUpLoadReq", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);
				
					if (!client->CheckHandshakeFinished())
						break;
					if (size == 16)
					{
						CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(packet);
						if (reqfile)
						{
							if (md4cmp(client->GetUploadFileID(), packet) != 0)
								client->SetCommentDirty();
							client->SetUploadFileID(reqfile);
							client->SetActiveUpReqFlag(1/*OP_STARTUPLOADREQ*/); // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
							client->SendCommentInfo(reqfile);
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
							if(client->IsLanClient())
								theApp.uploadqueue->AddLanClient(client);
							else
#endif //LANCAST // NEO: NLC END <-- Xanatos --
								theApp.uploadqueue->AddClientToQueue(client);
							// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
							if(thePrefs.SendExtraInfo() && client && client->GetExtraInfoVersion())
								client->SendExtraInfoPacket(NIX_REQUP | NIX_RANKING | NIX_SUI);
							// NEO: NXI END <-- Xanatos --
						}
						else
							client->CheckFailedFileIdReqs(packet);
					}
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					else if(thePrefs.IsArgosBadProtDetection()) // wrong Startuploadrequest (bionic community)
						theApp.argos->DoArgos(client->GetConnectIP(),AR_BADPROT,2);
#endif // ARGOS // NEO: NA END <-- Xanatos --
					break;
				}
				case OP_QUEUERANK:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_QueueRank", client);
					theStats.AddDownDataOverheadFileRequest(size);
					client->ProcessEdonkeyQueueRank(packet, size);
					client->SetRemoteEDT(0, EDT_UNDEFINED); // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
					break;
				}
				case OP_ACCEPTUPLOADREQ:
				{
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
					SetPriorityReceive(true);
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
					SetPrioritySend(true);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_AcceptUploadReq", client, (size >= 16) ? packet : NULL);
						if (size > 0)
							Debug(_T("  ***NOTE: Packet contains %u additional bytes\n"), size);
						Debug(_T("  QR=%d\n"), client->IsRemoteQueueFull() ? (UINT)-1 : (UINT)client->GetRemoteQueueRank());
					}
					theStats.AddDownDataOverheadFileRequest(size);
					client->ProcessAcceptUpload();
					break;
				}
				case OP_REQUESTPARTS:
				{
					// see also OP_REQUESTPARTS_I64
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_RequestParts", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar reqfilehash[16];
					data.ReadHash16(reqfilehash);

					uint32 auStartOffsets[3];
					auStartOffsets[0] = data.ReadUInt32();
					auStartOffsets[1] = data.ReadUInt32();
					auStartOffsets[2] = data.ReadUInt32();

					uint32 auEndOffsets[3];
					auEndOffsets[0] = data.ReadUInt32();
					auEndOffsets[1] = data.ReadUInt32();
					auEndOffsets[2] = data.ReadUInt32();

					if (thePrefs.GetDebugClientTCPLevel() > 0){
						Debug(_T("  Start1=%u  End1=%u  Size=%u\n"), auStartOffsets[0], auEndOffsets[0], auEndOffsets[0] - auStartOffsets[0]);
						Debug(_T("  Start2=%u  End2=%u  Size=%u\n"), auStartOffsets[1], auEndOffsets[1], auEndOffsets[1] - auStartOffsets[1]);
						Debug(_T("  Start3=%u  End3=%u  Size=%u\n"), auStartOffsets[2], auEndOffsets[2], auEndOffsets[2] - auStartOffsets[2]);
					}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (thePrefs.CloseMaellaBackdoor() && !client->IsHotFileSwapAllowed(reqfilehash))
						return false;
#endif // ARGOS // NEO: NA END <-- Xanatos --

					for (int i = 0; i < ARRSIZE(auStartOffsets); i++)
					{
						if (auEndOffsets[i] > auStartOffsets[i])
						{
							Requested_Block_Struct* reqblock = new Requested_Block_Struct;
							reqblock->StartOffset = auStartOffsets[i];
							reqblock->EndOffset = auEndOffsets[i];
							md4cpy(reqblock->FileID, reqfilehash);
							reqblock->transferred = 0;
							reqblock->unverified = false; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --
							reqblock->filedata = NULL; // NEO: RBT - [ReadBlockThread] <-- Xanatos --
							client->AddReqBlock(reqblock);
						}
						else
						{
							if (thePrefs.GetVerbose())
							{
								if (auEndOffsets[i] != 0 || auStartOffsets[i] != 0)
									DebugLogWarning(_T("Client requests invalid %u. file block %u-%u (%d bytes): %s"), i, auStartOffsets[i], auEndOffsets[i], auEndOffsets[i] - auStartOffsets[i], client->DbgGetClientInfo());
							}
						}
					}
					// NEO: RBT - [ReadBlockThread] -- Xanatos -->
					if(client->GetUploadState() == US_UPLOADING)
						client->CreateNextBlockPackage();
					// NEO: RBT END <-- Xanatos --
					break;
				}
				case OP_CANCELTRANSFER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_CancelTransfer", client);
					theStats.AddDownDataOverheadFileRequest(size);
					// NEO: MOD - [CodeImprovement] -- Xanatos -->
					if (theApp.uploadqueue->RemoveFromUploadQueue(client, _T("Remote client canceled transfer.")))
						client->SetUploadFileID(NULL); //Xman Code Improvement
					// NEO: MOD END <-- Xanatos --
					break;
				}
				case OP_END_OF_DOWNLOAD:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_EndOfDownload", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);
					if (size>=16 && !md4cmp(client->GetUploadFileID(),packet)){
						// NEO: MOD - [CodeImprovement] -- Xanatos -->
						if (theApp.uploadqueue->RemoveFromUploadQueue(client, _T("Remote client ended transfer.")))
							client->SetUploadFileID(NULL); //Xman Code Improvement
						// NEO: MOD END <-- Xanatos --
					}
					else
						client->CheckFailedFileIdReqs(packet);
					break;
				}
				case OP_HASHSETREQUEST:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_HashSetReq", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					if (size != 16)
						throw GetResString(IDS_ERR_WRONGHPACKAGESIZE);
					client->SendHashsetPacket(packet);
					break;
				}
				case OP_HASHSETANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_HashSetAnswer", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);
					client->ProcessHashSet(packet,size);
					break;
				}
				case OP_SENDINGPART:
				{
					// see also OP_SENDINGPART_I64
					if (thePrefs.GetDebugClientTCPLevel() > 1)
						DebugRecv("OP_SendingPart", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(24);
					if (client->GetRequestFile() && !client->GetRequestFile()->IsStopped() 
					 && (!client->GetRequestFile()->IsStandBy()) // NEO: SD - [StandByDL] <-- Xanatos --
					 && (client->GetRequestFile()->GetStatus()==PS_READY || client->GetRequestFile()->GetStatus()==PS_EMPTY)
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					 && !client->IsBanned() // Don't accept upload from banned clients, tray may send corrupt data
#endif //ARGOS // NEO: NA END <-- Xanatos --
					)
					{
						client->ProcessBlockPacket(packet, size, false, false);
						if (client->GetRequestFile()->IsStopped() || client->GetRequestFile()->GetStatus()==PS_PAUSED || client->GetRequestFile()->GetStatus()==PS_ERROR)
						{
							client->SendCancelTransfer();
							client->SetDownloadState(client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
						}
					}
					else
					{
						client->SendCancelTransfer();
						client->SetDownloadState((client->GetRequestFile()==NULL || client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
					}
					break;
				}
				case OP_OUTOFPARTREQS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_OutOfPartReqs", client);
					theStats.AddDownDataOverheadFileRequest(size);
					if (client->GetDownloadState() == DS_DOWNLOADING)
					{
						client->SetDownloadState(DS_ONQUEUE, _T("The remote client decided to stop/complete the transfer (got OP_OutOfPartReqs)."));
					}
					break;
				}
				case OP_CHANGE_CLIENT_ID:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_ChangedClientID", client);
					theStats.AddDownDataOverheadOther(size);

					CSafeMemFile data(packet, size);
					uint32 nNewUserID = data.ReadUInt32();
					uint32 nNewServerIP = data.ReadUInt32();
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						Debug(_T("  NewUserID=%u (%08x, %s)  NewServerIP=%u (%08x, %s)\n"), nNewUserID, nNewUserID, ipstr(nNewUserID), nNewServerIP, nNewServerIP, ipstr(nNewServerIP));
					if (IsLowID(nNewUserID))
					{	// client changed server and has a LowID
						CServer* pNewServer = theApp.serverlist->GetServerByIP(nNewServerIP);
						if (pNewServer != NULL)
						{
							client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
							client->SetServerIP(nNewServerIP);
							client->SetServerPort(pNewServer->GetPort());
						}
					}
					else if (nNewUserID == client->GetIP())
					{	// client changed server and has a HighID(IP)
						client->SetUserIDHybrid(ntohl(nNewUserID));
						CServer* pNewServer = theApp.serverlist->GetServerByIP(nNewServerIP);
						if (pNewServer != NULL)
						{
							client->SetServerIP(nNewServerIP);
							client->SetServerPort(pNewServer->GetPort());
						}
					}
					else{
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							Debug(_T("***NOTE: OP_ChangedClientID unknown contents\n"));
					}
					UINT uAddData = (UINT)(data.GetLength() - data.GetPosition());
					if (uAddData > 0){
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							Debug(_T("***NOTE: OP_ChangedClientID contains add. data %s\n"), DbgGetHexDump(packet + data.GetPosition(), uAddData));
					}
					break;
				}
				case OP_CHANGE_SLOT:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_ChangeSlot", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					// sometimes sent by Hybrid
					break;
				}
				case OP_MESSAGE:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_Message", client);
					theStats.AddDownDataOverheadOther(size);
					
					if (size < 2)
						throw CString(_T("invalid message packet"));
					CSafeMemFile data(packet, size);
					UINT length = data.ReadUInt16();
					if (length+2 != size)
						throw CString(_T("invalid message packet"));
					
					//filter me?
					if ( (thePrefs.MsgOnlyFriends() && !client->IsFriend()) || (thePrefs.MsgOnlySecure() && client->GetUserName().IsEmpty()/*==NULL*/ )) // NEO: FIX - [StabilityFix] <-- Xanatos --
					{
						if (!client->GetMessageFiltered()){
							if (thePrefs.GetVerbose())
								AddDebugLogLine(false,_T("Filtered Message from '%s' (IP:%s)"), client->GetUserName(), ipstr(client->GetConnectIP()));
						}
						client->SetMessageFiltered(true);
						break;
					}

					if (length > MAX_CLIENT_MSG_LEN){
						if (thePrefs.GetVerbose())
							AddDebugLogLine(false, _T("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."), client->GetUserName(), ipstr(client->GetConnectIP()), length - MAX_CLIENT_MSG_LEN);
						length = MAX_CLIENT_MSG_LEN;
					}

					//AddLogLine(true, GetResString(IDS_NEWMSG), client->GetUserName(), ipstr(client->GetConnectIP()));

					CString strMessage(data.ReadString(client->GetUnicodeSupport()!=utf8strNone, length));
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						Debug(_T("  %s\n"), strMessage);

					// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
					/* Xanatos:
					* I Should implement this separatly in the way the comments ar implemented,
					* but since this info does not have a real function, its only for fun,
					* so i chose the easyest implementation...
					*/
					if(!thePrefs.SendExtraInfoString().IsEmpty())
						if(strMessage.Compare(EIS_STRING_INFO_REQ)==0){
							theApp.emuledlg->chatwnd->chatselector.StartSession(client, false);
							CString Infos = thePrefs.SendExtraInfoString();
							for(int pos = 0; pos >= 0;){
								CString Info = Infos.Tokenize (_T("\n"),pos).Trim();
								if (Info.IsEmpty())
									continue;
								theApp.emuledlg->chatwnd->chatselector.SendMessage(StrLine(_T("%s %s"),EIS_STRING_INFO_ANS, Info));
							}
							theApp.emuledlg->chatwnd->chatselector.EndSession(client);
							break;
						}
					// NEO: NXI END <-- Xanatos --

					
					theApp.emuledlg->chatwnd->chatselector.ProcessMessage(client, strMessage);

					if(!client->IsSpammer()) // NEO: MOD <-- Xanatos --
						AddLogLine(true, GetResString(IDS_NEWMSG), client->GetUserName(), ipstr(client->GetConnectIP()));

					break;
				}
				case OP_ASKSHAREDFILES:
				{	
					// client wants to know what we have in share, let's see if we allow him to know that
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedFiles", client);
					theStats.AddDownDataOverheadOther(size);


					CPtrList list;
					bool bUseCustomPerm = thePrefs.UseCustomPermissions(); // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
					if (bUseCustomPerm || thePrefs.CanSeeShares()==vsfaEverybody || (thePrefs.CanSeeShares()==vsfaFriends && client->IsFriend())) // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
					{
						CCKey bufKey;
						CKnownFile* cur_file;
						for (POSITION pos = theApp.sharedfiles->m_Files_map.GetStartPosition();pos != 0;)
						{
							theApp.sharedfiles->m_Files_map.GetNextAssoc(pos,bufKey,cur_file);
							// NEO: SSP - [ShowSharePermissions] -- Xanatos -->
							// only show the files that you agree to show (because sometimes people would like to show
							// most of their files but hesitate to show a few ones (for some reasons :))
							int Perm = ((cur_file->GetPermissions() == PERM_DEFAULT) ? thePrefs.CanSeeShares() : cur_file->GetPermissions());
							if (bUseCustomPerm && (
								Perm == PERM_NONE ||
								(Perm == PERM_FRIENDS && !client->IsFriend()) ||
								(Perm == PERM_COMMUNITY && !client->IsCommunity()) // NEO: NC - [NiceCommunity]
								))
								continue;
							// NEO: SSP END <-- Xanatos --
							if (!cur_file->IsLargeFile() || client->SupportsLargeFiles())
								list.AddTail((void*&)cur_file);
						}
						AddLogLine(true, GetResString(IDS_REQ_SHAREDFILES), client->GetUserName(), client->GetUserIDHybrid(), GetResString(IDS_ACCEPTED));
					}
					else
					{
						AddLogLine(true, GetResString(IDS_REQ_SHAREDFILES), client->GetUserName(), client->GetUserIDHybrid(), GetResString(IDS_DENIED));
					}

					// now create the memfile for the packet
					uint32 iTotalCount = list.GetCount();
					CSafeMemFile tempfile(80);
					tempfile.WriteUInt32(iTotalCount);
					while (list.GetCount())
					{
						theApp.sharedfiles->CreateOfferedFilePacket((CKnownFile*)list.GetHead(), &tempfile, NULL, client);
						list.RemoveHead();
					}

					// create a packet and send it
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__AskSharedFilesAnswer", client);
					Packet* replypacket = new Packet(&tempfile);
					replypacket->opcode = OP_ASKSHAREDFILESANSWER;
					theStats.AddUpDataOverheadOther(replypacket->size);
					SendPacket(replypacket, true, true);
					break;
				}
				case OP_ASKSHAREDFILESANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedFilesAnswer", client);
					theStats.AddDownDataOverheadOther(size);
					client->ProcessSharedFileList(packet,size);
					break;
				}
                case OP_ASKSHAREDDIRS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedDirectories", client);
                    theStats.AddDownDataOverheadOther(size);

					bool bUseCustomPerm = thePrefs.UseCustomPermissions(); // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
                    if (bUseCustomPerm || thePrefs.CanSeeShares()==vsfaEverybody || (thePrefs.CanSeeShares()==vsfaFriends && client->IsFriend()))  // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
					{
						AddLogLine(true, GetResString(IDS_SHAREDREQ1), client->GetUserName(), client->GetUserIDHybrid(), GetResString(IDS_ACCEPTED));

						// NEO: SSD - [ShareSubDirectories] -- Xanatos -->
						// This is used to process directories from files and be able to
						// get virtual and physical directories
						CStringList toSend;		// String list, because it's easier and faster
						CCKey bufKey;
						CKnownFile* cur_file;
						for (POSITION pos = theApp.sharedfiles->m_Files_map.GetStartPosition();pos != 0;)
							{
							theApp.sharedfiles->m_Files_map.GetNextAssoc(pos,bufKey,cur_file);							
							// NEO: SSP - [ShowSharePermissions] -- Xanatos -->
							// due to file browse permissions
							int Perm = ((cur_file->GetPermissions() == PERM_DEFAULT) ? thePrefs.CanSeeShares() : cur_file->GetPermissions());
							if (bUseCustomPerm && (
								Perm == PERM_NONE ||
								(Perm == PERM_FRIENDS && !client->IsFriend()) ||
								(Perm == PERM_COMMUNITY && !client->IsCommunity()) // NEO: NC - [NiceCommunity]
								))
								continue;
							// NEO: SSP END <-- Xanatos --
							CString path = cur_file->GetPath(true); // NEO: VSF - [VirtualSharedFiles] <-- Xanatos --
							
							PathRemoveBackslash(path.GetBuffer());
                            				path.ReleaseBuffer();
							path.MakeLower();
							if (toSend.Find(path) == NULL)
								toSend.AddTail(path);
						}		

                        CSafeMemFile tempfile(80);
						tempfile.WriteUInt32(toSend.GetCount());
						for (POSITION pos = toSend.GetHeadPosition();pos != 0;){
							CString str_send = toSend.GetNext(pos);							                        
							tempfile.WriteString((LPCTSTR)str_send, client->GetUnicodeSupport());
						}	
						// NEO: SSD END <-- Xanatos --

						//TODO: Don't send shared directories which do not contain any files
						// add shared directories
						/*CString strDir;
						CStringArray arFolders;
                        POSITION pos = thePrefs.shareddir_list.GetHeadPosition();
                        while (pos)
						{
                            strDir = thePrefs.shareddir_list.GetNext(pos);
                            PathRemoveBackslash(strDir.GetBuffer());
                            strDir.ReleaseBuffer();
							bool bFoundFolder = false;
							for (int i = 0; i < arFolders.GetCount(); i++)
							{
								if (strDir.CompareNoCase(arFolders.GetAt(i)) == 0)
								{
									bFoundFolder = true;
									break;
								}
							}
							if (!bFoundFolder)
								arFolders.Add(strDir);
						}

						// add incoming folders
                       	for (int iCat = 0; iCat < thePrefs.GetCatCount(); iCat++)
						{
							strDir = thePrefs.GetCategory(iCat)->incomingpath;
							PathRemoveBackslash(strDir.GetBuffer());
							strDir.ReleaseBuffer();
							bool bFoundFolder = false;
							for (int i = 0; i < arFolders.GetCount(); i++)
							{
								if (strDir.CompareNoCase(arFolders.GetAt(i)) == 0)
								{
									bFoundFolder = true;
									break;
								}
							}
							if (!bFoundFolder)
								arFolders.Add(strDir);
						}

						// add temporary folder
						strDir = OP_INCOMPLETE_SHARED_FILES;
						bool bFoundFolder = false;
						for (int i = 0; i < arFolders.GetCount(); i++)
						{
							if (strDir.CompareNoCase(arFolders.GetAt(i)) == 0)
							{
								bFoundFolder = true;
								break;
							}
						}
						if (!bFoundFolder)
							arFolders.Add(strDir);

						// build packet
                        CSafeMemFile tempfile(80);
                        tempfile.WriteUInt32(arFolders.GetCount());
						for (int i = 0; i < arFolders.GetCount(); i++)
                            tempfile.WriteString(arFolders.GetAt(i), client->GetUnicodeSupport());*/

						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__AskSharedDirsAnswer", client);
						Packet* replypacket = new Packet(&tempfile);
                        replypacket->opcode = OP_ASKSHAREDDIRSANS;
                        theStats.AddUpDataOverheadOther(replypacket->size);
                        SendPacket(replypacket, true, true);
					}
					else
					{
						AddLogLine(true, GetResString(IDS_SHAREDREQ1), client->GetUserName(), client->GetUserIDHybrid(), GetResString(IDS_DENIED));
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__AskSharedDeniedAnswer", client);
                        Packet* replypacket = new Packet(OP_ASKSHAREDDENIEDANS, 0);
						theStats.AddUpDataOverheadOther(replypacket->size);
                        SendPacket(replypacket, true, true);
                    }
                    break;
                }
                case OP_ASKSHAREDFILESDIR:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedFilesInDirectory", client);
                    theStats.AddDownDataOverheadOther(size);

					CSafeMemFile data(packet, size);
                    CString strReqDir = data.ReadString(client->GetUnicodeSupport()!=utf8strNone);
                    PathRemoveBackslash(strReqDir.GetBuffer());
                    strReqDir.ReleaseBuffer();
					bool bUseCustomPerm = thePrefs.UseCustomPermissions(); // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
                    if (bUseCustomPerm || thePrefs.CanSeeShares()==vsfaEverybody || (thePrefs.CanSeeShares()==vsfaFriends && client->IsFriend())) // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
					{
						AddLogLine(true, GetResString(IDS_SHAREDREQ2), client->GetUserName(), client->GetUserIDHybrid(), strReqDir, GetResString(IDS_ACCEPTED));
                        ASSERT( data.GetPosition() == data.GetLength() );
                        CTypedPtrList<CPtrList, CKnownFile*> list;
						// NEO: VSF - [VirtualSharedFiles] -- Xanatos --
						/*if (strReqDir == OP_INCOMPLETE_SHARED_FILES)
						{
							// get all shared files from download queue
							int iQueuedFiles = theApp.downloadqueue->GetFileCount();
							for (int i = 0; i < iQueuedFiles; i++)
							{
								CPartFile* pFile = theApp.downloadqueue->GetFileByIndex(i);
								if (pFile == NULL || pFile->GetStatus(true) != PS_READY || (pFile->IsLargeFile() && !client->SupportsLargeFiles()))
									break;
								list.AddTail(pFile);
							}
						}
						else*/
						// itsonlyme: virtualDirs remove - incoming directory is already given as virtual
						{
							// get all shared files from requested directory
							for (POSITION pos = theApp.sharedfiles->m_Files_map.GetStartPosition();pos != 0;)
							{
								CCKey bufKey;
								CKnownFile* cur_file;
								theApp.sharedfiles->m_Files_map.GetNextAssoc(pos, bufKey, cur_file);
								// NEO: SSP - [ShowSharePermissions] -- Xanatos -->
								// only show the files that you agree to show (because sometimes people would like to show
								// most of their files but hesitate to show a few ones (for some reasons :))
								int Perm = ((cur_file->GetPermissions() == PERM_DEFAULT) ? thePrefs.CanSeeShares() : cur_file->GetPermissions());
								if (bUseCustomPerm && (
									Perm == PERM_NONE ||
									(Perm == PERM_FRIENDS && !client->IsFriend()) ||
									(Perm == PERM_COMMUNITY && !client->IsCommunity()) // NEO: NC - [NiceCommunity]
									))
									continue;
								// NEO: SSP END <-- Xanatos --
								CString strSharedFileDir(cur_file->GetPath(true)); // NEO: VSF - [VirtualSharedFiles] <-- Xanatos --
								PathRemoveBackslash(strSharedFileDir.GetBuffer());
								strSharedFileDir.ReleaseBuffer();
								if (strReqDir.CompareNoCase(strSharedFileDir) == 0 && (!cur_file->IsLargeFile() || client->SupportsLargeFiles()))
									list.AddTail(cur_file);
							}
						}

						// Currently we are sending each shared directory, even if it does not contain any files.
						// Because of this we also have to send an empty shared files list..
						CSafeMemFile tempfile(80);
						tempfile.WriteString(strReqDir, client->GetUnicodeSupport());
						tempfile.WriteUInt32(list.GetCount());
						while (list.GetCount())
						{
							theApp.sharedfiles->CreateOfferedFilePacket(list.GetHead(), &tempfile, NULL, client);
							list.RemoveHead();
						}

						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__AskSharedFilesInDirectoryAnswer", client);
						Packet* replypacket = new Packet(&tempfile);
						replypacket->opcode = OP_ASKSHAREDFILESDIRANS;
						theStats.AddUpDataOverheadOther(replypacket->size);
						SendPacket(replypacket, true, true);
					}
                    else
					{
						AddLogLine(true, GetResString(IDS_SHAREDREQ2), client->GetUserName(), client->GetUserIDHybrid(), strReqDir, GetResString(IDS_DENIED));
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__AskSharedDeniedAnswer", client);
                        Packet* replypacket = new Packet(OP_ASKSHAREDDENIEDANS, 0);
                        theStats.AddUpDataOverheadOther(replypacket->size);
                        SendPacket(replypacket, true, true);
                    }
                    break;
                }
				case OP_ASKSHAREDDIRSANS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedDirectoriesAnswer", client);
                    theStats.AddDownDataOverheadOther(size);
					client->ProcessSharedDirsList(packet,size);	// NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
                    /*if (client->GetFileListRequested() == 1)
					{
						CSafeMemFile data(packet, size);
						UINT uDirs = data.ReadUInt32();
                        for (UINT i = 0; i < uDirs; i++)
						{
                            CString strDir = data.ReadString(client->GetUnicodeSupport()!=utf8strNone);
							// Better send the received and untouched directory string back to that client
							//PathRemoveBackslash(strDir.GetBuffer());
							//strDir.ReleaseBuffer();
							AddLogLine(true, GetResString(IDS_SHAREDANSW), client->GetUserName(), client->GetUserIDHybrid(), strDir);

							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__AskSharedFilesInDirectory", client);
                            CSafeMemFile tempfile(80);
							tempfile.WriteString(strDir, client->GetUnicodeSupport());
                            Packet* replypacket = new Packet(&tempfile);
                            replypacket->opcode = OP_ASKSHAREDFILESDIR;
                            theStats.AddUpDataOverheadOther(replypacket->size);
                            SendPacket(replypacket, true, true);
                        }
                        ASSERT( data.GetPosition() == data.GetLength() );
                        client->SetFileListRequested(uDirs);
                    }
					else
						AddLogLine(true, GetResString(IDS_SHAREDANSW2), client->GetUserName(), client->GetUserIDHybrid());*/
                    break;
                }
                case OP_ASKSHAREDFILESDIRANS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedFilesInDirectoryAnswer", client);
                    theStats.AddDownDataOverheadOther(size);

					CSafeMemFile data(packet, size);
                    CString strDir = data.ReadString(client->GetUnicodeSupport()!=utf8strNone);
					PathRemoveBackslash(strDir.GetBuffer());
					strDir.ReleaseBuffer();
                    if (client->GetFileListRequested() > 0)
					{
						AddLogLine(true, GetResString(IDS_SHAREDINFO1), client->GetUserName(), client->GetUserIDHybrid(), strDir);
						client->ProcessSharedFileList(packet + (UINT)data.GetPosition(), (UINT)(size - data.GetPosition()), strDir);
						if (client->GetFileListRequested() == 0)
							AddLogLine(true, GetResString(IDS_SHAREDINFO2), client->GetUserName(), client->GetUserIDHybrid());
                    }
					else
						AddLogLine(true, GetResString(IDS_SHAREDANSW3), client->GetUserName(), client->GetUserIDHybrid(), strDir);
                    break;
                }
                case OP_ASKSHAREDDENIEDANS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AskSharedDeniedAnswer", client);
                    theStats.AddDownDataOverheadOther(size);

					AddLogLine(true, GetResString(IDS_SHAREDREQDENIED), client->GetUserName(), client->GetUserIDHybrid());
					client->SetDeniesShare(); // NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
					//client->SetFileListRequested(0);
                    break;
                }
#ifdef WEBCACHE // NEO: WC - [WebCache] // NEO: NMP - [NeoModProt] -- Xanatos -->
				case OP_HTTP_CACHED_BLOCK:
					ProcessModPacket(packet, size, opcode, size); // for backwards compatybility
					break;
#endif // NEO: WC END // NEO: NMP END <-- Xanatos --

				default:
					theStats.AddDownDataOverheadOther(size);
					PacketToDebugLogLine(_T("eDonkey"), packet, size, opcode);
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (thePrefs.IsArgosOpcodeDetection()){
						TOpCode* OpCode = new TOpCode;
						OpCode->OpSource = OC_PACKET;
						OpCode->OpCode = (uint8)opcode;
						OpCode->OpValue = 0;
						if(client){
							theApp.argos->AddClientToTest(client,OpCode);
						}else{
							SOCKADDR_IN sockAddr = {0};
							int nSockAddrLen = sizeof(sockAddr);
							GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
							theApp.argos->AddClientToTest(sockAddr.sin_addr.S_un.S_addr,OpCode);
						}
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --
					break;
			}
		}
		catch(CFileException* error)
		{
			error->Delete();
			throw GetResString(IDS_ERR_INVALIDPACKAGE);
		}
		catch(CMemoryException* error)
		{
			error->Delete();
			throw CString(_T("Memory exception"));
		}
	}
	// NEO: MOD - [UnusedCode] -- Xanatos --
	/*catch(CClientException* ex) // nearly same as the 'CString' exception but with optional deleting of the client
	{
		if (thePrefs.GetVerbose() && !ex->m_strMsg.IsEmpty())
			DebugLogWarning(_T("Error: %s - while processing eDonkey packet: opcode=%s  size=%u; %s"), ex->m_strMsg, DbgGetDonkeyClientTCPOpcode(opcode), size, DbgGetClientInfo());
		if (client && ex->m_bDelete)
			client->SetDownloadState(DS_ERROR, _T("Error while processing eDonkey packet (CClientException): ") + ex->m_strMsg);
		Disconnect(ex->m_strMsg);
		ex->Delete();
		return false;
	}*/
	catch(CString error)
	{
		if (thePrefs.GetVerbose() && !error.IsEmpty()){
			if (opcode == OP_REQUESTFILENAME /*low priority for OP_REQUESTFILENAME*/)
				DebugLogWarning(_T("Error: %s - while processing eDonkey packet: opcode=%s  size=%u; %s"), error, DbgGetDonkeyClientTCPOpcode(opcode), size, DbgGetClientInfo());
			else
				DebugLogWarning(_T("Error: %s - while processing eDonkey packet: opcode=%s  size=%u; %s"), error, DbgGetDonkeyClientTCPOpcode(opcode), size, DbgGetClientInfo());
		}
		if (client)
			client->SetDownloadState(DS_ERROR, _T("Error while processing eDonkey packet (CString exception): ") + error);	
		Disconnect(_T("Error when processing packet.") + error);
		return false;
	}
	return true;
}

bool CClientReqSocket::ProcessExtPacket(const BYTE* packet, uint32 size, UINT opcode, UINT uRawSize)
{
	try
	{
		try
		{
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
			if (!client && opcode != OP_PORTTEST && opcode != OP_SWAP_SOCKET)
#else
			if (!client && opcode != OP_PORTTEST)
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
			{
				theStats.AddDownDataOverheadOther(uRawSize);
				throw GetResString(IDS_ERR_UNKNOWNCLIENTACTION);
			}
			if (thePrefs.m_iDbgHeap >= 2 && opcode!=OP_PORTTEST)
				ASSERT_VALID(client);
			switch(opcode)
			{
                case OP_MULTIPACKET:
				case OP_MULTIPACKET_EXT:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0){
						if (opcode == OP_MULTIPACKET_EXT)
							DebugRecv("OP_MultiPacket_Ext", client, (size >= 24) ? packet : NULL);
						else
							DebugRecv("OP_MultiPacket", client, (size >= 16) ? packet : NULL);
					}

					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();

					if( client->GetKadPort() )
						Kademlia::CKademlia::Bootstrap(ntohl(client->GetIP()), client->GetKadPort());

					CSafeMemFile data_in(packet, size);
					uchar reqfilehash[16];
					data_in.ReadHash16(reqfilehash);
					uint64 nSize = 0;
					if (opcode == OP_MULTIPACKET_EXT){
						nSize = data_in.ReadUInt64();
					}
					CKnownFile* reqfile;
					if ( (reqfile = theApp.sharedfiles->GetFileByID(reqfilehash)) == NULL ){
						if ( !((reqfile = theApp.downloadqueue->GetFileByID(reqfilehash)) != NULL
						 && reqfile->GetFileSize() > (uint64)PARTSIZE) 
						 || (reqfile->IsUnshared(md4cmp(client->GetUploadFileID(), reqfilehash) == 0 && client->GetUploadState() == US_ONUPLOADQUEUE )) // NEO: USC - [UnShareCommand] <-- Xanatos --
						){
							// send file request no such file packet (0x48)
							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__FileReqAnsNoFil", client, packet);
							client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
							Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
							md4cpy(replypacket->pBuffer, packet);
							theStats.AddUpDataOverheadFileRequest(replypacket->size);
							SendPacket(replypacket, true);
							if(!reqfile) // NEO: USC - [UnShareCommand] <-- Xanatos --
								client->CheckFailedFileIdReqs(reqfilehash);
							break;
						}
					}
					if (reqfile->IsLargeFile() && !client->SupportsLargeFiles()){
						if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__FileReqAnsNoFil", client, packet);
						client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
						Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
						md4cpy(replypacket->pBuffer, packet);
						theStats.AddUpDataOverheadFileRequest(replypacket->size);
						SendPacket(replypacket, true);
						DebugLogWarning(_T("Client without 64bit file support requested large file; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
						break;
					}
					if (nSize != 0 && nSize != reqfile->GetFileSize()){
						if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__FileReqAnsNoFil", client, packet);
						client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
						Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
						md4cpy(replypacket->pBuffer, packet);
						theStats.AddUpDataOverheadFileRequest(replypacket->size);
						SendPacket(replypacket, true);
						DebugLogWarning(_T("Size Mismatch on requested file, sending FNF; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
						break;
					}

					if (!client->GetWaitStartTime())
						client->SetWaitStartTime();

					// if we are downloading this file, this could be a new source
					// no passive adding of files with only one part
					if (reqfile->IsPartFile() && reqfile->GetFileSize() > (uint64)PARTSIZE)
					{
						if ((UINT)((CPartFile*)reqfile)->PartPrefs.GetHardLimit() > ((CPartFile*)reqfile)->GetSourceCount()) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
							theApp.downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, client, true);
					}

					// check to see if this is a new file they are asking for
					if (md4cmp(client->GetUploadFileID(), reqfilehash) != 0)
						client->SetCommentDirty();

					client->SetUploadFileID(reqfile);
					client->SetActiveUpReqFlag(0); // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus] -- Xanatos --

					uint8 opcode_in;
					CSafeMemFile data_out(128);
					data_out.WriteHash16(reqfile->GetFileHash());
					bool bAnswerFNF = false;
					while (data_in.GetLength()-data_in.GetPosition() && !bAnswerFNF)
					{
						opcode_in = data_in.ReadUInt8();
						switch (opcode_in)
						{
							case OP_REQUESTFILENAME:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPReqFileName", client, packet);

								if (!client->ProcessExtendedInfo(&data_in, status, reqfile)) // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
								{
									if (thePrefs.GetDebugClientTCPLevel() > 0)
										DebugSend("OP__FileReqAnsNoFil", client, packet);
									client->SetActiveUpReqFlag(4/*OP_FILEREQANSNOFIL*/); // NEO: NMPm - [NeoModProtMultiPacket] <-- Xanatos --
									Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
									md4cpy(replypacket->pBuffer, reqfile->GetFileHash());
									theStats.AddUpDataOverheadFileRequest(replypacket->size);
									SendPacket(replypacket, true);
									DebugLogWarning(_T("Partcount Mismatch on requested file, sending FNF; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());
									bAnswerFNF = true;
									break;
								}
								data_out.WriteUInt8(OP_REQFILENAMEANSWER);
								data_out.WriteString(reqfile->GetFileName(true), client->GetUnicodeSupport()); // NEO: PP - [PasswordProtection] <-- Xanatos --
								break;
							}
							case OP_AICHFILEHASHREQ:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPAichFileHashReq", client, packet);

								if (client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
									&& reqfile->GetAICHHashset()->HasValidMasterHash())
								{
									data_out.WriteUInt8(OP_AICHFILEHASHANS);
									reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
								}
								break;
							}
							case OP_SETREQFILEID:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPSetReqFileID", client, packet);

								data_out.WriteUInt8(OP_FILESTATUS);
								// NEO: IPS - [InteligentPartSharing] -- Xanatos -->
								if (reqfile->IsPartFile())
									((CPartFile*)reqfile)->WritePartStatus(&data_out, status);
								else if(!reqfile->WritePartSelection(&data_out, status)) 
									data_out.WriteUInt16(0);
								// NEO: IPS END <-- Xanatos --
								break;
							}
							//We still send the source packet seperately.. 
							//We could send it within this packet.. If agreeded, I will fix it..
							case OP_REQUESTSOURCES:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPReqSources", client, packet);

								if (thePrefs.GetDebugSourceExchange())
									AddDebugLogLine(false, _T("SXRecv: Client source request; %s, File=\"%s\""), client->DbgGetClientInfo(), reqfile->GetFileName());

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
								if(thePrefs.IsArgosXSExploitDetection()){
									if(client->CheckXSAsk())
										break;
								}
#endif // ARGOS // NEO: NA END <-- Xanatos --

								//Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
								if (client->GetSourceExchangeVersion() > 1)
								{
									//data_out.WriteUInt8(OP_ANSWERSOURCES);
									DWORD dwTimePassed = ::GetTickCount() - client->GetLastSrcReqTime() + CONNECTION_LATENCY;
									bool bNeverAskedBefore = client->GetLastSrcReqTime() == 0;
									if (reqfile->KnownPrefs.SendXS() && ( // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
										//if not complete and file is rare
										(    reqfile->IsPartFile()
										  && (bNeverAskedBefore || dwTimePassed > thePrefs.GetXSClientIntervalsMs() /*SOURCECLIENTREASKS*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
										  && ((CPartFile*)reqfile)->GetSourceCount() <= (UINT)thePrefs.GetRareFileLimit() /*RARE_FILE*/
										) ||
										//OR if file is not rare or if file is complete
										(bNeverAskedBefore || dwTimePassed > thePrefs.GetXSClientIntervalsMs() /*SOURCECLIENTREASKS*/ * thePrefs.GetXSDelayValue() /*MINCOMMONPENALTY*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
									   ))
									{
										client->SetLastSrcReqTime();
										Packet* tosend = reqfile->CreateSrcInfoPacket(client);
										if (tosend)
										{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
											client->SetLastSourcesSent();
#endif // ARGOS // NEO: NA END <-- Xanatos --
											if (thePrefs.GetDebugClientTCPLevel() > 0)
												DebugSend("OP__AnswerSources", client, reqfile->GetFileHash());
											theStats.AddUpDataOverheadSourceExchange(tosend->size);
											SendPacket(tosend, true);
										}
									}
									/*else
									{
										if (thePrefs.GetVerbose())
											AddDebugLogLine(false, _T("RCV: Source Request to fast. (This is testing the new timers to see how much older client will not receive this)"));
									}*/
								}
								break;
							}

							// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
							case OP_FILEINCSTATUS: // NEO: ICS - [InteligentChunkSelection]
							case OP_UPFILEINCSTATUS: // X!: for backwards compatybility
							case OP_FILEHIDENSTATUS: // NEO: RPS - [RealPartStatus]
							case OP_FILEBLOCKEDSTATUS: // NEO: RPS - [RealPartStatus]
#ifdef WEBCACHE // NEO: WC - [WebCache]
							case WC_TAG_WEBCACHENAME:
							//case WC_TAG_WEBCACHEID:
							case WC_TAG_MASTERKEY:
								if(opcode_in == WC_TAG_WEBCACHENAME)
									client->SetWebCacheInfoNeeded(true);
#endif // NEO: WC END
								client->ReadModMultiPacket(&data_in,reqfile,status,opcode_in);
								break;
							// NEO: NMPm END <-- Xanatos --
							default:
							{
								CString strError;
								strError.Format(_T("Invalid sub opcode 0x%02x received"), opcode_in);
								throw strError;
							}
						}
					}

					// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
					if(client->GetNeoModProtVersion() == 0){
						//client->ProcessModFileStatus(false, status, reqfile); // NEO: SCFS - [SmartClientFileStatus]// X-ToDo: can we need this here

						client->WriteModMultiPacket(&data_out, reqfile, status, false);
					}
					// NEO: NMPm END <-- Xanatos --

					if (data_out.GetLength() > 16 && !bAnswerFNF)
					{
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__MultiPacketAns", client, reqfile->GetFileHash());
						Packet* reply = new Packet(&data_out, OP_EMULEPROT);
						reply->opcode = OP_MULTIPACKETANSWER;
						theStats.AddUpDataOverheadFileRequest(reply->size);
						SendPacket(reply, true);
					}
					break;
				}
				case OP_MULTIPACKETANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_MultiPacketAns", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();

					if( client->GetKadPort() )
						Kademlia::CKademlia::Bootstrap(ntohl(client->GetIP()), client->GetKadPort());

					CSafeMemFile data_in(packet, size);
					uchar reqfilehash[16];
					data_in.ReadHash16(reqfilehash);
					CPartFile* reqfile = theApp.downloadqueue->GetFileByID(reqfilehash);
					//Make sure we are downloading this file.
					if (reqfile==NULL){
						// NEO: ASP - [ActiveSpreading] -- Xanatos -->
						if(theApp.sharedfiles->GetFileByID(reqfilehash))
							break;
						// NEO: ASP END <-- Xanatos --
						client->CheckFailedFileIdReqs(reqfilehash);
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MULTIPACKETANSWER; reqfile==NULL)");
					}
					if (client->GetRequestFile()==NULL)
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MULTIPACKETANSWER; client->GetRequestFile()==NULL)");
					if (reqfile != client->GetRequestFile())
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MULTIPACKETANSWER; reqfile!=client->GetRequestFile())");

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --

					uint8 opcode_in;
					while(data_in.GetLength()-data_in.GetPosition())
					{
						opcode_in = data_in.ReadUInt8();
						switch(opcode_in)
						{
							case OP_REQFILENAMEANSWER:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPReqFileNameAns", client, packet);

								client->ProcessFileInfo(&data_in, reqfile);
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
								if(thePrefs.SaveSourceFileList() && client->Source())
									client->Source()->AddSeenFile(reqfile->GetFileHash(),reqfile->GetFileSize());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
								break;
							}
							case OP_FILESTATUS:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPFileStatus", client, packet);

								client->ProcessFileStatus(false, &data_in, status, reqfile); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
								break;
							}
							case OP_AICHFILEHASHANS:
							{
								if (thePrefs.GetDebugClientTCPLevel() > 0)
									DebugRecv("OP_MPAichFileHashAns", client);

								client->ProcessAICHFileHash(&data_in, reqfile);
								break;
							}
							// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
							case OP_SUBCHUNKMAPS: // NEO: SCT - [SubChunkTransfer]
							case OP_FILEINCSTATUS: // NEO: ICS - [InteligentChunkSelection]
							case OP_FILEHIDENSTATUS: // NEO: RPS - [RealPartStatus]
							case OP_FILEBLOCKEDSTATUS: // NEO: RPS - [RealPartStatus]
#ifdef WEBCACHE // NEO: WC - [WebCache]
							case WC_TAG_WEBCACHENAME:
							//case WC_TAG_WEBCACHEID:
							case WC_TAG_MASTERKEY:
#endif // NEO: WC END
								client->ReadModMultiPacket(&data_in,reqfile,status,opcode_in);
								break;
							// NEO: NMPm END <-- Xanatos --
							default:
							{
								CString strError;
								strError.Format(_T("Invalid sub opcode 0x%02x received"), opcode_in);
								throw strError;
							}
						}
					}

					// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
					if(client->GetNeoModProtVersion() == 0)
						client->ProcessModFileStatus(false, status, reqfile); // NEO: SCFS - [SmartClientFileStatus]
					// NEO: NMPm END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
					if (thePrefs.IsWebCacheEnabled() && client->SupportsWebCache()
						&& client->SupportsMultiOHCBs() && client->IsTrustedOHCBSender())
					{
						Packet* tosend = client->CreateMFRPacket();
						if (tosend)
						{
							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__multiFileRequest", client, reqfile->GetFileHash());
							theStats.AddUpDataOverheadOther(tosend->size);
							SendPacket(tosend, true);
						}
					}
#endif // NEO: WC END <-- Xanatos --
					break;
				}
				case OP_EMULEINFO:
				{
					theStats.AddDownDataOverheadOther(uRawSize);
					client->ProcessMuleInfoPacket(packet,size);
					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_EmuleInfo", client);
						Debug(_T("  %s\n"), client->DbgGetMuleInfo());
					}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if(thePrefs.IsArgosFakeClientDetection()){
						//UINT nClientMajVersion = (client->GetVersion() >> 17) & 0x7f;
						UINT nClientMinVersion = (client->GetVersion() >> 10) & 0x7f;
						//UINT nClientUpVersion  = (client->GetVersion() >>  7) & 0x07;
						if(nClientMinVersion > 30) // Clients above 0.30 does not send this packet anymore
							theApp.argos->DoArgos(client->GetConnectIP(),AR_FAKECLIENT);
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --

					// start secure identification, if
					//  - we have received eD2K and eMule info (old eMule)
					if (client->GetInfoPacketsReceived() == IP_BOTH)
						client->InfoPacketsReceived();

					client->SendMuleInfoPacket(true);
					break;
				}
				case OP_EMULEINFOANSWER:
				{
					theStats.AddDownDataOverheadOther(uRawSize);
					client->ProcessMuleInfoPacket(packet,size);
					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_EmuleInfoAnswer", client);
						Debug(_T("  %s\n"), client->DbgGetMuleInfo());
					}

					// start secure identification, if
					//  - we have received eD2K and eMule info (old eMule)
					if (client->GetInfoPacketsReceived() == IP_BOTH)
						client->InfoPacketsReceived();
					break;
				}
				case OP_SECIDENTSTATE:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_SecIdentState", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					client->ProcessSecIdentStatePacket(packet, size);
					if (client->GetSecureIdentState() == IS_SIGNATURENEEDED)
						client->SendSignaturePacket();
					else if (client->GetSecureIdentState() == IS_KEYANDSIGNEEDED)
					{
						client->SendPublicKeyPacket();
						client->SendSignaturePacket();
					}
					break;
				}
				case OP_PUBLICKEY:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_PublicKey", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					client->ProcessPublicKeyPacket(packet, size);
					break;
				}
  				case OP_SIGNATURE:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_Signature", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					client->ProcessSignaturePacket(packet, size);
					break;
				}
				case OP_QUEUERANKING:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_QueueRanking", client);
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();
					client->ProcessEmuleQueueRank(packet, size);
					// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
					if (thePrefs.UseEstimatedDownloadTime() && client->GetDownloadTimeVersion() > 0 && client->GetNeoModProtVersion() == 0) // NEO: NMPm - [NeoModProtMultiPacket]
					{
						uint32 avg_time, err_time;
						avg_time = PeekUInt32(packet+4);
						err_time = PeekUInt32(packet+8);
						client->SetRemoteEDT(avg_time, err_time);
					}
					// NEO: EDT END <-- Xanatos --
					break;
				}
 				case OP_REQUESTSOURCES:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_RequestSources", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadSourceExchange(uRawSize);
					client->CheckHandshakeFinished();

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if(thePrefs.IsArgosXSExploitDetection()){
						if(client->CheckXSAsk())
							break;
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --

					if (client->GetSourceExchangeVersion() > 1)
					{
						if (size != 16)
							throw GetResString(IDS_ERR_BADSIZE);

						if (thePrefs.GetDebugSourceExchange())
							AddDebugLogLine(false, _T("SXRecv: Client source request; %s, %s"), client->DbgGetClientInfo(), DbgGetFileInfo(packet));

						//first check shared file list, then download list
						CKnownFile* reqfile;
						if ((reqfile = theApp.sharedfiles->GetFileByID(packet)) != NULL ||
							(reqfile = theApp.downloadqueue->GetFileByID(packet)) != NULL)
						{
							// There are some clients which do not follow the correct protocol procedure of sending
							// the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
							// are doing this, they will not get the optimal set of sources which we could offer if
							// the would follow the above noted protocol sequence. They better to it the right way
							// or they will get just a random set of sources because we do not know their download
							// part status which may get cleared with the call of 'SetUploadFileID'.
							client->SetUploadFileID(reqfile);

							DWORD dwTimePassed = ::GetTickCount() - client->GetLastSrcReqTime() + CONNECTION_LATENCY;
							bool bNeverAskedBefore = client->GetLastSrcReqTime() == 0;
							if (reqfile->KnownPrefs.SendXS() && ( // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
								//if not complete and file is rare
								(    reqfile->IsPartFile()
								  && (bNeverAskedBefore || dwTimePassed > thePrefs.GetXSClientIntervalsMs()/*SOURCECLIENTREASKS*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
								  && ((CPartFile*)reqfile)->GetSourceCount() <= (UINT)thePrefs.GetRareFileLimit() /*RARE_FILE*/
								) ||
								//OR if file is not rare or if file is complete
								(bNeverAskedBefore || dwTimePassed > thePrefs.GetXSClientIntervalsMs()/*SOURCECLIENTREASKS*/ * thePrefs.GetXSDelayValue() /*MINCOMMONPENALTY*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
							   ))
							{
								client->SetLastSrcReqTime();
								Packet* tosend = reqfile->CreateSrcInfoPacket(client);
								if (tosend)
								{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
									client->SetLastSourcesSent();
#endif // ARGOS // NEO: NA END <-- Xanatos --
									if (thePrefs.GetDebugClientTCPLevel() > 0)
										DebugSend("OP__AnswerSources", client, reqfile->GetFileHash());
									theStats.AddUpDataOverheadSourceExchange(tosend->size);
									SendPacket(tosend, true, true);
								}
							}
						}
						else
							client->CheckFailedFileIdReqs(packet);
					}
					break;
				}
 				case OP_ANSWERSOURCES:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AnswerSources", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadSourceExchange(uRawSize);
					client->CheckHandshakeFinished();

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					client->IncXSAnswer();
#endif // ARGOS // NEO: NA END <-- Xanatos --

					CSafeMemFile data(packet, size);
					uchar hash[16];
					data.ReadHash16(hash);
					if(CPartFile* file = theApp.downloadqueue->GetFileByID(hash))
					{
						if (file->IsPartFile())
						{
							// NEO: NST - [NeoSourceTweaks] -- Xanatos -->
							//if(!(((CPartFile*)file)->PartPrefs.UseXS()) && !(((CPartFile*)file)->IsCollectXSSources()))
							//	break;
							// NEO: END <-- Xanatos --
							//set the client's answer time
							client->SetLastSrcAnswerTime();
							//and set the file's last answer time
							file->SetLastAnsweredTime();
							file->AddClientSources(&data, client->GetSourceExchangeVersion(), client);
						}
					}
					// NEO: ASP - [ActiveSpreading] -- Xanatos -->
					else if(CKnownFile* file = theApp.sharedfiles->GetFileByID(hash)){
						client->SetLastSrcAnswerTime();
						file->AddXSAnswerCount();
						file->ActiveSpread(&data, client->GetSourceExchangeVersion(), client);
					}
					// NEO: ASP END <-- Xanatos --
					else
						client->CheckFailedFileIdReqs(hash);
					break;
				}
				case OP_FILEDESC:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_FileDesc", client);
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();
					client->ProcessMuleCommentPacket(packet,size);
					break;
				}
				case OP_REQUESTPREVIEW:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_RequestPreView", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadOther(uRawSize);
					client->CheckHandshakeFinished();
	
					if (thePrefs.CanSeeShares()==vsfaEverybody || (thePrefs.CanSeeShares()==vsfaFriends && client->IsFriend()))	
					{
						client->ProcessPreviewReq(packet,size);	
						if (thePrefs.GetVerbose())
							AddDebugLogLine(true,_T("Client '%s' (%s) requested Preview - accepted"), client->GetUserName(), ipstr(client->GetConnectIP()));
					}
					else
					{
						// we don't send any answer here, because the client should know that he was not allowed to ask
						if (thePrefs.GetVerbose())
							AddDebugLogLine(true,_T("Client '%s' (%s) requested Preview - denied"), client->GetUserName(), ipstr(client->GetConnectIP()));
					}
					break;
				}
				case OP_PREVIEWANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_PreviewAnswer", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadOther(uRawSize);
					client->CheckHandshakeFinished();

					client->ProcessPreviewAnswer(packet, size);
					break;
				}
				case OP_PEERCACHE_QUERY:
				{
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					if (!client->ProcessPeerCacheQuery(packet, size))
					{
						CSafeMemFile dataSend(128);
						dataSend.WriteUInt8(PCPCK_VERSION);
						dataSend.WriteUInt8(PCOP_NONE);
						if (thePrefs.GetDebugClientTCPLevel() > 0){
							DebugSend("OP__PeerCacheAnswer", client);
							Debug(_T("  %s\n"), _T("Not supported"));
						}
						Packet* pEd2kPacket = new Packet(&dataSend, OP_EMULEPROT, OP_PEERCACHE_ANSWER);
						theStats.AddUpDataOverheadFileRequest(pEd2kPacket->size);
						SendPacket(pEd2kPacket);
					}
					break;
				}
				case OP_PEERCACHE_ANSWER:
				{
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					if ( (!client->ProcessPeerCacheAnswer(packet, size)) && client->GetDownloadState() != DS_NONEEDEDPARTS)
					{
						// We have sent a PeerCache Query to the remote client, for any reason the remote client
						// can not process it -> fall back to ed2k download.
						client->SetPeerCacheDownState(PCDS_NONE);
						ASSERT( client->m_pPCDownSocket == NULL );

						// PC-TODO: Check client state.
						ASSERT( client->GetDownloadState() == DS_DOWNLOADING );
						client->SetDownloadState(DS_ONQUEUE, _T("Peer cache query trouble")); // clear block requests
						if (client)
							client->StartDownload();
					}
					break;
				}
				case OP_PEERCACHE_ACK:
				{
					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->ProcessPeerCacheAcknowledge(packet, size);
					break;
				}
				case OP_PUBLICIP_ANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_PublicIPAns", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					client->ProcessPublicIPAnswer(packet, size);
					break;
				}
				case OP_PUBLICIP_REQ:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_PublicIPReq", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__PublicIPAns", client);
					Packet* pPacket = new Packet(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
					PokeUInt32(pPacket->pBuffer, client->GetIP());
					theStats.AddUpDataOverheadOther(pPacket->size);
					SendPacket(pPacket);
					break;
				}
				case OP_PORTTEST:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_PortTest", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					m_bPortTestCon=true;
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__PortTest", client);
					Packet* replypacket = new Packet(OP_PORTTEST, 1);
					replypacket->pBuffer[0]=0x12;
					theStats.AddUpDataOverheadOther(replypacket->size);
					SendPacket(replypacket);
					break;
				}
				case OP_CALLBACK:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_Callback", client);
					theStats.AddDownDataOverheadFileRequest(uRawSize);

					if(!Kademlia::CKademlia::IsRunning())
						break;
					CSafeMemFile data(packet, size);
					Kademlia::CUInt128 check;
					data.ReadUInt128(&check);
					check.Xor(Kademlia::CUInt128(true));
					if(check == Kademlia::CKademlia::GetPrefs()->GetKadID())
					{
						Kademlia::CUInt128 fileid;
						data.ReadUInt128(&fileid);
						uchar fileid2[16];
						fileid.ToByteArray(fileid2);
						CKnownFile* reqfile;
						if ( (reqfile = theApp.sharedfiles->GetFileByID(fileid2)) == NULL )
						{
							if ( (reqfile = theApp.downloadqueue->GetFileByID(fileid2)) == NULL)
							{
								client->CheckFailedFileIdReqs(fileid2);
								break;
							}
						}

						uint32 ip = data.ReadUInt32();
						uint16 tcp = data.ReadUInt16();
						CUpDownClient* callback;
						callback = theApp.clientlist->FindClientByIP(ntohl(ip), tcp);
						if( callback == NULL )
						{
							callback = new CUpDownClient(NULL,tcp,ip,0,0);
							theApp.clientlist->AddClient(callback);
						}
						callback->TryToConnect(true);
					}
					break;
				}
				case OP_BUDDYPING:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_BuddyPing", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					CUpDownClient* buddy = theApp.clientlist->GetBuddy();
					if( buddy != client || client->GetKadVersion() == 0 || !client->AllowIncomeingBuddyPingPong() )
						//This ping was not from our buddy or wrong version or packet sent to fast. Ignore
						break;
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("OP__BuddyPong", client);
					Packet* replypacket = new Packet(OP_BUDDYPONG, 0, OP_EMULEPROT);
					theStats.AddDownDataOverheadOther(replypacket->size);
					SendPacket(replypacket);
					client->SetLastBuddyPingPongTime();
					break;
				}
				case OP_BUDDYPONG:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_BuddyPong", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					CUpDownClient* buddy = theApp.clientlist->GetBuddy();
					if( buddy != client || client->GetKadVersion() == 0 )
						//This pong was not from our buddy or wrong version. Ignore
						break;
					client->SetLastBuddyPingPongTime();
					//All this is for is to reset our socket timeout.
					break;
				}
				case OP_REASKCALLBACKTCP:
				{
					// NEO: MOD - [CodeImprovement] -- Xanatos -->
					// David: there is no need to duplicate this entier code part

					CUpDownClient* buddy = theApp.clientlist->GetBuddy();
					if (buddy != client // This callback was not from our buddy.. Ignore.
					 || size < 4+2+16) // This PAcket is invalid
					{
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_ReaskCallbackTCP", client, NULL);
						theStats.AddDownDataOverheadFileRequest(uRawSize);
						break;
					}

					uint32 destip = PeekUInt32(packet);
					uint16 destport = PeekUInt16(packet+4);
					uchar reqfilehash[16];
					md4cpy(&reqfilehash[0],packet+4+2);
					
					// NEO: NMP - [NeoModProt]
					if(isnulmd4(reqfilehash))
					{
						theStats.AddDownDataOverheadFileRequest(4+2+16);
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_ReaskCallbackTCP (MOD)", client, reqfilehash);
						uint8 modopcode = PeekUInt8(packet+4+2+16);
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
						if(modopcode == OP_SECURE_CALLBACK_REQ)
						{
							if(!Kademlia::CKademlia::IsRunning())
								break;

							CSafeMemFile data(packet+(4+2+16+1),size-(4+2+16+1));
							Kademlia::CUInt128 check;
							data.ReadUInt128(&check);
							check.Xor(Kademlia::CUInt128(true));
							if(check == Kademlia::CKademlia::GetPrefs()->GetKadID())
							{
								Kademlia::CUInt128 fileid;
								data.ReadUInt128(&fileid);
								uchar fileid2[16];
								fileid.ToByteArray(fileid2);
								CKnownFile* reqfile;
								if ( (reqfile = theApp.sharedfiles->GetFileByID(fileid2)) == NULL )
								{
									if ( (reqfile = theApp.downloadqueue->GetFileByID(fileid2)) == NULL)
									{
										client->CheckFailedFileIdReqs(fileid2);
										break;
									}
								}

								uint32 ip = destip;
								uint16 tcp = data.ReadUInt16();
								CUpDownClient* callback;
								callback = theApp.clientlist->FindClientByIP(ntohl(ip), tcp);
								if( callback == NULL )
								{
									callback = new CUpDownClient(NULL,tcp,ip,0,0);
									theApp.clientlist->AddClient(callback);
								}
								callback->SetSecureCommunicationSupport();
								callback->SetRequierEncryption();
								callback->SetSupportSecureCallback();
								callback->TryToConnect(true);
							}
						}
						else
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
							theApp.clientudp->ProcessModPacket(packet+(4+2+16+1),size-(4+2+16+1),modopcode,destip,destport);
					}
					else
					// NEO: NMP END
					{
						theStats.AddDownDataOverheadFileRequest(4+2);
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_ReaskCallbackTCP", client, reqfilehash);
						theApp.clientudp->ProcessPacket(packet+(4+2),size-(4+2),OP_REASKCALLBACKTCP,destip,destport);
					}
					// NEO: MOD END <-- Xanatos --

					break;
				}
				case OP_AICHANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AichAnswer", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(uRawSize);

					client->ProcessAICHAnswer(packet,size);
					break;
				}
				case OP_AICHREQUEST:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AichRequest", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(uRawSize);

					client->ProcessAICHRequest(packet,size);
					break;
				}
				case OP_AICHFILEHASHANS:
				{
					// those should not be received normally, since we should only get those in MULTIPACKET
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AichFileHashAns", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(uRawSize);

					CSafeMemFile data(packet, size);
					client->ProcessAICHFileHash(&data, NULL);
					break;
				}
				case OP_AICHFILEHASHREQ:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AichFileHashReq", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(uRawSize);

					// those should not be received normally, since we should only get those in MULTIPACKET
					CSafeMemFile data(packet, size);
					uchar abyHash[16];
					data.ReadHash16(abyHash);
					CKnownFile* pPartFile = theApp.sharedfiles->GetFileByID(abyHash);
					if (pPartFile == NULL){
						client->CheckFailedFileIdReqs(abyHash);
						break;
					}
					if (client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
						&& pPartFile->GetAICHHashset()->HasValidMasterHash())
					{
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__AichFileHashAns", client, abyHash);
						CSafeMemFile data_out;
						data_out.WriteHash16(abyHash);
						pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
						Packet* response = new Packet(&data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
						theStats.AddUpDataOverheadFileRequest(response->size);
						SendPacket(response);
					}
					break;
				}
				case OP_REQUESTPARTS_I64:
				{
					// see also OP_REQUESTPARTS
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_RequestParts_I64", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar reqfilehash[16];
					data.ReadHash16(reqfilehash);

					uint64 auStartOffsets[3];
					auStartOffsets[0] = data.ReadUInt64();
					auStartOffsets[1] = data.ReadUInt64();
					auStartOffsets[2] = data.ReadUInt64();

					uint64 auEndOffsets[3];
					auEndOffsets[0] = data.ReadUInt64();
					auEndOffsets[1] = data.ReadUInt64();
					auEndOffsets[2] = data.ReadUInt64();

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (thePrefs.CloseMaellaBackdoor() && !client->IsHotFileSwapAllowed(reqfilehash))
						return false;
#endif // ARGOS // NEO: NA END <-- Xanatos --

					if (thePrefs.GetDebugClientTCPLevel() > 0){
						Debug(_T("  Start1=%I64u  End1=%I64u  Size=%I64u\n"), auStartOffsets[0], auEndOffsets[0], auEndOffsets[0] - auStartOffsets[0]);
						Debug(_T("  Start2=%I64u  End2=%I64u  Size=%I64u\n"), auStartOffsets[1], auEndOffsets[1], auEndOffsets[1] - auStartOffsets[1]);
						Debug(_T("  Start3=%I64u  End3=%I64u  Size=%I64u\n"), auStartOffsets[2], auEndOffsets[2], auEndOffsets[2] - auStartOffsets[2]);
					}

					for (int i = 0; i < ARRSIZE(auStartOffsets); i++)
					{
						if (auEndOffsets[i] > auStartOffsets[i])
						{
							Requested_Block_Struct* reqblock = new Requested_Block_Struct;
							reqblock->StartOffset = auStartOffsets[i];
							reqblock->EndOffset = auEndOffsets[i];
							md4cpy(reqblock->FileID, reqfilehash);
							reqblock->transferred = 0;
							reqblock->unverified = false; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --
							reqblock->filedata = NULL; // NEO: RBT - [ReadBlockThread] <-- Xanatos --
							client->AddReqBlock(reqblock);
						}
						else
						{
							if (thePrefs.GetVerbose())
							{
								if (auEndOffsets[i] != 0 || auStartOffsets[i] != 0)
									DebugLogWarning(_T("Client requests invalid %u. file block %I64u-%I64u (%I64d bytes): %s"), i, auStartOffsets[i], auEndOffsets[i], auEndOffsets[i] - auStartOffsets[i], client->DbgGetClientInfo());
							}
						}
					}
					// NEO: RBT - [ReadBlockThread] -- Xanatos -->
					if(client->GetUploadState() == US_UPLOADING)
						client->CreateNextBlockPackage();
					// NEO: RBT END <-- Xanatos --
					break;
				}
				case OP_COMPRESSEDPART:
				case OP_SENDINGPART_I64:
				case OP_COMPRESSEDPART_I64:
				{
					// see also OP_SENDINGPART
					if (thePrefs.GetDebugClientTCPLevel() > 1){
						if (opcode == OP_COMPRESSEDPART)
							DebugRecv("OP_CompressedPart", client, (size >= 16) ? packet : NULL);
						else if (opcode == OP_SENDINGPART_I64)
							DebugRecv("OP_SendingPart_I64", client, (size >= 16) ? packet : NULL);
						else
							DebugRecv("OP_CompressedPart_I64", client, (size >= 16) ? packet : NULL);
					}
					
					theStats.AddDownDataOverheadFileRequest(24);
					client->CheckHandshakeFinished();

					if (client->GetRequestFile() && !client->GetRequestFile()->IsStopped() 
					 && (!client->GetRequestFile()->IsStandBy()) // NEO: SD - [StandByDL] <-- Xanatos --
					 && (client->GetRequestFile()->GetStatus()==PS_READY || client->GetRequestFile()->GetStatus()==PS_EMPTY)
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					 && !client->IsBanned() // Don't accept upload from banned clients, tray may send corrupt data
#endif //ARGOS // NEO: NA END <-- Xanatos --
					 )
					{
						client->ProcessBlockPacket(packet, size, (opcode == OP_COMPRESSEDPART || opcode == OP_COMPRESSEDPART_I64), (opcode == OP_SENDINGPART_I64 || opcode == OP_COMPRESSEDPART_I64) );
						if (client->GetRequestFile()->IsStopped() || client->GetRequestFile()->GetStatus()==PS_PAUSED || client->GetRequestFile()->GetStatus()==PS_ERROR)
						{
							client->SendCancelTransfer();
							client->SetDownloadState(client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
						}
					}
					else
					{
						client->SendCancelTransfer();
						client->SetDownloadState((client->GetRequestFile()==NULL || client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
					}
					break;
				}
				// NEO: NMP - [NeoModProt] -- Xanatos -->
				case OP_SUBCHUNKMAPS: // NEO: SCT - [SubChunkTransfer]
				// NEO: XCFS - [ExtendedClientFileStatus]
			    case OP_FILEINCSTATUS:
				case OP_UPFILEINCSTATUS: // X!: for backwards compatybility
				case OP_FILEHIDENSTATUS:
				case OP_FILEBLOCKEDSTATUS:
				// NEO: XCFS END
			    case OP_EXTRAINFO: // NEO: NXI - [NeoExtraInfo]
#ifdef ISPBYPASS // NEO: MP - [MultiPort]
				case OP_AUX_PORT:
#endif // ISPBYPASS // NEO: MP END
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap]
				case OP_SWAP_SOCKET:
#endif // ISPBYPASS // NEO: CHS END
					ProcessModPacket(packet, size, opcode, uRawSize); // for backwards compatybility
					break;
				// NEO: NMP END <-- Xanatos --
				
				default:
					theStats.AddDownDataOverheadOther(uRawSize);
					PacketToDebugLogLine(_T("eMule"), packet, size, opcode);
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (client && thePrefs.IsArgosOpcodeDetection()){
						TOpCode* OpCode = new TOpCode;
						OpCode->OpSource = OC_PACKET_EX;
						OpCode->OpCode = (uint8)opcode;
						OpCode->OpValue = 0;
						theApp.argos->AddClientToTest(client,OpCode);
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --
					break;
			}
		}
		catch(CFileException* error)
		{
			error->Delete();
			throw GetResString(IDS_ERR_INVALIDPACKAGE);
		}
		catch(CMemoryException* error)
		{
			error->Delete();
			throw CString(_T("Memory exception"));
		}
	}
	// NEO: MOD - [UnusedCode] -- Xanatos --
	/*catch(CClientException* ex) // nearly same as the 'CString' exception but with optional deleting of the client
	{
		if (thePrefs.GetVerbose() && !ex->m_strMsg.IsEmpty())
			DebugLogWarning(_T("Error: %s - while processing eMule packet: opcode=%s  size=%u; %s"), ex->m_strMsg, DbgGetMuleClientTCPOpcode(opcode), size, DbgGetClientInfo());
		if (client && ex->m_bDelete)
			client->SetDownloadState(DS_ERROR, _T("Error while processing eMule packet: ") + ex->m_strMsg);
		Disconnect(ex->m_strMsg);
		ex->Delete();
		return false;
	}*/
	catch(CString error)
	{
		if (thePrefs.GetVerbose() && !error.IsEmpty())
			DebugLogWarning(_T("Error: %s - while processing eMule packet: opcode=%s  size=%u; %s"), error, DbgGetMuleClientTCPOpcode(opcode), size, DbgGetClientInfo());
		if (client)
			client->SetDownloadState(DS_ERROR, _T("ProcessExtPacket error. ") + error);
		Disconnect(_T("ProcessExtPacket error. ") + error);
		return false;
	}
	return true;
}

void CClientReqSocket::PacketToDebugLogLine(LPCTSTR protocol, const uchar* packet, uint32 size, UINT opcode)
{
	if (thePrefs.GetVerbose())
	{
		CString buffer; 
	    buffer.Format(_T("Unknown %s Protocol Opcode: 0x%02x, Size=%u, Data=["), protocol, opcode, size);
		for (uint32 i = 0; i < size && i < 50; i++){
			if (i > 0)
				buffer += _T(' ');
			TCHAR temp[3];
		    _stprintf(temp, _T("%02x"), packet[i]);
			buffer += temp;
		}
		buffer += (i == size) ? _T("]") : _T("..]");
		DbgAppendClientInfo(buffer);
		DebugLogWarning(_T("%s"), buffer);
	}
}

CString CClientReqSocket::DbgGetClientInfo()
{
	CString str;
	SOCKADDR_IN sockAddr = {0};
	int nSockAddrLen = sizeof(sockAddr);
	GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
	if (sockAddr.sin_addr.S_un.S_addr != 0 && (client == NULL || sockAddr.sin_addr.S_un.S_addr != client->GetIP()))
		str.AppendFormat(_T("IP=%s"), ipstr(sockAddr.sin_addr));
	if (client){
		if (!str.IsEmpty())
			str += _T("; ");
		str += _T("Client=") + client->DbgGetClientInfo();
	}
	return str;
}

void CClientReqSocket::DbgAppendClientInfo(CString& str)
{
	CString strClientInfo(DbgGetClientInfo());
	if (!strClientInfo.IsEmpty()){
		if (!str.IsEmpty())
			str += _T("; ");
		str += strClientInfo;
	}
}

void CClientReqSocket::OnConnect(int nErrorCode)
{
	SetConState(SS_Complete);
	CEMSocket::OnConnect(nErrorCode);
	if (nErrorCode)
	{
		// NEO: TCR - [TCPConnectionRetry] -- Xanatos -->
		if(client
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
		&& ((nErrorCode != WSAECONNREFUSED && nErrorCode != WSAETIMEDOUT) || (m_Socket->IsAsyncSocket() && !((CTCPSocket*)m_Socket)->GetLastProxyError().IsEmpty()) )
#else
		&& ((nErrorCode != WSAECONNREFUSED && nErrorCode != WSAETIMEDOUT) || !GetLastProxyError().IsEmpty() )
#endif //NATTUNNELING // NEO: UTCP END
		 )
			client->SetForDelete(); //Xman: in such a case don't give the clients more connection-retrys
		// NEO: TCR END <-- Xanatos --

		//don't show this "error" because it's too normal and I only saw:
	    CString strTCPError;
		strTCPError = GetFullErrorMessage(nErrorCode);
	//	if (thePrefs.GetVerbose())
	//	{
	//		strTCPError = GetFullErrorMessage(nErrorCode);
	//	    if ((nErrorCode != WSAECONNREFUSED && nErrorCode != WSAETIMEDOUT) || !GetLastProxyError().IsEmpty())
	//		    DebugLogError(_T("Client TCP socket (OnConnect): %s; %s"), strTCPError, DbgGetClientInfo());
	//	}
		Disconnect(strTCPError);
	}
	else
	{
		//This socket may have been delayed by SP2 protection, lets make sure it doesn't time out instantly.
		ResetTimeOutTimer();

		// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
		if(thePrefs.IsTCPDisableNagle()){
			BOOL noDelay = true;
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
			m_Socket->SetSockOpt(TCP_NODELAY, &noDelay, sizeof(noDelay), IPPROTO_TCP);
#else
			SetSockOpt(TCP_NODELAY, &noDelay, sizeof(noDelay), IPPROTO_TCP);
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
		}
		// NEO: NBC END <-- Xanatos --
	}
}

void CClientReqSocket::OnSend(int nErrorCode)
{
	ResetTimeOutTimer();
	CEMSocket::OnSend(nErrorCode);
}

void CClientReqSocket::OnError(int nErrorCode)
{
	CString strTCPError;
	if (thePrefs.GetVerbose())
	{
		if (nErrorCode == ERR_WRONGHEADER)
			strTCPError = _T("Error: Wrong header");
		else if (nErrorCode == ERR_TOOBIG)
			strTCPError = _T("Error: Too much data sent");
		else
			strTCPError = GetErrorMessage(nErrorCode);
		DebugLogWarning(_T("Client TCP socket: %s; %s"), strTCPError, DbgGetClientInfo());
	}
	Disconnect(strTCPError);
}

bool CClientReqSocket::PacketReceivedCppEH(Packet* packet)
{
	bool bResult;
	UINT uRawSize = packet->size;
	switch (packet->prot){
		case OP_EDONKEYPROT:
			bResult = ProcessPacket((const BYTE*)packet->pBuffer, packet->size, packet->opcode);
			break;
		case OP_PACKEDPROT:
			if (!packet->UnPackPacket()){
				if (thePrefs.GetVerbose())
					DebugLogError(_T("Failed to decompress client TCP packet; %s; %s"), DbgGetClientTCPPacket(packet->prot, packet->opcode, packet->size), DbgGetClientInfo());
				bResult = false;
				break;
			}
		case OP_EMULEPROT:
			bResult = ProcessExtPacket((const BYTE*)packet->pBuffer, packet->size, packet->opcode, uRawSize);
			break;
		// NEO: NMP - [NeoModProt] -- Xanatos -->
		case OP_MODPACKEDPROT:
			if (!packet->UnPackPacket())
			{
				if (thePrefs.GetVerbose())
					AddDebugLogLine(false, _T("Failed to decompress client Mod TCP packet; %s; %s"), DbgGetClientTCPPacket(packet->prot, packet->opcode, packet->size), DbgGetClientInfo());
				bResult = false;
				break;
			}
		case OP_MODPROT:
			bResult = ProcessModPacket((const BYTE*)packet->pBuffer, packet->size, packet->opcode, uRawSize);
			break;
		// NEO: NMP END <-- Xanatos --
		default:{
			theStats.AddDownDataOverheadOther(uRawSize);
			if (thePrefs.GetVerbose())
				DebugLogWarning(_T("Received unknown client TCP packet; %s; %s"), DbgGetClientTCPPacket(packet->prot, packet->opcode, packet->size), DbgGetClientInfo());

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			if (thePrefs.IsArgosOpcodeDetection()){
				TOpCode* OpCode = new TOpCode;
				OpCode->OpSource = OC_RAW_TCP;
				OpCode->OpCode = packet->prot;
				OpCode->OpValue = 0;
				if(client){
					theApp.argos->AddClientToTest(client,OpCode);
				}else{
					SOCKADDR_IN sockAddr = {0};
					int nSockAddrLen = sizeof(sockAddr);
					GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
					theApp.argos->AddClientToTest(sockAddr.sin_addr.S_un.S_addr,OpCode);
				}
			}
#endif // ARGOS // NEO: NA END <-- Xanatos --

			if (client){
				client->SetDownloadState(DS_ERROR, _T("Unknown protocol"));
				// NEO: MOD - [CodeImprovement] -- Xanatos -->
				theApp.clientlist->m_globDeadSourceList.AddDeadSource(client); //Xman Xtreme Mod  I don't AddDeadsource in disconnected
				// NEO: MOD END <-- Xanatos --
			}
			Disconnect(_T("Unknown protocol"));
			bResult = false;
		}
	}
	return bResult;
}

#if !NO_USE_CLIENT_TCP_CATCH_ALL_HANDLER
int FilterSE(DWORD dwExCode, LPEXCEPTION_POINTERS pExPtrs, CClientReqSocket* reqsock, Packet* packet)
{
	if (thePrefs.GetVerbose())
	{
		CString strExError;
		if (pExPtrs){
			const EXCEPTION_RECORD* er = pExPtrs->ExceptionRecord;
			strExError.Format(_T("Error: Unknown exception %08x in CClientReqSocket::PacketReceived at 0x%08x"), er->ExceptionCode, er->ExceptionAddress);
		}
		else
			strExError.Format(_T("Error: Unknown exception %08x in CClientReqSocket::PacketReceived"), dwExCode);

		// we already had an unknown exception, better be prepared for dealing with invalid data -> use another exception handler
		try{
			CString strError = strExError;
			strError.AppendFormat(_T("; %s"), DbgGetClientTCPPacket(packet?packet->prot:0, packet?packet->opcode:0, packet?packet->size:0));
			reqsock->DbgAppendClientInfo(strError);
			DebugLogError(_T("%s"), strError);
		}
		catch(...){
			ASSERT(0);
			DebugLogError(_T("%s"), strExError);
		}
	}
	
	// this searches the next exception handler -> catch(...) in 'CAsyncSocketExHelperWindow::WindowProc'
	// as long as I do not know where and why we are crashing, I prefere to have it handled that way which
	// worked fine in 28a/b.
	//
	// 03-Jän-2004 [bc]: Returning the execution to the catch-all handler in 'CAsyncSocketExHelperWindow::WindowProc'
	// can make things even worse, because in some situations, the socket will continue fireing received events. And
	// because the processed packet (which has thrown the exception) was not removed from the EMSocket buffers, it would
	// be processed again and again.
	//return EXCEPTION_CONTINUE_SEARCH;

	// this would continue the program "as usual" -> return execution to the '__except' handler
	return EXCEPTION_EXECUTE_HANDLER;
}
#endif

#if !NO_USE_CLIENT_TCP_CATCH_ALL_HANDLER
int CClientReqSocket::PacketReceivedSEH(Packet* packet)
{
	int iResult;
	// this function is only here to get a chance of determining the crash address via SEH
	__try{
		iResult = PacketReceivedCppEH(packet);
	}
	__except(FilterSE(GetExceptionCode(), GetExceptionInformation(), this, packet)){
		iResult = -1;
	}
	return iResult;
}
#endif

bool CClientReqSocket::PacketReceived(Packet* packet)
{
	bool bResult;
#if !NO_USE_CLIENT_TCP_CATCH_ALL_HANDLER
	int iResult = PacketReceivedSEH(packet);
	if (iResult < 0)
	{
		if (client){
			client->SetDownloadState(DS_ERROR, _T("Unknown Exception"));
			// NEO: MOD - [CodeImprovement] -- Xanatos -->
			theApp.clientlist->m_globDeadSourceList.AddDeadSource(client); //Xman Xtreme Mod  I don't AddDeadsource in disconnected
			// NEO: MOD END <-- Xanatos --
		}
		Disconnect(_T("Unknown Exception"));
		bResult = false;
	}
	else
		bResult = iResult!=0;
#else
	bResult = PacketReceivedCppEH(packet);
#endif
	return bResult;
}

void CClientReqSocket::OnReceive(int nErrorCode)
{
	ResetTimeOutTimer();
	CEMSocket::OnReceive(nErrorCode);
}

bool CClientReqSocket::Create()
{
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	BOOL result = TRUE;
	if(m_Socket->IsAsyncSocket())
		result = ((CTCPSocket*)m_Socket)->Create(0, SOCK_STREAM, FD_WRITE|FD_READ|FD_CLOSE|FD_CONNECT,CT2CA(theApp.GetBindAddress())); // NEO: MOD - [BindToAdapter]
#else
	BOOL result = CAsyncSocketEx::Create(0, SOCK_STREAM, FD_WRITE|FD_READ|FD_CLOSE|FD_CONNECT,CT2CA(theApp.GetBindAddress())); // NEO: MOD - [BindToAdapter] <-- Xanatos --
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(client && client->IsLanClient())
		SetOnLan();
#endif //LANCAST // NEO: NLC END <-- Xanatos --
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	if (result)
		theApp.listensocket->AddConnection(true);
#else
	theApp.listensocket->AddConnection();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
	return (result != FALSE);
}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
SocketSentBytes CClientReqSocket::Send(uint32 maxNumberOfBytesToSend, uint32 minFragSize, bool onlyAllowedToSendControlPacket, uint16 maxNumberOfPacketsToSend) {
    SocketSentBytes returnStatus = CEMSocket::Send(maxNumberOfBytesToSend,minFragSize,onlyAllowedToSendControlPacket,maxNumberOfPacketsToSend);
    if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0))
        ResetTimeOutTimer();

    return returnStatus;
}

int CClientReqSocket::Receive(uint32 size) {
    int returnStatus = CEMSocket::Receive(size);
    if(returnStatus > 0)
        ResetTimeOutTimer();

    return returnStatus;
}
#else
SocketSentBytes CClientReqSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
{
    SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
    if (returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0))
        ResetTimeOutTimer();
    return returnStatus;
}

SocketSentBytes CClientReqSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
{
    SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
    if (returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0))
        ResetTimeOutTimer();
    return returnStatus;
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

void CClientReqSocket::SendPacket(Packet* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
{
	ResetTimeOutTimer();
	CEMSocket::SendPacket(packet, delpacket, controlpacket, actualPayloadSize);
}

bool CListenSocket::SendPortTestReply(char result, bool disconnect)
{
	POSITION pos2;
	for(POSITION pos1 = socket_list.GetHeadPosition(); ( pos2 = pos1 ) != NULL; )
	{
		socket_list.GetNext(pos1);
		CClientReqSocket* cur_sock = socket_list.GetAt(pos2);
		if (cur_sock->m_bPortTestCon)
		{
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__PortTest", cur_sock->client);
			Packet* replypacket = new Packet(OP_PORTTEST, 1);
			replypacket->pBuffer[0]=result;
			theStats.AddUpDataOverheadOther(replypacket->size);
			cur_sock->SendPacket(replypacket);
			if (disconnect)
				cur_sock->m_bPortTestCon = false;
			return true;
		}
	}
	return false;
}


// NEO: NMP - [NeoModProt] -- Xanatos -->
bool CClientReqSocket::ProcessModPacket(const BYTE* packet, uint32 size, UINT opcode, UINT uRawSize)
{
	try
	{
		try
		{
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap]
			if (!client && opcode != OP_SWAP_SOCKET)
#else
			if (!client)
#endif // ISPBYPASS // NEO: CHS END
			{
				theStats.AddDownDataOverheadOther(uRawSize);
				throw GetResString(IDS_ERR_UNKNOWNCLIENTACTION);
			}
			if (thePrefs.m_iDbgHeap >= 2)
				ASSERT_VALID(client);

			switch(opcode)
			{
				// NEO: NMPi - [NeoModProtInfo]
				case OP_MODINFOPACKET:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP__ModInfoPacket", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					if(client->GetNeoModProtVersion() == 0)
						throw CString(_T("Recieved Neo Mod Info Packet from a cleint whitch doe snot support this feature!"));

					client->ProcessModInfoPacket(packet,size);

					// Now after we have all informations about the cleint the connection is established
					client->ConnectionEstablished();

					// start secure identification, if
					//  - we have received OP_MODINFOPACKET, (Neo Compatible new eMule mods)
					if (client->GetInfoPacketsReceived() == IP_BOTH)
						client->InfoPacketsReceived();
					break;
				}	
				// NEO: NMPi END

#ifdef ISPBYPASS // NEO: MP - [MultiPort]
				case OP_AUX_PORT:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_AUXPort", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					client->ProcessAUXPort(packet, size);
					break;
				}
#endif // ISPBYPASS // NEO: MP END

#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap]
				case OP_SWAP_SOCKET:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_SwapSocket", client);
					theStats.AddDownDataOverheadOther(uRawSize);

					ASSERT(m_Encryption);

					SOCKADDR_IN sockAddr = {0};
					int nSockAddrLen = sizeof(sockAddr);
					GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);

					uint32 clientIP = sockAddr.sin_addr.S_un.S_addr;
					uint16 clientPort = PeekUInt16(packet);
					client = theApp.clientlist->FindClientByIP(clientIP, clientPort);
					if(client == NULL)
						throw GetResString(IDS_ERR_NOHELLO);

 #ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler]
					bool onUpQueue = false;
					eSlotType SlotType = client->socket->m_eSlotType; // NEO: BM - [BandwidthModeration]
					if(client->socket->onUpQueue)
					{
						theApp.uploadBandwidthThrottler->RemoveFromStandardList(client->socket);
						client->socket->onUpQueue = false;
						onUpQueue = true;
					}
 #endif // NEO_UBT // NEO: NUBT END

					// remove old socket
					client->socket->client = NULL;
					client->socket->Safe_Delete();

					// set new secure socket
					client->socket = this;

					if(client->PreferUnencryptedPayload() && thePrefs.IsPreferUnEnCryptedPayload() && m_Encryption)
						m_Encryption->SetPlainPayload();

 #ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler]					
					if(onUpQueue)
					{
  #ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler]
						SetPriorityReceive(true);
  #endif // NEO_DBT // NEO: NDBT END
						SetPrioritySend(true);
						client->socket->m_eSlotType = SlotType; // NEO: BM - [BandwidthModeration]
						theApp.uploadBandwidthThrottler->AddToStandardList(client->socket);
					}
 #endif // NEO_UBT // NEO: NUBT END

					break;
				}
#endif // ISPBYPASS // NEO: CHS END

				// NEO: NMPm - [NeoModProtMultiPacket]
				case OP_MODMULTIPACKET: 
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_ModMultiPacket", client, (size >= 24) ? packet : NULL);

					if(client->GetActiveUpReqFlag() == 4/*OP_FILEREQANSNOFIL*/) // the file already failed for the normal multi packet, just break
						break;

					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();

					CSafeMemFile data_in(packet, size);
					uchar reqfilehash[16];
					data_in.ReadHash16(reqfilehash);
					CKnownFile* reqfile;
					if ( (reqfile = theApp.sharedfiles->GetFileByID(reqfilehash)) == NULL ){
						if ( !((reqfile = theApp.downloadqueue->GetFileByID(reqfilehash)) != NULL
						 && reqfile->GetFileSize() > (uint64)PARTSIZE)
						 || (reqfile->IsUnshared(md4cmp(client->GetUploadFileID(), reqfilehash) == 0 && client->GetUploadState() == US_ONUPLOADQUEUE )) // NEO: USC - [UnShareCommand]
						){
							ASSERT(0); // How did this happen GetActiveUpReqFlag() should have prevented us form comming here
							if(!reqfile) // NEO: USC - [UnShareCommand]
								client->CheckFailedFileIdReqs(reqfilehash);
							break;
						}
					}

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus]

					client->ReadModMultiPacket(&data_in,reqfile,status);

					CSafeMemFile data_out(128);
					data_out.WriteHash16(reqfile->GetFileHash());

					client->WriteModMultiPacket(&data_out, reqfile, status, false);

					if (data_out.GetLength() > 16)
					{
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugSend("OP__ModMultiPacketAns", client, reqfile->GetFileHash());
						Packet* reply = new Packet(&data_out, OP_MODPROT);
						reply->opcode = OP_MODMULTIPACKETANSWER;
						theStats.AddUpDataOverheadFileRequest(reply->size);
						SendPacket(reply, true);
					}
					break;
				}
				case OP_MODMULTIPACKETANSWER:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_ModMultiPacketAns", client, (size >= 16) ? packet : NULL);

					theStats.AddDownDataOverheadFileRequest(uRawSize);
					client->CheckHandshakeFinished();

					CSafeMemFile data_in(packet, size);
					uchar reqfilehash[16];
					data_in.ReadHash16(reqfilehash);
					CPartFile* reqfile = theApp.downloadqueue->GetFileByID(reqfilehash);
					//Make sure we are downloading this file.
					if (reqfile==NULL){
						// NEO: ASP - [ActiveSpreading]
						if(theApp.sharedfiles->GetFileByID(reqfilehash))
							break;
						// NEO: ASP END
						client->CheckFailedFileIdReqs(reqfilehash);
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; reqfile==NULL)");
					}
					if (client->GetRequestFile()==NULL)
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; client->GetRequestFile()==NULL)");
					if (reqfile != client->GetRequestFile())
						throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (OP_MODMULTIPACKETANSWER; reqfile!=client->GetRequestFile())");

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); // NEO: SCFS - [SmartClientFileStatus]

					client->ReadModMultiPacket(&data_in,reqfile,status);
					client->ProcessModFileStatus(false, status, reqfile); // NEO: SCFS - [SmartClientFileStatus]

					break;
				}
				// NEO: NMPm END

				// NEO: SCT - [SubChunkTransfer] 
				case OP_SUBCHUNKMAPS:
				{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_SubChunkMaps", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar cfilehash[16];
					data.ReadHash16(cfilehash);

					CPartFile* reqfile = theApp.downloadqueue->GetFileByID(cfilehash);
					if (reqfile == NULL){
						// NEO: ASP - [ActiveSpreading]
						if(theApp.sharedfiles->GetFileByID(cfilehash))
							break;
						// NEO: ASP END
						client->CheckFailedFileIdReqs(cfilehash);
						break;
					}

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); 
					status->ReadSubChunkMaps(&data);
					if(client->GetDownloadState() == DS_NONEEDEDPARTS) // the file must be NNP or we will perform a secund unned ask
						client->ProcessModFileStatus(false, status, reqfile, false, true);
					break;
				}
				// NEO: SCT END

				// NEO: XCFS - [ExtendedClientFileStatus]
				case OP_FILEINCSTATUS:
				//case OP_UPFILEINCSTATUS:
				case OP_FILEHIDENSTATUS:
				case OP_FILEBLOCKEDSTATUS:
				{
					EPartStatus type = CFS_Normal;
					switch(opcode){
					// NEO: ICS - [InteligentChunkSelection]
					case OP_FILEINCSTATUS:
					case OP_UPFILEINCSTATUS: // X!: for backwards compatybility
						type = CFS_Incomplete;
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_FileImcompleteStatus", client, (size >= 16) ? packet : NULL);
						break;
					// NEO: ICS END
					// NEO: RPS - [RealPartStatus]
					case OP_FILEHIDENSTATUS:
						type = CFS_Hiden;
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_FileHidenStatus", client, (size >= 16) ? packet : NULL);
						break;
					case OP_FILEBLOCKEDSTATUS:
						type = CFS_Blocked;
						if (thePrefs.GetDebugClientTCPLevel() > 0)
							DebugRecv("OP_FileBlockedStatus", client, (size >= 16) ? packet : NULL);
						break;
					// NEO: RPS END
					}
					theStats.AddDownDataOverheadFileRequest(size);

					CSafeMemFile data(packet, size);
					uchar cfilehash[16];
					data.ReadHash16(cfilehash);

					CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(cfilehash);
					if(reqfile == NULL)
						reqfile = (CKnownFile*)theApp.downloadqueue->GetFileByID(cfilehash);
					if (reqfile == NULL){
						client->CheckFailedFileIdReqs(cfilehash);
						break;
					}

					CClientFileStatus* status = client->GetFileStatus(reqfile, true); 
					status->ReadFileStatus(&data, type);
					reqfile->UpdatePartsInfoEx(type);
					if(reqfile->IsPartFile() && client->GetDownloadState() == DS_NONEEDEDPARTS && opcode == OP_FILEHIDENSTATUS) // only hidden status is interresant
						client->ProcessModFileStatus(false, status, (CPartFile*)reqfile, false, false, true);
					break;
				}
				// NEO: XCFS END

				// NEO: NMPx - [NeoModProtXS]
				case OP_ANSWERSOURCES:
					ProcessExtPacket(packet, size, opcode, uRawSize); // we use the same propacket processor as for the official XS
					break;
				// NEO: NMPx END

				// NEO: NXI - [NeoExtraInfo]
				case OP_EXTRAINFO:{
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_ExtraInfo", client, (size >= 16) ? packet : NULL);
					theStats.AddDownDataOverheadOther(size);
					CSafeMemFile data((BYTE*)packet,size);
					client->ProcessExtraInfoPacket(&data);
					break;
				}
				// NEO: NXI END

				// NEO: PTM - [PrivatTransferManagement]
				case OP_PTM_STATUS:
					if (thePrefs.GetDebugClientTCPLevel() > 0){
						DebugRecv("OP_PTMStatus", client, (size >= 16) ? packet : NULL);
						if (size > 1)
							Debug(_T("  ***NOTE: Packet contains %u additional bytes\n"), size-1);
					}

					if(size >= 1)
						client->m_FreeDownload = PeekUInt8(packet);
					theStats.AddDownDataOverheadFileRequest(size);
					break;
				// NEO: PTM END

#ifdef WEBCACHE // NEO: WC - [WebCache]
				case OP_DONT_SEND_OHCBS:
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP__Dont_Send_Ohcbs recv", client);
					if (thePrefs.GetLogWebCacheEvents())
					AddDebugLogLine( false, _T("OP__Dont_Send_Ohcbs RECEIVED")); // yonatan tmp
					theStats.AddDownDataOverheadOther(size);
					if( client->SupportsWebCache() && client->SupportsOhcbSuppression() )
						client->m_bIsAcceptingOurOhcbs = false;
					break;

				//JP TEST THIS!!! (WE ARE NOT USING IT YET)
				case OP_RESUME_SEND_OHCBS: //we are not using it yet, but might in the future
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP_RESUME_SEND_OHCBS received from", client);
					if (thePrefs.GetLogWebCacheEvents())
						AddDebugLogLine( false, _T("OP_RESUME_SEND_OHCBS RECEIVED")); // yonatan tmp
					theStats.AddDownDataOverheadOther(size);
					if( client->SupportsWebCache() && client->SupportsOhcbSuppression() )
						client->m_bIsAcceptingOurOhcbs = true;
					break;

				case OP_HTTP_CACHED_BLOCK:
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP__Http_Cached_Block", client);
					theStats.AddDownDataOverheadOther(size);
					if( thePrefs.IsWebCacheDownloadEnabled() && client->SupportsWebCache() ) 
					{
						// CHECK HANDSHAKE?
						if (thePrefs.GetLogWebCacheEvents())
							AddDebugLogLine( false, _T("Received WCBlock - TCP") );
						new CWebCachedBlock( packet, size, client ); // Starts DL or places block on queue
					}
					break;

				case OP_XPRESS_MULTI_HTTP_CACHED_BLOCKS:
				case OP_MULTI_HTTP_CACHED_BLOCKS:
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugRecv("OP__Multi_Http_Cached_Blocks", client);
					theStats.AddDownDataOverheadOther(size);
					if( thePrefs.IsWebCacheDownloadEnabled() && client->SupportsWebCache() ) 
					{
						// CHECK HANDSHAKE?
						if (thePrefs.GetLogWebCacheEvents())
							AddDebugLogLine( false, _T("Received MultiWCBlocks - TCP") );
						//new CWebCachedBlock( (char*)packet, size, client ); // Starts DL or places block on queue
						CSafeMemFile data((BYTE*)packet,size);
						uint32 uploadID;
						uploadID = data.ReadUInt32();
						if (client->m_uWebCacheUploadId != uploadID)
							throw CString(_T("WebCacke Error: m_uWebCacheUploadId != uploadID"));

						if(!WebCachedBlockList.ProcessWCBlocks(packet, size, opcode, client))
							throw CString(_T("WebCacke Error: WebCachedBlockList.ProcessWCBlocks"));
					}
					return false;

				case OP_MULTI_FILE_REQ:
					{
						if (!client->SupportsMultiOHCBs() || !client->SupportsWebCache())
							throw CString(_T("WebCacke Error: recieved packet froma cleint taht does not support it"));

		//				client->requestedFiles.RemoveAll();
		//				client->requestedFiles.AddFiles(&CSafeMemFile(BYTE(packet)));
						CSafeMemFile data_in((BYTE*)packet,size);
						client->requestedFiles.AddFiles(&data_in, client);

						Packet* toSend = WC_OHCBManager.GetWCBlocksForClient(client);
						if(toSend)
						{
							if (thePrefs.GetDebugClientTCPLevel() > 0)
								DebugSend("OP__multiOHCB", client);
							theStats.AddUpDataOverheadOther(toSend->size);
							SendPacket(toSend, true);
						}
						break;
					}
#endif // NEO: WC END

				default:
					theStats.AddDownDataOverheadOther(uRawSize);
					PacketToDebugLogLine(_T("ModProt"), packet, size, opcode);
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (thePrefs.IsArgosOpcodeDetection()){
						TOpCode* OpCode = new TOpCode;
						OpCode->OpSource = OC_PACKET_MOD;
						OpCode->OpCode = (uint8)opcode;
						OpCode->OpValue = 0;
						if(client){
							theApp.argos->AddClientToTest(client,OpCode);
						}else{
							SOCKADDR_IN sockAddr = {0};
							int nSockAddrLen = sizeof(sockAddr);
							GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
							theApp.argos->AddClientToTest(sockAddr.sin_addr.S_un.S_addr,OpCode);
						}
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --
			}
		}
		catch(CFileException* error)
		{
			error->Delete();
			throw GetResString(IDS_ERR_INVALIDPACKAGE);
		}
		catch(CMemoryException* error)
		{
			error->Delete();
			throw CString(_T("Memory exception"));
		}
	}
	catch(CString error)
	{
		if (thePrefs.GetVerbose() && !error.IsEmpty())
			DebugLogWarning(_T("Error: %s - while processing Mod packet: opcode=%s  size=%u; %s"), error, DbgGetMuleClientTCPOpcode(opcode), size, DbgGetClientInfo());
		// Note: don't disconnect cleints on mod prot errors, teh extensions are just addons and if thai fail the cleint will work anyway
		//if (client)
		//	client->SetDownloadState(DS_ERROR, _T("ProcessExtPacket error. ") + error);
		//Disconnect(_T("ProcessExtPacket error. ") + error); 
		//return false;
	}
	return true;
}
// NEO: NMP END <-- Xanatos --


#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
CPortListener::CPortListener()
{
	bListening = false;
	// NEO: SCC - [SecureClinetConnection]
	bSecure = false;
	// obtional DH parameters
	abyPrime = NULL;
	abyBase = 0;
	// NEO: SCC END
	m_port=0;

	m_nPendingConnections = 0;

	mapping = NULL; // NEO: UPNP - [UPnPNat]
}


CPortListener::~CPortListener()
{
	// NEO: UPNP - [UPnPNat]
	if(mapping)
		theApp.RemoveUPnPNatPort(mapping);
	// NEO: UPNP END

	delete [] abyPrime; // NEO: SCC - [SecureClinetConnection]

	Close();
}

// NEO: SCC - [SecureClinetConnection]
using namespace CryptoPP;
void CPortListener::SetCustomDH()
{
	if(abyPrime == NULL)
		abyPrime = new byte[SOCKET_KEY_SIZE];

	CString Prime = theApp.GetProfileString(_T("PortDH"),StrLine(_T("Prime%u"),m_port));
	CString Base = theApp.GetProfileString(_T("PortDH"),StrLine(_T("Base%u"),m_port));
	if(Prime.IsEmpty() || Base.IsEmpty())
	{
		AutoSeededRandomPool rng;
		DH* KeyAgreement = new DH(*(RandomNumberGenerator*)&rng,SOCKET_KEY_SIZE*8);
		Integer integerPrime = KeyAgreement->GetGroupParameters().GetModulus();
		Integer integerBase = KeyAgreement->GetGenerator();

		for (int i=0; i<SOCKET_KEY_SIZE; i++)
			abyPrime[i] = integerPrime.GetByte(SOCKET_KEY_SIZE-(i+1));
		abyBase = integerBase.GetByte(0);

		Prime = EncodeBase16(abyPrime,SOCKET_KEY_SIZE);
		Base = EncodeBase16(&abyBase,1);

		theApp.WriteProfileString(_T("PortDH"),StrLine(_T("Prime%u"),m_port),Prime);
		theApp.WriteProfileString(_T("PortDH"),StrLine(_T("Base%u"),m_port),Base);

		delete KeyAgreement;
	}
	else
	{
		DecodeBase16(Prime,Prime.GetLength(),abyPrime,SOCKET_KEY_SIZE);
		DecodeBase16(Base,Base.GetLength(),&abyBase,1);
	}
}
// NEO: SCC END
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --

CListenSocket::CListenSocket()
{
	maxconnectionreached = 0;
	m_OpenSocketsInterval = 0;
	memset(m_ConnectionStates, 0, sizeof m_ConnectionStates);
	peakconnections = 0;
	totalconnectionchecks = 0;
	averageconnections = 0.0;
	activeconnections = 0;
#ifndef ISPBYPASS // NEO: MP -- Xanatos -->
	bListening = false;
	mapping = NULL; // NEO: UPNP - [UPnPNat]
	m_nPendingConnections = 0;
	m_port=0;
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
	m_nHalfOpen = 0;
	m_nComp = 0;
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
	m_AcceptSocketsLimit=0; // 60*thePrefs.GetMaxConperFive();
	m_CreateSocketsLimit=0; // 40*thePrefs.GetMaxConperFive();
	m_AllSocketsLimit=0; // 80*thePrefs.GetMaxConperFive();
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
}

CListenSocket::~CListenSocket()
{
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	KillAllPorts();
#else
	Close();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
	KillAllSockets();
}

// NEO: MOD -- Xanatos -->
bool CListenSocket::Rebind()
{
	// NEO: MOD - [BindToAdapter]
	//if (thePrefs.GetPort() == m_port)
	//	return false;

#ifdef ISPBYPASS // NEO: MP - [MultiPort]
	KillAllPorts();
#else
	Close(); //KillAllSockets();
#endif // ISPBYPASS // NEO: MP END

	if(!StartListening()){
		LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),thePrefs.GetPort(true)); // NEO: NATS - [NatSupport] <-- Xanatos --
		return false;
	}

	return true;
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
bool CPortListener::Rebind()
{
	Close();
	if(!StartListening(m_port)){
		LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),m_port);
		return false;
	}

	return true;
}
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
// NEO: MOD END <-- Xanatos --

bool CListenSocket::StartListening()
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
{
	if(!StartListening(thePrefs.GetPort(true))) // NEO: NATS - [NatSupport] <-- Xanatos --
		return false;

	if(thePrefs.UseEncryptedPorts()){
		if(thePrefs.GetEncryptedLegacyPort()){ // it may be 0 == dissabled, but it shouldn't
			if(!StartListening(thePrefs.GetEncryptedLegacyPort(),2)) // our legacy port with default DH parameters
				LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),thePrefs.GetEncryptedLegacyPort());
		}

		CString Ports = thePrefs.GetEncryptedPorts(); 
		for(int pos = 0; pos >= 0;){
			CString Port = Ports.Tokenize (_T(","),pos).Trim();
			if (Port.IsEmpty())
				continue;
			int pos2 = Port.Find(_T("-"));
			if(pos2 != -1){ // port range
				uint16 begin = (uint16)_tstoi(Port.Mid(0,pos2));
				uint16 end = (uint16)_tstoi(Port.Mid(pos2+1));
				if(begin && begin < end)
					for(uint16 port = begin; port<=end; port++ )
						if(!StartListening(port,TRUE))
							LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),port);
			}else{ // single port
				uint16 port = (uint16)_tstoi(Port);
				if(port)
					if(!StartListening(port,TRUE))
						LogError(LOG_STATUSBAR, GetResString(IDS_MAIN_SOCKETERROR),port);
			}
		}
	}
	return true;
}

bool CListenSocket::StartListening(uint16 port, BOOL Secure) // NEO: SCC - [SecureClinetConnection]
{
	CPortListener* listner;
	if(!port_map.Lookup(port,listner))
	{
		listner = new CPortListener();
		listner->StartListening(port, Secure); // NEO: SCC - [SecureClinetConnection]
		if(listner->IsListening()){
			ASSERT(port_map[listner->GetConnectedPort()] == NULL);
			port_map.SetAt(listner->GetConnectedPort(),listner); // NEO: NATS - [NatSupport] <-- Xanatos --
		}else{
			delete listner;
			return false;
		}
	}

	return true;
}

bool CPortListener::StartListening(uint16 port, BOOL Secure) // NEO: SCC - [SecureClinetConnection]
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
{
	// Creating the socket with SO_REUSEADDR may solve LowID issues if emule was restarted
	// quickly or started after a crash, but(!) it will also create another problem. If the
	// socket is already used by some other application (e.g. a 2nd emule), we though bind
	// to that socket leading to the situation that 2 applications are listening at the same
	// port!
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	if (!Create(port, SOCK_STREAM, FD_ACCEPT, CT2CA(theApp.GetBindAddress()), FALSE/*bReuseAddr*/)) // NEO: MOD - [BindToAdapter] <-- Xanatos --
#else
	if (!Create(thePrefs.GetPort(true), SOCK_STREAM, FD_ACCEPT, CT2CA(theApp.GetBindAddress()), FALSE/*bReuseAddr*/)) // NEO: MOD - [BindToAdapter] // NEO: NATS - [NatSupport] <-- Xanatos --
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
		return false;

	// Rejecting a connection with conditional WSAAccept and not using SO_CONDITIONAL_ACCEPT
	// -------------------------------------------------------------------------------------
	// recv: SYN
	// send: SYN ACK (!)
	// recv: ACK
	// send: ACK RST
	// recv: PSH ACK + OP_HELLO packet
	// send: RST
	// --- 455 total bytes (depending on OP_HELLO packet)
	// In case SO_CONDITIONAL_ACCEPT is not used, the TCP/IP stack establishes the connection
	// before WSAAccept has a chance to reject it. That's why the remote peer starts to send
	// it's first data packet.
	// ---
	// Not using SO_CONDITIONAL_ACCEPT gives us 6 TCP packets and the OP_HELLO data. We
	// have to lookup the IP only 1 time. This is still way less traffic than rejecting the
	// connection by closing it after the 'Accept'.

	// Rejecting a connection with conditional WSAAccept and using SO_CONDITIONAL_ACCEPT
	// ---------------------------------------------------------------------------------
	// recv: SYN
	// send: ACK RST
	// recv: SYN
	// send: ACK RST
	// recv: SYN
	// send: ACK RST
	// --- 348 total bytes
	// The TCP/IP stack tries to establish the connection 3 times until it gives up. 
	// Furthermore the remote peer experiences a total timeout of ~ 1 minute which is
	// supposed to be the default TCP/IP connection timeout (as noted in MSDN).
	// ---
	// Although we get a total of 6 TCP packets in case of using SO_CONDITIONAL_ACCEPT,
	// it's still less than not using SO_CONDITIONAL_ACCEPT. But, we have to lookup
	// the IP 3 times instead of 1 time.

	//if (thePrefs.GetConditionalTCPAccept() && !thePrefs.GetProxy().UseProxy) {
	//	int iOptVal = 1;
	//	VERIFY( SetSockOpt(SO_CONDITIONAL_ACCEPT, &iOptVal, sizeof iOptVal) );
	//}

	if (!Listen())
		return false;

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	m_port = port;
	// NEO: SCC - [SecureClinetConnection]
	if(Secure)
		bSecure = true; 
	if(Secure == TRUE)
		SetCustomDH();
	// NEO: SCC END
#else
	m_port = thePrefs.GetPort(true); // NEO: NATS - [NatSupport] <-- Xanatos --
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --

	// NEO: IFWS - [ICSFirewall] -- Xanatos -->
	if(thePrefs.GetICFSupport()){
		bool bResult = (theApp.m_pFirewallOpener->OpenPort(m_port, NAT_PROTOCOL_TCP, EMULE_DEFAULTRULENAME_TCP, thePrefs.GetICFClearOnClose() /*|| thePrefs.GetUseRandomPorts()*/));
		theApp.QueueLogLine(false, GetResString(bResult ? IDS_X_FO_TEMPTCP_S : IDS_X_FO_TEMPTCP_F), m_port);
	}
	// NEO: IFWS END <-- Xanatos --

	// NEO: UPNP - [UPnPNat] -- Xanatos -->
	if(mapping)
		theApp.RemoveUPnPNatPort(mapping);

	if (thePrefs.IsUPnPEnabled()){
		mapping = new MyUPnP::UPNPNAT_MAPPING; 
		mapping->ref = &mapping;

		mapping->internalPort = mapping->externalPort = m_port;
		mapping->protocol = MyUPnP::UNAT_TCP;
		mapping->description = EMULE_DEFAULTRULENAME_TCP;
		if (theApp.AddUPnPNatPort(mapping, thePrefs.GetUPnPNatTryRandom()))
			m_port = mapping->externalPort;
	}
	// NEO: UPNP END <-- Xanatos --

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	if(Secure == false)
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
		thePrefs.SetTCPPort(m_port); // NEO: NATS - [NatSupport] <-- Xanatos --

	bListening = true;
	return true;
}

void CListenSocket::ReStartListening()
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
{
	CPortListener* listner;
	uint16 port;
	for (POSITION pos = port_map.GetStartPosition();pos != 0;){
		port_map.GetNextAssoc(pos,port,listner);
		listner->ReStartListening();
	}
}

void CPortListener::ReStartListening()
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
{
	bListening = true;

	ASSERT( m_nPendingConnections >= 0 );
	if (m_nPendingConnections > 0)
	{
		m_nPendingConnections--;
		OnAccept(0);
	}
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
void CPortListener::StopListening()
{
	bListening = false;
	theApp.listensocket->IncMaxConnectionReached();
}
#else
void CListenSocket::StopListening()
{
	bListening = false;
	maxconnectionreached++;
}
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --


static int _iAcceptConnectionCondRejected;

int CALLBACK AcceptConnectionCond(LPWSABUF lpCallerId, LPWSABUF /*lpCallerData*/, LPQOS /*lpSQOS*/, LPQOS /*lpGQOS*/,
								  LPWSABUF /*lpCalleeId*/, LPWSABUF /*lpCalleeData*/, GROUP FAR* /*g*/, DWORD /*dwCallbackData*/)
{
	if (lpCallerId && lpCallerId->buf && lpCallerId->len >= sizeof SOCKADDR_IN)
	{
		LPSOCKADDR_IN pSockAddr = (LPSOCKADDR_IN)lpCallerId->buf;
		ASSERT( pSockAddr->sin_addr.S_un.S_addr != 0 && pSockAddr->sin_addr.S_un.S_addr != INADDR_NONE );

		if (theApp.ipfilter->IsFiltered(pSockAddr->sin_addr.S_un.S_addr)){
			if (thePrefs.GetLogFilteredIPs())
				AddDebugLogLine(false, _T("Rejecting connection attempt (IP=%s) - IP filter (%s)"), ipstr(pSockAddr->sin_addr.S_un.S_addr), theApp.ipfilter->GetLastHit());
			_iAcceptConnectionCondRejected = 1;
			return CF_REJECT;
		}

		if (theApp.clientlist->IsBannedClient(pSockAddr->sin_addr.S_un.S_addr)){
			if (thePrefs.GetLogBannedClients()){
				CUpDownClient* pClient = theApp.clientlist->FindClientByIP(pSockAddr->sin_addr.S_un.S_addr);
				AddDebugLogLine(false, _T("Rejecting connection attempt of banned client %s %s"), ipstr(pSockAddr->sin_addr.S_un.S_addr), pClient->DbgGetClientInfo());
			}
			_iAcceptConnectionCondRejected = 2;
			return CF_REJECT;
		}
	}
	else {
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Client TCP socket: AcceptConnectionCond unexpected lpCallerId"));
	}

	return CF_ACCEPT;
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
void CPortListener::OnAccept(int nErrorCode)
#else
void CListenSocket::OnAccept(int nErrorCode)
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
{
	if (!nErrorCode)
	{
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
		if(thePrefs.IsIncludeTCPAck())
			theApp.bandwidthControl->AddDownIP(); // SYN
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
		m_nPendingConnections++;
		if (m_nPendingConnections < 1){
			ASSERT(0);
			m_nPendingConnections = 1;
		}

		if (theApp.listensocket->TooManySockets(true) && !theApp.serverconnect->IsConnecting()){ // NEO: MP - [MultiPort] <-- Xanatos --
			StopListening();
			return;
		}
		else if (!bListening)
			ReStartListening(); //If the client is still at maxconnections, this will allow it to go above it.. But if you don't, you will get a lowID on all servers.


		uint32 nFataErrors = 0;
		while (m_nPendingConnections > 0)
		{
			m_nPendingConnections--;
			CClientReqSocket* newclient;
			SOCKADDR_IN SockAddr = {0};
			int iSockAddrLen = sizeof SockAddr;
			if (thePrefs.GetConditionalTCPAccept() && !thePrefs.GetProxySettings().UseProxy)
			{
				_iAcceptConnectionCondRejected = 0;
				SOCKET sNew = WSAAccept(m_SocketData.hSocket, (SOCKADDR*)&SockAddr, &iSockAddrLen, AcceptConnectionCond, 0);
				if (sNew == INVALID_SOCKET){
				    DWORD nError = GetLastError();
				    if (nError == WSAEWOULDBLOCK){
					    DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections);
					    m_nPendingConnections = 0;
					    break;
				    }
				    else{
						if (nError != WSAECONNREFUSED || _iAcceptConnectionCondRejected == 0){
						    DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
							nFataErrors++;
						}
						else if (_iAcceptConnectionCondRejected == 1)
							theStats.filteredclients++;
				    }
				    if (nFataErrors > 10){
					    // the question is what todo on a error. We cant just ignore it because then the backlog will fill up
					    // and lock everything. We can also just endlos try to repeat it because this will lock up eMule
					    // this should basically never happen anyway
					    // however if we are in such a position, try to reinitalize the socket.
					    DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
						Rebind(); // NEO: MOD <-- Xanatos --
					    //Close();
					    //StartListening();
					    m_nPendingConnections = 0;
					    break;
				    }
					continue;
				}
				newclient = new CClientReqSocket;

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
				if(bSecure){ // On secure AUX ports we accept only encrpyted connections
					newclient->m_Encryption = new CSocketCryptor();
					if(abyPrime) // if this is a high security socket
						newclient->m_Encryption->SetDH(abyPrime, abyBase);
				}
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
				VERIFY( ((CTCPSocket*)newclient->m_Socket)->InitAsyncSocketExInstance() );
				((CTCPSocket*)newclient->m_Socket)->m_SocketData.hSocket = sNew;
				((CTCPSocket*)newclient->m_Socket)->AttachHandle(sNew);
#else
				VERIFY( newclient->InitAsyncSocketExInstance() );
				newclient->m_SocketData.hSocket = sNew;
				newclient->AttachHandle(sNew);
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
				theApp.listensocket->AddConnection(false); // NEO: MP - [MultiPort] <-- Xanatos --
#else
				theApp.listensocket->AddConnection(); // NEO: MP - [MultiPort] <-- Xanatos --
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
			}
			else
			{
				newclient = new CClientReqSocket;
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
			    if (!Accept(*((CTCPSocket*)newclient->m_Socket), (SOCKADDR*)&SockAddr, &iSockAddrLen)){
#else
			    if (!Accept(*newclient, (SOCKADDR*)&SockAddr, &iSockAddrLen)){
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
				    newclient->Safe_Delete();
				    DWORD nError = GetLastError();
				    if (nError == WSAEWOULDBLOCK){
					    DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections);
					    m_nPendingConnections = 0;
					    break;
				    }
				    else{
					    DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
					    nFataErrors++;
				    }
				    if (nFataErrors > 10){
					    // the question is what todo on a error. We cant just ignore it because then the backlog will fill up
					    // and lock everything. We can also just endlos try to repeat it because this will lock up eMule
					    // this should basically never happen anyway
					    // however if we are in such a position, try to reinitalize the socket.
					    DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
						Rebind(); // NEO: MOD <-- Xanatos --
					    //Close();
					    //StartListening();
					    m_nPendingConnections = 0;
					    break;
				    }
				    continue;
				}
	    
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
				theApp.listensocket->AddConnection(false); // NEO: MP - [MultiPort] <-- Xanatos --
#else
				theApp.listensocket->AddConnection(); // NEO: MP - [MultiPort] <-- Xanatos --
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
    
			    if (SockAddr.sin_addr.S_un.S_addr == 0) // for safety..
			    {
				    iSockAddrLen = sizeof SockAddr;
				    newclient->GetPeerName((SOCKADDR*)&SockAddr, &iSockAddrLen);
				    DebugLogWarning(_T("SockAddr.sin_addr.S_un.S_addr == 0;  GetPeerName returned %s"), ipstr(SockAddr.sin_addr.S_un.S_addr));
			    }
    
			    ASSERT( SockAddr.sin_addr.S_un.S_addr != 0 && SockAddr.sin_addr.S_un.S_addr != INADDR_NONE );
    
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
				// JP detect fake HighID
				// MOD BEGIN netfinity: Fake HighID
				if (IsGoodIP(SockAddr.sin_addr.S_un.S_addr, true))
					thePrefs.HighIDConfirmed = true;
				// MOD END netfinity
#endif // NEO: WC END <-- Xanatos --
			    if (
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
				!theApp.lancast->IsLanIP(SockAddr.sin_addr.S_un.S_addr) &&
#endif //LANCAST // NEO: NLC END <-- Xanatos --
				 theApp.ipfilter->IsFiltered(SockAddr.sin_addr.S_un.S_addr)
				 ){
				    if (thePrefs.GetLogFilteredIPs())
					    AddDebugLogLine(false, _T("Rejecting connection attempt (IP=%s) - IP filter (%s)"), ipstr(SockAddr.sin_addr.S_un.S_addr), theApp.ipfilter->GetLastHit());
				    newclient->Safe_Delete();
				    theStats.filteredclients++;
				    continue;
			    }
    
			    if (theApp.clientlist->IsBannedClient(SockAddr.sin_addr.S_un.S_addr)){
				    if (thePrefs.GetLogBannedClients()){
					    CUpDownClient* pClient = theApp.clientlist->FindClientByIP(SockAddr.sin_addr.S_un.S_addr);
					    AddDebugLogLine(false, _T("Rejecting connection attempt of banned client %s %s"), ipstr(SockAddr.sin_addr.S_un.S_addr), pClient->DbgGetClientInfo());
				    }
				    newclient->Safe_Delete();
				    continue;
			    }
			}
			newclient->AsyncSelect(FD_WRITE | FD_READ | FD_CLOSE);

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
			if(bSecure){ // On secure AUX ports we accept only encrpyted connections
				newclient->m_Encryption = new CSocketCryptor();
				if(abyPrime) // if this is a high security socket
					newclient->m_Encryption->SetDH(abyPrime, abyBase);
			}
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
			if(thePrefs.IsLancastEnabled() && theApp.lancast->IsLanIP(SockAddr.sin_addr.S_un.S_addr))
				newclient->SetOnLan();
#endif //LANCAST // NEO: NLC END <-- Xanatos --

			// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
			if(thePrefs.IsTCPDisableNagle()){
				BOOL noDelay = true;
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
				newclient->m_Socket->SetSockOpt(TCP_NODELAY, &noDelay, sizeof(noDelay), IPPROTO_TCP);
#else
				newclient->SetSockOpt(TCP_NODELAY, &noDelay, sizeof(noDelay), IPPROTO_TCP);
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
			}
			// NEO: NBC END <-- Xanatos --
		}

		ASSERT( m_nPendingConnections >= 0 );
	}
}

void CListenSocket::Process()
{
	m_OpenSocketsInterval = 0;
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if(thePrefs.IsWebCacheEnabled()){
		if( !SINGLEProxyClient )
			WebCachedBlockList.TryToDL();
		else
			SINGLEProxyClient->CheckDownloadTimeout();
	}
#endif // NEO: WC END <-- Xanatos --
	for (POSITION pos = socket_list.GetHeadPosition(); pos; ) // NEO: MOD - [LoopImprovement] <-- Xanatos --
	{
		CClientReqSocket* cur_sock = socket_list.GetNext(pos); // NEO: MOD - [LoopImprovement] <-- Xanatos --
		if (cur_sock->deletethis)
		{
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
			if (cur_sock->m_Socket->IsNatSocket() ? ((CNATSocket*)cur_sock->m_Socket)->IsShutDown() != true : ((CTCPSocket*)cur_sock->m_Socket)->m_SocketData.hSocket != INVALID_SOCKET){
#else
			if (cur_sock->m_SocketData.hSocket != INVALID_SOCKET){
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
				cur_sock->Close();			// calls 'closesocket'
			}
			else{
				cur_sock->Delete_Timed();	// may delete 'cur_sock'
			}
		}
		else{
			cur_sock->CheckTimeOut();		// may call 'shutdown'
		}
	}

	if (!IsListening() // NEO: MOD - [CodeImprovement] <-- Xanatos --
	 && (GetOpenSockets() + 5 < thePrefs.GetMaxConnections() || theApp.serverconnect->IsConnecting()))
		ReStartListening();
}

void CListenSocket::RecalculateStats()
{
	memset(m_ConnectionStates, 0, sizeof m_ConnectionStates);
	for (POSITION pos = socket_list.GetHeadPosition(); pos != NULL; )
	{
		switch (socket_list.GetNext(pos)->GetConState())
		{
			case ES_DISCONNECTED:
				m_ConnectionStates[0]++;
				break;
			case ES_NOTCONNECTED:
				m_ConnectionStates[1]++;
				break;
			case ES_CONNECTED:
				m_ConnectionStates[2]++;
				break;
		}
   }
}

void CListenSocket::AddSocket(CClientReqSocket* toadd)
{
	socket_list.AddTail(toadd);
}

void CListenSocket::RemoveSocket(CClientReqSocket* todel)
{
	for (POSITION pos = socket_list.GetHeadPosition(); pos != NULL; )
	{
		POSITION posLast = pos;
		if (socket_list.GetNext(pos) == todel)
			socket_list.RemoveAt(posLast);
	}
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
void CListenSocket::KillAllPorts()
{
	CPortListener* cur_listner;
	uint16 port;
	for (POSITION pos = port_map.GetStartPosition();pos != 0;){
		port_map.GetNextAssoc(pos,port,cur_listner);
		port_map.RemoveKey(port);
		delete cur_listner;
	}
}
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --

void CListenSocket::KillAllSockets()
{
	for (POSITION pos = socket_list.GetHeadPosition(); pos != 0; pos = socket_list.GetHeadPosition())
	{
		CClientReqSocket* cur_socket = socket_list.GetAt(pos);
		if (cur_socket->client)
			delete cur_socket->client;
		else
			delete cur_socket;
	}
}

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
void CListenSocket::AddConnection(bool created){
	if(!created && thePrefs.IsIncludeTCPAck()){
		theApp.bandwidthControl->AddUpIP();
		theApp.bandwidthControl->AddDownIP(); // We dont got the packet now, but we expect to get it soon
	}

	// Experimental Socket Overhead
	if (created) 
		m_CreateSocketsLimit-=100;
	else
		m_AcceptSocketsLimit-=100;
	if (m_AcceptSocketsLimit > 0)
		m_AllSocketsLimit-=100;

	m_OpenSocketsInterval++;
	//opensockets++;
}
#else
void CListenSocket::AddConnection()
{
	m_OpenSocketsInterval++;
}
#endif // NEO_BC // NEO: NBC END <-- Xanatos --

bool CListenSocket::TooManySockets(bool bIgnoreInterval)
{
	if (   GetOpenSockets() > thePrefs.GetMaxConnections()
		|| (m_OpenSocketsInterval > (thePrefs.GetMaxConperFive() * GetMaxConperFiveModifier()) && !bIgnoreInterval)
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
		|| ((m_CreateSocketsLimit < 100 || m_AllSocketsLimit < 100) && !bIgnoreInterval)
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
		|| (m_nHalfOpen >= thePrefs.GetMaxHalfConnections() && !bIgnoreInterval))
		return true;
	return false;
}

// NEO: OCC - [ObelixConnectionControl] -- Xanatos -->
bool CListenSocket::TooManySocketsOCC(){

	static bool LockOCC = false;
	//added by Obelix. Not very pretty, but a*3>b*4 is at least 3 times faster than a*.75>b and 2 times faster than a*3/4>b
	//ActiveConnections > 75% MaxConnetions 
	const float Ctrl = (float)thePrefs.GetObelixConnectionControlValue()/100;
	if((thePrefs.GetMaxConnections()*Ctrl < GetOpenSockets())){
		LockOCC = true;
		return true;
	}else{
		if(LockOCC){
			const float LockCtrl = ((float)(thePrefs.GetObelixConnectionControlValue()*3)/(100*4));
			if((thePrefs.GetMaxConnections()*LockCtrl < GetOpenSockets()))
				return true;
			else
				LockOCC = false;
		}
		return false;
	}
}
// NEO: OCC END <-- Xanatos --

bool CListenSocket::IsValidSocket(CClientReqSocket* totest)
{
	return socket_list.Find(totest) != NULL;
}

#ifdef _DEBUG
void CListenSocket::Debug_ClientDeleted(CUpDownClient* deleted)
{
	for (POSITION pos = socket_list.GetHeadPosition(); pos != NULL;)
	{
		CClientReqSocket* cur_sock = socket_list.GetNext(pos);
		if (!AfxIsValidAddress(cur_sock, sizeof(CClientReqSocket)))
			AfxDebugBreak();
		if (thePrefs.m_iDbgHeap >= 2)
			ASSERT_VALID(cur_sock);
		if (cur_sock->client == deleted)
			AfxDebugBreak();
	}
}
#endif

void CListenSocket::UpdateConnectionsStatus()
{
	activeconnections = GetOpenSockets();
	if (peakconnections < activeconnections)
		peakconnections = activeconnections;
	if (peakconnections > thePrefs.GetConnPeakConnections())
		thePrefs.SetConnPeakConnections(peakconnections);
	if (theApp.IsWorkingAllowed()) // NEO: SO - [StandAlone] <-- Xanatos --
	{
		totalconnectionchecks++;
		float percent = (float)(totalconnectionchecks - 1) / (float)totalconnectionchecks;
		if (percent > 0.99F)
			percent = 0.99F;
		averageconnections = (averageconnections * percent) + (float)activeconnections * (1.0F - percent);
	}
}

float CListenSocket::GetMaxConperFiveModifier()
{
	float SpikeSize = GetOpenSockets() - averageconnections;
	if (SpikeSize < 1.0F)
		return 1.0F;

	float SpikeTolerance = 25.0F * (float)thePrefs.GetMaxConperFive() / 10.0F;
	if (SpikeSize > SpikeTolerance)
		return 0;

	float Modifier = 1.0F - SpikeSize / SpikeTolerance;
	return Modifier;
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
uint16 CListenSocket::GetSecretPort(bool bPublic)
{
	if(port_map.GetCount() == 0)
		return 0;

	if(bPublic){
		CPortListener* listner;
		if(port_map.Lookup(thePrefs.GetEncryptedLegacyPort(),listner))
			return listner->GetConnectedPort();
		else
			return 0;
	}

	srand( (unsigned)time( NULL ) );
	int index = (rand()%(port_map.GetCount()));

	CPortListener* cur_listner;
	uint16 port = 0;
	uint16 port_prev = 0;
	for (POSITION pos = port_map.GetStartPosition();pos != 0;){
		port_prev = port;
		port_map.GetNextAssoc(pos,port,cur_listner);
		if(index == 0){
			if(cur_listner->m_port != thePrefs.GetPort())
				return cur_listner->m_port;
			else if(pos == NULL)
				return port_prev;
		}else
			index--;
	}

	ASSERT(0);
	return 0;
}

bool CListenSocket::GetSecretPortDH(uint16 port, byte* &abyPrime, byte &abyBase)
{
	CPortListener* listner;
	if(port_map.Lookup(port,listner) && listner->abyPrime){
		abyPrime = listner->abyPrime;
		abyBase = listner->abyBase;
		return true;
	}
	return false;
}

uint16 CListenSocket::GetConnectedPort()
{
	CPortListener* listner;
	if(port_map.Lookup(thePrefs.GetPort(),listner))
		return listner->GetConnectedPort();
	return 0;
}

bool CListenSocket::IsListening(uint16 port)
{
	if(port == 0)
		port = thePrefs.GetPort();
	CPortListener* listner;
	if(port_map.Lookup(port,listner))
		return listner->IsListening();
	return false;
}
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --

#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
void CListenSocket::SetLimitForConnections(){
	if (thePrefs.IsManageConnections() && !thePrefs.OnQuickStart()){ // NEO: QS - [QuickStart]
		float	factor = thePrefs.GetManageConnectionsFactor();

		int upload = (int)(theApp.bandwidthControl->GetMaxUpload() * 4 * factor);
		int download = (int)(theApp.bandwidthControl->GetMaxDownload() * 4 * factor);
		int limit = upload;
		if (limit > download)
			limit = download;
		if (limit < (int)(20 * factor))
			limit = (int)(20 * factor);
		if (limit > (int)(1000 * factor))
			limit = (int)(1000 * factor);

		if (m_CreateSocketsLimit > 0 && m_CreateSocketsLimit < min(8 * limit, 500 * factor))
			m_CreateSocketsLimit += limit*3;
		else
			m_CreateSocketsLimit = limit*3;

		if (m_AcceptSocketsLimit > 0 && m_AcceptSocketsLimit < min(16 * limit, 500 * factor))
			m_AcceptSocketsLimit += limit*4;
		else
			m_AcceptSocketsLimit = limit*4;

		if (m_AllSocketsLimit > 0 && m_AllSocketsLimit < min(16 * limit, 500 * factor))
			m_AllSocketsLimit += limit*5;
		else
			m_AllSocketsLimit = limit*5;
	}
	else {
		m_AcceptSocketsLimit = 0x7fffffff;
		m_CreateSocketsLimit = 0x7fffffff;
		m_AllSocketsLimit = 0x7fffffff;
	}
}
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
