//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 "emule.h"
#include <zlib/zlib.h>
#include "UpDownClient.h"
#include "PartFile.h"
#include "OtherFunctions.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "Preferences.h"
#include "SafeFile.h"
#include "Packets.h"
#include "Statistics.h"
#include "ClientCredits.h"
#include "DownloadQueue.h"
#include "ClientUDPSocket.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "PeerCacheFinder.h"
#include "Exceptions.h"
#include "clientlist.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "Kademlia/Kademlia/Search.h"
#include "SHAHashSet.h"
#include "SharedFileList.h"
#include "Log.h"
#include "Neo/NeoOpCodes.h"// NEO: NXI - [NeoExtraInfo] <-- Xanatos --
#include "Neo/Edt.h" // NEO: EDT - [EstimatedDownloadTime] <-- 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 NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
#include <math.h>
#endif // NEO_SS // NEO: NSS END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#include "Neo/ClientFileStatus.h"// NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
#include "Neo/WebCache/WebCacheSocket.h" // yonatan http
#endif // NEO: WC END <-- Xanatos --
#include "Neo/Functions.h" // NEO: MOD <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
#include "Neo/AbstractSocket.h"
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --

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

//	members of CUpDownClient
//	which are mainly used for downloading functions 
CBarShader CUpDownClient::s_StatusBar(16);
// NEO: MFSB - [MultiFileStatusBars] -- Xanatos -->
//void CUpDownClient::DrawStatusBar(CDC* dc, LPCRECT rect, bool onlygreyrect, bool  bFlat) const
void CUpDownClient::DrawStatusBar(CDC* dc, LPCRECT rect, CPartFile* file, bool  bFlat) const
{
	if (g_bLowColorDesktop)
		bFlat = true;

	COLORREF crNeither;
	if (bFlat) {
		if (g_bLowColorDesktop)
			crNeither = RGB(192, 192, 192);
		else
			crNeither = RGB(224, 224, 224);
	} else {
		crNeither = RGB(240, 240, 240);
	}

	ASSERT(file);
	if(file == NULL)
		return;

	s_StatusBar.SetFileSize(file->GetFileSize());
	s_StatusBar.SetHeight(rect->bottom - rect->top);
	s_StatusBar.SetWidth(rect->right - rect->left);
	s_StatusBar.Fill(crNeither);

	// NEO: SCFS - [SmartClientFileStatus]
	CClientFileStatus* status = GetFileStatus(file);

	uint8* thisAbyPartStatus = status ? status->GetPartStatus() : NULL;
	uint8* thisAbyIncPartStatus = status ? status->GetPartStatus(CFS_Incomplete) : NULL; // NEO: ICS - [InteligentChunkSelection]
	uint8* thisAbyHidenPartStatus = status ? status->GetPartStatus(CFS_Hiden) : NULL; // NEO: RPS - [RealPartStatus]
	uint8* thisAbyBlockedPartStatus = status ? status->GetPartStatus(CFS_Blocked) : NULL; // NEO: RPS - [RealPartStatus]
	uint8* thisAbySeenPartStatus = status ? status->GetPartStatus(CFS_History) : NULL; // NEO: AHOS - [AntiHideOS]
	// NEO: SCFS END

	uint16	abyfilesize = 0; // NEO: MOD - [Percentage]

	if (thisAbyPartStatus
	  || thisAbyIncPartStatus // NEO: ICS - [InteligentChunkSelection]
	  || thisAbyHidenPartStatus // NEO: RPS - [RealPartStatus]
	  || thisAbyBlockedPartStatus // NEO: RPS - [RealPartStatus]
	  || thisAbySeenPartStatus // NEO: AHOS - [AntiHideOS]
		) {
		COLORREF crBoth;
		COLORREF crClientOnly;
		COLORREF crClientOnlyBlocks; // NEO: SCT - [SubChunkTransfer]
		COLORREF crPending;
		COLORREF crNextPending;
		COLORREF crMeOnly; // NEO: MOD - [SeeTheNeed]
		COLORREF crClientPartial; // NEO: ICS - [InteligentChunkSelection]
		COLORREF crSeen; // NEO: AHOS - [AntiHideOS]
		COLORREF crHiden; // NEO: RPS - [RealPartStatus]
		COLORREF crBlocked; // NEO: RPS - [RealPartStatus]
		COLORREF crA4AF;

		if (g_bLowColorDesktop) {
			crBoth = RGB(0, 0, 0);
			crClientOnly = RGB(0, 0, 255);
			crClientOnlyBlocks = RGB(128, 128, 255); // NEO: SCT - [SubChunkTransfer]
			crPending = RGB(0, 255, 0);
			crNextPending = RGB(255, 255, 0);
			crMeOnly = RGB(112,112,112); // NEO: MOD - [SeeTheNeed]
			crClientPartial = RGB(170,50,224); // NEO: ICS - [InteligentChunkSelection]
			crHiden = RGB(128,255,128); // NEO: RPS - [RealPartStatus]
			crBlocked = RGB(255,128,192); // NEO: RPS - [RealPartStatus]
			crSeen = RGB(255,240,240); // NEO: AHOS - [AntiHideOS]
			crA4AF = RGB(192, 100, 255);
		} else if (bFlat) {
			crBoth = RGB(0, 0, 0);
			crClientOnly = RGB(0, 100, 255);
			crClientOnlyBlocks = RGB(128, 128, 255); // NEO: SCT - [SubChunkTransfer]
			crPending = RGB(0,150,0);
			crNextPending = RGB(255,208,0);
			crMeOnly = RGB(112,112,112); // NEO: MOD - [SeeTheNeed]
			crClientPartial = RGB(170,50,224); // NEO: ICS - [InteligentChunkSelection]
			crHiden = RGB(128,255,128); // NEO: RPS - [RealPartStatus]
			crBlocked = RGB(255,128,192); // NEO: RPS - [RealPartStatus]
			crSeen = RGB(255,240,240); // NEO: AHOS - [AntiHideOS]
			crA4AF = RGB(192, 100, 255);
		} else {
			crBoth = RGB(104, 104, 104);
			crClientOnly = RGB(0, 100, 255);
			crClientOnlyBlocks = RGB(128, 128, 255); // NEO: SCT - [SubChunkTransfer]
			crPending = RGB(0, 150, 0);
			crNextPending = RGB(255,208,0);
			crMeOnly = RGB(172,172,172); // NEO: MOD - [SeeTheNeed]
			crClientPartial = RGB(170,50,224); // NEO: ICS - [InteligentChunkSelection]
			crHiden = RGB(128,255,128); // NEO: RPS - [RealPartStatus]
			crBlocked = RGB(255,128,192); // NEO: RPS - [RealPartStatus]
			crSeen = RGB(255,240,240); // NEO: AHOS - [AntiHideOS]
			crA4AF = RGB(192, 100, 255);
		}

		char* pcNextPendingBlks = NULL;
		if (m_nDownloadState == DS_DOWNLOADING && file == reqfile){
			pcNextPendingBlks = new char[file->GetPartCount()];
			memset(pcNextPendingBlks, 'N', file->GetPartCount()); // do not use '_strnset' for uninitialized memory!
			for (POSITION pos = m_PendingBlocks_list.GetHeadPosition(); pos != 0; ){
				UINT uPart = (UINT)(m_PendingBlocks_list.GetNext(pos)->block->StartOffset / PARTSIZE);
				if (uPart < file->GetPartCount())
					pcNextPendingBlks[uPart] = 'Y';
			}
		}

		tBlockMap* BlockMap; // NEO: SCT - [SubChunkTransfer]

		for (UINT i = 0;i < file->GetPartCount();i++){
			if (thisAbyPartStatus && thisAbyPartStatus[i]){ // NEO: ICS - [InteligentChunkSelection]
				uint64 uEnd;
				if (PARTSIZE*(uint64)(i+1) > file->GetFileSize())
					uEnd = file->GetFileSize();
				else
					uEnd = PARTSIZE*(uint64)(i+1);

				abyfilesize++; // NEO: MOD - [Percentage]

				if (file->IsComplete(PARTSIZE*(uint64)i,PARTSIZE*(uint64)(i+1)-1, false))
					s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crBoth);
				else if (file == reqfile)
				{	
					if (m_nDownloadState == DS_DOWNLOADING && m_nLastBlockOffset >= PARTSIZE*(uint64)i && m_nLastBlockOffset < uEnd)
						s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crPending);
					else if (pcNextPendingBlks != NULL && pcNextPendingBlks[i] == 'Y')
						s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crNextPending);
					else
						s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crClientOnly);
				}
				else
					s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crA4AF);
			}
			// NEO: ICS - [InteligentChunkSelection]
			else if (thisAbyIncPartStatus && thisAbyIncPartStatus[i]){
				uint64 uEnd;
				if ((uint32)PARTSIZE*(uint64)(i+1) > file->GetFileSize()) 
					uEnd = file->GetFileSize(); 
				else 
					uEnd = PARTSIZE*(uint64)(i+1); 
				s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crClientPartial);
				// NEO: SCT - [SubChunkTransfer]
				if (status->GetBlockMap(i,&BlockMap))
				{
					for (uint8 j = 0; j < 53; j++)
					{
						uint64 uStart;
						if(PARTSIZE*(uint64)i + EMBLOCKSIZE*(uint64)j < PARTSIZE*(uint64)i)
							uStart = PARTSIZE*(uint64)i;
						else
							uStart = PARTSIZE*(uint64)i + EMBLOCKSIZE*(uint64)j;
						uint64 uEnd;
						if (PARTSIZE*(uint64)i + EMBLOCKSIZE*(uint64)(j+1) > (uint64) file->GetFileSize())
							uEnd = file->GetFileSize();
						else
							uEnd = PARTSIZE*(uint64)i + EMBLOCKSIZE*(uint64)(j+1);
						if (BlockMap->IsBlockDone(j))
						{
							if (file->IsComplete(uStart, uEnd - 1, false))
								s_StatusBar.FillRange(uStart, uEnd, crBoth);
							else if (m_nDownloadState == DS_DOWNLOADING && m_nLastBlockOffset >= uStart && m_nLastBlockOffset < uEnd  && file == reqfile)
								s_StatusBar.FillRange(uStart, uEnd, crPending);
							else if (pcNextPendingBlks != NULL && pcNextPendingBlks[i] == 'Y')
								s_StatusBar.FillRange(uStart, uEnd, crNextPending);
							else
								s_StatusBar.FillRange(uStart, uEnd, crClientOnlyBlocks);
						}
					}
				}
				// NEO: SCT END
			}
			// NEO: ICS END
			// NEO: RPS - [RealPartStatus]
			else if (thisAbyHidenPartStatus && thisAbyHidenPartStatus[i]){
				uint64 uEnd;
				if ((uint32)PARTSIZE*(uint64)(i+1) > file->GetFileSize()) 
					uEnd = file->GetFileSize(); 
				else 
					uEnd = PARTSIZE*(uint64)(i+1); 

				abyfilesize++; // NEO: MOD - [Percentage]

				s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crHiden);
			}
			else if (thisAbyBlockedPartStatus && thisAbyBlockedPartStatus[i]){
				uint64 uEnd;
				if ((uint32)PARTSIZE*(uint64)(i+1) > file->GetFileSize()) 
					uEnd = file->GetFileSize(); 
				else 
					uEnd = PARTSIZE*(uint64)(i+1); 
				
				abyfilesize++; // NEO: MOD - [Percentage]

				s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crBlocked);
			}
			// NEO: PRS END
			// NEO: AHOS - [AntiHideOS]
			else if (thisAbySeenPartStatus && thisAbySeenPartStatus[i]){
				uint64 uEnd;
				if (PARTSIZE*(uint64)(i+1) > file->GetFileSize())
					uEnd = file->GetFileSize(); 
				else 
					uEnd = PARTSIZE*(uint64)(i+1); 

				abyfilesize++; // NEO: MOD - [Percentage]

				s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crSeen);				
			}
			// NEO: AHOS END
			// NEO: MOD - [SeeTheNeed]
			else if (file->IsComplete(PARTSIZE*(uint64)i,PARTSIZE*(uint64)(i+1)-1,false)){ 
				uint64 uEnd; 
				if ((uint64)(PARTSIZE*(uint64)(i+1)) > file->GetFileSize()) 
					uEnd = file->GetFileSize(); 
				else 
					uEnd = PARTSIZE*(uint64)(i+1); 

				s_StatusBar.FillRange(PARTSIZE*(uint64)i, uEnd, crMeOnly);
			} 
			// NEO: MOD END
		}
		delete[] pcNextPendingBlks;
	}
	s_StatusBar.Draw(dc, rect->left, rect->top, bFlat);

	// NEO: MOD - [Percentage]
	if(thePrefs.ShowClientPercentage() && file->GetPartCount())
	{
		float percent = (float)abyfilesize*100.0f/file->GetPartCount();
		if (percent > 0.05f)
		{
			CString buffer;
			CRect rc(rect);
			COLORREF oldclr = dc->SetTextColor(RGB(0,0,0));
			int iOMode = dc->SetBkMode(TRANSPARENT);
			buffer.Format(_T("%.1f%%"), percent);
			CFont *pOldFont = dc->SelectObject(&theApp.emuledlg->transferwnd->downloadlistctrl.m_fontSmall);

			#define DLC_DT_TEXT (DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX|DT_END_ELLIPSIS)
			rc.OffsetRect(-1,0);
			dc->DrawText(buffer, buffer.GetLength(), rc, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
			rc.OffsetRect(2,0);
			dc->DrawText(buffer, buffer.GetLength(), rc, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
			rc.OffsetRect(-1,-1);
			dc->DrawText(buffer, buffer.GetLength(), rc, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
			rc.OffsetRect(0,2);
			dc->DrawText(buffer, buffer.GetLength(), rc, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
			rc.OffsetRect(0,-1);
			dc->SetTextColor(RGB(230,230,230));
			dc->DrawText(buffer, buffer.GetLength(), rc, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);

			dc->SelectObject(pOldFont);
			dc->SetBkMode(iOMode);
			dc->SetTextColor(oldclr);
		}
	}
	// NEO: MOD END
} 
// NEO: MFSB END <-- Xanatos --

bool CUpDownClient::Compare(const CUpDownClient* tocomp, bool bIgnoreUserhash) const
{
	//Compare only the user hash..
	if(!bIgnoreUserhash && HasValidHash() && tocomp->HasValidHash())
	    return !md4cmp(this->GetUserHash(), tocomp->GetUserHash());

	if (HasLowID())
	{
		//User is firewalled.. Must do two checks..
		if (GetIP()!=0	&& GetIP() == tocomp->GetIP())
		{
			//The IP of both match
            if (GetUserPort()!=0 && GetUserPort() == tocomp->GetUserPort())
				//IP-UserPort matches
                return true;
			if (GetKadPort()!=0	&& GetKadPort() == tocomp->GetKadPort())
				//IP-KadPort Matches
				return true;
		}
        if (GetUserIDHybrid()!=0
			&& GetUserIDHybrid() == tocomp->GetUserIDHybrid()
			&& GetServerIP()!=0
			&& GetServerIP() == tocomp->GetServerIP()
			&& GetServerPort()!=0
			&& GetServerPort() == tocomp->GetServerPort())
			//Both have the same lowID, Same serverIP and Port..
            return true;

#if defined(_DEBUG)
		if ( HasValidBuddyID() && tocomp->HasValidBuddyID() )
		{
			//JOHNTODO: This is for future use to see if this will be needed...
			if(!md4cmp(GetBuddyID(), tocomp->GetBuddyID()))
				return true;
		}
#endif

		//Both IP, and Server do not match..
		return false;
    }

	//User is not firewalled.
    if (GetUserPort()!=0)
	{
		//User has a Port, lets check the rest.
		if (GetIP() != 0 && tocomp->GetIP() != 0)
		{
			//Both clients have a verified IP..
			if(GetIP() == tocomp->GetIP() && GetUserPort() == tocomp->GetUserPort())
				//IP and UserPort match..
				return true;
		}
		else
		{
			//One of the two clients do not have a verified IP
			if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetUserPort() == tocomp->GetUserPort())
				//ID and Port Match..
                return true;
		}
    }
	if(GetKadPort()!=0)
	{
		//User has a Kad Port.
		if(GetIP() != 0 && tocomp->GetIP() != 0)
		{
			//Both clients have a verified IP.
			if(GetIP() == tocomp->GetIP() && GetKadPort() == tocomp->GetKadPort())
				//IP and KadPort Match..
				return true;
		}
		else
		{
			//One of the users do not have a verified IP.
            if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetKadPort() == tocomp->GetKadPort())
				//ID and KadProt Match..
                return true;
		}
	}
	//No Matches..
	return false;
}

// Return bool is not if you asked or not..
// false = Client was deleted!
// true = client was not deleted!
bool CUpDownClient::AskForDownload(bool bIgnoreConLimit) // NEO: MCH - [ManualClientHandling] <-- Xanatos --
{
	bool socketinitiated = (socket && socket->IsConnected()); // NEO: MOD <-- Xanatos --
	if (theApp.listensocket->TooManySockets(bIgnoreConLimit) && !socketinitiated ) // NEO: MCH - [ManualClientHandling] <-- Xanatos --
	{
		if (GetDownloadState() != DS_TOOMANYCONNS)
			SetDownloadState(DS_TOOMANYCONNS);
		return true;
	}

	if (m_bUDPPending)
	{
		m_nFailedUDPPackets++;
		theApp.downloadqueue->AddFailedUDPFileReasks();
	}
	m_bUDPPending = false;

	// NEO: SD - [StandByDL] -- Xanatos -->
	if(m_byFileRequestState == FR_STANDBY && socketinitiated){ // NEO: USPS - [UnSolicitedPartStatus]
		SendStartupLoadReq(); // we have a socket and we had asked, so we can nw finish the reask
		return true;
	}
	// NEO: SD END <-- Xanatos -->

    SwapToAnotherFile(_T("A4AF check before tcp file reask. CUpDownClient::AskForDownload()"), true, false, false, NULL, true, true);
	SetDownloadState(DS_CONNECTING);
	return TryToConnect(bIgnoreConLimit); // NEO: MCH - [ManualClientHandling] <-- Xanatos --
}

bool CUpDownClient::IsSourceRequestAllowed() const
{
	// NEO: MSH - [ManualSourceHandling] -- Xanatos -->
	if(reqfile->IsCollectXSSources())
		return true;
	// NEO: MSH END <-- Xanatos --
    return IsSourceRequestAllowed(reqfile);
}

bool CUpDownClient::IsSourceRequestAllowed(CPartFile* partfile, bool sourceExchangeCheck) const
{
	DWORD dwTickCount = ::GetTickCount() + CONNECTION_LATENCY;
	unsigned int nTimePassedClient = dwTickCount - GetLastAskedForSources(); // GetLastSrcAnswerTime(); // NEO: FIX <-- Xanatos --
	unsigned int nTimePassedFile   = dwTickCount - partfile->GetLastAnsweredTime();
	bool bNeverAskedBefore = GetLastAskedForSources() == 0;
	bool bCompleteSource = IsCompleteSource(partfile); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#if defined(NEO_SS) || defined(NEO_SK) // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
	UINT uSources = partfile->GetActiveSourceCount();
#else
	UINT uSources = partfile->GetSourceCount();
#endif // NEO_SS // NEO_SK // NEO: NSS END <-- Xanatos --
    UINT uValidSources = partfile->GetValidSourcesCount();

    if (partfile != reqfile) {
        uSources++;
        uValidSources++;
    }

    UINT uReqValidSources = reqfile->GetValidSourcesCount();

	// NEO: NST - [NeoSourceTweaks] -- Xanatos -->
	if(!partfile->PartPrefs.UseXS())
		return false;

	UINT iLimit = (UINT)partfile->PartPrefs.GetXSLimit();
	UINT iIntervals = (UINT)partfile->PartPrefs.GetXSIntervalsMs();
	UINT iCLientIntervals = (UINT)thePrefs.GetXSClientIntervalsMs();
	UINT iRateFile = (UINT)thePrefs.GetRareFileLimit();
	UINT iXSDelay = (UINT)partfile->PartPrefs.GetXSDelayValue();
	// NEO: END <-- Xanatos --

	return (
	         //if client has the correct extended protocol
	         ExtProtocolAvailable() && GetSourceExchangeVersion() > 1 &&
	         //AND if we need more sources
	         iLimit > uSources && // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
	         //AND if...
	         (
	           //source is not complete and file is very rare
	           ( !bCompleteSource
				 && (bNeverAskedBefore || nTimePassedClient > iCLientIntervals /*SOURCECLIENTREASKS*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
			     && (uSources <= (UINT)iRateFile /*RARE_FILE*/ /5)
				 && (!sourceExchangeCheck || partfile == reqfile || uValidSources < uReqValidSources && uReqValidSources > 3)
	           ) ||
	           //source is not complete and file is rare
	           ( !bCompleteSource
				 && (bNeverAskedBefore || nTimePassedClient > iCLientIntervals /*SOURCECLIENTREASKS*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
			     && (uSources <= iRateFile /*RARE_FILE*/  || (!sourceExchangeCheck || partfile == reqfile) && uSources <= RARE_FILE / 2 + uValidSources)
				 && (nTimePassedFile > iIntervals /*SOURCECLIENTREASKF*/) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
				 && (!sourceExchangeCheck || partfile == reqfile || uValidSources < /*SOURCECLIENTREASKS*/iCLientIntervals/iIntervals/*SOURCECLIENTREASKF*/ && uValidSources < uReqValidSources) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
	           ) ||
	           // OR if file is not rare
			   ( (bNeverAskedBefore || nTimePassedClient > (unsigned)(iCLientIntervals /*SOURCECLIENTREASKS*/ * iXSDelay /*MINCOMMONPENALTY*/)) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
				 && (nTimePassedFile > (unsigned)(/*SOURCECLIENTREASKF*/ iIntervals * iXSDelay /*MINCOMMONPENALTY*/)) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
				 && (!sourceExchangeCheck || partfile == reqfile || uValidSources < /*SOURCECLIENTREASKS*/iCLientIntervals/iIntervals/*SOURCECLIENTREASKF*/ && uValidSources < uReqValidSources) // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
	           )
	         )
	       );
}

void CUpDownClient::SendFileRequest()
{
	ASSERT(reqfile != NULL);
	if (!reqfile)
		return;

	// normally asktime has already been reset here, but then SwapToAnotherFile will return without much work, so check to make sure
	SwapToAnotherFile(_T("A4AF check before tcp file reask. CUpDownClient::SendFileRequest()"), true, false, false, NULL, true, true);

	AddAskedCountDown();

	CSafeMemFile dataFileReq(16+16);
	dataFileReq.WriteHash16(reqfile->GetFileHash());

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

	if (SupportMultiPacket())
	{
		if (SupportExtMultiPacket()){
			dataFileReq.WriteUInt64(reqfile->GetFileSize());
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__MultiPacket_Ext", this, reqfile->GetFileHash());
		}
		else{
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__MultiPacket", this, reqfile->GetFileHash());
		}

		// OP_REQUESTFILENAME + ExtInfo
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__MPReqFileName", this, reqfile->GetFileHash());
		dataFileReq.WriteUInt8(OP_REQUESTFILENAME);
		if (GetExtendedRequestsVersion() > 0)
			 // NEO: IPS - [InteligentPartSharing] <-- Xanatos --
			if (reqfile->IsPartFile())
				reqfile->WritePartStatus(&dataFileReq, status);
			else if(!reqfile->WritePartSelection(&dataFileReq, status))
				dataFileReq.WriteUInt16(0);
			// NEO: IPS END <-- Xanatos --
		if (GetExtendedRequestsVersion() > 1)
			reqfile->WriteCompleteSourcesCount(&dataFileReq);

		// OP_SETREQFILEID
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__MPSetReqFileID", this, reqfile->GetFileHash());
		if (reqfile->GetPartCount() > 1)
			dataFileReq.WriteUInt8(OP_SETREQFILEID);

		if (IsEmuleClient())
		{
			SetRemoteQueueFull(true);
			SetRemoteQueueRank(0);
			SetRemoteEDT(0, EDT_UNDEFINED); // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
		}

		// OP_REQUESTSOURCES
		if (IsSourceRequestAllowed())
		{
			if (thePrefs.GetDebugClientTCPLevel() > 0) {
				DebugSend("OP__MPReqSources", this, reqfile->GetFileHash());
				if (GetLastAskedForSources() == 0)
					Debug(_T("  first source request\n"));
				else
					Debug(_T("  last source request was before %s\n"), CastSecondsToHM((GetTickCount() - GetLastAskedForSources())/1000));
			}
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			// David: because official client has a bug, only count the XSReqs under special conditions
			// Note: This will be fixed in future official releases so we will need to add a version check here to
			// remark: this fails for complete sources the first time.. but this doesn't hurt
			if(((status && status->IsCompleteSource()) || !md4cmp(GetUploadFileID(), reqfile->GetFileHash())) //complete source of we want the same file
			 && reqfile->GetValidSourcesCount() > 10) //if we know at least 10 good sources, the remote client should know at least one
				IncXSReqs();
#endif // ARGOS // NEO: NA END <-- Xanatos --
			reqfile->SetLastAnsweredTimeTimeout();
			dataFileReq.WriteUInt8(OP_REQUESTSOURCES);
			SetLastAskedForSources();
			if (thePrefs.GetDebugSourceExchange())
				AddDebugLogLine(false, _T("SXSend: Client source request; %s, File=\"%s\""), DbgGetClientInfo(), reqfile->GetFileName());
		}

		// OP_AICHFILEHASHREQ
		if (IsSupportingAICH())
		{
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__MPAichFileHashReq", this, reqfile->GetFileHash());
			dataFileReq.WriteUInt8(OP_AICHFILEHASHREQ);
		}

		// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
		if(GetNeoModProtVersion() == 0)
			WriteModMultiPacket(&dataFileReq, reqfile, status, true);
		// NEO: NMPm END <-- Xanatos --

		Packet* packet = new Packet(&dataFileReq, OP_EMULEPROT);
		packet->opcode = SupportExtMultiPacket() ? OP_MULTIPACKET_EXT : OP_MULTIPACKET;
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet, true);

		// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
		if(GetNeoModProtVersion())
		{
			CSafeMemFile dataMod(16+16);
			dataMod.WriteHash16(reqfile->GetFileHash());
			// Note: we don't check the size as when the file would miss match 
			//		a flag would be set by the oficial mod prot processor whitch causes the mod packet to be dropped.
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__ModMultiPacket", this, reqfile->GetFileHash());

			WriteModMultiPacket(&dataMod, reqfile, status, true);

			Packet* modpacket = new Packet(&dataMod, OP_MODPROT);
			modpacket->opcode = OP_MODMULTIPACKET;
			theStats.AddUpDataOverheadFileRequest(modpacket->size);
			socket->SendPacket(modpacket, true);
		}
		// NEO: NMPm END <-- Xanatos --
	}
	else
	{
		//This is extended information
		if (GetExtendedRequestsVersion() > 0)
			 // NEO: IPS - [InteligentPartSharing] <-- Xanatos --
			if (reqfile->IsPartFile())
				reqfile->WritePartStatus(&dataFileReq, status);
			else if(!reqfile->WritePartSelection(&dataFileReq, status))
				dataFileReq.WriteUInt16(0);
			// NEO: IPS END <-- Xanatos --
		if (GetExtendedRequestsVersion() > 1)
			reqfile->WriteCompleteSourcesCount(&dataFileReq);

		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__FileRequest", this, reqfile->GetFileHash());
		Packet* packet = new Packet(&dataFileReq);
		packet->opcode = OP_REQUESTFILENAME;
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet, true);

		// 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid).
		// if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we
		// know that the file is shared, we know also that the file is complete and don't need to request the file status.
		if (reqfile->GetPartCount() > 1
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			|| (SupportsWebCache() && thePrefs.IsWebCacheEnabled())	// Superlexx - webcache - webcache-enabled clients might use IFP
#endif // NEO: WC END <-- Xanatos --
		){
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__SetReqFileID", this, reqfile->GetFileHash());
		    CSafeMemFile dataSetReqFileID(16);
			dataSetReqFileID.WriteHash16(reqfile->GetFileHash());
		    packet = new Packet(&dataSetReqFileID);
		    packet->opcode = OP_SETREQFILEID;
		    theStats.AddUpDataOverheadFileRequest(packet->size);
		    socket->SendPacket(packet, true);
		}
	
		if (IsEmuleClient())
		{
			SetRemoteQueueFull(true);
			SetRemoteQueueRank(0);
			SetRemoteEDT(0, EDT_UNDEFINED); // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
		}

		if (IsSourceRequestAllowed())
		{
			if (thePrefs.GetDebugClientTCPLevel() > 0) {
				DebugSend("OP__RequestSources", this, reqfile->GetFileHash());
				if (GetLastAskedForSources() == 0)
					Debug(_T("  first source request\n"));
				else
					Debug(_T("  last source request was before %s\n"), CastSecondsToHM((GetTickCount() - GetLastAskedForSources())/1000));
			}
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			// David: because official client has a bug, only count the XSReqs under special conditions
			// Note: This will be fixed in future official releases so we will need to add a version check here to
			// remark: this fails for complete sources the first time.. but this doesn't hurt
			if(((status && status->IsCompleteSource()) || !md4cmp(GetUploadFileID(), reqfile->GetFileHash())) //complete source of we want the same file
			 && reqfile->GetValidSourcesCount() > 10) //if we know at least 10 good sources, the remote client should know at least one
				IncXSReqs();
#endif // ARGOS // NEO: NA END <-- Xanatos --
			reqfile->SetLastAnsweredTimeTimeout();
			Packet* packet = new Packet(OP_REQUESTSOURCES,16,OP_EMULEPROT);
			md4cpy(packet->pBuffer,reqfile->GetFileHash());
			theStats.AddUpDataOverheadSourceExchange(packet->size);
			socket->SendPacket(packet, true, true);
			SetLastAskedForSources();
			if (thePrefs.GetDebugSourceExchange())
				AddDebugLogLine(false, _T("SXSend: Client source request; %s, File=\"%s\""), DbgGetClientInfo(), reqfile->GetFileName());
		}

		if (IsSupportingAICH())
		{
			if (thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__AichFileHashReq", this, reqfile->GetFileHash());
			Packet* packet = new Packet(OP_AICHFILEHASHREQ,16,OP_EMULEPROT);
			md4cpy(packet->pBuffer,reqfile->GetFileHash());
			theStats.AddUpDataOverheadFileRequest(packet->size);
			socket->SendPacket(packet,true,true);
		}

		SendExtendedFileStatus(reqfile,true); // NEO: XCFS - [ExtendedClientFileStatus] <-- Xanatos --		
	}
	
	SetLastAskedTime();

	m_byFileRequestState = (uint8) (reqfile->IsStandBy() ? FR_STANDBY : FR_INPROGRES); // NEO: USPS - [UnSolicitedPartStatus] // NEO: SD - [StandByDL] <-- Xanatos --
}

