//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 "UrlClient.h"
#include "Opcodes.h"
#include "Packets.h"
#include "UploadQueue.h"
#include "Statistics.h"
#include "ClientList.h"
#include "ClientUDPSocket.h"
#include "SharedFileList.h"
#include "KnownFileList.h"
#include "PartFile.h"
#include "ClientCredits.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "OtherFunctions.h"
#include "SafeFile.h"
#include "DownloadQueue.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "Log.h"
#include "Collection.h"
#include <math.h> // NEO: NFS - [NeoScoreSystem] <-- Xanatos --
#include "Neo/Functions.h" // NEO: MOD <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
#include "Neo/SourceList.h"
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#ifdef NEO_BC // NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
#include "Neo/BandwidthControl/BandwidthControl.h"
#endif // NEO_BC // NEO: NBC END <-- Xanatos --
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
#include "Neo/voodoo.h"
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --
#include "Neo/NeoOpcodes.h" // NEO: PTM - [PrivatTransferManagement] <-- 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 --
#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 uploading functions 

CBarShader CUpDownClient::s_UpStatusBar(16);

// NEO: MFSB - [MultiFileStatusBars] -- Xanatos -->
//void CUpDownClient::DrawUpStatusBar(CDC* dc, RECT* rect, bool onlygreyrect, bool  bFlat) const
void CUpDownClient::DrawUpStatusBar(CDC* dc, RECT* rect, Requested_File_Struct* file, bool  bFlat) const
{
    COLORREF crNeither;
	COLORREF crNextSending;
	COLORREF crBoth;
	COLORREF crSending;
	COLORREF crClientPartial; // NEO: ICS - [InteligentChunkSelection]
	COLORREF crSeen; // NEO: AHOS - [AntiHideOS]
	COLORREF crHiden; // NEO: RPS - [RealPartStatus]
	COLORREF crBlocked; // NEO: RPS - [RealPartStatus]
	COLORREF crBuffer; // NEO: MOD - [ShowBuffered]

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	if (!HaveTrickleSlot() ||
#else
    if(GetSlotNumber() <= theApp.uploadqueue->GetActiveUploadsCount() ||
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
       (GetUploadState() != US_UPLOADING && GetUploadState() != US_CONNECTING) ) {
        crNeither = RGB(224, 224, 224);
	    crNextSending = RGB(255,208,0);
	    crBoth = bFlat ? RGB(0, 0, 0) : RGB(104, 104, 104);
	    crSending = RGB(0, 150, 0);
		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]
		crBuffer = RGB(255, 100, 100); // NEO: MOD - [ShowBuffered]

    } else {
        // grayed out
        crNeither = RGB(248, 248, 248);
	    crNextSending = RGB(255,244,191);
	    crBoth = RGB(191, 191, 191);
	    crSending = RGB(191, 229, 191);
		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]
 		crBuffer = RGB(255, 216, 216); // NEO: MOD - [ShowBuffered]
    }

    if(file) {
		// NEO: SCFS - [SmartClientFileStatus]
		CKnownFile* currequpfile = theApp.sharedfiles->GetFileByID(file->fileid);
		if(currequpfile == NULL)
			currequpfile = (CKnownFile*)theApp.downloadqueue->GetFileByID(file->fileid);
		if(currequpfile == NULL)
			currequpfile = theApp.knownfiles->FindKnownFileByID(file->fileid);
		if(currequpfile == NULL)
			return;

		EMFileSize filesize = currequpfile->GetFileSize();
		UINT UpPartCount = currequpfile->GetPartCount();

		CClientFileStatus* status = GetFileStatus(currequpfile);

		uint8* thisAbyUpPartStatus = status ? status->GetPartStatus() : NULL;
		uint8* thisAbyUpIncPartStatus = status ? status->GetPartStatus(CFS_Incomplete) : NULL; // NEO: ICS - [InteligentChunkSelection]
		uint8* thisAbyUpHidenPartStatus = status ? status->GetPartStatus(CFS_Hiden) : NULL; // NEO: RPS - [RealPartStatus]
		uint8* thisAbyUpBlockedPartStatus = status ? status->GetPartStatus(CFS_Blocked) : NULL; // NEO: RPS - [RealPartStatus]
		uint8* thisAbyUpSeenPartStatus = status ? status->GetPartStatus(CFS_History) : NULL; // NEO: AHOS - [AntiHideOS]
		// NEO: SCFS END

	    s_UpStatusBar.SetFileSize(filesize); 
	    s_UpStatusBar.SetHeight(rect->bottom - rect->top); 
	    s_UpStatusBar.SetWidth(rect->right - rect->left); 
	    s_UpStatusBar.Fill(crNeither); 

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

		for (UINT i = 0;i < UpPartCount;i++){
			if(thisAbyUpPartStatus && thisAbyUpPartStatus[i]){
				s_UpStatusBar.FillRange(PARTSIZE*(uint64)(i),PARTSIZE*(uint64)(i+1),crBoth);
				abyfilesize++; // NEO: MOD - [Percentage]
			// NEO: ICS - [InteligentChunkSelection]
			}else if(thisAbyUpIncPartStatus && thisAbyUpIncPartStatus[i])
				s_UpStatusBar.FillRange(PARTSIZE*(uint64)(i),PARTSIZE*(uint64)(i+1),crClientPartial);
			// NEO: ICS END
			// NEO: RPS - [RealPartStatus]
			else if(thisAbyUpHidenPartStatus && thisAbyUpHidenPartStatus[i]){
				s_UpStatusBar.FillRange(PARTSIZE*(uint64)(i),PARTSIZE*(uint64)(i+1),crHiden);
				abyfilesize++; // NEO: MOD - [Percentage]
			}else if(thisAbyUpBlockedPartStatus && thisAbyUpBlockedPartStatus[i]){
				s_UpStatusBar.FillRange(PARTSIZE*(uint64)(i),PARTSIZE*(uint64)(i+1),crBlocked);
				abyfilesize++; // NEO: MOD - [Percentage]
			}
			// NEO: PRS END
			// NEO: AHOS - [AntiHideOS]
			else if(thisAbyUpSeenPartStatus && thisAbyUpSeenPartStatus[i]){
				s_UpStatusBar.FillRange(PARTSIZE*(uint64)(i),PARTSIZE*(uint64)(i+1),crSeen);
				abyfilesize++; // NEO: MOD - [Percentage]
			}
			// NEO: AHOS END
		}

		if(file == requpfile){
			const Requested_Block_Struct* block;
			if (!m_BlockRequests_queue.IsEmpty()){
				block = m_BlockRequests_queue.GetHead();
				if(block){
					uint32 start = (uint32)block->StartOffset/PARTSIZE;
					s_UpStatusBar.FillRange((uint64)start*PARTSIZE, (uint64)(start+1)*PARTSIZE, crNextSending);
				}
			}
			if (!m_DoneBlocks_list.IsEmpty()){
				block = m_DoneBlocks_list.GetTail();
				if(block){
					uint32 start = (uint32)block->StartOffset/PARTSIZE;
					s_UpStatusBar.FillRange((uint64)start*PARTSIZE, (uint64)(start+1)*PARTSIZE, crNextSending);
				}
			}
			if (!m_DoneBlocks_list.IsEmpty()){
				for(POSITION pos=m_DoneBlocks_list.GetHeadPosition();pos!=0;){
					block = m_DoneBlocks_list.GetNext(pos);
					s_UpStatusBar.FillRange(block->StartOffset, block->EndOffset + 1, crSending);
				}
			}
			// NEO: MOD - [ShowBuffered]
            // Also show what data is buffered (with color crBuffer)
            uint64 total = 0;
    
		    for(POSITION pos=m_DoneBlocks_list.GetTailPosition();pos!=0; ){
			    Requested_Block_Struct* block = m_DoneBlocks_list.GetPrev(pos);
    
                if(total + (block->EndOffset-block->StartOffset) <= GetQueueSessionPayloadUp()) {
                    // block is sent
			        s_UpStatusBar.FillRange(block->StartOffset, block->EndOffset, crSending);
                    total += block->EndOffset-block->StartOffset;
                }
                else if (total < GetQueueSessionPayloadUp()){
                    // block partly sent, partly in buffer
                    total += block->EndOffset-block->StartOffset;
                    uint64 rest = total - GetQueueSessionPayloadUp();
                    uint64 newEnd = block->EndOffset-rest;
    
    			    s_UpStatusBar.FillRange(block->StartOffset, newEnd, crSending);
    			    s_UpStatusBar.FillRange(newEnd, block->EndOffset, crBuffer);
                }
                else{
                    // entire block is still in buffer
                    total += block->EndOffset-block->StartOffset;
    			    s_UpStatusBar.FillRange(block->StartOffset, block->EndOffset, crBuffer);
                }
		    }
			// NEO: MOD END
		}
   	    s_UpStatusBar.Draw(dc, rect->left, rect->top, bFlat);

		// NEO: MOD - [Percentage]
		if(thePrefs.ShowClientPercentage() && UpPartCount)
		{
			float percent = (float)abyfilesize*100.0f/UpPartCount;
			if(percent > 0.05f)
			{
				CString buffer;
				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)
				OffsetRect(rect, -1,0);
				dc->DrawText(buffer, buffer.GetLength(), rect, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
				OffsetRect(rect, 2,0);
				dc->DrawText(buffer, buffer.GetLength(), rect, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
				OffsetRect(rect, -1,-1);
				dc->DrawText(buffer, buffer.GetLength(), rect, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
				OffsetRect(rect, 0,2);
				dc->DrawText(buffer, buffer.GetLength(), rect, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);
				OffsetRect(rect, 0,-1);
				dc->SetTextColor(RGB(230,230,230));
				dc->DrawText(buffer, buffer.GetLength(), rect, (DLC_DT_TEXT & ~DT_LEFT) | DT_CENTER);

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

} 
// NEO: MFSB END <-- Xanatos --

void CUpDownClient::SetUploadState(EUploadState eNewState)
{
	if (eNewState != m_nUploadState)
	{
		if (m_nUploadState == US_UPLOADING)
		{
			// Reset upload data rate computation
			m_nUpDatarate = 0;
			m_nSumForAvgUpDataRate = 0;
			m_AvarageUDR_list.RemoveAll();
		}
		if (eNewState == US_UPLOADING){
			m_fSentOutOfPartReqs = 0;

			// NEO: NBC - [NeoBandwidthControl] -- Xanatos -->
			int sendBuff = 0;
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
			if(IsLanClient() && thePrefs.IsSetLanUploadBuffer())
				sendBuff = thePrefs.GetLanUploadBufferSize();
			else
#endif //LANCAST // NEO: NLC END
			if(thePrefs.IsSetUploadBuffer())
				sendBuff = thePrefs.GetUploadBufferSize();

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

		// don't add any final cleanups for US_NONE here
		m_nUploadState = (_EUploadState)eNewState;
		theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(this);
	}
}

/**
 * Gets the queue score multiplier for this client, taking into consideration client's credits
 * and the requested file's priority.
 */
float CUpDownClient::GetCombinedFilePrioAndCredit() {
	if (credits == 0){
		ASSERT ( IsKindOf(RUNTIME_CLASS(CUrlClient)) );
		return 0.0F;
	}

	// NEO: NCS - [NeoCreditSystem] -- Xanatos -->
	float modif = 1.0F;
	if(thePrefs.UseCreditSystem())
		if (thePrefs.UseNeoCreditSystem())
			modif = credits->GetNeoScoreRatio(GetRequestFile() != NULL /*GetDownloadState() == DS_ONQUEUE*/,GetIP());
		else
			modif = credits->GetScoreRatio(GetIP()); 

    return 10.0f * modif * (float)GetFilePrioAsNumber();
	// NEO: NCS END <-- Xanatos --
}

/**
 * Gets the file multiplier for the file this client has requested.
 */
int CUpDownClient::GetFilePrioAsNumber() const {
	CKnownFile* currequpfile = theApp.sharedfiles->GetFileByID(requpfileid);
	if(!currequpfile)
		return 0;
	
	// TODO coded by tecxx & herbert, one yet unsolved problem here:
	// sometimes a client asks for 2 files and there is no way to decide, which file the 
	// client finally gets. so it could happen that he is queued first because of a 
	// high prio file, but then asks for something completely different.

	// NEO: MOD -- Xanatos -->
	int filepriority = thePrefs.UseOldPrioritySystem() ? 10 : 7;
#ifndef A4AF_CATS // NEO: MAC - [MorphA4AFCategories]
	switch(currequpfile->GetUpPriorityEx()){ // NEO: NRT - [NeoReleaserTweaks]
#else
	switch(currequpfile->GetUpPriority()){
#endif // A4AF_CATS // NEO: MAC END
		case PR_VERYHIGH:	filepriority = thePrefs.UseOldPrioritySystem()	? 50	: 18;	break;
		case PR_HIGH:		filepriority = thePrefs.UseOldPrioritySystem()	? 20	: 9; 	break;
		case PR_NORMAL:		filepriority = thePrefs.UseOldPrioritySystem()	? 10	: 7; 	break;
		case PR_LOW:		filepriority = thePrefs.UseOldPrioritySystem()	? 5		: 6; 	break;
		case PR_VERYLOW:	filepriority = thePrefs.UseOldPrioritySystem()	? 2		: 2;	break;
	}

    return filepriority;
	// NEO: MOD END <-- Xanatos --
}

// NEO: MQ - [MultiQueue] -- Xanatos -->
uint32 CUpDownClient::GetFileScore(bool isDownloading, uint32 downloadingTime) const{
	CKnownFile* currequpfile = theApp.sharedfiles->GetFileByID(requpfileid);
	if(!currequpfile)
		return 0;

	// Score proportional to the waiting time since the last upload
	uint32 elapsedTime;
	if(isDownloading == false){		
		// Normal score based on the last upload of this file
		elapsedTime = GetTickCount() - currequpfile->GetStartUploadTime();
	}
	else {
		// We dont want one client to download forever
		if(downloadingTime < 900000){
			// Bonus during the first 15 minutes.
			return (0x6FFFFFFF); // ~6*3.1 days
		}
		else {
			// Normal score based on the current upload of this file
			// Remark: m_startUploadTime was actualized when the upload started (block sent)
			elapsedTime = ::GetTickCount() - currequpfile->GetStartUploadTime();
		}
	}

	uint32 filepriority = 4;
#ifndef A4AF_CATS // NEO: MAC - [MorphA4AFCategories]
	switch(currequpfile->GetUpPriorityEx()){ // NEO: NRT - [NeoReleaserTweaks]
#else
	switch(currequpfile->GetUpPriority()){
#endif // A4AF_CATS // NEO: MAC END
		case PR_VERYHIGH:	filepriority = elapsedTime/1;	break;
		case PR_HIGH:     	filepriority = elapsedTime/2;	break;
		case PR_NORMAL:   	filepriority = elapsedTime/4;	break;
		case PR_LOW:      	filepriority = elapsedTime/8;	break;
		case PR_VERYLOW:  	filepriority = elapsedTime/16;	break;
	} 

	return filepriority;
}
// NEO: MQ END <-- Xanatos --

// NEO: PRSF - [PushSmallRareFiles] -- Xanatos -->
float CUpDownClient::GetSmallFilePushRatio(CKnownFile* currequpfile) const {
	float boost = 1;
	float filesizeinchunks = ((float)currequpfile->GetFileSize() / (float)MB2B(thePrefs.GetPushSmallFilesSize()));
	if (filesizeinchunks < 1.0f) {
		if (filesizeinchunks > 0.001)
			boost = 1.0f / filesizeinchunks;
		else
			boost = 100.0f;
	}
	return boost < 1 ? 1 : boost;
}
float CUpDownClient::GetRareFilePushRatio(CKnownFile* currequpfile) const{
	float boost = 1;
	uint32 QueuedCount = currequpfile->GetQueuedCount();
	if (QueuedCount)
		boost = (float)thePrefs.GetPushRareFilesValue() / QueuedCount;
	return boost < 1 ? 1 : boost;
}
float CUpDownClient::GetRatioFilePushRatio(CKnownFile* currequpfile) const{
	float boost = 1;
	float ratio;
	if(currequpfile->IsPartFile()){
		if((uint64)((CPartFile*)currequpfile)->GetCompletedSize() == 0)
			return 1.0f;
		ratio = ((float)currequpfile->statistic.GetAllTimeTransferred()/((float)((CPartFile*)currequpfile)->GetCompletedSize()) );
	}else
		ratio = ((float)currequpfile->statistic.GetAllTimeTransferred()/(float)(uint64)currequpfile->GetFileSize());
	if(ratio < 1.0f)
		boost = (float)thePrefs.GetPushRatioFilesValue() * (1.0f - ratio);
	return boost < 1 ? 1 : boost;
}
// NEO: PRSF END <-- Xanatos --

/**
 * Gets the current waiting score for this client, taking into consideration waiting
 * time, priority of requested file, and the client's credits.
 */
uint32 CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue, bool forceTimeScore, bool noRelease, CKnownFile* UpFile) const // NEO: RQ - [RandomQueue] // NEO: RT - [ReleaseTweaks] <-- Xanatos --
{
	if (!GetIP()/*m_pszUsername*/) // NEO: FIX - [StabilityFix] <-- Xanatos --
		return 0;

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if(IsProxy())  // JP Proxies don't have credits
		return 0;
#endif // NEO: WC END <-- Xanatos --

	if (credits == 0){
		ASSERT ( IsKindOf(RUNTIME_CLASS(CUrlClient)) );
		return 0;
	}

	CKnownFile* currequpfile = UpFile ? UpFile : theApp.sharedfiles->GetFileByID(requpfileid); // NEO: NA - [NeoArgos] <-- Xanatos --
	if(!currequpfile)
		return 0;
	
	// bad clients (see note in function)
	if (credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY)
		return 0;

	// friend slot
	//if (GetFriendSlot(true) /*&& !HasLowID()*/) // NEO: NMFS - [NiceMultiFriendSlots] <-- Xanatos --
	//	return 0x0FFFFFFF;

	if (GetUploadState()==US_BANNED) // NEO: MOD - [CodeImprovement] <-- Xanatos --
		return 0;

#ifndef ARGOS // NEO: NA -- Xanatos -->
	if (m_bGPLEvildoer)
		return 0;
#endif // ARGOS // NEO: NA END <-- Xanatos --

	if (sysvalue && HasLowID() && !(socket && socket->IsConnected())){
		return 0;
	}

	bool bRandomQueue = (!forceTimeScore && thePrefs.UseRandomQueue()); // NEO: RQ - [RandomQueue] <-- Xanatos --

	// calculate score, based on waitingtime and other factors
	float fBaseValue;
	if (onlybasevalue)
		fBaseValue = 100;
	// NEO: RQ - [RandomQueue] -- Xanatos -->
	else if (bRandomQueue)
		fBaseValue = 1;
	// NEO: RQ END <-- Xanatos --
	else if (!isdownloading)
		fBaseValue = (float)(::GetTickCount()-GetWaitStartTime())/1000;
	else{
		// we dont want one client to download forever
		// the first 15 min downloadtime counts as 15 min waitingtime and you get a 15 min bonus while you are in the first 15 min :)
		// (to avoid 20 sec downloads) after this the score won't raise anymore 
		fBaseValue = (float)(m_dwUploadTime-GetWaitStartTime());
		ASSERT ( m_dwUploadTime-GetWaitStartTime() >= 0 ); //oct 28, 02: changed this from "> 0" to ">= 0"
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
		fBaseValue += (float)(m_dwShieldTime) ? m_dwShieldTime : 1800000; // BC for Slot Focus (minutes changed to send MB)
#else
		fBaseValue += (float)(::GetTickCount() - m_dwUploadTime > 900000)? 900000:1800000;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
		fBaseValue /= 1000;
	}

	// NEO: NCS - [NeoCreditSystem] -- Xanatos -->
	float modif = 1.0F;
	if(thePrefs.UseCreditSystem()){
		if (thePrefs.UseNeoCreditSystem()){
			modif = credits->GetNeoScoreRatio(GetRequestFile() != NULL /*GetDownloadState() == DS_ONQUEUE*/,GetIP());
			if(thePrefs.UseNeoScoreSystem())
				modif *= 5;
		}
		else{
			modif = credits->GetScoreRatio(GetIP());
			// NEO: RQ - [RandomQueue]
			if(bRandomQueue)
				modif = log(modif);
			// NEO: RQ END
		}
		if(modif < 1.0F)
			modif = 1.0F;
	}
	// NEO: NCS END <-- Xanatos --

	// NEO: NFS - [NeoScoreSystem] -- Xanatos -->
	/* Xanatos:
	* New File Score system, the File score increase exponentialy to the waiting time
	* For very long waiting times the credints loose thair importance.
	* This system is more Fair that the Official System.
	* 
	* This must be calculated bevoure additional boosts! 
	* It may be beter to calculate this also bevoure file Priority but than it would harm the multiqueue...
	*/
	#define exp 2.71828182845905
	if(thePrefs.UseNeoScoreSystem() && !bRandomQueue) // NEO: RQ - [RandomQueue]
	{
		const float NormalTime = 3600 * 9 * 24; // This value control how fast the Score rises (smaller means faster!)
		const float MaxTime = 3600 * 7 * 24; // This value control the maximal Credit Boost
		const float TimeValue = 3600 * 3 * 24; // This value control the Rising of the Credit Boost (smaller means faster!)
		const float BaseTime = fBaseValue / 1000;
		float t, tmp, temp;

		t = pow(BaseTime,3) / pow(NormalTime,2);
		tmp = (!thePrefs.UseCreditSystem()) ? 0 :  MaxTime * (1 - pow((float)exp,(float)-(BaseTime * modif / TimeValue)) );

		temp = (t / 2) + BaseTime;
		if(tmp)
			temp += (tmp / 2);

		if(temp < 0.1F)
			temp = 0.1F;
		fBaseValue = temp * 1000;
	}
	else
	  if(thePrefs.UseCreditSystem())
		fBaseValue *= modif;
	// NEO: NFS <-- Xanatos --

	// NEO: MQ - [MultiQueue] -- Xanatos -->
	if(thePrefs.UseMultiQueue()){
		// File Score
		// Remark: there is an overflow after ~49 days
		uint32 fileScore = GetFileScore(isdownloading, GetUpStartTimeDelay()); // about +1 point each mili second 

		// Final score	
		// Remark: The whole timming of eMule should be rewritten. 
		//         The rollover of the main timer (GetTickCount) is not supported.
		//         A logarithmic scale would fit better here, but it might be slower.
		uint32 runTime = (GetTickCount() - theStats.starttime) / 1000;
		if(runTime <= 3600)
			// Less than 1 hour
			fBaseValue = fileScore + fBaseValue; // 1 second resolution
		if(runTime <= 2*3600)
			// Less than 2 hours
			fBaseValue = fileScore + fBaseValue/10; // 10 seconds resolution
		else
			// More than 2 hours
			fBaseValue = fileScore + fBaseValue/100; // 100 seconds resolution

		// NEO: RQ - [RandomQueue]
		if(bRandomQueue)
			fBaseValue /= 1000;
		// NEO: RQ END
	}
	else{
		int filepriority = GetFilePrioAsNumber();
		//if (!onlybasevalue) // David: include all expected the tine in the rating
		fBaseValue *= (float(filepriority)/10.0f);
	}
	// NEO: MQ END <-- Xanatos --

	// NEO: RT - [ReleaseTweaks] -- Xanatos -->
	if(currequpfile->GetReleasePriority() && !noRelease){
		fBaseValue += currequpfile->GetReleaseModifyer(); // get it to work for very new users
		fBaseValue *= currequpfile->GetReleaseModifyer(); 
	}
	// NEO: RT END <-- Xanatos --

	// NEO: PRSF - [PushSmallRareFiles] -- Xanatos -->
	if (thePrefs.IsPushSmallFiles())
		fBaseValue *= GetSmallFilePushRatio(currequpfile);
	if (thePrefs.IsPushRareFiles())
		fBaseValue *= GetRareFilePushRatio(currequpfile);
	if (thePrefs.IsPushRatioFiles())
		fBaseValue *= GetRatioFilePushRatio(currequpfile);
	// NEO: PRSF END <-- Xanatos --

	//if( (IsEmuleClient() || this->GetClientSoft() < 10) && m_byEmuleVersion <= 0x19 )
	//	fBaseValue *= 0.5f;

	// NEO: RQ - [RandomQueue] -- Xanatos -->
	if (!onlybasevalue && bRandomQueue && fBaseValue > 0)
		fBaseValue = pow((float)(rand()+1)/(RAND_MAX+2), 1.0F/fBaseValue)*1000000;
	// NEO: RQ END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	//	JP Webcache release START
	// boost clients if webcache upload will likely result in 3 or more proxy-downloads
	if (thePrefs.IsWebCacheEnabled()
	 && SupportsWebCache() 
	 && !GetWebCacheName().IsEmpty()
	 //&& thePrefs.IsWebcacheReleaseAllowed()
	 && currequpfile->GetReleaseViaWebCache())
	{
		uint32 WebCacheClientCounter = currequpfile->GetNumberOfClientsRequestingThisFileUsingThisWebcache(GetWebCacheName(), 10);
		if (WebCacheClientCounter >= 3)
		{
			fBaseValue *= WebCacheClientCounter;
			fBaseValue += 5000;
		}
	}
	//	JP Webcache release END
#endif // NEO: WC END <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(theApp.argos->IsArgos(GetConnectIP()))
		fBaseValue *= theApp.argos->GetPunishment(this);
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// NEO: RT - [ReleaseTweaks] -- Xanatos -->
	if(fBaseValue >= 0x7FFFFFFF) // Very high Release Priority in combination with other boosts may coase an overflow.
		return 0x7FFFFFFF;
	// NEO: RT END <-- Xanatos --

	return (uint32)fBaseValue;
}

/*class CSyncHelper
{
public:
	CSyncHelper()
	{
		m_pObject = NULL;
	}
	~CSyncHelper()
	{
		if (m_pObject)
			m_pObject->Unlock();
	}
	CSyncObject* m_pObject;
};*/

void CUpDownClient::CreateNextBlockPackage()
{
	// NEO: RBT - [ReadBlockThread] -- Xanatos -->
	uint32 uBufferSize = 100*1024;
#ifdef LANCAST // NEO: NLC - [NeoLanCast]
	if(IsLanClient())
		uBufferSize = PARTSIZE;
	else
#endif //LANCAST // NEO: NLC END
	if(GetDatarate() > KB2B(400))
		uBufferSize = 53 * EMBLOCKSIZE;
	else if(GetDatarate() > KB2B(200))
		uBufferSize = 36 * EMBLOCKSIZE;
	else if(GetDatarate() > KB2B(100))
		uBufferSize = 18 * EMBLOCKSIZE;
	else if(GetDatarate() > KB2B(50))
		uBufferSize = 9 * EMBLOCKSIZE;
	else if(GetDatarate() > KB2B(25))
		uBufferSize = 6 * EMBLOCKSIZE;
	else if(GetDatarate() > KB2B(5))
		uBufferSize = 3 * EMBLOCKSIZE;
	else
		uBufferSize = EMBLOCKSIZE;
	// NEO: RBT END <-- Xanatos --

    // See if we can do an early return. There may be no new blocks to load from disk and add to buffer, or buffer may be large enough allready.
    if(m_BlockRequests_queue.IsEmpty() // There are no new blocks requested
       || (m_addedPayloadQueueSession > GetQueueSessionPayloadUp() && m_addedPayloadQueueSession-GetQueueSessionPayloadUp() > /*50*102*/ ((uBufferSize * 3) / 4)) // the buffered data is large enough allready // NEO: RBT - [ReadBlockThread] <-- Xanatos --
	  )
        return;

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	if (!m_dwShieldTime && GetQueueSessionPayloadUp() > MinToMB()){ // BC for Slot Focus (minutes changed to send MB)
		m_dwShieldTime = ::GetTickCount() - m_dwUploadTime;
		if (m_dwShieldTime > 900000) //Max 15 min shield
			m_dwShieldTime = 900000;
	}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

	UINT tmpPayloadQueue = 0; // NEO: RBT - [ReadBlockThread] <-- Xanatos --
    //CFile file;
	byte* filedata = 0; 
	//CString fullname;
	//CSyncHelper lockFile; 

	//bool bFromPF = true; // Statistic to breakdown uploaded data by complete file vs. partfile.
	try{
        // Buffer new data if current buffer is less than 100 KBytes
		POSITION pos = m_BlockRequests_queue.GetHeadPosition(); // NEO: RBT - [ReadBlockThread] <-- Xanatos --
        while (pos // !m_BlockRequests_queue.IsEmpty()
         && ((m_addedPayloadQueueSession + tmpPayloadQueue) <= GetQueueSessionPayloadUp() || (m_addedPayloadQueueSession + tmpPayloadQueue) - GetQueueSessionPayloadUp() < /*100*1024*/ uBufferSize) // NEO: RBT - [ReadBlockThread] <-- Xanatos --
	    )
		{

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			//Xman: At this point we do the check if it is time to 
		    //kick the client if we kick soon, we don't add new packages
			m_bUpEndSoon=theApp.uploadqueue->CheckForTimeOver(this);
			if(m_bUpEndSoon==true)
				break;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

			// NEO: RBT - [ReadBlockThread] -- Xanatos -->
			POSITION removepos = pos;
			Requested_Block_Struct* currentblock = m_BlockRequests_queue.GetNext(pos);
			CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(currentblock->FileID);
			if (!srcfile)
				throw GetResString(IDS_ERR_REQ_FNF);

			uint64 i64uTogo;
			if (currentblock->StartOffset > currentblock->EndOffset)
				i64uTogo = currentblock->EndOffset + (srcfile->GetFileSize() - currentblock->StartOffset);
			else
				i64uTogo = currentblock->EndOffset - currentblock->StartOffset;

			if(currentblock->filedata == RBT_ACTIVE){
				tmpPayloadQueue += (UINT)i64uTogo; // dont allow to many blocks to be queued
				continue; // data reading in progress sbipp this block
			}else if(currentblock->filedata == RBT_ERROR) 
				throw GetResString(IDS_ERR_OPEN); // error data couldn't be read

			// NEO: MPS - [ManualPartSharing]
			uint8 PartStatus = srcfile->GetPartState((UINT)(currentblock->StartOffset / PARTSIZE));
			if(PartStatus == PR_PART_OFF)
				throw StrLine(GetResString(IDS_X_PARTPERM_ACCESS_BLOCKED), GetUserName(), (UINT)(currentblock->StartOffset / PARTSIZE), srcfile->GetFileName());
			// NEO: MPS END

			if (srcfile->IsPartFile() && !((CPartFile*)srcfile)->IsComplete(currentblock->StartOffset,i64uTogo + currentblock->StartOffset - 1, true))
				throw GetResString(IDS_ERR_INCOMPLETEBLOCK);

			if( i64uTogo > EMBLOCKSIZE*3 )
				throw GetResString(IDS_ERR_LARGEREQBLOCK);

			uint32 togo = (uint32)i64uTogo;
				
			if(currentblock->filedata == NULL)
			{
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
				if(srcfile->IsVoodooFile()){
					CVoodooSocket* master = srcfile->GetAnyMaster();
					if(master == NULL)
						throw StrLine(GetResString(IDS_X_VOODOO_UL_FAILD_NO_MASTER),srcfile->GetFileName());
					ASSERT(theApp.voodoo->IsValidSocket(master));

					sDataRequest DataRequest;
					DataRequest.IdKey = (uint32) currentblock;
					DataRequest.StartOffset = currentblock->StartOffset;
					DataRequest.EndOffset  = currentblock->EndOffset;
					DataRequest.Client = (uint32) this;

					master->RequestFileData(srcfile,DataRequest);
				}else
#endif // VOODOO // NEO: VOODOO END
					srcfile->SetReadBlockFromFile(currentblock->StartOffset, togo, this, currentblock);

				SetUploadFileID(srcfile); //Xman Fix Filtered Block Request

				currentblock->filedata = RBT_ACTIVE;

				tmpPayloadQueue += (UINT)i64uTogo; // dont allow to many blocks to be queued
				continue;
			}

			filedata = currentblock->filedata;
			currentblock->filedata = NULL;

			bool bFromPF = srcfile->IsPartFile(); // This is not a part file...
			// NEO: RBT END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			if (IsUploadingToWebCache()) // Superlexx - encryption: encrypt here
			{
				Crypt.RefreshLocalKey();
				Crypt.encryptor.SetKey(Crypt.localKey, WC_KEYLENGTH);
				Crypt.encryptor.DiscardBytes(16); // we must throw away 16 bytes of the key stream since they were already used once, 16 is the file hash length
				Crypt.encryptor.ProcessString(filedata, togo);
			}
#endif // NEO: WC END <-- Xanatos --

			if (!IsUploadingToPeerCache() 
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			 && !IsUploadingToWebCache()
#endif // NEO: WC END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
			 && !IsLanClient() // compression is a real performance killer on a lan network
#endif //LANCAST // NEO: NLC END <-- Xanatos --
			 && m_byDataCompVer == 1 && srcfile->IsCompressible() && !thePrefs.GetDontCompressBlocks()) // NEO: MOD - [IsCompressible] <-- Xanatos --
				CreatePackedPackets(filedata,togo,currentblock,bFromPF);
			else
				CreateStandartPackets(filedata,togo,currentblock,bFromPF);
			
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			CClientReqSocket* cur_socket;
			if((cur_socket = GetFileUploadSocket()) != NULL && cur_socket->m_IsReady == false)
			{
				cur_socket->m_IsReady = true;
				theApp.uploadBandwidthThrottler->SetNoNeedSlot();
			}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

			// file statistic
			srcfile->statistic.AddTransferred(currentblock->StartOffset, togo);	// NEO: NPT - [NeoPartTraffic] <-- Xanatos --

            m_addedPayloadQueueSession += togo;

			// NEO: RBT - [ReadBlockThread] -- Xanatos -->
			m_BlockRequests_queue.RemoveAt(removepos);
			m_DoneBlocks_list.AddHead(currentblock);
			// NEO: RBT END <-- Xanatos --

			delete[] filedata;
			filedata = NULL;

			srcfile->UpdateStartUploadTime(); // NEO: MQ - [MultiQueue] <-- Xanatos --
		}
	}
	catch(CString error)
	{
		if (thePrefs.GetVerbose())
			DebugLogWarning(GetResString(IDS_ERR_CLIENTERRORED), GetUserName(), error);
		theApp.uploadqueue->RemoveFromUploadQueue(this, _T("Client error: ") + error);
		if(filedata)
			delete[] filedata;
		return;
	}
}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
// Minutes to MB, Change 15 minutes to bytes (because of slot focus)
uint32 CUpDownClient::MinToMB() const{
	uint32 result = (uint32)(thePrefs.GetUploadPerSlots() * MIN2S(15)); //900 second ~ 15 minutes;
	if (result < MB2B(1))
		result = MB2B(1);
	return result;
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

bool CUpDownClient::ProcessExtendedInfo(CSafeMemFile* data, CClientFileStatus* status, CKnownFile* tempreqfile, bool bUDP) // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
{
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
	if (GetExtendedRequestsVersion() == 0)
		return true;

	if(!status->ReadFileStatus(data,CFS_Normal,false))
		return false;

	bool bPartsNeeded = false;
	bool bRemotePartsNeeded = false;

	if(tempreqfile->IsPartFile()) 
	{
		uint8* abyPartStatus = status->GetPartStatus();
		ASSERT(abyPartStatus);
		UINT PartCount = status->GetPartCount();
		for (UINT i = 0; i < PartCount; i++)
		{
			if (((CPartFile*)tempreqfile)->IsComplete((uint64)i*PARTSIZE, ((uint64)(i+1)*PARTSIZE)-1, true) && tempreqfile->GetPartState(i) == PR_PART_ON) // NEO: IPS - [InteligentPartSharing]
			{
				if(!bUDP && !abyPartStatus[i])
				{
					bRemotePartsNeeded = true;
					//if(!bUDP || bPartsNeeded)
					break;
				}
			}
			else
			{
				if(bUDP && abyPartStatus[i])
				{
					bPartsNeeded = true;
					//if(bUDP || bRemotePartsNeeded)
					break;
				}
			}
		}

		// NEO: BPS - [BetterPassiveSourceFinding]
		if(bUDP && bPartsNeeded) // we need passiv source handling here only when we are udp
			HandleFileStatus(((CPartFile*)tempreqfile), true, true, true);
		// NEO: BPS END
	}
	// NEO: SCT - [SubChunkTransfer]
	if(!bUDP && !bRemotePartsNeeded) // if we are udp than the client have found some blocks he need so he can't be US_NONEEDEDPARTS
		SetUploadState(US_NONEEDEDPARTS);
	// NEO: SCT END
	// NEO: SCFS END <-- Xanatos --

	/*
	delete[] m_abyUpPartStatus;
	m_abyUpPartStatus = NULL;
	m_nUpPartCount = 0;
	m_nUpCompleteSourcesCount= 0;
	if (GetExtendedRequestsVersion() == 0)
		return true;

	uint16 nED2KUpPartCount = data->ReadUInt16();
	if (!nED2KUpPartCount)
	{
		m_nUpPartCount = tempreqfile->GetPartCount();
		m_abyUpPartStatus = new uint8[m_nUpPartCount];
		memset(m_abyUpPartStatus, 0, m_nUpPartCount);
	}
	else
	{
		if (tempreqfile->GetED2KPartCount() != nED2KUpPartCount)
		{
			//We already checked if we are talking about the same file.. So if we get here, something really strange happened!
			m_nUpPartCount = 0;
			return false;
		}
		m_nUpPartCount = tempreqfile->GetPartCount();
		m_abyUpPartStatus = new uint8[m_nUpPartCount];
		uint16 done = 0;
		while (done != m_nUpPartCount)
		{
			uint8 toread = data->ReadUInt8();
			for (UINT i = 0; i != 8; i++)
			{
				m_abyUpPartStatus[done] = ((toread >> i) & 1) ? 1 : 0;
//				We may want to use this for another feature..
//				if (m_abyUpPartStatus[done] && !tempreqfile->IsComplete((uint64)done*PARTSIZE,((uint64)(done+1)*PARTSIZE)-1))
//					bPartsNeeded = true;
				done++;
				if (done == m_nUpPartCount)
					break;
			}
		}
	}
	*/

	if (GetExtendedRequestsVersion() > 1)
	{
		uint16 nCompleteCountLast = status->GetCompleteSourcesCount(); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
		uint16 nCompleteCountNew = data->ReadUInt16();
		status->SetCompleteSourcesCount(nCompleteCountNew); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
		if (nCompleteCountLast != nCompleteCountNew)
			tempreqfile->UpdatePartsInfo();
	}
	theApp.emuledlg->transferwnd->queuelistctrl.RefreshClient(this);

	return true;
}

void CUpDownClient::CreateStandartPackets(byte* data,uint32 togo, Requested_Block_Struct* currentblock, bool bFromPF){
	uint32 nPacketSize;
	CMemFile memfile((BYTE*)data,togo);

	// NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	uint32 splittingsize = max(10*1024, GetDatarate()); // basic speed 10 KB/s
	if (togo > splittingsize) 
		nPacketSize = togo/(uint32)(togo/splittingsize);
	else
		nPacketSize = togo;
	// NEO: NUBT END <-- Xanatos --

	while (togo){
		if (togo < nPacketSize*2)
			nPacketSize = togo;
		ASSERT( nPacketSize );
		togo -= nPacketSize;

		uint64 statpos = (currentblock->EndOffset - togo) - nPacketSize;
		uint64 endpos = (currentblock->EndOffset - togo);
		if (IsUploadingToPeerCache())
		{
			if (m_pPCUpSocket == NULL){
				ASSERT(0);
				CString strError;
				strError.Format(_T("Failed to upload to PeerCache - missing socket; %s"), DbgGetClientInfo());
				throw strError;
			}
			USES_CONVERSION;
			CSafeMemFile dataHttp(10240);
			if (m_iHttpSendState == 0)
			{
				CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(GetUploadFileID());
				CStringA str;
				str.AppendFormat("HTTP/1.0 206\r\n");
				str.AppendFormat("Content-Range: bytes %I64u-%I64u/%I64u\r\n", currentblock->StartOffset, currentblock->EndOffset - 1, srcfile->GetFileSize());
				str.AppendFormat("Content-Type: application/octet-stream\r\n");
				str.AppendFormat("Content-Length: %u\r\n", (uint32)(currentblock->EndOffset - currentblock->StartOffset));
				str.AppendFormat("Server: eMule/%s\r\n", T2CA(theApp.m_strCurVersionLong));
				str.AppendFormat("\r\n");
				dataHttp.Write((LPCSTR)str, str.GetLength());
				theStats.AddUpDataOverheadFileRequest((UINT)dataHttp.GetLength());

				m_iHttpSendState = 1;
				if (thePrefs.GetDebugClientTCPLevel() > 0){
					DebugSend("PeerCache-HTTP", this, GetUploadFileID());
					Debug(_T("  %hs\n"), str);
				}
			}
			dataHttp.Write(data, nPacketSize);
			data += nPacketSize;

			if (thePrefs.GetDebugClientTCPLevel() > 1){
				DebugSend("PeerCache-HTTP data", this, GetUploadFileID());
				Debug(_T("  Start=%I64u  End=%I64u  Size=%u\n"), statpos, endpos, nPacketSize);
			}

			UINT uRawPacketSize = (UINT)dataHttp.GetLength();
			LPBYTE pRawPacketData = dataHttp.Detach();
			CRawPacket* packet = new CRawPacket((char*)pRawPacketData, uRawPacketSize, bFromPF);
			m_pPCUpSocket->SendPacket(packet, true, false, nPacketSize);
			free(pRawPacketData);
		}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		else if (IsUploadingToWebCache())
		{
			if (m_pWCUpSocket == NULL){
				ASSERT(0);
				CString strError;
				strError.Format(_T("Failed to upload to WebCache - missing socket; %s"), DbgGetClientInfo());
				throw strError;
			}
			USES_CONVERSION;
			CSafeMemFile dataHttp(10240);
			if (m_iHttpSendState == 0) // yonatan - not sure it's wise to use this (also used by PC).
			{
				//MORPH - Changed by SiRoB, Optimization requpfile
				/*
				CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(GetUploadFileID());
				*/
				//CKnownFile* srcfile = CheckAndGetReqUpFile();
				CStringA str;
//				str.AppendFormat("HTTP/1.1 200 OK\r\n"); // DFA
				str.AppendFormat("HTTP/1.0 200 OK\r\n");
				str.AppendFormat("Content-Length: %I64u\r\n", currentblock->EndOffset - currentblock->StartOffset);
				str.AppendFormat("Expires: Mon, 03 Sep 2007 01:23:45 GMT\r\n" ); // rolled-back to 1.1b code (possible bug w/soothsayers' proxy)
				str.AppendFormat("Cache-Control: public\r\n");
				str.AppendFormat("Cache-Control: no-transform\r\n");
				str.AppendFormat("Connection: keep-alive\r\nProxy-Connection: keep-alive\r\n");
				//MORPH START - Changed by SiRoB, ModID
				str.AppendFormat("Server: eMule/%s %s\r\n", T2CA(theApp.m_strCurVersionLong), T2CA(theApp.GetAppTitle()));
				//MORPH END   - Changed by SiRoB, ModID
				str.AppendFormat("\r\n");
				dataHttp.Write((LPCSTR)str, str.GetLength());
				theStats.AddUpDataOverheadFileRequest((UINT)dataHttp.GetLength());

				m_iHttpSendState = 1;
				if (thePrefs.GetDebugClientTCPLevel() > 0){
					DebugSend("WebCache-HTTP", this, GetUploadFileID());
					Debug(_T("  %hs\n"), str);
				}
			}
			dataHttp.Write(data, nPacketSize);
			data += nPacketSize;

			if (thePrefs.GetDebugClientTCPLevel() > 1){
				DebugSend("WebCache-HTTP data", this, GetUploadFileID());
				Debug(_T("  Start=%I64u  End=%I64u  Size=%u\n"), statpos, endpos, nPacketSize);
			}

			UINT uRawPacketSize = (UINT)dataHttp.GetLength();
			LPBYTE pRawPacketData = dataHttp.Detach();
			CRawPacket* packet = new CRawPacket((char*)pRawPacketData, uRawPacketSize, bFromPF);
			m_pWCUpSocket->SendPacket(packet, true, false, nPacketSize);
			free(pRawPacketData);
		}
#endif // NEO: WC END <-- Xanatos --
		else
		{
			Packet* packet;
			if (statpos > 0xFFFFFFFF || endpos > 0xFFFFFFFF){
				packet = new Packet(OP_SENDINGPART_I64,nPacketSize+32, OP_EMULEPROT, bFromPF);
				md4cpy(&packet->pBuffer[0],GetUploadFileID());
				PokeUInt64(&packet->pBuffer[16], statpos);
				PokeUInt64(&packet->pBuffer[24], endpos);
				memfile.Read(&packet->pBuffer[32],nPacketSize);
				theStats.AddUpDataOverheadFileRequest(32);
			}
			else{
				packet = new Packet(OP_SENDINGPART,nPacketSize+24, OP_EDONKEYPROT, bFromPF);
				md4cpy(&packet->pBuffer[0],GetUploadFileID());
				PokeUInt32(&packet->pBuffer[16], (uint32)statpos);
				PokeUInt32(&packet->pBuffer[20], (uint32)endpos);
				memfile.Read(&packet->pBuffer[24],nPacketSize);
				theStats.AddUpDataOverheadFileRequest(24);
			}

			if (thePrefs.GetDebugClientTCPLevel() > 0){
				DebugSend("OP__SendingPart", this, GetUploadFileID());
				Debug(_T("  Start=%I64u  End=%I64u  Size=%u\n"), statpos, endpos, nPacketSize);
			}
			// put packet directly on socket
			
			socket->SendPacket(packet,true,false, nPacketSize);
		}
	}
}

void CUpDownClient::CreatePackedPackets(byte* data, uint32 togo, Requested_Block_Struct* currentblock, bool bFromPF){
	BYTE* output = new BYTE[togo+300];
	uLongf newsize = togo+300;
	// NEO: MOD - [CompressionLevel] -- Xanatos -->
	int	compressLevel = 9;
	if (theApp.uploadqueue->GetDatarate() > 102400)
		compressLevel = 1;
	else if (theApp.uploadqueue->GetDatarate() > 51200)
		compressLevel = 3;
	else if (theApp.uploadqueue->GetDatarate() > 20480)
		compressLevel = 6;
	UINT result = compress2(output, &newsize, data, togo, compressLevel);
	// NEO: MOD END <-- Xanatos --
	if (result != Z_OK || togo <= newsize){
		delete[] output;
		CreateStandartPackets(data,togo,currentblock,bFromPF);
		return;
	}
	CMemFile memfile(output,newsize);
    uint32 oldSize = togo;
	togo = newsize;
	uint32 nPacketSize;

	// NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	uint32 splittingsize = max(10*1024, GetDatarate()); // basic speed 10 KB/s
	if (togo > splittingsize) 
		nPacketSize = togo/(uint32)(togo/splittingsize);
	else
		nPacketSize = togo;
	// NEO: NUBT END <-- Xanatos --
    
    uint32 totalPayloadSize = 0;

    while (togo){
		if (togo < nPacketSize*2)
			nPacketSize = togo;
		ASSERT( nPacketSize );
		togo -= nPacketSize;
		uint64 statpos = currentblock->StartOffset;
		Packet* packet;
		if (currentblock->StartOffset > 0xFFFFFFFF || currentblock->EndOffset > 0xFFFFFFFF){
			packet = new Packet(OP_COMPRESSEDPART_I64,nPacketSize+28,OP_EMULEPROT,bFromPF);
			md4cpy(&packet->pBuffer[0],GetUploadFileID());
			PokeUInt64(&packet->pBuffer[16], statpos);
			PokeUInt32(&packet->pBuffer[24], newsize);
			memfile.Read(&packet->pBuffer[28],nPacketSize);
			theStats.AddUpDataOverheadFileRequest(32); // NEO: FIX <-- Xanatos --
		}
		else{
			packet = new Packet(OP_COMPRESSEDPART,nPacketSize+24,OP_EMULEPROT,bFromPF);
			md4cpy(&packet->pBuffer[0],GetUploadFileID());
			PokeUInt32(&packet->pBuffer[16], (uint32)statpos);
			PokeUInt32(&packet->pBuffer[20], newsize);
			memfile.Read(&packet->pBuffer[24],nPacketSize);
			theStats.AddUpDataOverheadFileRequest(24); // NEO: FIX <-- Xanatos --
		}

		if (thePrefs.GetDebugClientTCPLevel() > 0){
			DebugSend("OP__CompressedPart", this, GetUploadFileID());
			Debug(_T("  Start=%I64u  BlockSize=%u  Size=%u\n"), statpos, newsize, nPacketSize);
		}
        // approximate payload size
        uint32 payloadSize = nPacketSize*oldSize/newsize;

        if(togo == 0 && totalPayloadSize+payloadSize < oldSize) {
            payloadSize = oldSize-totalPayloadSize;
        }
        totalPayloadSize += payloadSize;

        // put packet directly on socket
        socket->SendPacket(packet,true,false, payloadSize);
	}
	delete[] output;
}

void CUpDownClient::SetUploadFileID(CKnownFile* newreqfile)
{
	CKnownFile* oldreqfile;
	//We use the knownfilelist because we may have unshared the file..
	//But we always check the download list first because that person may have decided to redownload that file.
	//Which will replace the object in the knownfilelist if completed.
	if ((oldreqfile = theApp.downloadqueue->GetFileByID(requpfileid)) == NULL)
		oldreqfile = theApp.knownfiles->FindKnownFileByID(requpfileid);

#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface] -- Xanatos -->
	// David: Note if the master orders downlaod of a file we have in share without this fix wi will expirience an crash
	if (newreqfile == oldreqfile || (newreqfile && !md4cmp(newreqfile->GetFileHash(),requpfileid))) // X-ToDo: dissalow voodo downlaod of complete files, serve the master from teh complete file
#else
	if (newreqfile == oldreqfile)
#endif // VOODOO // NEO: VOODOO END <-- Xanatos --
		return;

	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	/*
	// clear old status
	delete[] m_abyUpPartStatus;
	m_abyUpPartStatus = NULL;

	m_nUpPartCount = 0;
	m_nUpCompleteSourcesCount= 0;
	*/

	if (newreqfile)
	{
		GetFileStatus(newreqfile, true); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
		newreqfile->AddUploadingClient(this);
		md4cpy(requpfileid, newreqfile->GetFileHash());
		requpfile = AddRequestStruct(requpfileid); // NEO: MFSB - [MultiFileStatusBars] <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] // NEO: SFL - [SourceFileList] -- Xanatos -->
		if(thePrefs.SaveSourceFileList() && source)
			source->AddSeenFile(newreqfile->GetFileHash(),newreqfile->GetFileSize());
#endif // NEO_CD // NEO: NCD END // NEO: SFL END <-- Xanatos --
	}
	else{
		md4clr(requpfileid);
		requpfile = NULL; // NEO: MFSB - [MultiFileStatusBars] <-- Xanatos --
	}

	if (oldreqfile){
		oldreqfile->RemoveUploadingClient(this);
		ClearUploadBlockRequests(); //Xman Fix Filtered Block Request // NEO: MOD <-- Xanatos --
	}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	if(newreqfile)
		SendAUXPortWhenNeeded();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
}

void CUpDownClient::AddReqBlock(Requested_Block_Struct* reqblock)
{
    if(GetUploadState() != US_UPLOADING) {
        if(thePrefs.GetLogUlDlEvents())
            AddDebugLogLine(DLP_LOW, false, _T("UploadClient: Client tried to add req block when not in upload slot! Prevented req blocks from being added. %s"), DbgGetClientInfo());
		delete reqblock;
        return;
    }

	if(HasCollectionUploadSlot()){
		CKnownFile* pDownloadingFile = theApp.sharedfiles->GetFileByID(reqblock->FileID);
		if(pDownloadingFile != NULL){
			if ( !(pDownloadingFile->IsCollection() /*CCollection::HasCollectionExtention(pDownloadingFile->GetFileName(true))*/ && pDownloadingFile->GetFileSize() < (uint64)MAXPRIORITYCOLL_SIZE) ){ // NEO: MOD - [IsCollection] <-- Xanatos --
				AddDebugLogLine(DLP_HIGH, false, _T("UploadClient: Client tried to add req block for non collection while having a collection slot! Prevented req blocks from being added. %s"), DbgGetClientInfo());
				delete reqblock;
				return;
			}
		}
		else
			ASSERT( false );
	}

    for (POSITION pos = m_DoneBlocks_list.GetHeadPosition(); pos != 0; ){
        const Requested_Block_Struct* cur_reqblock = m_DoneBlocks_list.GetNext(pos);
        if (reqblock->StartOffset == cur_reqblock->StartOffset && reqblock->EndOffset == cur_reqblock->EndOffset){
            delete reqblock;
            return;
        }
    }
    for (POSITION pos = m_BlockRequests_queue.GetHeadPosition(); pos != 0; ){
        const Requested_Block_Struct* cur_reqblock = m_BlockRequests_queue.GetNext(pos);
        if (reqblock->StartOffset == cur_reqblock->StartOffset && reqblock->EndOffset == cur_reqblock->EndOffset){
            delete reqblock;
            return;
        }
    }

    m_BlockRequests_queue.AddTail(reqblock);
}

uint32 CUpDownClient::SendBlockData(){
    uint64 sentBytesCompleteFile = 0;
    uint64 sentBytesPartFile = 0;
    uint64 sentBytesPayload = 0;

    if (GetFileUploadSocket() && (m_ePeerCacheUpState != PCUS_WAIT_CACHE_REPLY))
	{
		CEMSocket* s = GetFileUploadSocket();
		UINT uUpStatsPort;
        if (m_pPCUpSocket && IsUploadingToPeerCache())
		{
			uUpStatsPort = (UINT)-1;

            // Check if filedata has been sent via the normal socket since last call.
            uint64 sentBytesCompleteFileNormalSocket = socket->GetSentBytesCompleteFileSinceLastCallAndReset();
            uint64 sentBytesPartFileNormalSocket = socket->GetSentBytesPartFileSinceLastCallAndReset();

			if(thePrefs.GetVerbose() && (sentBytesCompleteFileNormalSocket + sentBytesPartFileNormalSocket > 0)) {
                AddDebugLogLine(false, _T("Sent file data via normal socket when in PC mode. Bytes: %I64i."), sentBytesCompleteFileNormalSocket + sentBytesPartFileNormalSocket);
			}
        }
		else
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		if(m_pWCUpSocket && IsUploadingToWebCache()) {
			uUpStatsPort = (UINT)-3; //<<0.45a

            // Check if filedata has been sent via the normal socket since last call.
            uint64 sentBytesCompleteFileNormalSocket = socket->GetSentBytesCompleteFileSinceLastCallAndReset();
            uint64 sentBytesPartFileNormalSocket = socket->GetSentBytesPartFileSinceLastCallAndReset();

			if(thePrefs.GetVerbose() && (sentBytesCompleteFileNormalSocket + sentBytesPartFileNormalSocket > 0)) {
                AddDebugLogLine(false, _T("Sent file data via normal socket when in WC mode. Bytes: %I64i."), sentBytesCompleteFileNormalSocket + sentBytesPartFileNormalSocket);
			}
        }
		else


#endif // NEO: WC END <-- Xanatos --
			uUpStatsPort = GetUserPort();

	    // Extended statistics information based on which client software and which port we sent this data to...
	    // This also updates the grand total for sent bytes, etc.  And where this data came from.
        sentBytesCompleteFile = s->GetSentBytesCompleteFileSinceLastCallAndReset();
        sentBytesPartFile = s->GetSentBytesPartFileSinceLastCallAndReset();
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
		if(!IsLanClient())
#endif //LANCAST // NEO: NLC END <-- Xanatos --
		{
			// NEO: PTM - [PrivatTransferManagement] -- Xanatos -->
			thePrefs.Add2SessionTransferData(GetClientSoft(), uUpStatsPort, false, true, (UINT)sentBytesCompleteFile, I2B(IsPrivatUpload()), GetReleaseSlot()); // NEO: BM - [BandwidthModeration]
			thePrefs.Add2SessionTransferData(GetClientSoft(), uUpStatsPort, true, true, (UINT)sentBytesPartFile, I2B(IsPrivatUpload()), GetReleaseSlot()); // NEO: BM - [BandwidthModeration]
			// NEO: PTM END <-- Xanatos --
		}

		m_nTransferredUp = (UINT)(m_nTransferredUp + sentBytesCompleteFile + sentBytesPartFile);
		AddUploadedSize(sentBytesCompleteFile + sentBytesPartFile); // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
        credits->AddUploaded((UINT)(sentBytesCompleteFile + sentBytesPartFile), GetIP(), (GetRequestFile() != NULL /*GetDownloadState() == DS_ONQUEUE*/)); // NEO: NCS - [NeoCreditSystem] <-- Xanatos --

        sentBytesPayload = s->GetSentPayloadSinceLastCallAndReset();
        m_nCurQueueSessionPayloadUp = (UINT)(m_nCurQueueSessionPayloadUp + sentBytesPayload);

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
		//Xman: in CreateNextBlockPackage we saw this upload end soon,
		//after all packets are send, we cancel this upload
		if (m_bUpEndSoon && socket->StandardPacketQueueIsEmpty()) {
			m_bUpEndSoon = false;
#else
        if (theApp.uploadqueue->CheckForTimeOver(this)) {
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
			theApp.uploadqueue->RemoveFromUploadQueue(this, _T("Completed transfer") ,true );

			// NEO: USC - [UnShareCommand]-- Xanatos -->
			CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(requpfileid);
			if (srcfile && !srcfile->IsUnshared())
			// NEO: USC END <-- Xanatos --
				SendOutOfPartReqsAndAddToWaitingQueue();
		}else 
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			if(m_bUpEndSoon==false)
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
		{
            // read blocks from file and put on socket
            CreateNextBlockPackage();
        }
    }

	// NEO: ASM - [AccurateSpeedMeasure] -- Xanatos --

    return (UINT)(sentBytesCompleteFile + sentBytesPartFile);
}

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

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

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

	// We call this metod once per secund this is delay enough
    // Check if it's time to update the display.
	DWORD curTick = ::GetTickCount();
	if (curTick-m_lastRefreshedULDisplay > MINWAIT_BEFORE_ULDISPLAY_WINDOWUPDATE+m_random_update_wait) {
        // Update display
        theApp.emuledlg->transferwnd->uploadlistctrl.RefreshClient(this);
        theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(this);
        m_lastRefreshedULDisplay = curTick;
    }

	return m_nUpDatarate;
}

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

void CUpDownClient::SendOutOfPartReqsAndAddToWaitingQueue()
{
	//OP_OUTOFPARTREQS will tell the downloading client to go back to OnQueue..
	//The main reason for this is that if we put the client back on queue and it goes
	//back to the upload before the socket times out... We get a situation where the
	//downloader thinks it already sent the requested blocks and the uploader thinks
	//the downloader didn't send any request blocks. Then the connection times out..
	//I did some tests with eDonkey also and it seems to work well with them also..
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__OutOfPartReqs", this);
	Packet* pPacket = new Packet(OP_OUTOFPARTREQS, 0);
	theStats.AddUpDataOverheadFileRequest(pPacket->size);
	socket->SendPacket(pPacket, true, true);
	m_fSentOutOfPartReqs = 1;
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	if(!IsLanClient())
#endif //LANCAST // NEO: NLC END <-- Xanatos --
		theApp.uploadqueue->AddClientToQueue(this, true);
}

/**
 * See description for CEMSocket::TruncateQueues().
 */
void CUpDownClient::FlushSendBlocks(){ // call this when you stop upload, or the socket might be not able to send
    if (socket)      //socket may be NULL...
        socket->TruncateQueues();
}

void CUpDownClient::SendHashsetPacket(const uchar* forfileid)
{
	CKnownFile* file = theApp.sharedfiles->GetFileByID(forfileid);
	if (!file){
		CheckFailedFileIdReqs(forfileid);
		throw GetResString(IDS_ERR_REQ_FNF) + _T(" (SendHashsetPacket)");
	}

	CSafeMemFile data(1024);
	data.WriteHash16(file->GetFileHash());
	UINT parts = file->GetHashCount();
	data.WriteUInt16((uint16)parts);
	for (UINT i = 0; i < parts; i++)
		data.WriteHash16(file->GetPartHash(i));
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__HashSetAnswer", this, forfileid);
	Packet* packet = new Packet(&data);
	packet->opcode = OP_HASHSETANSWER;
	theStats.AddUpDataOverheadFileRequest(packet->size);
	socket->SendPacket(packet,true,true);
}

void CUpDownClient::ClearUploadBlockRequests()
{
	FlushSendBlocks();

	for (POSITION pos = m_BlockRequests_queue.GetHeadPosition();pos != 0;){
		// NEO: RBT - [ReadBlockThread] -- Xanatos -->
		if (m_BlockRequests_queue.GetAt(pos)->filedata != RBT_ACTIVE && m_BlockRequests_queue.GetAt(pos)->filedata != RBT_ERROR && m_BlockRequests_queue.GetAt(pos)->filedata != NULL) 
			delete[] m_BlockRequests_queue.GetAt(pos)->filedata;
		delete m_BlockRequests_queue.GetNext(pos);
		// NEO: RBT END <-- Xanatos --
	}
	m_BlockRequests_queue.RemoveAll();
	
	for (POSITION pos = m_DoneBlocks_list.GetHeadPosition();pos != 0;)
		delete m_DoneBlocks_list.GetNext(pos);
	m_DoneBlocks_list.RemoveAll();
}

void CUpDownClient::SendRankingInfo(){
	if (!ExtProtocolAvailable())
		return;
	UINT nRank = theApp.uploadqueue->GetWaitingPosition(this);
	if (!nRank)
		return;
	Packet* packet = new Packet(OP_QUEUERANKING,12,OP_EMULEPROT);
	PokeUInt16(packet->pBuffer+0, (uint16)nRank);
	memset(packet->pBuffer+2, 0, 10);
	// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
	if (thePrefs.UseEstimatedDownloadTime() && GetDownloadTimeVersion() > 0) // NEO: NMPm - [NeoModProtMultiPacket] 
	{
		uint32 avg_value;
		uint32 err_value;
		EstimateDownloadTime(avg_value, err_value);
		PokeUInt32(packet->pBuffer+4,avg_value);
		PokeUInt32(packet->pBuffer+8,err_value);
	}
	// NEO: EDT END <-- Xanatos --
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__QueueRank", this);
	theStats.AddUpDataOverheadFileRequest(packet->size);
	socket->SendPacket(packet,true,true);
}

// NEO: PTM - [PrivatTransferManagement] -- Xanatos -->
void CUpDownClient::SendAcceptUpload(){

	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__AcceptUploadReq", this);

	Packet* packet =  new Packet(OP_ACCEPTUPLOADREQ,0);

#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler]
	socket->SetPriorityReceive(true);
#endif // NEO_DBT // NEO: NDBT END
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler]
	socket->SetPrioritySend(true);
#endif // NEO_UBT // NEO: NUBT END

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

	if(const uint8 state = IsPrivatUpload()){
		Packet* PTMpacket = new Packet(OP_PTM_STATUS,1,OP_MODPROT);
		PokeUInt8(PTMpacket->pBuffer, state);
		theStats.AddUpDataOverheadFileRequest(PTMpacket->size);
		socket->SendPacket(PTMpacket,true);
	}
}
// NEO: PTM END <-- Xanatos --

void CUpDownClient::SendCommentInfo(/*const*/ CKnownFile *file)
{
	// NEO: XC - [ExtendedComments] -- Xanatos -->
	if (file == NULL || !ExtProtocolAvailable() || m_byAcceptCommentVer < 1)
		return;
	if (file != theApp.sharedfiles->GetFileByID(requpfileid)){
		if(m_byAcceptCommentVer < 2)	// not supported by remote user
			return;
	} else {
		if (!m_bCommentDirty)	// only send upfile comment once
			return;
		m_bCommentDirty = false;
	}
	// NEO: XC END <-- Xanatos --
	//if (!m_bCommentDirty || file == NULL || !ExtProtocolAvailable() || m_byAcceptCommentVer < 1)
	//	return;
	//m_bCommentDirty = false;

	UINT rating = file->GetFileRating();
	const CString& desc = file->GetFileComment();
	if (file->GetFileRating() == 0 && desc.IsEmpty())
		return;

	CSafeMemFile data(256);
	// NEO: XC - [ExtendedComments] -- Xanatos -->
	if(m_byAcceptCommentVer >= 2)
		data.WriteHash16(file->GetFileHash());
	// NEO: XC END <-- Xanatos --
	data.WriteUInt8((uint8)rating);
	data.WriteLongString(desc, GetUnicodeSupport());
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__FileDesc", this, file->GetFileHash());
	Packet *packet = new Packet(&data,OP_EMULEPROT);
	packet->opcode = OP_FILEDESC;
	theStats.AddUpDataOverheadFileRequest(packet->size);
	socket->SendPacket(packet,true);
}

// NEO: MFSB - [MultiFileStatusBars] -- Xanatos -->
Requested_File_Struct* CUpDownClient::AddRequestStruct(const uchar* fileid)
{
	Requested_File_Struct* cur_struct = GetRequestStruct(fileid);
	if(cur_struct)
		return cur_struct;

	Requested_File_Struct* new_struct = new Requested_File_Struct;
	md4cpy(new_struct->fileid,fileid);
	new_struct->lastasked = 0;
	new_struct->badrequests = 0;
	m_RequestedFiles_list.AddHead(new_struct);
	return new_struct;
}

Requested_File_Struct* CUpDownClient::GetRequestStruct(const uchar* fileid)
{
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition(); pos != 0; ){
		Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetNext(pos);
		if (!md4cmp(cur_struct->fileid,fileid))
			return cur_struct;
	}
	return NULL;
}

void CUpDownClient::AddRequestCount(const uchar* fileid)
{
	Requested_File_Struct* cur_struct = GetRequestStruct(fileid);
	if(cur_struct){
		if(cur_struct->lastasked){
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			if(thePrefs.IsAgressionDetection() && !GetFriendSlot()){
				if (::GetTickCount() - cur_struct->lastasked < thePrefs.GetAgressionIntervalsMs() ){
					if (GetDownloadState() != DS_DOWNLOADING)
						cur_struct->badrequests++;
					if (cur_struct->badrequests >= thePrefs.GetAgressionThreshold()){
						if(thePrefs.UseArgosSystem())
							theApp.argos->DoArgos(GetConnectIP(),AR_AGRESSIV);
						else
							Ban();
					}
				}
				else{
					if (cur_struct->badrequests > 0)
						cur_struct->badrequests--;
				}
			}
#else
			if (::GetTickCount() - cur_struct->lastasked < MIN_REQUESTTIME && !GetFriendSlot()){ 
				if (GetDownloadState() != DS_DOWNLOADING)
					cur_struct->badrequests++;
				if (cur_struct->badrequests >= BADCLIENTBAN)
					Ban();
			}
			else{
				if (cur_struct->badrequests)
					cur_struct->badrequests--;
			}
#endif // ARGOS // NEO: NA END <-- Xanatos --
		}
		cur_struct->lastasked = ::GetTickCount();
	}
}
// NEO: MFSB - [MultiFileStatusBars] <-- Xanatos --

void  CUpDownClient::UnBan()
{
	theApp.clientlist->AddTrackClient(this);
	theApp.clientlist->RemoveBannedClient(GetIP());
	SetUploadState(US_NONE);
	ClearWaitStartTime();
	theApp.emuledlg->transferwnd->ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;)
	{
		Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetNext(pos);
		cur_struct->badrequests = 0;
		cur_struct->lastasked = 0;	
	}
}

void CUpDownClient::Ban(LPCTSTR pszReason)
{
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if(IsProxy())
		return;
#endif // NEO: WC END <-- Xanatos --
	SetChatState(MS_NONE);
	theApp.clientlist->AddTrackClient(this);
	if (!IsBanned()){
		if (thePrefs.GetLogBannedClients())
			AddDebugLogLine(false,_T("Banned: %s; %s"), pszReason==NULL ? _T("Aggressive behaviour") : pszReason, DbgGetClientInfo());
	}
#ifdef _DEBUG
	else{
		if (thePrefs.GetLogBannedClients())
			AddDebugLogLine(false,_T("Banned: (refreshed): %s; %s"), pszReason==NULL ? _T("Aggressive behaviour") : pszReason, DbgGetClientInfo());
	}
#endif
	theApp.clientlist->AddBannedClient(GetIP());
	// NEO: FIX -- Xanatos -->
	theApp.uploadqueue->RemoveFromWaitingQueue(this);
	if(theApp.uploadqueue->IsOnUploadQueue(this))
		theApp.uploadqueue->RemoveFromUploadQueue(this,_T("Ban"));
	// NEO: FIX END <-- Xanatos --
	SetUploadState(US_BANNED);
	// NEO: FIX -- Xanatos -->
	if(GetDownloadState() != DS_NONE)
		SetDownloadState(DS_BANNED);
	// NEO: FIX END <-- Xanatos --
	theApp.emuledlg->transferwnd->ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
	theApp.emuledlg->transferwnd->queuelistctrl.RefreshClient(this);
	if (socket != NULL && socket->IsConnected())
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
		socket->m_Socket->ShutDown(SD_RECEIVE); // let the socket timeout, since we dont want to risk to delete the client right now. This isnt acutally perfect, could be changed later
#else
		socket->ShutDown(SD_RECEIVE); // let the socket timeout, since we dont want to risk to delete the client right now. This isnt acutally perfect, could be changed later
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
}

uint32 CUpDownClient::GetWaitStartTime() const
{
	if (credits == NULL){
		ASSERT ( false );
		return 0;
	}
	uint32 dwResult = credits->GetSecureWaitStartTime(GetIP());
	if (dwResult > m_dwUploadTime && IsDownloading()){
		//this happens only if two clients with invalid securehash are in the queue - if at all
		dwResult = m_dwUploadTime-1;

		if (thePrefs.GetVerbose())
			DEBUG_ONLY(AddDebugLogLine(false,_T("Warning: CUpDownClient::GetWaitStartTime() waittime Collision (%s)"),GetUserName()));
	}
	return dwResult;
}

void CUpDownClient::SetWaitStartTime(){
	if (credits == NULL){
		return;
	}
	credits->SetSecWaitStartTime(GetIP());
}

void CUpDownClient::ClearWaitStartTime(){
	if (credits == NULL){
		return;
	}
	credits->ClearWaitStartTime();
}

// NEO: SQ - [SaveUploadQueue] -- Xanatos -->
void CUpDownClient::SaveQueueWaitTime(){
	if (credits == NULL){
		return;
	}
	credits->SaveQueueWaitTime();
}

void CUpDownClient::ClearQueueWaitTime(){
	if (credits == NULL){
		return;
	}
	credits->ClearQueueWaitTime();
}
// NEO: SQ END <-- Xanatos --

// NEO: NMFS - [NiceMultiFriendSlots] -- Xanatos -->
bool CUpDownClient::GetFriendSlot(bool bIntern) const
{
	if(!m_bFriendSlot)
		return false;
	if (credits && theApp.clientcredits->CryptoAvailable()){
		switch(credits->GetCurrentIdentState(GetIP())){
			case IS_IDFAILED:
			case IS_IDNEEDED:
			case IS_IDBADGUY:
				return false;
		}
	}

	// Note: we save the slots between sessions, so when the momentan max amount is used dont let the client be promoted handle it as usual
	if(bIntern && !IsDownloading() && theApp.uploadqueue->GetPrivatSlots() >= (thePrefs.IsFriendSlotLimit() ? thePrefs.GetFriendSlotLimit() : 1))
		return false;	
	if(!IsFriend())
		return false;
	return true;
}
// NEO: NMFS END <-- Xanatos --

// NEO: RT - [ReleaseTweaks] -- Xanatos -->
bool CUpDownClient::GetReleaseSlot(bool bPS)
{
	CKnownFile* accfile = GetUploadingFile();
	if(accfile == NULL)
		accfile = theApp.sharedfiles->GetFileByID(requpfileid);
	if(!theApp.sharedfiles->IsFilePtrInList(accfile))
		return false;
	return bPS ? accfile->GetPowerShared() : accfile->GetReleasePriority();
}
// NEO: RT END <-- Xanatos --

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
CClientReqSocket* CUpDownClient::GetFileUploadSocket(bool bLog) 
#else
CEMSocket* CUpDownClient::GetFileUploadSocket(bool bLog)
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
{
#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_pPCUpSocket && (IsUploadingToPeerCache() || m_ePeerCacheUpState == PCUS_WAIT_CACHE_REPLY))
	{
        if (bLog && thePrefs.GetVerbose())
            AddDebugLogLine(false, _T("%s got peercache socket."), DbgGetClientInfo());
        return m_pPCUpSocket;
    }
#ifdef WEBCACHE // NEO: WC - [WebCache]
    else if(m_pWCUpSocket && IsUploadingToWebCache()) {
        if (bLog && thePrefs.GetVerbose())
            AddDebugLogLine(false, _T("%s got webcache socket."), DbgGetClientInfo());

        return m_pWCUpSocket;
    }
#endif //WEBCACHE // NEO: WC END
	else
	{
        if (bLog && thePrefs.GetVerbose())
            AddDebugLogLine(false, _T("%s got normal socket."), DbgGetClientInfo());
        return socket;
    }
}

void CUpDownClient::SetCollectionUploadSlot(bool bValue){
	ASSERT( !IsDownloading() || bValue == m_bCollectionUploadSlot );
	m_bCollectionUploadSlot = bValue;
}

#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
bool CUpDownClient::HaveTrickleSlot() const {
	CClientReqSocket* socket = (const_cast<CUpDownClient*>(this))->GetFileUploadSocket();
	if (socket) 
		return socket->m_eSlotState != SS_FULL; 
	else 
		return false;
}

bool CUpDownClient::IsPriorityClient() const {
	CClientReqSocket* socket = (const_cast<CUpDownClient*>(this))->GetFileUploadSocket();
	if (socket) 
		return socket == theApp.uploadBandwidthThrottler->GetPrioritySocket(); 
	else 
		return false;
}

float CUpDownClient::GetSocketRatio() const {
	CClientReqSocket* socket = (const_cast<CUpDownClient*>(this))->GetFileUploadSocket();
	if (socket) 
		return socket->GetAvgRatio(); 
	else 
		return 0.0F;
}
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
bool CUpDownClient::IsHotFileSwapAllowed(const uchar* reqfilehash)
{
	// Close Backdoor v2 (idea Maella)
	//after seeing that many official clients swap the file just when they get an uploadslot
	//I decided to allow the upload if the new requested file
	//has same or higher priority
	//
	// Remark: There is a security leak that a leecher mod could exploit here.
	//         A client might send reqblock for another file than the one it 
	//         was granted to download. As long as the file ID in reqblock
	//         is the same in all reqblocks, it won't be rejected.  
	//         With this a client might be in a waiting queue with a high 
	//         priority but download block of a file set to a lower priority.
	CKnownFile* reqfileNr1 = theApp.sharedfiles->GetFileByID(reqfilehash);
	CKnownFile* reqfileNr2 = theApp.sharedfiles->GetFileByID(GetUploadFileID());
	if(reqfileNr1==NULL) 
	{
		//We don't know the requesting file, this can happen when we delete the file during upload
		//the prevent to run in a file exception when creating next block
		//send a cancel and remove client from queue
		Packet* packet = new Packet(OP_OUTOFPARTREQS, 0); 
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet, true, true);
		theApp.uploadqueue->RemoveFromUploadQueue(this,_T("client want download unknown file"));
		SetUploadFileID(NULL); 
		return false;
	}
	else if(reqfileNr2 == NULL)
	{
		return false;
	}
	else if(reqfileNr2!=NULL && GetScore(false,true,true,false,false,reqfileNr1) < GetScore(false,true,true,false,false,reqfileNr2)) // NEO: RT - [ReleaseTweaks]
	{
		if(thePrefs.GetLogUlDlEvents()){
			AddDebugLogLine(false, _T("--> Upload session ended due wrong requested FileID (client=%s, expected=%s, asked=%s)"), 
				GetUserName(),reqfileNr2->GetFileName(), reqfileNr1->GetFileName());
		}
		theApp.uploadqueue->RemoveFromUploadQueue(this, _T("wrong file"),true); 
		SetUploadFileID(reqfileNr1);
		SetActiveUpReqFlag(1 /*OP_STARTUPLOADREQ*/); // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
		SendOutOfPartReqsAndAddToWaitingQueue();
		if(thePrefs.CloseMaellaBackdoor() == TRUE)
			SetWaitStartTime(); // Reset Waiting time as punishment
		return false;
	}
	else if(reqfileNr2!=reqfileNr1)
	{
		if(thePrefs.GetLogUlDlEvents()){
			AddDebugLogLine(false, _T("--> we allow to upload different file: (client=%s, expected=%s, asked=%s)"), 
				GetUserName(),reqfileNr2->GetFileName(), reqfileNr1->GetFileName());
		}
	}

	return true;
}

bool CUpDownClient::CheckUDPFileReaskPing()
{
	// We dont need data for every file becouse when the client swap he swap TCP and the next UDP reask shall aproch as usual in 29 munites
	if (GetLastUpRequest() && ::GetTickCount() - GetLastUpRequest() < thePrefs.GetAgressionIntervalsMs() )
	{
		if (GetDownloadState() != DS_DOWNLOADING)
			m_uFastUDPCounter++;
		if (m_uFastUDPCounter >= thePrefs.GetAgressionThreshold()){
			if(thePrefs.UseArgosSystem()){
				theApp.argos->DoArgos(GetConnectIP(),AR_AGRESSIV,TRUE);
			}else{
				Ban();
				return true;
			}
		}
	}
	else{
		if (m_uFastUDPCounter > 0)
			m_uFastUDPCounter--;
	}

	return theApp.argos->IsArgos(GetConnectIP(),AR_AGRESSIV);
}

void CUpDownClient::CheckFileNotFound()
{
	if(reqfile && GetUploadState()!=US_NONE)
	{
		CKnownFile* upfile = theApp.sharedfiles->GetFileByID(GetUploadFileID());
		if(upfile && upfile == reqfile) //we speak about the same file
		{
			// we just mark the file and don't ban now, the client may have unshared the file or something simmilar
			m_fileFNF = reqfile;

			if(GetUploadState() != US_UPLOADING)
				theApp.uploadqueue->RemoveFromUploadQueue(this, _T("Src says he does not have the file he's dl'ing"));
			theApp.uploadqueue->RemoveFromWaitingQueue(this);
		}
		else if(!reqfile)
			m_fileFNF = NULL;
	}
}

bool CUpDownClient::CheckFileRequest(CKnownFile* file)
{
	// if the client asks again for the file he claimed to can't find but also had asket for it befoure, hi is for sure lying
	if(m_fileFNF == file){ // got you, you'v said you wouldn't have it
		theApp.argos->DoArgos(GetConnectIP(),AR_FILEFAKER);
		return true;
	}

	return false;
}
#endif // ARGOS // NEO: NA END <-- Xanatos --

// NEO: ASP - [ActiveSpreading] -- Xanatos -->
// David: This method is verry simmilar to CUpDownClient::SendFileRequest(), howeever to have a clean code I decided to copy it here
// The only what we want achiev is that the remote cleint add us as a passive source 
//  For this we only need to send the OP_REQUESTFILENAME, the rest of the reask can be dropped, 
//   so multi packet is unneded as we send only one packet anyway
void CUpDownClient::SendFileAdvertisement(CKnownFile* file)
{
	CSafeMemFile dataFileReq(16+16);
	dataFileReq.WriteHash16(file->GetFileHash());

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

	//This is extended information
	if (GetExtendedRequestsVersion() > 0)
		// NEO: IPS - [InteligentPartSharing]
		if (file->IsPartFile())
			((CPartFile*)file)->WritePartStatus(&dataFileReq, status);
		else if(!file->WritePartSelection(&dataFileReq, status))
			dataFileReq.WriteUInt16(0);
		// NEO: IPS END
	if (GetExtendedRequestsVersion() > 1)
		((CPartFile*)file)->WriteCompleteSourcesCount(&dataFileReq); // this function refers anyway only to a variable in CKnownFile

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

	if (file->CanCheckXSSources(this))
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0) {
			DebugSend("OP__RequestSources", this, file->GetFileHash());
			if (GetLastAskedForSources() == 0)
				Debug(_T("  first source request\n"));
			else
				Debug(_T("  last source request was before %s\n"), CastSecondsToHM((GetTickCount() - GetLastAskedForSources())/1000));
		}
		Packet* packet = new Packet(OP_REQUESTSOURCES,16,OP_EMULEPROT);
		md4cpy(packet->pBuffer,file->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(), file->GetFileName());
	}	
}
// NEO: ASP END <-- Xanatos --