// NEO: MOD - [SFSafeHash] -- Xanaots -->
void CUpDownClient::RequestHashset()
{
	if (socket)
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__HashSetRequest", this, reqfile->GetFileHash());
		Packet* packet = new Packet(OP_HASHSETREQUEST,16);
		md4cpy(packet->pBuffer,reqfile->GetFileHash());
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet,true,true);
		SetDownloadState(DS_REQHASHSET);
		m_fHashsetRequesting = 1;
		reqfile->hashsetneeded = false;
	}
	else
		ASSERT(0);
}
// NEO: MOD END <-- Xanaots --

void CUpDownClient::SendStartupLoadReq()
{
	// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
	//Xman fix for startupload (downloading side)
	if(m_fActiveDownReqFlag == 1)	
	{
		//we know now, client was sending OP_ACCEPTUPLOADREQ
		//he wants do upload to use, so we don't send SendStartupLoadReq
		//but we send now the blockrequest
		StartDownload();
		AddDebugLogLine(false, _T("-->don't send StartupLoadReq, client: %s, File: %s"), DbgGetClientInfo(), GetClientFilename());
		m_fActiveDownReqFlag = 0;
		return;
	}
	// NEO: FSUR END <-- Xanatos --

	if(!m_fKeepAlivePending) // NEO: DKA - [DownloadKeepAlive] <-- Xanatos --
	{
		// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
		if(GetDownloadState()==DS_DOWNLOADING)
		{
			//Xman 4.4: in very rare cases we want sendStartupLoadReq on Downloading
			//this case is NOT right after starting a download... it happend during a downloadsession
			//no idea what was going on here, because the protocolstepflag should handle all cases
			AddDebugLogLine(false,_T("--> SendStartuploadReq on DS-DOWNLOADING: %s !!! IF YOU EVER SEE THIS LETT ME KNOW !!!"), DbgGetClientInfo());
			ASSERT(0); // David: Can this exception also heppan in this mod?
			return;
		}
		// NEO: FSUR END <-- Xanatos --
		SetDownloadState(DS_ONQUEUE); // NEO: FIX <-- Xanatos -- // when DisableDownloadLimit is called the socket may get deleted
	}

	if (socket==NULL || reqfile==NULL)
	{
		ASSERT(0);
		return;
	}
	// SetDownloadState(DS_ONQUEUE);
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__StartupLoadReq", this);
	CSafeMemFile dataStartupLoadReq(16);
	dataStartupLoadReq.WriteHash16(reqfile->GetFileHash());
	Packet* packet = new Packet(&dataStartupLoadReq);
	packet->opcode = OP_STARTUPLOADREQ;
	theStats.AddUpDataOverheadFileRequest(packet->size);
	socket->SendPacket(packet, true, true);
	m_fQueueRankPending = 1;
	m_fUnaskQueueRankRecv = 0;

	m_byFileRequestState = FR_COMPLETED; // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --

	// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
	if(thePrefs.SendExtraInfo() && GetExtraInfoVersion())
		SendExtraInfoPacket(NIX_REQDOWN);
	// NEO: NXI END <-- Xanatos --
}

void CUpDownClient::ProcessFileInfo(CSafeMemFile* data, CPartFile* file)
{
	if (file==NULL)
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessFileInfo; file==NULL)");
	if (reqfile==NULL)
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessFileInfo; reqfile==NULL)");
	if (file != reqfile)
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessFileInfo; reqfile!=file)");

	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
	CString	strClientFilename = data->ReadString(GetUnicodeSupport()!=utf8strNone);
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		Debug(_T("  Filename=\"%s\"\n"), strClientFilename);

	CClientFileStatus* status = GetFileStatus(file,true);
	status->SetFileName(strClientFilename);
	// NEO: SCFS END <-- Xanatos --

	// NEO: FDC - [FileNameDisparityCheck] -- Xanatos -->
	if(thePrefs.UseFileCheck())
		reqfile->CheckFilename(strClientFilename);
	// NEO: FDC END <-- Xanatos --

	// 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid).
	// if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we
	// know that the file is shared, we know also that the file is complete and don't need to request the file status.
	if (reqfile->GetPartCount() == 1
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		&& (!SupportsWebCache() || !thePrefs.IsWebCacheEnabled()) // Superlexx - webcache - webcache-enabled clients might use IFP
#endif // NEO: WC END <-- Xanatos --
	){
		
		status->FillDefault(); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
		/*
		delete[] m_abyPartStatus;
		m_abyPartStatus = NULL;
		m_nPartCount = reqfile->GetPartCount();
		m_abyPartStatus = new uint8[m_nPartCount];
		memset(m_abyPartStatus,1,m_nPartCount);
		m_bCompleteSource = true;

		if (thePrefs.GetDebugClientTCPLevel() > 0)
		{
		    int iNeeded = 0;
		    for (UINT i = 0; i < m_nPartCount; i++)
			    if (!reqfile->IsComplete((uint64)i*PARTSIZE, ((uint64)(i+1)*PARTSIZE)-1, false))
				    iNeeded++;
			char* psz = new char[m_nPartCount + 1];
			for (UINT i = 0; i < m_nPartCount; i++)
				psz[i] = m_abyPartStatus[i] ? '#' : '.';
			psz[i] = '\0';
			Debug(_T("  Parts=%u  %hs  Needed=%u\n"), m_nPartCount, psz, iNeeded);
			delete[] psz;
		}*/
		UpdateDisplayedInfo();
		reqfile->UpdateAvailablePartsCount();
		// even if the file is <= PARTSIZE, we _may_ need the hashset for that file (if the file size == PARTSIZE)
		if (reqfile->hashsetneeded)
		{
			RequestHashset(); // NEO: MOD - [SFSafeHash] <-- Xanaots --
		}
		else if(m_byFileRequestState == FR_INPROGRES) // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --
		{
			SendStartupLoadReq();
		}
		// NEO: SD - [StandByDL] -- Xanatos -->
		else if(m_byFileRequestState == FR_STANDBY)
		{
			SetDownloadState(DS_HALTED);
		}
		// NEO: SD END <-- Xanatos -->
		reqfile->UpdatePartsInfo();
		// NEO: ICS - [InteligentChunkSelection] -- Xanatos -->
		if(GetIncompletePartVersion())
			reqfile->UpdatePartsInfoEx(CFS_Incomplete);
		// NEO: ICS END <-- Xanatos --
		// NEO: RPS - [RealPartStatus] -- Xanatos -->
		if(GetHidenPartStatusVersion())
			reqfile->UpdatePartsInfoEx(CFS_Hiden);
		if(GetBlockedPartStatusVersion())
			reqfile->UpdatePartsInfoEx(CFS_Blocked);
		// NEO: RPS END <-- Xanatos --
	}

	// NEO: XC - [ExtendedComments] -- Xanatos -->
	if(m_byAcceptCommentVer >= 2)
		SendCommentInfo(file);
	// NEO: XC END <-- Xanatos --
}

void CUpDownClient::ProcessFileStatus(bool bUdpPacket, CSafeMemFile* data, CClientFileStatus* status, CPartFile* file) // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
{
	if ( !reqfile || file != reqfile )
	{
		if (reqfile==NULL)
			throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessFileStatus; reqfile==NULL)");
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessFileStatus; reqfile!=file)");
	}

	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
	status->ReadFileStatus(data,CFS_Normal);

	bool bPartsNeeded = false;

	uint8* abyPartStatus = (file->PartPrefs.UseAntiHideOS()) ? status->GetPartStatusHistory() : status->GetPartStatus(); // NEO: AHOS - [AntiHideOS]
	if(abyPartStatus)
	{
		UINT PartCount = status->GetPartCount();
		for (UINT i = 0; i < PartCount; i++)
		{
			if (abyPartStatus[i])
			{
				if (!file->IsComplete((uint64)i*PARTSIZE, ((uint64)(i+1)*PARTSIZE)-1, false)){
					bPartsNeeded = true;
					break;
					//iNeeded++;
				}
			}
		}
	}
	// NEO: SCFS END <-- Xanatos --

	/*
	uint16 nED2KPartCount = data->ReadUInt16();
	delete[] m_abyPartStatus;
	m_abyPartStatus = NULL;
	bool bPartsNeeded = false;
	int iNeeded = 0;
	if (!nED2KPartCount)
	{
		m_nPartCount = reqfile->GetPartCount();
		m_abyPartStatus = new uint8[m_nPartCount];
		memset(m_abyPartStatus, 1, m_nPartCount);
		bPartsNeeded = true;
		m_bCompleteSource = true;
		if (bUdpPacket ? (thePrefs.GetDebugClientUDPLevel() > 0) : (thePrefs.GetDebugClientTCPLevel() > 0))
		{
			for (UINT i = 0; i < m_nPartCount; i++)
			{
				if (!reqfile->IsComplete((uint64)i*PARTSIZE, ((uint64)(i+1)*PARTSIZE)-1, false))
					iNeeded++;
			}
		}
	}
	else
	{
		if (reqfile->GetED2KPartCount() != nED2KPartCount) {
			if (thePrefs.GetVerbose()) {
				DebugLogWarning(_T("FileName: \"%s\""), m_strClientFilename);
				DebugLogWarning(_T("FileStatus: %s"), DbgGetFileStatus(nED2KPartCount, data));
			}
			CString strError;
			strError.Format(_T("ProcessFileStatus - wrong part number recv=%u  expected=%u  %s"), nED2KPartCount, reqfile->GetED2KPartCount(), DbgGetFileInfo(reqfile->GetFileHash()));
			m_nPartCount = 0;
			throw strError;
		}
		m_nPartCount = reqfile->GetPartCount();

		m_bCompleteSource = false;
		m_abyPartStatus = new uint8[m_nPartCount];
		UINT done = 0;
		while (done != m_nPartCount)
		{
			uint8 toread = data->ReadUInt8();
			for (UINT i = 0; i != 8; i++)
			{
				m_abyPartStatus[done] = ((toread>>i)&1)? 1:0; 	
				if (m_abyPartStatus[done])
				{
					if (!reqfile->IsComplete((uint64)done*PARTSIZE, ((uint64)(done+1)*PARTSIZE)-1, false)){
						bPartsNeeded = true;
						iNeeded++;
					}
				}
				done++;
				if (done == m_nPartCount)
					break;
			}
		}
	}

	if (bUdpPacket ? (thePrefs.GetDebugClientUDPLevel() > 0) : (thePrefs.GetDebugClientTCPLevel() > 0))
	{
		TCHAR* psz = new TCHAR[m_nPartCount + 1];
		for (UINT i = 0; i < m_nPartCount; i++)
			psz[i] = m_abyPartStatus[i] ? _T('#') : _T('.');
		psz[i] = _T('\0');
		Debug(_T("  Parts=%u  %s  Needed=%u\n"), m_nPartCount, psz, iNeeded);
		delete[] psz;
	}
	*/

	UpdateDisplayedInfo(bUdpPacket);
	/*reqfile*/file->UpdateAvailablePartsCount(); // NEO: MOD <-- Xanatos --

	HandleFileStatus(file, bUdpPacket, bPartsNeeded); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --

	reqfile->UpdatePartsInfo();
}

// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
void CUpDownClient::ProcessModFileStatus(bool bUdpPacket, CClientFileStatus* status, CPartFile* file, bool bCheckPassive, bool bOnlySCT, bool bOnlyCatch)
{
	if(GetDownloadState() != DS_NONEEDEDPARTS)
		return; // nothing to do here
	else if(file != reqfile && reqfile) // if we have swpaed to an other file
		return; // we also does have nithing to do here

	if (!bCheckPassive && reqfile==NULL) // NEO: BPS - [BetterPassiveSourceFinding] 
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessModStatus; reqfile==NULL)");

	bool bPartsNeeded = false;

	// NEO: SCT - [SubChunkTransfer] 
	if(!bCheckPassive && !bOnlyCatch // when it comes from ExtendedInfo then it does not contain a SCT map
	 && file->PartPrefs.UseSubChunkTransfer() && GetSubChunksVer()) // only when needed/supported
	{
		UINT PartCount = status->GetPartCount();
		for (UINT uPart = 0; uPart < PartCount; uPart++)
		{
			tBlockMap* RemoteBlockMap = NULL;
			if (status->GetBlockMap(uPart,&RemoteBlockMap))
			{
				if(thePrefs.UseSubChunkVerification() == TRUE && !RemoteBlockMap->IsVerified()) // NEO: SCV - [SubChunkVerification]
					continue; // we are not interrested on unveryfied blocks

				tBlockMap* LocalBlockMap = NULL;
				if(file->GetBlockMap((uint16)uPart,&LocalBlockMap))
				{
					for(uint8 uBlock = 0; uBlock < 53;uBlock++)
					{
						if (RemoteBlockMap->IsBlockDone(uBlock) && !LocalBlockMap->IsBlockDone(uBlock))
						{
							bPartsNeeded = true;
						}
					}
				}
				else if(file->IsPureGap((uint64)uPart*PARTSIZE, (uint64)(uPart + 1)*PARTSIZE - 1)) // at this point it can be only pureGap or Complete
				{
					bPartsNeeded = true;
				}
			}
		}
	}
	// NEO: SCT END

	// NEO: NPC - [NeoPartCatch]
	if(!bPartsNeeded && !bOnlySCT && file->PartPrefs.UseRealPartStatus())
	{
		uint8* abyHidenPartStatus = status->GetPartStatus(CFS_Hiden);
		uint8* abyBlockedPartStatus = status->GetPartStatus(CFS_Blocked);
		if(abyHidenPartStatus || abyBlockedPartStatus)
		{
			UINT PartCount = status->GetPartCount();
			for (UINT i = 0; i < PartCount; i++)
			{
				if ((abyHidenPartStatus && abyHidenPartStatus[i])
					|| (abyBlockedPartStatus && abyBlockedPartStatus[i]))
				{
					if (!file->IsComplete((uint64)i*PARTSIZE, ((uint64)(i+1)*PARTSIZE)-1, false)){
						bPartsNeeded = true;
						break;
						//iNeeded++;
					}
				}
			}
		}
	}
	// NEO: NPC END
	
	if(bPartsNeeded) // only when we found a part that interrests us
		HandleFileStatus(file, bUdpPacket, bPartsNeeded);
}

void CUpDownClient::HandleFileStatus(CPartFile* file, bool bUdpPacket, bool bPartsNeeded, bool bCheckPassive)
{
	// NEO: BPS - [BetterPassiveSourceFinding]
	//Xman better passive source finding
	//problem is: if a client just began to download a file, we receive an FNF
	//later, if it has some chunks we don't find it via passive source finding because 
	//that works only on TCP-reask but not via UDP
	if(bCheckPassive)
	{
		if(bPartsNeeded)
		{
			//the client was a NNS but isn't any more
			if(GetDownloadState() == DS_NONEEDEDPARTS && reqfile == file)
				SetSafeReAskTime();
			else
			//the client maybe isn't in our downloadqueue.. let's look if we should add the client
			if ((UINT)file->PartPrefs.GetHardLimit() > file->GetSourceCount()) // NEO: NST - [NeoSourceTweaks]
				theApp.downloadqueue->CheckAndAddKnownSource(file, this, true);
		}
	}
	else
	// NEO: BPS END

	// NOTE: This function is invoked from TCP and UDP socket!
	if (!bUdpPacket)
	{
		if (!bPartsNeeded)
        {
			SetDownloadState(DS_NONEEDEDPARTS);
            SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::ProcessFileStatus() TCP"), true, false, false, NULL, true, true);
        }
        else if (reqfile->hashsetneeded) //If we are using the eMule filerequest packets, this is taken care of in the Multipacket!
		{
			RequestHashset(); // NEO: MOD - [SFSafeHash]
		}
		else if(m_byFileRequestState == FR_INPROGRES) // NEO: USPS - [UnSolicitedPartStatus]
		{
			SendStartupLoadReq();
		}
		// NEO: SD - [StandByDL]
		else if(m_byFileRequestState == FR_STANDBY)
		{
			SetDownloadState(DS_HALTED);
		}
		// NEO: SD END
	}
	else
	{
		if (!bPartsNeeded)
        {
			SetDownloadState(DS_NONEEDEDPARTS);
            SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::ProcessFileStatus() UDP"), true, false, false, NULL, true, false); // NEO: MOD <-- Xanatos --
        }
		else
			SetDownloadState(DS_ONQUEUE);
	}
}
// NEO: SCFS END <-- Xanatos --

bool CUpDownClient::AddRequestForAnotherFile(CPartFile* file){
	ASSERT(reqfile != file); // NEO: ND - [NeoDebug] <-- Xanatos --
	for (POSITION pos = m_OtherNoNeeded_list.GetHeadPosition();pos != 0;){
		if (m_OtherNoNeeded_list.GetNext(pos) == file)
			return false;
	}
	for (POSITION pos = m_OtherRequests_list.GetHeadPosition();pos != 0;){
		if (m_OtherRequests_list.GetNext(pos) == file)
			return false;
	}
	m_OtherRequests_list.AddTail(file);
	file->A4AFsrclist.AddTail(this); // [enkeyDEV(Ottavio84) -A4AF-]

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
	if(thePrefs.SaveSourceFileList() && source)
		source->AddSeenFile(file->GetFileHash(),file->GetFileSize());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --

	return true;
}

void CUpDownClient::ClearDownloadBlockRequests()
{
	// NEO: DBR - [DynamicBlockRequest] -- Xanatos --
	//for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;){
	//	Requested_Block_Struct* cur_block = m_DownloadBlocks_list.GetNext(pos);
	//	if (reqfile){
	//		reqfile->RemoveBlockFromList(cur_block->StartOffset,cur_block->EndOffset);
	//	}
	//	delete cur_block;
	//}
	//m_DownloadBlocks_list.RemoveAll();

	for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;){
		Pending_Block_Struct *pending = m_PendingBlocks_list.GetNext(pos);
		if (reqfile){
			reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset);
		}

		delete pending->block;
		// Not always allocated
		if (pending->zStream){
			inflateEnd(pending->zStream);
			delete pending->zStream;
		}
		delete pending;
	}
	m_PendingBlocks_list.RemoveAll();
}

void CUpDownClient::SetDownloadState(EDownloadState nNewState, LPCTSTR pszReason){

	if (m_nDownloadState != nNewState){
		switch( nNewState )
		{
			case DS_CONNECTING:
	            m_dwLastTriedToConnect = ::GetTickCount();
				break;
#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
			case DS_LOADED:
			case DS_RESERVE:
			case DS_RETIRED:
			case DS_LOADEDWAITING:
#endif // NEO_SS // NEO: NSS END <-- Xanatos --
#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
			case DS_UNREACHABLE:
#endif // NEO_SK // NEO: NSK END <-- Xanatos --
#if defined(NEO_SK) || defined(NEO_SS) // NEO: NSK - [NeoSourceKeeper] // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
			case DS_REVIVAL:
				break;
#endif // NEO_SK // NEO_SS // NEO: NSK END // NEO: NSS END <-- Xanatos --
			case DS_HALTED: // NEO: SD - [StandByDL] <-- Xanatos --
			case DS_TOOMANYCONNSKAD:
				//This client had already been set to DS_CONNECTING.
				//So we reset this time so it isn't stuck at TOOMANYCONNS for 20mins.
				m_dwLastTriedToConnect = ::GetTickCount()-/*20*60*1000*/(reqfile ? reqfile->PartPrefs.GetReaskIntervalsMs(true) : thePrefs.GetReaskIntervalsMs(true)); // NEO: DR - [DownloadReask] <-- Xanatos --
				break;
			case DS_WAITCALLBACKKAD:
			case DS_WAITCALLBACK:
				break;
			// NEO: XSC - [ExtremeSourceCache] -- Xanatos -->
			case DS_CACHED:
				m_uCacheStartTime = ::GetTickCount();
				break;
			// NEO: XSC END <-- Xanatos --
            case DS_NONEEDEDPARTS:
                // Since tcp asks never sets reask time if the result is DS_NONEEDEDPARTS
                // If we set this, we will not reask for that file until some time has passed.
                SetLastAskedTime();
                //DontSwapTo(reqfile);
			// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
			case DS_NONE:
			case DS_ONQUEUE: // to be set when we recive OP_OUTOFPARTREQS 
				m_fActiveDownReqFlag = 0;
			// NEO: FSUR END <-- Xanatos --
			default:
				switch( m_nDownloadState )
				{
					case DS_WAITCALLBACK:
					case DS_WAITCALLBACKKAD:
						break;
					default:
						m_dwLastTriedToConnect = ::GetTickCount()-/*20*60*1000*/(reqfile ? reqfile->PartPrefs.GetReaskIntervalsMs(true) : thePrefs.GetReaskIntervalsMs(true)); // NEO: DR - [DownloadReask] <-- Xanatos --
						break;
				}
				break;
		}

		if (reqfile){
		    if(nNewState == DS_DOWNLOADING){
                if(thePrefs.GetLogUlDlEvents())
                    AddDebugLogLine(DLP_VERYLOW, false, _T("Download session started. User: %s in SetDownloadState(). New State: %i"), DbgGetClientInfo(), nNewState);

			    reqfile->AddDownloadingSource(this);
		    }
		    else if(m_nDownloadState == DS_DOWNLOADING){
			    reqfile->RemoveDownloadingSource(this);
		    }
		}

        if(nNewState == DS_DOWNLOADING && socket){
		    socket->SetTimeOut(CONNECTION_TIMEOUT*4);

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			m_bWebcacheFailedTry = false; //MORPH - Added by SiRoB, New ResolveWebCachename
#endif // NEO: WC END <-- Xanatos --

			// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
			int recvBuff = 0;
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
			if(IsLanClient() && thePrefs.IsSetLanDownloadBuffer())
				recvBuff = thePrefs.GetLanDownloadBufferSize();
			else
#endif //LANCAST // NEO: NLC END
			if(thePrefs.IsSetDownloadBuffer())
				recvBuff = thePrefs.GetDownloadBufferSize();

			if(recvBuff){
#if !defined DONT_USE_SOCKET_BUFFERING // NEO: DSB - [DynamicSocketBuffer]
				socket->SetRecvBufferSize(recvBuff);
#endif // NEO: DSB - [DynamicSocketBuffer]	
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
				socket->m_Socket->SetSockOpt(SO_RCVBUF, &recvBuff, sizeof(recvBuff), SOL_SOCKET);
#else
				socket->SetSockOpt(SO_RCVBUF, &recvBuff, sizeof(recvBuff), SOL_SOCKET);
#endif //NATTUNNELING // NEO: UTCP END
			}
			// NEO: NBC END <-- Xanatos --
        }

		if (m_nDownloadState == DS_DOWNLOADING ){
			if(socket)
				socket->SetTimeOut(CONNECTION_TIMEOUT);

			if (thePrefs.GetLogUlDlEvents()) {
				switch( nNewState )
				{
					case DS_NONEEDEDPARTS:
						pszReason = _T("NNP. You don't need any parts from this client.");
				}

                if(thePrefs.GetLogUlDlEvents())
                    AddDebugLogLine(DLP_VERYLOW, false, _T("Download session ended: %s; User: %s in SetDownloadState(). New State: %i, Length: %s, Transferred: %s."), pszReason, DbgGetClientInfo(), nNewState, CastSecondsToHM(GetDownTimeDifference(false)/1000), CastItoXBytes(GetSessionDown(), false, false));
			}

#ifdef ARGOS // NEO: NA -- Xanatos -->
			if(thePrefs.IsFailedDetection()){
				//Xman filter clients with failed downloads
				if(GetSessionDown() < KB2B((uint32)thePrefs.GetFailedThreshold())){
					m_faileddownloads++;
					if(m_faileddownloads >= thePrefs.GetFailedTries())
						theApp.argos->DoArgos(GetConnectIP(),AR_FAILED);
				}else{
					m_faileddownloads=0; 
					theApp.argos->UnArgos(GetConnectIP(),AR_FAILED);
				}
			}
#endif // ARGOS // NEO: NA END <-- Xanatos --

			ResetSessionDown();

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			if(!IsProxy())
#endif // NEO: WC END <-- Xanatos --
			{
				// -khaos--+++> Extended Statistics (Successful/Failed Download Sessions)
				if ( m_bTransferredDownMini && nNewState != DS_ERROR )
					thePrefs.Add2DownSuccessfulSessions(); // Increment our counters for successful sessions (Cumulative AND Session)
				else
					thePrefs.Add2DownFailedSessions(); // Increment our counters failed sessions (Cumulative AND Session)
				thePrefs.Add2DownSAvgTime(GetDownTimeDifference()/1000);
				// <-----khaos-
			}

			m_fKeepAlivePending = 0; // NEO: DKA - [DownloadKeepAlive] <-- Xanatos --

			m_nDownloadState = (_EDownloadState)nNewState;

			ClearDownloadBlockRequests();
				
			m_nDownDatarate = 0;
			m_AvarageDDR_list.RemoveAll();
			m_nSumForAvgDownDataRate = 0;

			/*if (nNewState == DS_NONE){
				// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
				delete[] m_abyPartStatus;
				m_abyPartStatus = NULL;
			}*/
			if (socket && nNewState != DS_ERROR)
				socket->DisableDownloadLimit();
		}
		m_nDownloadState = (_EDownloadState)nNewState;
		if( GetDownloadState() == DS_DOWNLOADING ){
			if ( IsEmuleClient() )
				SetRemoteQueueFull(false);
			SetRemoteQueueRank(0);
			SetRemoteEDT(0, EDT_UNDEFINED); // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
			SetAskedCountDown(0);
		}
		UpdateDisplayedInfo(true);
	}
}

void CUpDownClient::ProcessHashSet(const uchar* packet,uint32 size)
{
	if (!m_fHashsetRequesting)
		throw CString(_T("unwanted hashset"));
	if ( (!reqfile) || md4cmp(packet,reqfile->GetFileHash())){
		CheckFailedFileIdReqs(packet);
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessHashSet)");	
	}
	CSafeMemFile data(packet, size);
	if (reqfile->LoadHashsetFromFile(&data,true)){
		m_fHashsetRequesting = 0;
		reqfile->SetSinglePartHash((uint16)-1); // NEO: SSH - [SlugFillerSafeHash] <-- Xanatos --
	}
	else{
		reqfile->hashsetneeded = true;
		throw GetResString(IDS_ERR_BADHASHSET);
	}
	// NEO: SEF - [ShareAlsoEmptyFiles] -- Xanatos -->
	//if(!theApp.sharedfiles->IsFilePtrInList(reqfile))
	//	 theApp.sharedfiles->SafeAddKFile(reqfile);
	// NEO: SEF END <-- Xanatos --

	if(m_byFileRequestState == FR_INPROGRES) // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --
		SendStartupLoadReq();
	// NEO: SD - [StandByDL] -- Xanatos -->
	else if(m_byFileRequestState == FR_STANDBY)
		SetDownloadState(DS_HALTED);
	// NEO: SD END <-- Xanatos -->
}

void CUpDownClient::CreateBlockRequests(int iMaxBlocks)
{
	// NEO: DBR - [DynamicBlockRequest] -- Xanatos -->
	uint16 count;
    if(iMaxBlocks > m_PendingBlocks_list.GetCount() || iMaxBlocks == 0 && m_PendingBlocks_list.GetCount() == 0) {
        uint32 blocksize = EMBLOCKSIZE;
        if(iMaxBlocks > 0) {
            count = (uint16)iMaxBlocks - (uint16)m_PendingBlocks_list.GetCount();
			// when the client is a very fast one request larger blocks
			if(IsEmuleClient() /*&& m_byCompatibleClient==0*/ && ((GetVersion() >> 10) & 0x7f) >= 40){
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
				if(IsLanClient())
					blocksize = EMBLOCKSIZE*3;
#endif //LANCAST // NEO: NLC END
				if(GetDownloadDatarate() >= KB2B(300))
					blocksize = EMBLOCKSIZE*3;
				else if(GetDownloadDatarate() >= KB2B(200))
					blocksize = EMBLOCKSIZE*2;
			}
        } else {
            // when iMaxBlocks == 0 it means just a little remains of the file, and it's important
            // not to lock too much of the file for really slow downloads. If we lock too much
            // those slow downloads can prevent us from using faster connections, since there will
            // be no blocks left of the file to request from those faster clients.

            // so find one block to request
            count = 1;

            // but a small one (how small depends on how fast the client has sent us data so far)
            blocksize = min(EMBLOCKSIZE, max(123*GetDownloadDatarate(), 20*1024));
        }

        Requested_Block_Struct** toadd = new Requested_Block_Struct*[count];
		// NEO: MOD - [ChunkSelection]
		bool ret;
		switch(reqfile->PartPrefs.GetChunkSelectionMode()){
		case CS_ICS:
			ret = reqfile->GetNextRequestedBlockICS(this,toadd,&count, blocksize);
			break;
		case CS_RC4:
			ret = reqfile->GetNextRequestedBlockV4(this,toadd,&count, blocksize);
			break;
		case CS_NORMAL:
		default:
			ret = reqfile->GetNextRequestedBlock(this,toadd,&count, blocksize);
		}
		if (ret){
		// NEO: MOD END
            for (UINT i = 0; i < count; i++) {
		        Pending_Block_Struct* pblock = new Pending_Block_Struct;
		        pblock->block = toadd[i];
		        m_PendingBlocks_list.AddTail(pblock);
            }
		}
		delete[] toadd;
    }
	// NEO: DBR END <-- Xanatos --

	/*
	ASSERT( iMaxBlocks >= 1 /&& iMaxBlocks <= 3/ );
	if (m_DownloadBlocks_list.IsEmpty())
	{
		uint16 count;
        if(iMaxBlocks > m_PendingBlocks_list.GetCount()) {
            count = (uint16)(iMaxBlocks - m_PendingBlocks_list.GetCount());
        } else {
            count = 0;
        }

		Requested_Block_Struct** toadd = new Requested_Block_Struct*[count];
		// NEO: MOD - [ChunkSelection] -- Xanatos -->
		bool ret;
		switch(reqfile->PartPrefs.GetChunkSelectionMode()){
		case CS_ICS:
			ret = reqfile->GetNextRequestedBlockICS(this,toadd,&count);
			break;
		case CS_RC4:
			ret = reqfile->GetNextRequestedBlockV4(this,toadd,&count);
			break;
		case CS_NORMAL:
		default:
			ret = reqfile->GetNextRequestedBlock(this,toadd,&count);
		}
		if (ret){
		// NEO: MOD END <-- Xanatos --
			for (UINT i = 0; i < count; i++)
				m_DownloadBlocks_list.AddTail(toadd[i]);
		}
		delete[] toadd;
	}

	while (m_PendingBlocks_list.GetCount() < iMaxBlocks && !m_DownloadBlocks_list.IsEmpty())
	{
		Pending_Block_Struct* pblock = new Pending_Block_Struct;
		pblock->block = m_DownloadBlocks_list.RemoveHead();
		m_PendingBlocks_list.AddTail(pblock);
	}*/
}

void CUpDownClient::SendBlockRequests()
{
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	// MORPH START - Added by Commander, WebCache 1.2e
	if(!m_bWebcacheFailedTry && reqfile && thePrefs.IsWebCacheDownloadEnabled()
		&& UsesCachedTCPPort() // uses a port that is usually cached
		&& SupportsWebCache() // client knows webcache protocol
		&& !HasLowID()	// has highID
		&& AllowProxyConnection() // not too many open sockets to proxy
// yonatan tmp -	&& ((thePrefs.WebCacheIsTransparent() && GetUserPort() == 80)|| (!thePrefs.WebCacheIsTransparent() && ResolveWebCacheName())) // found HTTP proxy // Superlexx - TPS
		&& ( thePrefs.WebCacheIsTransparent() ?
			GetUserPort() == 80			// yes - proceed if uploader uses port 80
			: ResolveWebCacheName() )	// no - proceed if proxy address can be resolved
		&& (thePrefs.IsWebCacheCachesLocalTraffic() || !IsBehindOurWebCache()) //JP changed to new IsBehindOurWebCache-function 		// WC-TODO: Shorter names?
		&& (reqfile->GetNumberOfCurrentWebcacheConnectionsForThisFile() < reqfile->GetMaxNumberOfWebcacheConnectionsForThisFile() || thePrefs.IsLimitlesWebCache()) ) //JP Throttle OHCB-production
	{
		if (thePrefs.GetLogWebCacheEvents()) //JP log webcache events
			AddDebugLogLine(false, _T("Proxy-Connections for this file: %u Allowed: %u"), reqfile->GetNumberOfCurrentWebcacheConnectionsForThisFile(), reqfile->GetMaxNumberOfWebcacheConnectionsForThisFile());
		if (!m_PendingBlocks_list.IsEmpty()) return; //Added by SiRoB
		// Superlexx - COtN - start
		byte WC_TestFileHash[16] = { 0xE9, 0x05, 0x7A, 0xDC, 0x38, 0x05, 0x4A, 0xFA, 0x24, 0x81, 0x6E, 0x86, 0xBB, 0x08, 0xD2, 0x70 };
		bool isTestFile = md4cmp(reqfile->GetFileHash(), WC_TestFileHash)==0;
		bool doCache = false;
		CreateBlockRequests(1);
		if (m_PendingBlocks_list.IsEmpty())
		{
			SetDownloadState(DS_NONEEDEDPARTS, _T("NNP. We can't ask more block request. Client don't have any block for us or file is already fully requested."));
			if (!SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::SendBlockRequests()"), true, false, false, NULL, true, true)) 
				SendCancelTransfer();
			SetDownloadState(DS_ONQUEUE, _T("noNeededRequeue"));	// SLUGFILLER: noNeededRequeue
			return;
		}
		if (isTestFile)
			doCache = true;
		else
		{
#ifndef _DEBUG
			Pending_Block_Struct* pending = m_PendingBlocks_list.GetHead();
			//JP take successrate into account when deciding to do webcache download (rounded down)
			// Superlexx: modified this to actually work ;)
			uint32 minOHCBRecipients = (thePrefs.ses_WEBCACHEREQUESTS > 50 && thePrefs.ses_successfull_WCDOWNLOADS > 0) ? thePrefs.ses_WEBCACHEREQUESTS / thePrefs.ses_successfull_WCDOWNLOADS : 1;
			if (theApp.clientlist->GetNumberOfClientsBehindOurWebCacheHavingSameFileAndNeedingThisBlock(pending, minOHCBRecipients) >= minOHCBRecipients)
#endif _DEBUG
				doCache = true;
		}
	
		if( doCache ) {
			ASSERT( GetDownloadState() == DS_DOWNLOADING );
//		Crypt.useNewKey = true;	// Superlexx - moved this to SendWebCacheBlockRequests()
			if(SendWebCacheBlockRequests())
				return;
		}
	}
// Superlexx - COtN - end
// MORPH END - Added by Commander, WebCache 1.2e
#endif // NEO: WC END <-- Xanatos --

	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__RequestParts", this, reqfile!=NULL ? reqfile->GetFileHash() : NULL);

	m_dwLastBlockReceived = ::GetTickCount();
	// NEO: DKA - [DownloadKeepAlive] -- Xanatos -->
	if(m_fKeepAlivePending){
		AddDebugLogLine(false, _T("--> Download Keep Alive Ping canceled! clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
		m_fKeepAlivePending = 0; 
		m_byFileRequestState = FR_COMPLETED; // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --
	}
	// NEO: DKA END <-- Xanatos --

	if (!reqfile)
		return;

    // prevent locking of too many blocks when we are on a slow (probably standby/trickle) slot
    int blockCount = 3;
	// NEO: DBR - [DynamicBlockRequest] -- Xanatos -->
    if(IsEmuleClient() /*&& m_byCompatibleClient==0 && reqfile->GetFileSize()-reqfile->GetCompletedSize() <= (uint64)PARTSIZE*4*/) { // ZZUL tries to make clients request from same chunk, so it makes sense preventing also a slow client from preventing a chunk to be completed too long.
        // if there's less than two chunks left, request fewer blocks for
        // slow downloads, so they don't lock blocks from faster clients.
        // Only trust eMule clients to be able to handle less blocks than three
        if(GetDownloadDatarate() < 1500 && (reqfile->GetFileSize()-reqfile->GetCompletedSize() <= PARTSIZE*2 && reqfile->GetTransferringSrcCount() > 1 || reqfile->GetFileSize()-reqfile->GetCompletedSize() <= PARTSIZE)) {
            // if there's less than one chunk left, request one smaller block for
            // slow downloads, so they lock even less from faster clients.

            // the special blockcount = 0 causes one, smaller, block to be requested
            blockCount = 0;
		}
        else if(GetDownloadDatarate() < 2000 || reqfile->GetFileSize()-reqfile->GetCompletedSize() <= PARTSIZE && reqfile->GetTransferringSrcCount() > 1)
            blockCount = 1;
        else if(GetDownloadDatarate() < 2500)
            blockCount = 2;
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
		else if(IsLanClient())
            blockCount = 53; // on lan request entier chunks
#endif //LANCAST // NEO: NLC END
		// If we have a fast source request mor blocks at one to avoid latency problems
		else if(GetDownloadDatarate() > KB2B(400))
			blockCount = 53;
		else if(GetDownloadDatarate() > KB2B(200))
			blockCount = 36;
		else if(GetDownloadDatarate() > KB2B(100))
			blockCount = 18;
		else if(GetDownloadDatarate() > KB2B(50))
			blockCount = 9;
		else if(GetDownloadDatarate() > KB2B(25))
			blockCount = 6;
    }
	// NEO: DBR END <-- Xanatos --
    /*if(IsEmuleClient() && m_byCompatibleClient==0 && reqfile->GetFileSize()-reqfile->GetCompletedSize() <= (uint64)PARTSIZE*4) {
        // if there's less than two chunks left, request fewer blocks for
        // slow downloads, so they don't lock blocks from faster clients.
        // Only trust eMule clients to be able to handle less blocks than three
        if(GetDownloadDatarate() < 600) {
            blockCount = 1;
        } else if(GetDownloadDatarate() < 1200) {
            blockCount = 2;
        }
    }*/
	CreateBlockRequests(blockCount);

	if (m_PendingBlocks_list.IsEmpty()){
		/*SendCancelTransfer();
		SetDownloadState(DS_NONEEDEDPARTS);
        SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::SendBlockRequests()"), true, false, false, NULL, true, true);*/

		/*SetDownloadState(DS_NONEEDEDPARTS, _T("NNP. We can't ask more block request. Client don't have any block for us or file is already fully requested."));
		if (!SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::SendBlockRequests()"), true, false, false, NULL, true, true))
			SendCancelTransfer();*/

		// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
		//Xman 4.2 just in time swapping
		CPartFile* oldreqfile=reqfile;
		if(SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::SendBlockRequests()"), true, false, false, NULL, true, true) )
		{
			if(socket!=NULL && socket->IsConnected())
			{
				m_fActiveDownReqFlag = 1;
				SendFileRequest(); //ask for the file we swapped to
				if(thePrefs.GetLogA4AF())
					AddDebugLogLine(false, _T("-o- SendBlockRequests just in time swapping NNS: client %s, %s swapped from %s to %s"), DbgGetFullClientSoftVer(),GetUserName(), oldreqfile->GetFileName(), reqfile->GetFileName());
			}
			else // should not happen but in case
				AskForDownload(true);
		}
		else
		{
			SendCancelTransfer();
			SetDownloadState(DS_NONEEDEDPARTS, _T("No Needed Parts"));
		}
		//to be sure not to fall in an endless loop (which theoretically can't happen):
		DontSwapTo(oldreqfile);
		// NEO: FSUR END <-- Xanatos --

		return;
	}

	// NEO: DBR - [DynamicBlockRequest] -- Xanatos -->
	if(blockCount <= 3)
		SendBlockRequestsPacket(m_PendingBlocks_list.GetHeadPosition()); 
	else
	{
		POSITION pos = m_PendingBlocks_list.GetHeadPosition();
		while(pos != NULL)
		{
			POSITION startPos = pos;
			Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
			if(pending->fRequested)
				continue;
			SendBlockRequestsPacket(startPos);
		}
	}
	// NEO: DBR END <-- Xanatos --
}

POSITION CUpDownClient::SendBlockRequestsPacket(POSITION startPos) // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
{
	bool bI64Offsets = false;
	POSITION pos = startPos; //m_PendingBlocks_list.GetHeadPosition(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
	for (uint32 i = 0; i != 3; i++){
		if (pos){
			Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
			ASSERT( pending->block->StartOffset <= pending->block->EndOffset );
			if (pending->block->StartOffset > 0xFFFFFFFF || pending->block->EndOffset > 0xFFFFFFFF){
				bI64Offsets = true;
				if (!SupportsLargeFiles()){
					ASSERT( false );
					SendCancelTransfer();
					SetDownloadState(DS_ERROR);
					return NULL; // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
				}
				//break; // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
			}
			pending->fRequested = 1; // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
		}
	}
	POSITION endPos = pos; // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --

	Packet* packet;
	if (bI64Offsets){
		const int iPacketSize = 16+(3*8)+(3*8); // 64
		packet = new Packet(OP_REQUESTPARTS_I64, iPacketSize, OP_EMULEPROT);
		CSafeMemFile data((const BYTE*)packet->pBuffer, iPacketSize);
		data.WriteHash16(reqfile->GetFileHash());
		pos = startPos; //m_PendingBlocks_list.GetHeadPosition(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
		for (uint32 i = 0; i != 3; i++){
			if (pos){
				Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
				ASSERT( pending->block->StartOffset <= pending->block->EndOffset );
				//ASSERT( pending->zStream == NULL );
				//ASSERT( pending->totalUnzipped == 0 );
				pending->fZStreamError = 0;
				//pending->fRecovered = 0;
				data.WriteUInt64(pending->block->StartOffset);
			}
			else
				data.WriteUInt64(0);
		}
		pos = startPos; //m_PendingBlocks_list.GetHeadPosition(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
		for (uint32 i = 0; i != 3; i++){
			if (pos){
				Requested_Block_Struct* block = m_PendingBlocks_list.GetNext(pos)->block;
				uint64 endpos = block->EndOffset+1;
				data.WriteUInt64(endpos);
				if (thePrefs.GetDebugClientTCPLevel() > 0){
					CString strInfo;
					strInfo.Format(_T("  Block request %u: "), i);
					strInfo += DbgGetBlockInfo(block);
					strInfo.AppendFormat(_T(",  Complete=%s"), reqfile->IsComplete(block->StartOffset, block->EndOffset, false) ? _T("Yes(NOTE:)") : _T("No"));
					strInfo.AppendFormat(_T(",  PureGap=%s"), reqfile->IsPureGap(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
					strInfo.AppendFormat(_T(",  AlreadyReq=%s"), reqfile->IsAlreadyRequested(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
					strInfo += _T('\n');
					Debug(strInfo);
				}
			}
			else
			{
				data.WriteUInt64(0);
				if (thePrefs.GetDebugClientTCPLevel() > 0)
					Debug(_T("  Block request %u: <empty>\n"), i);
			}
		}
	}
	else{
		const int iPacketSize = 16+(3*4)+(3*4); // 40
		packet = new Packet(OP_REQUESTPARTS,iPacketSize);
		CSafeMemFile data((const BYTE*)packet->pBuffer, iPacketSize);
		data.WriteHash16(reqfile->GetFileHash());
		pos = startPos; //m_PendingBlocks_list.GetHeadPosition(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
		for (uint32 i = 0; i != 3; i++){
			if (pos){
				Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
				ASSERT( pending->block->StartOffset <= pending->block->EndOffset );
				//ASSERT( pending->zStream == NULL );
				//ASSERT( pending->totalUnzipped == 0 );
				pending->fZStreamError = 0;
				//pending->fRecovered = 0;
				data.WriteUInt32((uint32)pending->block->StartOffset);
			}
			else
				data.WriteUInt32(0);
		}
		pos = startPos; //m_PendingBlocks_list.GetHeadPosition(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
		for (uint32 i = 0; i != 3; i++){
			if (pos){
				Requested_Block_Struct* block = m_PendingBlocks_list.GetNext(pos)->block;
				uint64 endpos = block->EndOffset+1;
				data.WriteUInt32((uint32)endpos);
				if (thePrefs.GetDebugClientTCPLevel() > 0){
					CString strInfo;
					strInfo.Format(_T("  Block request %u: "), i);
					strInfo += DbgGetBlockInfo(block);
					strInfo.AppendFormat(_T(",  Complete=%s"), reqfile->IsComplete(block->StartOffset, block->EndOffset, false) ? _T("Yes(NOTE:)") : _T("No"));
					strInfo.AppendFormat(_T(",  PureGap=%s"), reqfile->IsPureGap(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
					strInfo.AppendFormat(_T(",  AlreadyReq=%s"), reqfile->IsAlreadyRequested(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
					strInfo += _T('\n');
					Debug(strInfo);
				}
			}
			else
			{
				data.WriteUInt32(0);
				if (thePrefs.GetDebugClientTCPLevel() > 0)
					Debug(_T("  Block request %u: <empty>\n"), i);
			}
		}
	}

	theStats.AddUpDataOverheadFileRequest(packet->size);
	socket->SendPacket(packet,true,true);

	return endPos; // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
}

/* Barry - Originally this only wrote to disk when a full 180k block 
           had been received from a client, and only asked for data in 
		   180k blocks.

		   This meant that on average 90k was lost for every connection
		   to a client data source. That is a lot of wasted data.

		   To reduce the lost data, packets are now written to a buffer
		   and flushed to disk regularly regardless of size downloaded.
		   This includes compressed packets.

		   Data is also requested only where gaps are, not in 180k blocks.
		   The requests will still not exceed 180k, but may be smaller to
		   fill a gap.
*/
void CUpDownClient::ProcessBlockPacket(const uchar *packet, uint32 size, bool packed, bool bI64Offsets)
{
	/* TODO rewrite debugoutput
	uint32 nDbgStartPos = *((uint32*)(packet+16));
	if (thePrefs.GetDebugClientTCPLevel() > 1){
		if (packed)
			Debug(_T("  Start=%u  BlockSize=%u  Size=%u  %s\n"), nDbgStartPos, *((uint32*)(packet + 16+4)), size-24, DbgGetFileInfo(packet));
		else
			Debug(_T("  Start=%u  End=%u  Size=%u  %s\n"), nDbgStartPos, *((uint32*)(packet + 16+4)), *((uint32*)(packet + 16+4)) - nDbgStartPos, DbgGetFileInfo(packet));
	}*/

	// Ignore if no data required
	if (!(GetDownloadState() == DS_DOWNLOADING || GetDownloadState() == DS_NONEEDEDPARTS)){
#ifdef _DEBUG_NEO	// NEO: ND - [NeoDebug] -- Xanatos -->
		TRACE("%s - Invalid download state Client: %s; State %s; File: %s \n", __FUNCTION__, CStringA(DbgGetClientInfo()), CStringA(GetDLStateString(GetDownloadState())), reqfile ? CStringA(reqfile->GetFileName()) : "null");
#else
		TRACE("%s - Invalid download state\n", __FUNCTION__);
#endif // _DEBUG_NEO // NEO: ND END <-- Xanatos --
		return;
	}

	// Update stats
	m_dwLastBlockReceived = ::GetTickCount();

	// Read data from packet
	CSafeMemFile data(packet, size);
	uchar fileID[16];
	data.ReadHash16(fileID);
	int nHeaderSize = 16;

	// Check that this data is for the correct file
	if ( (!reqfile) || md4cmp(packet, reqfile->GetFileHash()))
	{
		throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessBlockPacket)");
	}

	// Find the start & end positions, and size of this chunk of data
	uint64 nStartPos;
	uint64 nEndPos;
	uint32 nBlockSize = 0;
	
	if (bI64Offsets){
		nStartPos = data.ReadUInt64();
		nHeaderSize += 8;
	}
	else{
		nStartPos = data.ReadUInt32();
		nHeaderSize += 4;
	}
	if (packed)
	{
		nBlockSize = data.ReadUInt32();
		nHeaderSize += 4;
		nEndPos = nStartPos + (size - nHeaderSize);
	}
	else{
		if (bI64Offsets){
			nEndPos = data.ReadUInt64();
			nHeaderSize += 8;
		}
		else{
			nEndPos = data.ReadUInt32();
			nHeaderSize += 4;
		}
	}
	uint32 uTransferredFileDataSize = size - nHeaderSize;

	// Check that packet size matches the declared data size + header size (24)
	if (nEndPos == nStartPos || size != ((nEndPos - nStartPos) + nHeaderSize))
		throw GetResString(IDS_ERR_BADDATABLOCK) + _T(" (ProcessBlockPacket)");

	// -khaos--+++>
	// Extended statistics information based on which client and remote port sent this data.
	// The new function adds the bytes to the grand total as well as the given client/port.
	// bFromPF is not relevant to downloaded data.  It is purely an uploads statistic.
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(!IsLanClient())
#endif //LANCAST // NEO: NLC END <-- Xanatos --
		thePrefs.Add2SessionTransferData(GetClientSoft(), GetUserPort(), false, false, uTransferredFileDataSize, I2B(IsPrivatDownload()), reqfile->GetReleasePriority()); // NEO: BM - [BandwidthModeration] // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --
	// <-----khaos-

	//m_nDownDataRateMS += uTransferredFileDataSize;
	AddDownloadSize(uTransferredFileDataSize); // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --

	if (credits)
		credits->AddDownloaded(uTransferredFileDataSize, GetIP(), (GetRequestFile() != NULL /*GetDownloadState() == DS_ONQUEUE*/)); // NEO: NCS - [NeoCreditSystem] <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	theApp.argos->AddTrustedTransfer(GetConnectIP(),uTransferredFileDataSize);
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// Move end back one, should be inclusive
	nEndPos--;

	// Loop through to find the reserved block that this is within
	for (POSITION pos = m_PendingBlocks_list.GetHeadPosition(); pos != NULL; )
	{
		POSITION posLast = pos;
		Pending_Block_Struct *cur_block = m_PendingBlocks_list.GetNext(pos);
		if ((cur_block->block->StartOffset <= nStartPos) && (cur_block->block->EndOffset >= nStartPos))
		{
			// Found reserved block

			if (cur_block->fZStreamError){
				if (thePrefs.GetVerbose())
					AddDebugLogLine(false, _T("PrcBlkPkt: Ignoring %u bytes of block starting at %I64u because of errornous zstream state for file \"%s\" - %s"), uTransferredFileDataSize, nStartPos, reqfile->GetFileName(), DbgGetClientInfo());
				reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
				return;
			}

			// Remember this start pos, used to draw part downloading in list
			m_nLastBlockOffset = nStartPos;  

			// Occasionally packets are duplicated, no point writing it twice
			// This will be 0 in these cases, or the length written otherwise
			uint32 lenWritten = 0;

			// Handle differently depending on whether packed or not
			if (!packed)
			{
				// Write to disk (will be buffered in part file class)
				lenWritten = reqfile->WriteToBuffer(uTransferredFileDataSize, 
													packet + nHeaderSize,
													nStartPos,
													nEndPos,
													cur_block->block,
													GetIP()); // NEO: VOODOO - [UniversalPartfileInterface] <-- Xanatos --
			}
			else // Packed
			{
				ASSERT( (int)size > 0 );
				// Create space to store unzipped data, the size is only an initial guess, will be resized in unzip() if not big enough
				uint32 lenUnzipped = (size * 2); 
				// Don't get too big
				if (lenUnzipped > (EMBLOCKSIZE + 300))
					lenUnzipped = (EMBLOCKSIZE + 300);
				BYTE *unzipped = new BYTE[lenUnzipped];

				// Try to unzip the packet
				int result = unzip(cur_block, packet + nHeaderSize, uTransferredFileDataSize, &unzipped, &lenUnzipped);
				// no block can be uncompressed to >2GB, 'lenUnzipped' is obviously errornous.
				if (result == Z_OK && (int)lenUnzipped >= 0)
				{
					if (lenUnzipped > 0) // Write any unzipped data to disk
					{
						ASSERT( (int)lenUnzipped > 0 );

						// Use the current start and end positions for the uncompressed data
						nStartPos = cur_block->block->StartOffset + cur_block->totalUnzipped - lenUnzipped;
						nEndPos = cur_block->block->StartOffset + cur_block->totalUnzipped - 1;

						if (nStartPos > cur_block->block->EndOffset || nEndPos > cur_block->block->EndOffset){
							if (thePrefs.GetVerbose())
								DebugLogError(_T("PrcBlkPkt: ") + GetResString(IDS_ERR_CORRUPTCOMPRPKG),reqfile->GetFileName(),666);
							reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
							// There is no chance to recover from this error
						}
						else{
							// Write uncompressed data to file
							lenWritten = reqfile->WriteToBuffer(uTransferredFileDataSize,
								unzipped,
								nStartPos,
								nEndPos,
								cur_block->block,
								GetIP()); // NEO: VOODOO - [UniversalPartfileInterface] <-- Xanatos --
						}
					}
				}
				else
				{
					if (thePrefs.GetVerbose())
					{
						CString strZipError;
						if (cur_block->zStream && cur_block->zStream->msg)
							strZipError.Format(_T(" - %hs"), cur_block->zStream->msg);
						if (result == Z_OK && (int)lenUnzipped < 0){
							ASSERT(0);
							strZipError.AppendFormat(_T("; Z_OK,lenUnzipped=%d"), lenUnzipped);
						}
						DebugLogError(_T("PrcBlkPkt: ") + GetResString(IDS_ERR_CORRUPTCOMPRPKG) + strZipError, reqfile->GetFileName(), result);
					}
					reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);

					// If we had an zstream error, there is no chance that we could recover from it nor that we
					// could use the current zstream (which is in error state) any longer.
					if (cur_block->zStream){
						inflateEnd(cur_block->zStream);
						delete cur_block->zStream;
						cur_block->zStream = NULL;
					}

					// Although we can't further use the current zstream, there is no need to disconnect the sending 
					// client because the next zstream (a series of 10K-blocks which build a 180K-block) could be
					// valid again. Just ignore all further blocks for the current zstream.
					cur_block->fZStreamError = 1;
					cur_block->totalUnzipped = 0;
				}
				delete [] unzipped;
			}

			// These checks only need to be done if any data was written
			if (lenWritten > 0)
			{
				m_nTransferredDown += uTransferredFileDataSize;
				SetTransferredDownMini();

				// If finished reserved block
				if (nEndPos == cur_block->block->EndOffset)
				{
					reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
					delete cur_block->block;
					// Not always allocated
					if (cur_block->zStream){
						inflateEnd(cur_block->zStream);
						delete cur_block->zStream;
					}
					delete cur_block;
					m_PendingBlocks_list.RemoveAt(posLast);

					// Request next block
					if (thePrefs.GetDebugClientTCPLevel() > 0)
						DebugSend("More block requests", this);
					SendBlockRequests();
				}
			}

			// Stop looping and exit method
			return;
		}
	}

	TRACE("%s - Dropping packet\n", __FUNCTION__);
}

int CUpDownClient::unzip(Pending_Block_Struct* block, const BYTE* zipped, uint32 lenZipped, BYTE** unzipped, uint32* lenUnzipped, int iRecursion)
{
#define TRACE_UNZIP	/*TRACE*/

	TRACE_UNZIP("unzip: Zipd=%6u Unzd=%6u Rcrs=%d", lenZipped, *lenUnzipped, iRecursion);
  	int err = Z_DATA_ERROR;
  	try
	{
	    // Save some typing
	    z_stream *zS = block->zStream;
    
	    // Is this the first time this block has been unzipped
	    if (zS == NULL)
	    {
		    // Create stream
		    block->zStream = new z_stream;
		    zS = block->zStream;
    
		    // Initialise stream values
		    zS->zalloc = (alloc_func)0;
		    zS->zfree = (free_func)0;
		    zS->opaque = (voidpf)0;
    
		    // Set output data streams, do this here to avoid overwriting on recursive calls
		    zS->next_out = (*unzipped);
		    zS->avail_out = (*lenUnzipped);
    
		    // Initialise the z_stream
		    err = inflateInit(zS);
			if (err != Z_OK){
				TRACE_UNZIP("; Error: new stream failed: %d\n", err);
			    return err;
			}

			ASSERT( block->totalUnzipped == 0 );
		}

	    // Use whatever input is provided
		zS->next_in	 = const_cast<Bytef*>(zipped);
	    zS->avail_in = lenZipped;
    
	    // Only set the output if not being called recursively
	    if (iRecursion == 0)
	    {
		    zS->next_out = (*unzipped);
		    zS->avail_out = (*lenUnzipped);
	    }
    
	    // Try to unzip the data
		TRACE_UNZIP("; inflate(ain=%6u tin=%6u aout=%6u tout=%6u)", zS->avail_in, zS->total_in, zS->avail_out, zS->total_out);
	    err = inflate(zS, Z_SYNC_FLUSH);
    
	    // Is zip finished reading all currently available input and writing all generated output
	    if (err == Z_STREAM_END)
	    {
		    // Finish up
		    err = inflateEnd(zS);
			if (err != Z_OK){
				TRACE_UNZIP("; Error: end stream failed: %d\n", err);
			    return err;
			}
			TRACE_UNZIP("; Z_STREAM_END\n");

		    // Got a good result, set the size to the amount unzipped in this call (including all recursive calls)
		    (*lenUnzipped) = (zS->total_out - block->totalUnzipped);
		    block->totalUnzipped = zS->total_out;
	    }
	    else if ((err == Z_OK) && (zS->avail_out == 0) && (zS->avail_in != 0))
	    {
		    // Output array was not big enough, call recursively until there is enough space
			TRACE_UNZIP("; output array not big enough (ain=%u)\n", zS->avail_in);
    
		    // What size should we try next
		    uint32 newLength = (*lenUnzipped) *= 2;
		    if (newLength == 0)
			    newLength = lenZipped * 2;
    
		    // Copy any data that was successfully unzipped to new array
		    BYTE *temp = new BYTE[newLength];
			ASSERT( zS->total_out - block->totalUnzipped <= newLength );
		    memcpy(temp, (*unzipped), (zS->total_out - block->totalUnzipped));
		    delete [] (*unzipped);
		    (*unzipped) = temp;
		    (*lenUnzipped) = newLength;
    
		    // Position stream output to correct place in new array
		    zS->next_out = (*unzipped) + (zS->total_out - block->totalUnzipped);
		    zS->avail_out = (*lenUnzipped) - (zS->total_out - block->totalUnzipped);
    
		    // Try again
		    err = unzip(block, zS->next_in, zS->avail_in, unzipped, lenUnzipped, iRecursion + 1);
	    }
	    else if ((err == Z_OK) && (zS->avail_in == 0))
	    {
			TRACE_UNZIP("; all input processed\n");
		    // All available input has been processed, everything ok.
		    // Set the size to the amount unzipped in this call (including all recursive calls)
		    (*lenUnzipped) = (zS->total_out - block->totalUnzipped);
		    block->totalUnzipped = zS->total_out;
	    }
	    else
	    {
		    // Should not get here unless input data is corrupt
			if (thePrefs.GetVerbose())
			{
				CString strZipError;
				if (zS->msg)
					strZipError.Format(_T(" %d: '%hs'"), err, zS->msg);
				else if (err != Z_OK)
					strZipError.Format(_T(" %d: '%hs'"), err, zError(err));
				TRACE_UNZIP("; Error: %s\n", strZipError);
				DebugLogError(_T("Unexpected zip error%s in file \"%s\""), strZipError, reqfile ? reqfile->GetFileName() : NULL);
			}
	    }
    
	    if (err != Z_OK)
		    (*lenUnzipped) = 0;
  	}
  	catch (...){
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Unknown exception in %hs: file \"%s\""), __FUNCTION__, reqfile ? reqfile->GetFileName() : NULL);
		err = Z_DATA_ERROR;
		ASSERT(0);
	}

	return err;
}

// NEO: ASM - [AccurateSpeedMeasure] -- Xanatos -->
uint32 CUpDownClient::CalculateDownloadRate(){
	// Add new sample
	TransferredData newSample;
	newSample.datalen = m_nSumForAvgDownDataRate;
	newSample.timestamp  = ::GetTickCount();
	m_AvarageDDR_list.AddHead(newSample);

	// Keep up to 21 samples (=> 20 seconds)
	while(m_AvarageDDR_list.GetSize() > 21){
		m_AvarageDDR_list.RemoveTail();
	}

	if(m_AvarageDDR_list.GetSize() > 1){	
		// Compute datarate (=> display)
		POSITION pos = m_AvarageDDR_list.FindIndex(thePrefs.GetDatarateSamples()); 
		if(pos == NULL)
			pos = m_AvarageDDR_list.GetTailPosition();
		TransferredData& oldestSample = m_AvarageDDR_list.GetAt(pos);
		uint32 deltaTime = newSample.timestamp - oldestSample.timestamp;
		uint32 deltaByte = newSample.datalen - oldestSample.datalen;
		if(deltaTime > 0)
			m_nDownDatarate = (UINT)((float)1000 * deltaByte / deltaTime);   // [bytes/s]
	}else
		m_nDownDatarate = 0;

    // Check if it's time to update the display.
	UpdateDisplayedInfo(true);

	return m_nDownDatarate;
}

UINT CUpDownClient::CheckDownloadRate(int dataratestocheck)
{
	if(m_AvarageDDR_list.GetSize() > 4 && dataratestocheck > 2){	
		POSITION pos = m_AvarageDDR_list.FindIndex(dataratestocheck);
		if(pos == NULL)
			pos = m_AvarageDDR_list.GetTailPosition();
		TransferredData& oldestSample = m_AvarageDDR_list.GetAt(pos);
		//TransferredData& newSample = m_AvarageDDR_list.GetHead();
		//uint32 deltaTime = newSample.timestamp - oldestSample.timestamp;
		//uint32 deltaByte = newSample.datalen - oldestSample.datalen;
		uint32 deltaTime = ::GetTickCount() - oldestSample.timestamp;
		uint32 deltaByte = m_nSumForAvgDownDataRate - oldestSample.datalen;
		if(deltaTime > 0)
			return (UINT)((float)1000 * deltaByte / deltaTime);   // [bytes/s]
	}
	return 0;
}
// NEO: ASM END <-- Xanatos --

void CUpDownClient::CheckDownloadTimeout()
{
	//SendBlockRequests(); // X-ToDo: would this be a good idea?

	if (IsDownloadingFromPeerCache() && m_pPCDownSocket && m_pPCDownSocket->IsConnected())
	{
		ASSERT( DOWNLOADTIMEOUT < m_pPCDownSocket->GetTimeOut() );
		if (GetTickCount() - m_dwLastBlockReceived > DOWNLOADTIMEOUT)
		{
			OnPeerCacheDownSocketTimeout();
		}
	}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	else if (IsDownloadingFromWebCache() && m_pWCDownSocket) // jp proxy stall fix removed: && m_pWCDownSocket->IsConnected())
	{
		ASSERT( DOWNLOADTIMEOUT < m_pWCDownSocket->GetTimeOut() );
		if (m_pWCDownSocket->IsConnected())
		{
			if (GetTickCount() - m_dwLastBlockReceived > DOWNLOADTIMEOUT)
			{
				OnWebCacheDownSocketTimeout();
			}
		}
		else //this shouldn't happen but aparently does maybe fixed by WebCacheDownSocket::OnConnect() function??
		{
			if (GetTickCount() - m_dwLastBlockReceived > DOWNLOADTIMEOUT)
			{
				if( thePrefs.GetLogWebCacheEvents() ) // yonatan tmp logging
					AddDebugLogLine( false, _T("Disconnected WCDownSocket Timed Out!!! PLEASE TELL THE WEBCACHE DEVELOPERS IF YOU EVER SEE THIS") );
				OnWebCacheDownSocketTimeout();
			}
		}
	}
	else if( !IsProxy() ) // proxies don't have a socket!
#else
	else
#endif // NEO: WC END <-- Xanatos --
	{
		if ((::GetTickCount() - m_dwLastBlockReceived) > DOWNLOADTIMEOUT)
		{
			ASSERT( socket != NULL );
			if (socket != NULL)
			{
				ASSERT( !socket->IsRawDataMode() );
				if (!socket->IsRawDataMode())
					SendCancelTransfer();
			}
			SetDownloadState(DS_ONQUEUE, _T("Timeout. More than 100 seconds since last complete block was received."));
		}
		// NEO: DKA - [DownloadKeepAlive] -- Xanatos -->
		else if(thePrefs.IsEnableDownloadKeepAlive() 
		 && (::GetTickCount() - m_dwLastBlockReceived) > thePrefs.GetDownloadKeepAliveTimeoutMs()
		 && m_fKeepAlivePending == 0)
		{
			ASSERT( socket != NULL );
			if (socket != NULL && !socket->IsRawDataMode() && socket->IsDownloadLimit() == false) // Fix downloadLimit
			{
				m_fKeepAlivePending = 1;
				m_fActiveDownReqFlag = 0; // NEO: FSUR - [FixStartupLoadReq]
				AddDebugLogLine(false, _T("--> Sending download keep alive ping %s - %s"),DbgGetClientInfo(), DbgGetFileInfo(reqfile ? reqfile->GetFileHash() : NULL));
				SendFileRequest(); // David: to have a cleaner code we will ping with the usual full request
			}
		}	
		// NEO: DKA END <-- Xanatos --
	}
}

uint16 CUpDownClient::GetAvailablePartCount() const
{
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
	CClientFileStatus* status = GetFileStatus(reqfile);
	if(status == NULL || status->GetPartStatus() == NULL)
		return 0;

	UINT result = 0;
	for (UINT i = 0; i < status->GetPartCount(); i++){
		if (status->GetPartStatus()[i])
			result++;
	}
	return (uint16)result;
	// NEO: SCFS END <-- Xanatos --
}

void CUpDownClient::SetRemoteQueueRank(UINT nr, bool bUpdateDisplay)
{
	// NEO: CQR - [CollorQueueRank] -- Xanatos -->
	if (!m_nInitialRemoteQueueRank)
		m_nInitialRemoteQueueRank = nr;
	//if (nr != m_nRemoteQueueRank )
		m_nDeltaRemoteQueueRank = (int)nr - (int)m_nRemoteQueueRank;
	// NEO: CQR END <-- Xanatos --

	m_nRemoteQueueRank = nr;
	UpdateDisplayedInfo(bUpdateDisplay);
}

void CUpDownClient::UDPReaskACK(uint16 nNewQR)
{
	m_bUDPPending = false;
	SetRemoteQueueRank(nNewQR, true);
    SetLastAskedTime();
}

void CUpDownClient::UDPReaskFNF()
{
	m_bUDPPending = false;
	if (GetDownloadState() != DS_DOWNLOADING){ // avoid premature deletion of 'this' client
		if (thePrefs.GetVerbose())
			AddDebugLogLine(DLP_LOW, false, _T("UDP FNF-Answer: %s - %s"),DbgGetClientInfo(), DbgGetFileInfo(reqfile ? reqfile->GetFileHash() : NULL));

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
		if(thePrefs.IsFileFakerDetection())
			CheckFileNotFound();
#endif //ARGOS // NEO: NA END <-- Xanatos --

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
		if(thePrefs.SaveSourceFileList() && source && reqfile)
			source->RemoveFile(reqfile->GetFileHash());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
			if (reqfile)
				reqfile->m_DeadSourceList.AddDeadSource(this);
		switch (GetDownloadState()) {
			case DS_ONQUEUE:
			case DS_NONEEDEDPARTS:
                DontSwapTo(reqfile);
                if (SwapToAnotherFile(_T("Source says it doesn't have the file. CUpDownClient::UDPReaskFNF()"), true, true, true, NULL, false, false))
					break;
				/*fall through*/
			default:
				theApp.downloadqueue->RemoveSource(this);
				if (!socket){
					if (Disconnected(_T("UDPReaskFNF socket=NULL")))
						delete this;
				}
		}
	}
	else
	{
		if (thePrefs.GetVerbose())
			DebugLogWarning(_T("UDP FNF-Answer: %s - did not remove client because of current download state"),GetUserName());
	}
}

void CUpDownClient::UDPReaskForDownload()
{
	ASSERT ( reqfile );
	if(!reqfile || m_bUDPPending)
		return;
	
	//TODO: This should be changed to determine if the last 4 UDP packets failed, not the total one.
	if( m_nTotalUDPPackets > 3 && ((float)(m_nFailedUDPPackets/m_nTotalUDPPackets) > .3))
		return;

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

	if (GetUDPPort() != 0 && GetUDPVersion() != 0 && thePrefs.GetUDPPort() != 0 &&
		(!theApp.IsFirewalled() || IsLowIDUDPPingSupport()) && !(socket && socket->IsConnected()) && !thePrefs.GetProxySettings().UseProxy) // NEO: NMP - [NeoModProt] <-- Xanatos --
	{ 
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
		if((!theApp.IsFirewalled() || IsLowIDUDPPingSupport()) && (!HasLowID() || GetNatTraversalState() & NT_TUNEL))
#else
		if((!theApp.IsFirewalled() || IsLowIDUDPPingSupport()) && !HasLowID() )
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
		{
			//don't use udp to ask for sources
			if(IsSourceRequestAllowed())
				return;
	
	        if(SwapToAnotherFile(_T("A4AF check before OP__ReaskFilePing. CUpDownClient::UDPReaskForDownload()"), true, false, false, NULL, true, true)) {
	            return; // we swapped, so need to go to tcp
	        }
	
			m_bUDPPending = true;
			CSafeMemFile data(128);
			data.WriteHash16(reqfile->GetFileHash());
			if (GetUDPVersion() > 3)
			{
				// NEO: IPS - [InteligentPartSharing] -- Xanatos -->
				if (reqfile->IsPartFile())
					reqfile->WritePartStatus(&data, status);
				else if(!reqfile->WritePartSelection(&data, status)) 
					data.WriteUInt16(0);
				// NEO: IPS END <-- Xanatos --
			}
			if (GetUDPVersion() > 2)
				data.WriteUInt16(reqfile->m_nCompleteSourcesCount);

			// NEO: XUDP - [UDPExtensions] -- Xanatos -->
			if(GetUDPxSupport())
				WriteModMultiPacket(&data, reqfile, status, true, true); // NEO: NMPm - [NeoModProtMultiPacket]
			// NEO: XUDP END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			if (thePrefs.IsWebCacheEnabled() && SupportsMultiOHCBs()
				&& AttachMultiOHCBsRequest(data))
			{
				//AttachMultiOHCBsRequest(data);
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugSend("OP__MultiFileReask", this, reqfile->GetFileHash());
				Packet* response = new Packet(&data, OP_MODPROT); // NEO: NMP - [NeoModProt] <-- Xanatos --
				response->opcode = OP_MULTI_FILE_REASK;
				theStats.AddUpDataOverheadFileRequest(response->size);
				theApp.downloadqueue->AddUDPFileReasks();
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
  #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
				SendPacketUDP(response, (GetNatTraversalState() & NT_TUNEL));
  #else
				SendPacketUDP(response);
  #endif //NATTUNNELING // NEO: NATT END
 #else
				theApp.clientudp->SendPacket(response,GetIP(),GetUDPPort());
 #endif // ISPBYPASS // NEO: SCC END
			}
			else
#endif // NEO: WC END <-- Xanatos --
			{
				if (thePrefs.GetDebugClientUDPLevel() > 0)
					DebugSend("OP__ReaskFilePing", this, reqfile->GetFileHash());
				Packet* response = new Packet(&data, OP_EMULEPROT);
				response->opcode = OP_REASKFILEPING;
				theStats.AddUpDataOverheadFileRequest(response->size);
				theApp.downloadqueue->AddUDPFileReasks();
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
				SendPacketUDP(response, (GetNatTraversalState() & NT_TUNEL));
 #else
				SendPacketUDP(response);
 #endif //NATTUNNELING // NEO: NATT END
#else
				theApp.clientudp->SendPacket(response,GetIP(),GetUDPPort());
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
			}
			m_nTotalUDPPackets++;
		}
		else if (!theApp.IsFirewalled() && HasLowID() && GetBuddyIP() && GetBuddyPort() && HasValidBuddyID()) // NEO: MOD <-- Xanatos --
		{
			m_bUDPPending = true;
			CSafeMemFile data(128);
			data.WriteHash16(GetBuddyID());
			data.WriteHash16(reqfile->GetFileHash());
			if (GetUDPVersion() > 3)
			{
				// NEO: IPS - [InteligentPartSharing] -- Xanatos -->
				if (reqfile->IsPartFile())
					reqfile->WritePartStatus(&data, status);
				else if(!reqfile->WritePartSelection(&data, status)) 
					data.WriteUInt16(0);
				// NEO: IPS END <-- Xanatos --
			}
			if (GetUDPVersion() > 2)
				data.WriteUInt16(reqfile->m_nCompleteSourcesCount);

			// NEO: XUDP - [UDPExtensions] -- Xanatos -->
			if(GetUDPxSupport())
				WriteModMultiPacket(&data, reqfile, status, true, true); // NEO: NMPm - [NeoModProtMultiPacket]
			// NEO: XUDP END <-- Xanatos --

			if (thePrefs.GetDebugClientUDPLevel() > 0)
				DebugSend("OP__ReaskCallbackUDP", this, reqfile->GetFileHash());
			Packet* response = new Packet(&data, OP_EMULEPROT);
			response->opcode = OP_REASKCALLBACKUDP;
			theStats.AddUpDataOverheadFileRequest(response->size);
			theApp.downloadqueue->AddUDPFileReasks();
			theApp.clientudp->SendPacket(response, GetBuddyIP(), GetBuddyPort() );
			m_nTotalUDPPackets++;
		}
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
		// Note: to can use this improvement you need to implement also XMan1's fix for the udp reask ping (m_bAddNextConnect)
		else if( HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && GetNatTraversalState() == NT_NONE)
		{
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			if(UseNATEncrpytion() && (thePrefs.IsSupportISPBypass() == 1 || thePrefs.IsSupportISPBypass() == 2) && (thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1))
				PrepareNATEncryption();
 #endif // ISPBYPASS // NEO: SCC END
			TryToSyncOverBuddy();
		}
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
	}
}

void CUpDownClient::UpdateDisplayedInfo(bool force)
{
//#ifdef _DEBUG
//	force = true;
//#endif
    DWORD curTick = ::GetTickCount();
    if(force || curTick-m_lastRefreshedDLDisplay > MINWAIT_BEFORE_DLDISPLAY_WINDOWUPDATE+m_random_update_wait) {
	    theApp.emuledlg->transferwnd->downloadlistctrl.UpdateItem(this);
		theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(this);
		theApp.emuledlg->transferwnd->downloadclientsctrl.RefreshClient(this);
        m_lastRefreshedDLDisplay = curTick;
    }
}

const bool CUpDownClient::IsInNoNeededList(const CPartFile* fileToCheck) const
{
    for (POSITION pos = m_OtherNoNeeded_list.GetHeadPosition();pos != 0;m_OtherNoNeeded_list.GetNext(pos))
	{
        if (m_OtherNoNeeded_list.GetAt(pos) == fileToCheck)
            return true;
    }

    return false;
}

const bool CUpDownClient::SwapToRightFile(CPartFile* SwapTo, CPartFile* cur_file, bool ignoreSuspensions, bool SwapToIsNNPFile, bool curFileisNNPFile, bool& wasSkippedDueToSourceExchange, bool doAgressiveSwapping, bool debug)
{
    bool printDebug = debug && thePrefs.GetLogA4AF();

    if(printDebug) {
        AddDebugLogLine(DLP_LOW, false, _T("oooo Debug: SwapToRightFile. Start compare SwapTo: %s and cur_file %s"), SwapTo?SwapTo->GetFileName():_T("null"), cur_file->GetFileName());
        AddDebugLogLine(DLP_LOW, false, _T("oooo Debug: doAgressiveSwapping: %s"), doAgressiveSwapping?_T("true"):_T("false"));
    }

    if (!SwapTo) {
        return true;
    }

    if(!curFileisNNPFile && cur_file->GetSourceCount() < (UINT)cur_file->PartPrefs.GetHardLimit() || // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
        curFileisNNPFile && cur_file->GetSourceCount() < (UINT)cur_file->PartPrefs.GetSwapLimit()) { // NEO: NST - [NeoSourceTweaks] <-- Xanatos --

            if(printDebug)
                AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: cur_file does probably not have too many sources."));

            if(SwapTo->GetSourceCount() > (UINT)SwapTo->PartPrefs.GetHardLimit() || // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
               SwapTo->GetSourceCount() >= (UINT)SwapTo->PartPrefs.GetSwapLimit() && // NEO: NST - [NeoSourceTweaks] <-- Xanatos --
               SwapTo == reqfile &&
               (
                GetDownloadState() == DS_LOWTOLOWIP ||
                GetDownloadState() == DS_REMOTEQUEUEFULL
               )
              ) {
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: SwapTo is about to be deleted due to too many sources on that file, so we can steal it."));
                return true;
            }

            if(ignoreSuspensions  || !IsSwapSuspended(cur_file, doAgressiveSwapping, curFileisNNPFile)) {
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: No suspend block."));

                DWORD tempTick = ::GetTickCount();
                bool rightFileHasHigherPrio = CPartFile::RightFileHasHigherPrio(SwapTo, cur_file);
                uint32 allNnpReaskTime = /*FILEREASKTIME*2*/cur_file->PartPrefs.GetNnPReaskIntervalsMs()*(m_OtherNoNeeded_list.GetSize() + (GetDownloadState() == DS_NONEEDEDPARTS)?1:0); // wait two reask interval for each nnp file before reasking an nnp file // NEO: DR - [DownloadReask] <-- Xanatos --

                if(!SwapToIsNNPFile && (!curFileisNNPFile || GetLastAskedTime(cur_file) == 0 || tempTick-GetLastAskedTime(cur_file) > allNnpReaskTime) && rightFileHasHigherPrio ||
                   SwapToIsNNPFile && curFileisNNPFile &&
                   (
                    GetLastAskedTime(SwapTo) != 0 &&
                    (
                     GetLastAskedTime(cur_file) == 0 ||
                     tempTick-GetLastAskedTime(SwapTo) < tempTick-GetLastAskedTime(cur_file) && (tempTick-GetLastAskedTime(cur_file) > allNnpReaskTime || rightFileHasHigherPrio && tempTick-GetLastAskedTime(SwapTo) < allNnpReaskTime)
                    ) ||
                    rightFileHasHigherPrio && GetLastAskedTime(SwapTo) == 0 && GetLastAskedTime(cur_file) == 0
                   ) ||
                   SwapToIsNNPFile && !curFileisNNPFile) {
                    if(printDebug)
                        if(!SwapToIsNNPFile && !curFileisNNPFile && rightFileHasHigherPrio)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Higher prio."));
                        else if(!SwapToIsNNPFile && (GetLastAskedTime(cur_file) == 0 || tempTick-GetLastAskedTime(cur_file) > allNnpReaskTime) && rightFileHasHigherPrio)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Time to reask nnp and it had higher prio."));
                        else if(GetLastAskedTime(SwapTo) != 0 &&
                                (
                                 GetLastAskedTime(cur_file) == 0 ||
                                 tempTick-GetLastAskedTime(SwapTo) < tempTick-GetLastAskedTime(cur_file) && (tempTick-GetLastAskedTime(cur_file) > allNnpReaskTime || rightFileHasHigherPrio && tempTick-GetLastAskedTime(SwapTo) < allNnpReaskTime)
                                )
                               )
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Both nnp and cur_file has longer time since reasked."));
                        else if(SwapToIsNNPFile && !curFileisNNPFile)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: SwapToIsNNPFile && !curFileisNNPFile"));
                        else
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Higher prio for unknown reason!"));

                    if(IsSourceRequestAllowed(cur_file) && (cur_file->AllowSwapForSourceExchange() || cur_file == reqfile && RecentlySwappedForSourceExchange()) ||
                       !(IsSourceRequestAllowed(SwapTo) && (SwapTo->AllowSwapForSourceExchange() || SwapTo == reqfile && RecentlySwappedForSourceExchange())) ||
                       (GetDownloadState()==DS_ONQUEUE && GetRemoteQueueRank() <= 50)) {
                        if(printDebug)
                            AddDebugLogLine(DLP_LOW, false, _T("oooo Debug: Source Request check ok."));
                        return true;
                    } else {
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Source Request check failed."));
                        wasSkippedDueToSourceExchange = true;
                    }
                }

                if(IsSourceRequestAllowed(cur_file, true) && (cur_file->AllowSwapForSourceExchange() || cur_file == reqfile && RecentlySwappedForSourceExchange()) &&
                   !(IsSourceRequestAllowed(SwapTo, true) && (SwapTo->AllowSwapForSourceExchange() || SwapTo == reqfile && RecentlySwappedForSourceExchange())) &&
                   (GetDownloadState()!=DS_ONQUEUE || GetDownloadState()==DS_ONQUEUE && GetRemoteQueueRank() > 50)) {
                    wasSkippedDueToSourceExchange = true;

                    if(printDebug)
                        AddDebugLogLine(DLP_LOW, false, _T("oooo Debug: Source Exchange."));
                    return true;
                }
            } else if(printDebug) {
                AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: Suspend block."));
            }
    } else if(printDebug) {
        AddDebugLogLine(DLP_VERYLOW, false, _T("oooo Debug: cur_file probably has too many sources."));
    }

    if(printDebug)
        AddDebugLogLine(DLP_LOW, false, _T("oooo Debug: Return false"));

    return false;
}

bool CUpDownClient::SwapToAnotherFile(LPCTSTR reason, bool bIgnoreNoNeeded, bool ignoreSuspensions, bool bRemoveCompletely, CPartFile* toFile, bool allowSame, bool isAboutToAsk, bool debug)
{
    bool printDebug = debug && thePrefs.GetLogA4AF();

    if(printDebug)
        AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Switching source %s Remove = %s; bIgnoreNoNeeded = %s; allowSame = %s; Reason = \"%s\""), DbgGetClientInfo(), (bRemoveCompletely ? _T("Yes") : _T("No")), (bIgnoreNoNeeded ? _T("Yes") : _T("No")), (allowSame ? _T("Yes") : _T("No")), reason);

    if(!bRemoveCompletely && allowSame && thePrefs.GetA4AFSaveCpu()) {
        // Only swap if we can't keep the old source
        if(printDebug)
            AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: return false since prefs setting to save cpu is enabled."));
        return false;
    }

	bool doAgressiveSwapping = (bRemoveCompletely || !allowSame || isAboutToAsk);
    if(printDebug)
        AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: doAgressiveSwapping: %s"), doAgressiveSwapping?_T("true"):_T("false"));

    if(!bRemoveCompletely && !ignoreSuspensions && allowSame && GetTimeUntilReask(reqfile, doAgressiveSwapping, true, false) > 0 && (GetDownloadState() != DS_NONEEDEDPARTS || m_OtherRequests_list.IsEmpty())) {
        if(printDebug)
            AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: return false due to not reached reask time: GetTimeUntilReask(...) > 0"));

        return false;
    }

    if(!bRemoveCompletely && allowSame && m_OtherRequests_list.IsEmpty() && (/* !bIgnoreNoNeeded ||*/ m_OtherNoNeeded_list.IsEmpty())) {
        // no file to swap too, and it's ok to keep it
        if(printDebug)
            AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: return false due to no file to swap too, and it's ok to keep it."));
        return false;
    }

    if (!bRemoveCompletely &&
        (GetDownloadState() != DS_ONQUEUE &&
         GetDownloadState() != DS_NONEEDEDPARTS &&
         GetDownloadState() != DS_TOOMANYCONNS &&
         GetDownloadState() != DS_REMOTEQUEUEFULL &&
         GetDownloadState() != DS_CONNECTED
        )) {
        if(printDebug)
            AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: return false due to wrong state."));
		return false;
    }

	CPartFile* SwapTo = NULL;
	CPartFile* cur_file = NULL;
	POSITION finalpos = NULL;
	CTypedPtrList<CPtrList, CPartFile*>* usedList = NULL;

    if(allowSame && !bRemoveCompletely) {
        SwapTo = reqfile;
        if(printDebug)
            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: allowSame: File %s SourceReq: %s"), reqfile->GetFileName(), IsSourceRequestAllowed(reqfile)?_T("true"):_T("false"));
    }

    bool SwapToIsNNP = (SwapTo != NULL && SwapTo == reqfile && GetDownloadState() == DS_NONEEDEDPARTS);

    CPartFile* skippedDueToSourceExchange = NULL;
    bool skippedIsNNP = false;

	if (!m_OtherRequests_list.IsEmpty()){
        if(printDebug)
            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: m_OtherRequests_list"));

		for (POSITION pos = m_OtherRequests_list.GetHeadPosition();pos != 0;m_OtherRequests_list.GetNext(pos)){
			cur_file = m_OtherRequests_list.GetAt(pos);

            if(printDebug)
                AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Checking file: %s SoureReq: %s"), cur_file->GetFileName(), IsSourceRequestAllowed(cur_file)?_T("true"):_T("false"));

            if(!bRemoveCompletely && !ignoreSuspensions && allowSame && IsSwapSuspended(cur_file, doAgressiveSwapping, false)) {
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: continue due to IsSwapSuspended(file) == true"));
                continue;
            }

            if (cur_file != reqfile && theApp.downloadqueue->IsPartFile(cur_file) && !cur_file->IsStopped() 
				&& (cur_file->GetStatus(false) == PS_READY || cur_file->GetStatus(false) == PS_EMPTY))	
			{
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: It's a partfile, not stopped, etc."));

				if (toFile != NULL){
					if (cur_file == toFile){
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Found toFile."));

                        SwapTo = cur_file;
                        SwapToIsNNP = false;
                		usedList = &m_OtherRequests_list;
						finalpos = pos;
						break;
					}
				} else {
                    bool wasSkippedDueToSourceExchange = false;
                    if(SwapToRightFile(SwapTo, cur_file, ignoreSuspensions, SwapToIsNNP, false, wasSkippedDueToSourceExchange, doAgressiveSwapping, debug)) {
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Swapping to file %s"), cur_file->GetFileName());

                        if(SwapTo && wasSkippedDueToSourceExchange) {
                            if(debug && thePrefs.GetLogA4AF()) AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Swapped due to source exchange possibility"));
                            bool discardSkipped = false;
                            if(SwapToRightFile(skippedDueToSourceExchange, SwapTo, ignoreSuspensions, skippedIsNNP, SwapToIsNNP, discardSkipped, doAgressiveSwapping, debug)) {
                                skippedDueToSourceExchange = SwapTo;
                                skippedIsNNP = skippedIsNNP?true:(SwapTo == reqfile && GetDownloadState() == DS_NONEEDEDPARTS);
                                if(printDebug)
                                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Skipped file was better than last skipped file."));
                            }
                        }

                        SwapTo = cur_file;
                        SwapToIsNNP = false;
                		usedList = &m_OtherRequests_list;
					    finalpos=pos;
                    } else {
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Keeping file %s"), SwapTo->GetFileName());
                        if(wasSkippedDueToSourceExchange) {
                            if(printDebug)
                                AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Kept the file due to source exchange possibility"));
                            bool discardSkipped = false;
                            if(SwapToRightFile(skippedDueToSourceExchange, cur_file, ignoreSuspensions, skippedIsNNP, false, discardSkipped, doAgressiveSwapping, debug)) {
                                skippedDueToSourceExchange = cur_file;
                                skippedIsNNP = false;
                                if(printDebug)
                                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Skipped file was better than last skipped file."));
                            }
                        }
                    }
                }
			}
		}
	}

    //if ((!SwapTo || SwapTo == reqfile && GetDownloadState() == DS_NONEEDEDPARTS) && bIgnoreNoNeeded){
        if(printDebug)
            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: m_OtherNoNeeded_list"));

		for (POSITION pos = m_OtherNoNeeded_list.GetHeadPosition();pos != 0;m_OtherNoNeeded_list.GetNext(pos)){
			cur_file = m_OtherNoNeeded_list.GetAt(pos);

            if(printDebug)
                AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Checking file: %s "), cur_file->GetFileName());

            if(!bRemoveCompletely && !ignoreSuspensions && allowSame && IsSwapSuspended(cur_file, doAgressiveSwapping, true)) {
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: continue due to !IsSwapSuspended(file) == true"));
                continue;
            }

			if (cur_file != reqfile && theApp.downloadqueue->IsPartFile(cur_file) && !cur_file->IsStopped() 
				&& (cur_file->GetStatus(false) == PS_READY || cur_file->GetStatus(false) == PS_EMPTY) )	
			{
                if(printDebug)
                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: It's a partfile, not stopped, etc."));

				if (toFile != NULL){
					if (cur_file == toFile){
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Found toFile."));
    
                        SwapTo = cur_file;
                		usedList = &m_OtherNoNeeded_list;
						finalpos = pos;
						break;
					}
				} else {
                    bool wasSkippedDueToSourceExchange = false;
                    if(SwapToRightFile(SwapTo, cur_file, ignoreSuspensions, SwapToIsNNP, true, wasSkippedDueToSourceExchange, doAgressiveSwapping, debug)) {
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Swapping to file %s"), cur_file->GetFileName());

                        if(SwapTo && wasSkippedDueToSourceExchange) {
                            if(printDebug)
                                AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Swapped due to source exchange possibility"));
                            bool discardSkipped = false;
                            if(SwapToRightFile(skippedDueToSourceExchange, SwapTo, ignoreSuspensions, skippedIsNNP, SwapToIsNNP, discardSkipped, doAgressiveSwapping, debug)) {
                                skippedDueToSourceExchange = SwapTo;
                                skippedIsNNP = skippedIsNNP?true:(SwapTo == reqfile && GetDownloadState() == DS_NONEEDEDPARTS);
                                if(printDebug)
                                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Skipped file was better than last skipped file."));
                            }
                        }

                        SwapTo = cur_file;
                        SwapToIsNNP = true;
                		usedList = &m_OtherNoNeeded_list;
					    finalpos=pos;
                    } else {
                        if(printDebug)
                            AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Keeping file %s"), SwapTo->GetFileName());
                        if(wasSkippedDueToSourceExchange) {
                            if(debug && thePrefs.GetVerbose()) AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Kept the file due to source exchange possibility"));
                            bool discardSkipped = false;
                            if(SwapToRightFile(skippedDueToSourceExchange, cur_file, ignoreSuspensions, skippedIsNNP, true, discardSkipped, doAgressiveSwapping, debug)) {
                                skippedDueToSourceExchange = cur_file;
                                skippedIsNNP = true;
                                if(printDebug)
                                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Skipped file was better than last skipped file."));
                            }
                        }
                    }
				}
			}
		}
	//}

    if (SwapTo){
        if(printDebug) {
            if(SwapTo != reqfile) {
                AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Found file to swap to %s"), SwapTo->GetFileName());
            } else {
                AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Will keep current file. %s"), SwapTo->GetFileName());
            }
        }

		CString strInfo(reason);
        if(skippedDueToSourceExchange) {
            bool wasSkippedDueToSourceExchange = false;
            bool skippedIsBetter = SwapToRightFile(SwapTo, skippedDueToSourceExchange, ignoreSuspensions, SwapToIsNNP, skippedIsNNP, wasSkippedDueToSourceExchange, doAgressiveSwapping, debug);
            if(skippedIsBetter || wasSkippedDueToSourceExchange) {
                SwapTo->SetSwapForSourceExchangeTick();
                SetSwapForSourceExchangeTick();

                strInfo = _T("******SourceExchange-Swap****** ") + strInfo;
                if(printDebug) {
                    AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Due to sourceExchange."));
                } else if(thePrefs.GetLogA4AF() && reqfile == SwapTo) {
                    AddDebugLogLine(DLP_LOW, false, _T("ooo Didn't swap source due to source exchange possibility. %s Remove = %s '%s' Reason: %s"), DbgGetClientInfo(), (bRemoveCompletely ? _T("Yes") : _T("No") ), (this->reqfile)?this->reqfile->GetFileName():_T("null"), strInfo);
                }
            } else if(printDebug) {
				AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Normal. SwapTo better than skippedDueToSourceExchange."));
            }
        } else if(printDebug) {
			AddDebugLogLine(DLP_VERYLOW, false, _T("ooo Debug: Normal. skippedDueToSourceExchange == NULL"));
        }

		if (SwapTo != reqfile && DoSwap(SwapTo,bRemoveCompletely, strInfo)){
            if(debug && thePrefs.GetLogA4AF()) AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Swap successful."));
            if(usedList && finalpos) {
			    usedList->RemoveAt(finalpos);
            }
			return true;
        } else if(printDebug) {
            AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Swap didn't happen."));
        }
    }

    if(printDebug)
        AddDebugLogLine(DLP_LOW, false, _T("ooo Debug: Done %s"), DbgGetClientInfo());

	return false;
}

bool CUpDownClient::DoSwap(CPartFile* SwapTo, bool bRemoveCompletely, LPCTSTR reason, bool bHandleClientReq) // NEO: MCM - [ManualClientManagement] <-- Xanatos --
{
    if (thePrefs.GetLogA4AF())
        AddDebugLogLine(DLP_LOW, false, _T("ooo Swapped source %s Remove = %s '%s'   -->   %s Reason: %s"), DbgGetClientInfo(), (bRemoveCompletely ? _T("Yes") : _T("No") ), (this->reqfile)?this->reqfile->GetFileName():_T("null"), SwapTo->GetFileName(), reason);

	// NEO: MCM - [ManualClientManagement] -- Xanatos -->
	if(bHandleClientReq){
		POSITION pos3 = m_OtherRequests_list.Find(SwapTo);
		if(pos3){
			m_OtherRequests_list.RemoveAt(pos3);
		}else{		
			POSITION pos4 = m_OtherNoNeeded_list.Find(SwapTo);
			if(pos4){
				m_OtherNoNeeded_list.RemoveAt(pos4);
			}
		}
	}
	// NEO: MCM END <-- Xanatos --

	// 17-Dez-2003 [bc]: This "reqfile->srclists[sourcesslot].Find(this)" was the only place where 
	// the usage of the "CPartFile::srclists[100]" is more effective than using one list. If this
	// function here is still (again) a performance problem there is a more effective way to handle
	// the 'Find' situation. Hint: usage of a node ptr which is stored in the CUpDownClient.
	POSITION pos = reqfile->srclist.Find(this);
	if(pos)
    {
    	reqfile->srclist.RemoveAt(pos);
    } else {
        AddDebugLogLine(DLP_HIGH, true, _T("o-o Unsync between parfile->srclist and client otherfiles list. Swapping client where client has file as reqfile, but file doesn't have client in srclist. %s Remove = %s '%s'   -->   '%s'  SwapReason: %s"), DbgGetClientInfo(), (bRemoveCompletely ? _T("Yes") : _T("No") ), (this->reqfile)?this->reqfile->GetFileName():_T("null"), SwapTo->GetFileName(), reason);
    }

	// remove this client from the A4AF list of our new reqfile
	POSITION pos2 = SwapTo->A4AFsrclist.Find(this);
	if (pos2) {
		SwapTo->A4AFsrclist.RemoveAt(pos2);
    } else {
        AddDebugLogLine(DLP_HIGH, true, _T("o-o Unsync between parfile->srclist and client otherfiles list. Swapping client where client has file in another list, but file doesn't have client in a4af srclist. %s Remove = %s '%s'   -->   '%s'  SwapReason: %s"), DbgGetClientInfo(), (bRemoveCompletely ? _T("Yes") : _T("No") ), (this->reqfile)?this->reqfile->GetFileName():_T("null"), SwapTo->GetFileName(), reason);
    }
	theApp.emuledlg->transferwnd->downloadlistctrl.RemoveSource(this,SwapTo);

	reqfile->RemoveDownloadingSource(this);

	if(!bRemoveCompletely)
	{
        reqfile->A4AFsrclist.AddTail(this);
		if (GetDownloadState() == DS_NONEEDEDPARTS)
			m_OtherNoNeeded_list.AddTail(reqfile);
		else
			m_OtherRequests_list.AddTail(reqfile);

		theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(reqfile,this,true);
    }
	else {
        m_fileReaskTimes.RemoveKey(reqfile);
		ClearFileStatus(reqfile); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
    }

#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
	if(!IsSurceSuspended(false,false))
#endif // NEO_SK // NEO: NSK END <-- Xanatos --
		SetDownloadState(DS_NONE);
	CPartFile* pOldRequestFile = reqfile;
	SetRequestFile(SwapTo);	
	pOldRequestFile->UpdatePartsInfo();
	// NEO: ICS - [InteligentChunkSelection] -- Xanatos -->
	if(GetIncompletePartVersion())
		pOldRequestFile->UpdatePartsInfoEx(CFS_Incomplete);
	// NEO: ICS END <-- Xanatos --
	// NEO: RPS - [RealPartStatus] -- Xanatos -->
	if(GetHidenPartStatusVersion())
		pOldRequestFile->UpdatePartsInfoEx(CFS_Hiden);
	if(GetBlockedPartStatusVersion())
		pOldRequestFile->UpdatePartsInfoEx(CFS_Blocked);
	// NEO: RPS END <-- Xanatos --
	pOldRequestFile->UpdateAvailablePartsCount();

	SwapTo->srclist.AddTail(this);
	theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(SwapTo,this,false);

	// NEO: MFSB - [MultiFileStatusBars] -- Xanatos -->
	SwapTo->UpdatePartsInfo();
	// NEO: ICS - [InteligentChunkSelection]
	if(GetIncompletePartVersion())
		SwapTo->UpdatePartsInfoEx(CFS_Incomplete);
	// NEO: ICS END
	// NEO: RPS - [RealPartStatus]
	if(GetHidenPartStatusVersion())
		SwapTo->UpdatePartsInfoEx(CFS_Hiden);
	if(GetBlockedPartStatusVersion())
		SwapTo->UpdatePartsInfoEx(CFS_Blocked);
	// NEO: RPS END
	SwapTo->UpdateAvailablePartsCount();
	// NEO: MFSB END <-- Xanatos --

	return true;
}

void CUpDownClient::DontSwapTo(/*const*/ CPartFile* file)
{
	DWORD dwNow = ::GetTickCount();

	for (POSITION pos = m_DontSwap_list.GetHeadPosition(); pos != 0; m_DontSwap_list.GetNext(pos))
		if(m_DontSwap_list.GetAt(pos).file == file) {
			m_DontSwap_list.GetAt(pos).timestamp = dwNow ;
			return;
		}
	PartFileStamp newfs = {file, dwNow };
	m_DontSwap_list.AddHead(newfs);
}

bool CUpDownClient::IsSwapSuspended(const CPartFile* file, const bool allowShortReaskTime, const bool fileIsNNP)
{
    if(file == reqfile) {
        return false;
    }

	// NEO: MCM - [ManualClientManagement] -- Xanatos -->
	if(IsSwapingDisabled())
		return true;
	// NEO: MCM END <-- Xanatos --

    // Don't swap if we have reasked this client too recently
    if(GetTimeUntilReask(file, allowShortReaskTime, true, fileIsNNP) > 0)
        return true;

	if (m_DontSwap_list.GetCount()==0)
		return false;

	for (POSITION pos = m_DontSwap_list.GetHeadPosition(); pos != 0 && m_DontSwap_list.GetCount()>0; m_DontSwap_list.GetNext(pos)){
		if(m_DontSwap_list.GetAt(pos).file == file){
			if ( ::GetTickCount() - m_DontSwap_list.GetAt(pos).timestamp  >= PURGESOURCESWAPSTOP ) {
				m_DontSwap_list.RemoveAt(pos);
				return false;
			}
			else
				return true;
		}
		else if (m_DontSwap_list.GetAt(pos).file == NULL) // in which cases should this happen?
			m_DontSwap_list.RemoveAt(pos);
	}

	return false;
}

uint32 CUpDownClient::GetTimeUntilReask(const CPartFile* file, const bool allowShortReaskTime, const bool useGivenNNP, const bool givenNNP) const {
    DWORD lastAskedTimeTick = GetLastAskedTime(file);
    if(lastAskedTimeTick != 0) {

		// NEO: SD - [StandByDL] -- Xanatos -->
		if(file->IsStandBy())
			return 0x7FFFFFFF; // file is in styndby and we hav asked once thats enough
		else if(m_byFileRequestState == FR_STANDBY) // NEO: USPS - [UnSolicitedPartStatus]
			return 0; // File was in styndby and we havn't finished the reask, finish it now
		// NEO: SD END <-- Xanatos -->

        DWORD tick = ::GetTickCount();

        DWORD reaskTime;
        if(allowShortReaskTime || file == reqfile && GetDownloadState() == DS_NONE) {
            reaskTime = MIN_REQUESTTIME; // X?: should this be also variable??? (beter no? or maby?)
        } else if(useGivenNNP && givenNNP ||
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			file == reqfile && GetDownloadState() == DS_NONEEDEDPARTS && (!thePrefs.IsWebCacheEnabled() || !SupportsWebCache()) || // Superlexx - webcache - reask webcache-enabled NNP-sources more often
#else
            file == reqfile && GetDownloadState() == DS_NONEEDEDPARTS ||
#endif // NEO: WC END <-- Xanatos --
            file != reqfile && IsInNoNeededList(file)) 
		{
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
			if(IsLanClient())
				reaskTime = /*FILEREASKTIME*2*/reqfile->PartPrefs.GetNnPLanReaskIntervalsMs(); // NEO: DR - [DownloadReask] <-- Xanatos --
			else
#endif //LANCAST // NEO: NLC END <-- Xanatos --
				reaskTime = /*FILEREASKTIME*2*/reqfile->PartPrefs.GetNnPReaskIntervalsMs(); // NEO: DR - [DownloadReask] <-- Xanatos --
        } else {
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
			if(IsLanClient())
				reaskTime = /*FILEREASKTIME*2*/reqfile->PartPrefs.GetLanReaskIntervalsMs(); // NEO: DR - [DownloadReask] <-- Xanatos --
			else
#endif //LANCAST // NEO: NLC END <-- Xanatos --
				reaskTime = /*FILEREASKTIME*/IsRemoteQueueFull() ? reqfile->PartPrefs.GetFullQReaskIntervalsMs() : reqfile->PartPrefs.GetReaskIntervalsMs(); // NEO: DR - [DownloadReask] <-- Xanatos --
        }

		// NEO: SR - [SpreadReask] -- Xanatos -->
		if(thePrefs.UseSpreadReask()
		&& !(thePrefs.UseLowID2HighIDAutoCallback() && HasLowID() && GetL2HACSupport())){ // NEO: L2H - [LowID2HighIDAutoCallback]
			reaskTime += m_uSpreadReaskModyfier;
			if(reaskTime + MIN2MS(4) > MAX_PURGEQUEUETIME) 
				reaskTime -= thePrefs.GetSpreadReaskValueMs();
		}
		// NEO: SR END <-- Xanatos --

        if(tick-lastAskedTimeTick < reaskTime) {
			// NEO: DR - [DownloadReask] -- Xanatos -->
			// Xanatos: Note m_bReaskPending causes us to perform only every secund reask of a lowID cleint over a callback, 
			// this saves soem overhead, but it requirers some fixes in case we use longer reast kimes than 29 min
			if(m_bReaskPending && GetDownloadState() == DS_NONEEDEDPARTS) // if the low ID is NNP in with the default 29*2 reask time we would lost the queue anyway
			{
				if((reaskTime*2)-(tick-lastAskedTimeTick) + MIN2MS(4) > MAX_PURGEQUEUETIME) // if we come near to loost our queue position tiuger immidate reask
					return 0;
			}
			// NEO: DR END <-- Xanatos --
            return reaskTime-(tick-lastAskedTimeTick);
        } else {
            return 0;
        }
    } else {
        return 0;
    }
}

uint32 CUpDownClient::GetTimeUntilReask(const CPartFile* file) const {
    return GetTimeUntilReask(file, false);
}

uint32 CUpDownClient::GetTimeUntilReask() const {
    return GetTimeUntilReask(reqfile);
}

bool CUpDownClient::IsValidSource() const
{
	// NEO: NSK - [NeoSourceKeeper] // NEO: NSS - [NeoSourceStorage] // NEO: XSC - [ExtremeSourceCache] -- Xanatos -->
	if(IsSurceSuspended()) // Dont send unavalibly/unproved sources
		return false;
	// NEO: NSK END // NEO: NSS END // NEO: XSC END <-- Xanatos --
	bool valid = false;
	switch(GetDownloadState())
	{
		case DS_DOWNLOADING:
		case DS_ONQUEUE:
		case DS_CONNECTED:
		case DS_NONEEDEDPARTS:
		case DS_REMOTEQUEUEFULL:
		case DS_REQHASHSET:
			valid = IsEd2kClient();
	}
	return valid;
}

void CUpDownClient::StartDownload()
{
	SetDownloadState(DS_DOWNLOADING);
	InitTransferredDownMini();
	SetDownStartTime();
	m_lastPartAsked = (uint16)-1;
	SendBlockRequests();
}

void CUpDownClient::SendCancelTransfer(Packet* packet)
{
	if (socket == NULL || !IsEd2kClient()){
		ASSERT(0);
		return;
	}
	
	if (!GetSentCancelTransfer())
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__CancelTransfer", this);

		bool bDeletePacket;
		Packet* pCancelTransferPacket;
		if (packet)
		{
			pCancelTransferPacket = packet;
			bDeletePacket = false;
		}
		else
		{
			pCancelTransferPacket = new Packet(OP_CANCELTRANSFER, 0);
			bDeletePacket = true;
		}
		theStats.AddUpDataOverheadFileRequest(pCancelTransferPacket->size);
		socket->SendPacket(pCancelTransferPacket,bDeletePacket,true);
		SetSentCancelTransfer(1);
	}

	if (m_pPCDownSocket)
	{
		m_pPCDownSocket->Safe_Delete();
		m_pPCDownSocket = NULL;
		SetPeerCacheDownState(PCDS_NONE);
	}

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if (m_pWCDownSocket)
	{
		m_pWCDownSocket->Safe_Delete();
		m_pWCDownSocket = NULL;
		SetWebCacheDownState(WCDS_NONE);
	}
#endif // NEO: WC END <-- Xanatos --
}

void CUpDownClient::SetRequestFile(CPartFile* pReqFile)
{
	if (pReqFile != reqfile || reqfile == NULL)
		ResetFileStatusInfo();

	reqfile = pReqFile;
	if(pReqFile)
		GetFileStatus(pReqFile, true); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
	if(thePrefs.SaveSourceFileList() && source && reqfile)
		source->AddSeenFile(reqfile->GetFileHash(),reqfile->GetFileSize());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
}

void CUpDownClient::ProcessAcceptUpload()
{
	m_FreeDownload = FALSE; // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --

	m_fQueueRankPending = 1;
	if (reqfile && !reqfile->IsStopped() 
	 && (!reqfile->IsStandBy()) // NEO: SD - [StandByDL] <-- Xanatos --
	 && (reqfile->GetStatus()==PS_READY || reqfile->GetStatus()==PS_EMPTY)
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	 && !IsBanned() // Don't accept upload from banned clients, tray may send corrupt data
#endif //ARGOS // NEO: NA END <-- Xanatos --
	)
	{
		SetSentCancelTransfer(0);
		if (GetDownloadState() == DS_ONQUEUE) // NEO: DKA - [DownloadKeepAlive] <-- Xanatos --
		{
			// PC-TODO: If remote client does not answer the PeerCache query within a timeout, 
			// automatically fall back to ed2k download.
			if ( !SupportPeerCache() // client knows peercahce protocol
				||!thePrefs.IsPeerCacheDownloadEnabled() // user has enabled peercache downlaods
				|| !theApp.m_pPeerCache->IsCacheAvailable() // we have found our cache and its usable
				|| !theApp.m_pPeerCache->IsClientPCCompatible(GetVersion(), GetClientSoft()) // the client version is accepted by the cache
				|| !SendPeerCacheFileRequest()) // request made
			{
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
				if(thePrefs.IsSupportISPBypass() && thePrefs.GetNeedISPBypass() 
				 && GetSecureCommunicationVersion()
				 //&& socket->GetRuntimeClass() == RUNTIME_CLASS(CClientReqSocket)
				 && socket->m_Encryption == NULL && !HasLowID()) // we can not swap low id, but this shouldn't be a problem sinse thay should initialise this socket secure already
					SwapSocket();
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
				StartDownload();
			}
		}
		// NEO: DKA - [DownloadKeepAlive] -- Xanatos -->
		else if(m_fKeepAlivePending) 
		{
			AddDebugLogLine(false, _T("--> Download Keep Alive Ping succesfuly resumed download session; clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
			m_fKeepAlivePending = 0; 
			m_fActiveDownReqFlag = 1; // just in case // NEO: FSUR - [FixStartupLoadReq]
			SendBlockRequests();
		}
		// NEO: DKA END <-- Xanatos --
		// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
		//Xman fix for startupload (downloading side)
		else if(m_fActiveDownReqFlag)
		{
			//do nothing
			//it seems there are buggy clients which are sending OP_ACCEPTUPLOADREQ each time after receiving some opcodes like OP_SETREQUFILEID
			//in this case we shouldn't repeat our below actions 
			AddDebugLogLine(false, _T("-->warning! OP_ACCEPTUPLOADREQ from protocolstepflag1, clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
		}
		else if(GetDownloadState() == DS_CONNECTED)
		{
			//the problem here is: we are during sending our packtes (e.g. OP_SETREQUFILEID) and the download begin
			//until we send OP_STARTUPLOADREQ. In this case, there is no need to send OP_STARTUPLOADREQ
			m_fActiveDownReqFlag = 1;
			AddDebugLogLine(false, _T("-->OP_ACCEPTUPLOADREQ from DS_CONNECTED, clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
		}
		//Xman end fix for startupload (downloading side)

		else if (GetDownloadState() == DS_DOWNLOADING)
		{
			//don't know why this happens, but it happens
			//only send a new blockrequest
			SendBlockRequests();
			AddDebugLogLine(false, _T("-->OP_ACCEPTUPLOADREQ from DS_DOWNLOADING, clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
		}
		else if(GetDownloadState() == DS_NONEEDEDPARTS)
		{
			//this case only happens in very rare situations (and not with Xtreme Mod)
						
			//try do swap just in time
			CPartFile* oldreqfile=reqfile;
			if(SwapToAnotherFile(false,false,false, NULL, false, true))
			{
				m_fActiveDownReqFlag = 1;
				SendFileRequest(); //ask for the file we swapped to
				if(thePrefs.GetLogA4AF())
					AddDebugLogLine(false, _T("-o- ProcessAcceptUpload just in time swapping NNS: client %s, %s swapped from %s to %s"), DbgGetFullClientSoftVer(),GetUserName(), oldreqfile->GetFileName(), reqfile->GetFileName());
			}
			//to be sure not to fall in an endless loop (which theoretically can't happen):
			DontSwapTo(oldreqfile);
		}
		else if(GetFileStatus(reqfile))
		{
			//if we have a partstatus, we can try to download (can happen at toomanyconnections)
			AddDebugLogLine(false, _T("-->OP_ACCEPTUPLOADREQ from bad state but we have partstatus, clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
			StartDownload();
		}
		else
		{
			AddDebugLogLine(false, _T("-->OP_ACCEPTUPLOADREQ from bad state no partstatus-->reask the client, clientversion:%s, File: %s"), DbgGetClientInfo(), GetClientFilename());
			m_fActiveDownReqFlag = 1;
			SendFileRequest();
		}
		// NEO: FSUR END <-- Xanatos --
	}
	else
	{
		SendCancelTransfer();
		SetDownloadState((reqfile==NULL || reqfile->IsStopped()) ? DS_NONE : DS_ONQUEUE);
	}
}

void CUpDownClient::ProcessEdonkeyQueueRank(const uchar* packet, UINT size)
{
	CSafeMemFile data(packet, size);
	uint32 rank = data.ReadUInt32();
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		Debug(_T("  QR=%u (prev. %d)\n"), rank, IsRemoteQueueFull() ? (UINT)-1 : (UINT)GetRemoteQueueRank());
	SetRemoteQueueRank(rank, GetDownloadState() == DS_ONQUEUE);
	CheckQueueRankFlood();
}

void CUpDownClient::ProcessEmuleQueueRank(const uchar* packet, UINT size)
{
	if (size != 12)
		throw GetResString(IDS_ERR_BADSIZE);
	uint16 rank = PeekUInt16(packet);
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		Debug(_T("  QR=%u\n"), rank); // no prev. QR available for eMule clients
	SetRemoteQueueFull(false);
	SetRemoteQueueRank(rank, GetDownloadState() == DS_ONQUEUE);
	CheckQueueRankFlood();
}

void CUpDownClient::CheckQueueRankFlood()
{
	if (m_fQueueRankPending == 0)
	{
		if (GetDownloadState() != DS_DOWNLOADING)
		{
			if (m_fUnaskQueueRankRecv < 3) // NOTE: Do not increase this nr. without increasing the bits for 'm_fUnaskQueueRankRecv'
				m_fUnaskQueueRankRecv++;
			if (m_fUnaskQueueRankRecv == 3)
			{
				if (theApp.clientlist->GetBadRequests(this) < 2)
					theApp.clientlist->TrackBadRequest(this, 1);
				if (theApp.clientlist->GetBadRequests(this) >= 2){
					theApp.clientlist->TrackBadRequest(this, -2); // reset so the client will not be rebanned right after the ban is lifted
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if(thePrefs.IsRankFloodDetection())
						if(thePrefs.UseArgosSystem())
							theApp.argos->DoArgos(GetConnectIP(),AR_RANKFLOODER);
						else
#endif // ARGOS // NEO: NA END <-- Xanatos --
					Ban(_T("QR flood"));
				}
				throw CString(thePrefs.GetLogBannedClients() ? _T("QR flood") : _T(""));
			}
		}
	}
	else
	{
		m_fQueueRankPending = 0;
		m_fUnaskQueueRankRecv = 0;
	}
}

uint32 CUpDownClient::GetLastAskedTime(const CPartFile* partFile) const
{
	CPartFile* file = (CPartFile*)partFile;
	if (file == NULL) {
		file = reqfile;
	}

	DWORD lastChangedTick;
	return m_fileReaskTimes.Lookup(file, lastChangedTick)?lastChangedTick:0;
}

void CUpDownClient::SetReqFileAICHHash(CAICHHash* val)
{
	if(m_pReqFileAICHHash != NULL && m_pReqFileAICHHash != val)
		delete m_pReqFileAICHHash;
	m_pReqFileAICHHash = val;
}

void CUpDownClient::SendAICHRequest(CPartFile* pForFile, uint16 nPart)
{
	CAICHRequestedData request;
	request.m_nPart = nPart;
	request.m_pClient = this;
	request.m_pPartFile = pForFile;
	CAICHHashSet::m_liRequestedData.AddTail(request);
	m_fAICHRequested = TRUE;
	CSafeMemFile data;
	data.WriteHash16(pForFile->GetFileHash());
	data.WriteUInt16(nPart);
	pForFile->GetAICHHashset()->GetMasterHash().Write(&data);
	Packet* packet = new Packet(&data, OP_EMULEPROT, OP_AICHREQUEST);
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__AichRequest", this, (uchar*)packet->pBuffer);
	theStats.AddUpDataOverheadFileRequest(packet->size);
	SafeSendPacket(packet);
}

void CUpDownClient::ProcessAICHAnswer(const uchar* packet, UINT size)
{
	if (m_fAICHRequested == FALSE){
		throw CString(_T("Received unrequested AICH Packet"));
	}
	m_fAICHRequested = FALSE;

	CSafeMemFile data(packet, size);
	if (size <= 16){	
		CAICHHashSet::ClientAICHRequestFailed(this);
		return;
	}
	uchar abyHash[16];
	data.ReadHash16(abyHash);
	CPartFile* pPartFile = theApp.downloadqueue->GetFileByID(abyHash);
	CAICHRequestedData request = CAICHHashSet::GetAICHReqDetails(this);
	uint16 nPart = data.ReadUInt16();
	if (pPartFile != NULL && request.m_pPartFile == pPartFile && request.m_pClient == this && nPart == request.m_nPart){
		CAICHHash ahMasterHash(&data);
		if ( (pPartFile->GetAICHHashset()->GetStatus() == AICH_TRUSTED || pPartFile->GetAICHHashset()->GetStatus() == AICH_VERIFIED)
			 && ahMasterHash == pPartFile->GetAICHHashset()->GetMasterHash())
		{
			// NEO: SCV - [SubChunkVerification] -- Xanatos -->
			// BEGIN NEO: SafeHash
			CSingleLock sLockA(pPartFile->GetSCV_mut()); // SCV locks the file
			sLockA.Lock();
			// END NEO: SafeHash
			// NEO: SCV END <-- Xanatos --
			if(pPartFile->GetAICHHashset()->ReadRecoveryData((uint64)request.m_nPart*PARTSIZE, &data)){
				// finally all checks passed, everythings seem to be fine
				if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
				AddDebugLogLine(DLP_DEFAULT, false, _T("AICH Packet Answer: Succeeded to read and validate received recoverydata"));
				CAICHHashSet::RemoveClientAICHRequest(this);
				pPartFile->AICHRecoveryDataAvailable(request.m_nPart);

				sLockA.Unlock();// NEO: SafeHash // NEO: SCV - [SubChunkVerification] <-- Xanatos --
				return;
			}
			else
				if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
				AddDebugLogLine(DLP_DEFAULT, false, _T("AICH Packet Answer: Failed to read or validate received recoverydata"));
			
			sLockA.Unlock();// NEO: SafeHash // NEO: SCV - [SubChunkVerification] <-- Xanatos --
		}
		else
			if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
			AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Answer: Masterhash differs from packethash or hashset has no trusted Masterhash"));
	}
	else
		if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
		AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Answer: requested values differ from values in packet"));

	CAICHHashSet::ClientAICHRequestFailed(this);
}

void CUpDownClient::ProcessAICHRequest(const uchar* packet, UINT size)
{
	if (size != (UINT)(16 + 2 + CAICHHash::GetHashSize()))
		throw CString(_T("Received AICH Request Packet with wrong size"));
	
	CSafeMemFile data(packet, size);
	uchar abyHash[16];
	data.ReadHash16(abyHash);
	uint16 nPart = data.ReadUInt16();
	CAICHHash ahMasterHash(&data);
	CKnownFile* pKnownFile = theApp.sharedfiles->GetFileByID(abyHash);
	if (pKnownFile != NULL){
		if (pKnownFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE && pKnownFile->GetAICHHashset()->HasValidMasterHash()
			&& pKnownFile->GetAICHHashset()->GetMasterHash() == ahMasterHash && pKnownFile->GetPartCount() > nPart
			&& pKnownFile->GetFileSize() > (uint64)EMBLOCKSIZE && (uint64)pKnownFile->GetFileSize() - PARTSIZE*(uint64)nPart > EMBLOCKSIZE)
		{
			CSafeMemFile fileResponse;
			fileResponse.WriteHash16(pKnownFile->GetFileHash());
			fileResponse.WriteUInt16(nPart);
			pKnownFile->GetAICHHashset()->GetMasterHash().Write(&fileResponse);
			if (pKnownFile->GetAICHHashset()->CreatePartRecoveryData((uint64)nPart*PARTSIZE, &fileResponse)){
				if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
				AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Request: Sucessfully created and send recoverydata for %s to %s"), pKnownFile->GetFileName(), DbgGetClientInfo());
				if (thePrefs.GetDebugClientTCPLevel() > 0)
					DebugSend("OP__AichAnswer", this, pKnownFile->GetFileHash());
				Packet* packAnswer = new Packet(&fileResponse, OP_EMULEPROT, OP_AICHANSWER);
				theStats.AddUpDataOverheadFileRequest(packAnswer->size);
				SafeSendPacket(packAnswer);
				return;
			}
			else
				if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
				AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Request: Failed to create recoverydata for %s to %s"), pKnownFile->GetFileName(), DbgGetClientInfo());
		}
		else
			if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
			AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Request: Failed to create ecoverydata - Hashset not ready or requested Hash differs from Masterhash for %s to %s"), pKnownFile->GetFileName(), DbgGetClientInfo());
	}
	else
		if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
		AddDebugLogLine(DLP_HIGH, false, _T("AICH Packet Request: Failed to find requested shared file -  %s"), DbgGetClientInfo());
	
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__AichAnswer", this, abyHash);
	Packet* packAnswer = new Packet(OP_AICHANSWER, 16, OP_EMULEPROT);
	md4cpy(packAnswer->pBuffer, abyHash);
	theStats.AddUpDataOverheadFileRequest(packAnswer->size);
	SafeSendPacket(packAnswer);
}

void CUpDownClient::ProcessAICHFileHash(CSafeMemFile* data, CPartFile* file)
{
	CPartFile* pPartFile = file;
	if (pPartFile == NULL){
		uchar abyHash[16];
		data->ReadHash16(abyHash);
		pPartFile = theApp.downloadqueue->GetFileByID(abyHash);
	}
	CAICHHash ahMasterHash(data);
	if(pPartFile != NULL && pPartFile == GetRequestFile()){
		SetReqFileAICHHash(new CAICHHash(ahMasterHash));
		pPartFile->GetAICHHashset()->UntrustedHashReceived(ahMasterHash, GetConnectIP());
	}
	else
		if(thePrefs.GetLogAICHEvents()) // NEO: MOD - [LogAICH] <-- Xanatos --
		AddDebugLogLine(DLP_HIGH, false, _T("ProcessAICHFileHash(): PartFile not found or Partfile differs from requested file, %s"), DbgGetClientInfo());
}

// NEO: NPC - [NeoPartCatch] -- Xanatos -->
bool CUpDownClient::IsPartAvailable(UINT part, int iMode, bool bAll, CPartFile* file)
{
	CClientFileStatus* status = GetFileStatus(file ? file : reqfile);
	if(status)
		return status->IsPartAvailable(part,iMode,bAll);
	return false;
}
// NEO: NPC END <-- Xanatos --

// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
void CUpDownClient::SetRemoteEDT(uint32 avg, uint32 err){
	m_DownloadTime = CTime::GetCurrentTime() + CTimeSpan(avg);
	m_DownloadTimeErr = err;
	m_DownloadTimeVal = avg;
	UpdateDisplayedInfo();
}

void CUpDownClient::EstimateDownloadTime(uint32 &avg_time, uint32 &err_time)
{
	avg_time = 0;
	err_time = EDT_UNDEFINED;
	if (!IsDownloading())
		theApp.edt->EstimateTime(this, avg_time, err_time);
}
// NEO: EDT END <-- Xanatos --

#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
CClientReqSocket* CUpDownClient::GetFileDownloadSocket(bool bLog) {
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(IsLanClient()){
        if (bLog && thePrefs.GetVerbose())
            AddDebugLogLine(false, _T("%s got normal lan socket."), DbgGetClientInfo());
        return socket;
	}else
#endif //LANCAST // NEO: NLC END <-- Xanatos --
    if(m_pPCDownSocket && (IsDownloadingFromPeerCache() || m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY)) {
        if(thePrefs.GetVerbose() && bLog)
            AddDebugLogLine(false, _T("%s got peercache socket."), DbgGetClientInfo());
        return m_pPCDownSocket;
	}
#ifdef WEBCACHE // NEO: WC - [WebCache]
	else if(m_pWCDownSocket && IsDownloadingFromWebCache() || m_eWebCacheDownState == WCDS_WAIT_CACHE_REPLY) {
        if(thePrefs.GetVerbose() && bLog)
            AddDebugLogLine(false, _T("%s got webcache socket."), DbgGetClientInfo());
        return m_pWCDownSocket;
    }
#endif //WEBCACHE // NEO: WC END
	else {
        if(thePrefs.GetVerbose() && bLog)
            AddDebugLogLine(false, _T("%s got normal socket."), DbgGetClientInfo());
        return socket;
    }
}
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --

#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
//
// This Function performs dynamic smooth outdating dependant of its given parameters
// minFail	: This specifies the minimun number of connection retries granted;
// addFail	: This specifies the additional number of connection retries granted
//			  if it is rare(ex: sources<<rareBelow);
// minDays	: This specifies the minimun number of days to be valid;
// addDays	: This specifies the additional number of days to be valid
//			  if it is rare(ex: sources<<rareBelow);;
// rareBelow: This magic number specifies a border. sourcenumbers below are handled
//            smoothly to be rare, that means the less sources you have, the more
//			  additional days and failedconns you get;
//
//  Each value corresponds to the others. That means if your entry has aged
//   for some days, you will have less connectionretries to go, and vice versa;
//  The small asymetry for being harder to connectionretries is wanted, being polite
//   not flooding the net.
//
// if you want to have a look at this function, open your M@ple/Scilab... and enter the following line.
// Rest a while this takes a minute...
// params used(minfail=5,addfail=3,mindays=10,adddays=16,rarebelow=40)
// g:=(x,y)->-5.*(2.*y-13.*RootOf(625*_Z^5+(128*x^2-1250)*_Z^4+300*_Z^3*y-600*_Z^2*y+36*_Z*y^2-72*y^2)^2)/
// RootOf(625*_Z^5+(128*x^2-1250)*_Z^4+300*_Z^3*y-600*_Z^2*y+36*_Z*y^2-72*y^2)^2;
// plot3d({trunc(g(trunc(x),y)),0},x=0..8,y=0..26,view=0..40,axes=boxed,
// labels=["fail","age","sources"],shading=none,lightmodel=light3,grid=[50,50]);

bool CUpDownClient::IsOutOfDate(bool bSmooth, UINT MaxFaildCount, UINT OutOfDateTime, UINT SourcesCount)
{
	double fail = GetFaildCount();
	double age = S2D(time(NULL) - GetLastSeen());
	double sources = SourcesCount;

	if(!bSmooth)
		return (fail > MaxFaildCount || age > OutOfDateTime);

	double minFail = MaxFaildCount; //5e+0;
	double addFail = minFail / 2; //3e+0;
	double minDays = OutOfDateTime; //10e+0;
	double addDays = minDays * 1.5; //16e+0;
	double rareBelow = thePrefs.GetRareFileLimit() /*RARE_FILE*/; //50e+0; 
	double A,B;

	//bound sources to range & default(-1)
	if (sources<0)	
		sources=rareBelow;
	else if (sources>rareBelow)	
		sources=rareBelow;

	// bound failcounter to range
	if (fail<0)
		fail=0;
	else if (fail>(minFail+addFail))
		fail=(minFail+addFail);

	//bound age(in days) to range
	if (age<0)
		age=0;
	else if (age>(minDays+addDays))	
		age=(minDays+addDays);
    
	A=fail/((((rareBelow-sources)*addFail)/rareBelow)+minFail);
	A=1-A*A;
	B=age/((((rareBelow-sources)*addDays)/rareBelow)+minDays);
	B=1-sqrt(B);
	A=(A+B)-1;

//#ifdef _DEBUG
//	TRACE("SmoothOutdating: Source of fail(%.0f),age(%.2f),sources(%.0f) returned %f\n",fail,age,sources,A);
//#endif
	return (A<=0);    	
}

bool CUpDownClient::IsLinkedLastSeen()
{
#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
	if(source)
		return (source->GetAvalibilityProbability(PM_MIN) == 100); // should be true only when the source is linked
	else
#endif // NEO_SA // NEO: NSA END
	return ((time(NULL) - GetLastSeen()) < FILEREASKTIME*2); // use NNP reask interval, or add the seting to ss groupe
}
#endif // NEO_SS // NEO: NSS END <-- Xanatos --

// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
bool CUpDownClient::IsCompleteSource(CKnownFile* file) const
{ 
	CClientFileStatus* status = GetFileStatus(file);
	if(status)
		return status->IsCompleteSource();
	return false;
}

const CString CUpDownClient::GetClientFilename() const{ 
	CClientFileStatus* status = GetFileStatus(reqfile);
	if(status)
		return status->GetFileName();
	return _T("");
}
// NEO: SCFS END <-- Xanatos --