//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.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 "zlib/zlib.h"
#include "UpDownClient.h"
#include "opcodes.h"
#include "packets.h"
#include "emule.h"
#include "uploadqueue.h"
#include "otherstructs.h"

//	members of CUpDownClient
//	which are mainly used for uploading functions 

uint32 CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue){
	//TODO: complete this (friends, uploadspeed, emuleuser etc etc)
	if (!m_pszUsername)
		return 0;
	if (sysvalue && HasLowID() && !(socket && socket->IsConnected())){
		return 0;
	}

	// Bot user?
	m_bIsBotuser = (strstr(m_pszUsername, "edk-files") || strstr(m_pszUsername, "finder")) && strstr(m_pszUsername, "com");

	// 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.
	//bool iscommunity = false;
	m_filepriority = 10; // standard	
	if(reqfileid != NULL){ 
		if(theApp.sharedfiles->GetFileByID(reqfileid) != NULL){ 
			switch(theApp.sharedfiles->GetFileByID(reqfileid)->GetPriority()){ 
				case PR_VERYHIGH: // Modified by Tarod for UAP
					if (theApp.sharedfiles->GetFileByID(reqfileid)->IsPartFile()) {
						m_filepriority = 50;
					} else {
						m_filepriority = 100;
					}
					break;
				case PR_HIGH: 
					m_filepriority = 20; 
					break; 
				case PR_LOW: 
					m_filepriority = 5; 
					break; 
				case PR_VERYLOW:
					m_filepriority = 2;
					break;
				case PR_NORMAL: 
					default: 
					m_filepriority = 10; 
				break; 
			} 
		} 
	} 
	// friend slot
	if (IsFriend() && GetFriendSlot())
		return 0xFFFFFFFF;
	// calculate score, based on waitingtime and other factors
	float fBaseValue;
	if (onlybasevalue)
		fBaseValue = 100;
	else if (!isdownloading)
		fBaseValue = (float)(::GetTickCount()-m_dwWaitTime)/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-m_dwWaitTime);
		ASSERT ( m_dwUploadTime-m_dwWaitTime >= 0 ); //oct 28, 02: changed this from "> 0" to ">= 0"
		fBaseValue += (float)(::GetTickCount() - m_dwUploadTime > 900000)? 900000:1800000;
		fBaseValue /= 1000;
	}

	if (m_bIsBotuser)
		fBaseValue *= 0.9f;
	if (HasLowID())
		fBaseValue *= 0.8f;
	if (GetDownloadState() == DS_DOWNLOADING)
		fBaseValue *= 1.5f; // since up/down credits are in, this isn't that improtant anymore
	if (IsFriend())
		fBaseValue *= 2.0f;
	//if (iscommunity)
	//	fBaseValue *= 2.0f;

	// Added by Tarod [Amdribant fix loadedsrc]
	ASSERT(credits != NULL);
	if(credits) { 
	fBaseValue *= credits->GetScoreRatio();
	} 
	// End by Tarod

	// Added by Tarod (herbert code)
	fBaseValue *= GetSmallFilePushRatio() ;
	fBaseValue *= GetRareFilePushRatio() ;
	// End by Tarod

	//if (!onlybasevalue) // it's better if we can see in waiting list complete rating with up priorities too
    fBaseValue *= ((float)(m_filepriority))/10.0f; 
	if (IsBanned())
		return 0;

	if (!isdownloading && !onlybasevalue){
		if (HasLowID() && !(socket && socket->IsConnected()) ){
			if (!theApp.serverconnect->IsConnected() || theApp.serverconnect->IsLowID() || theApp.listensocket->TooManySockets())
				return 0;
		}
	}
	return (uint32)fBaseValue;
}

// Added by Tarod based in herbert code and modifications by MatzeHH
float CUpDownClient::GetRareFilePushRatio(){
	//if(!theApp.glob_prefs->FairShareRarePush())
	//	return 1.0f;
	CKnownFile* srcfile = theApp.sharedfiles->GetFileByID((uchar*)reqfileid);
	if (srcfile == (CKnownFile*)NULL)
		return 1.0f;
	
	return srcfile->GetFileRatio() ;
}

float CUpDownClient::GetSmallFilePushRatio(){
	//if(!theApp.glob_prefs->FairShareRarePush())
	//	return 1.0f;
	CKnownFile* srcfile = theApp.sharedfiles->GetFileByID((uchar*)reqfileid);
	if (srcfile == (CKnownFile*)NULL)
		return 1.0f;

	// Modded by Tarod to: Min(100, Max(1, 9.5 / FS)) [9.5 Mbs. == Chunk Size]
	float filesizeinmb = ((float)srcfile->GetFileSize() / 1048576.0f);

	if (filesizeinmb > 0.0f && filesizeinmb < 9.5f) {
		float mul = 9.5f / filesizeinmb ;		// VQB formula
		
		return mul > 100.0f ? 100.0f : mul  ;
	}

	return 1.0f;
}
// End added by Tarod

// Checks if it is next requested block from another chunk of the actual file or from another file 
// 
// [Return] 
//   true : Next requested block is from another different chunk or file than last downloaded block 
//   false: Next requested block is from same chunk that last downloaded block 
bool CUpDownClient::IsDifferentPartBlock(void) // [Tarod 12/22/2002] 
{ 
	Requested_Block_Struct* last_done_block;
	Requested_Block_Struct* next_requested_block;
	uint32 last_done_part = 0xffffffff;
	uint32 next_requested_part = 0xffffffff;
	
	bool different_part = false;
	
	try {
		// Check if we have good lists and proceed to check for different chunks
		if (!m_BlockRequests_queue.IsEmpty() && !m_DoneBlocks_list.IsEmpty()) {

			// Get last block and next pending
			last_done_block = (Requested_Block_Struct*)m_DoneBlocks_list.GetHead();
			next_requested_block = (Requested_Block_Struct*)m_BlockRequests_queue.GetHead(); 
			
			// Calculate corresponding parts to blocks
			last_done_part = last_done_block->StartOffset / PARTSIZE;
			next_requested_part = next_requested_block->StartOffset / PARTSIZE; 
             
			// Test is we are asking same file and same part
			if (memcmp(last_done_block->FileID, next_requested_block->FileID, 16) != 0 || last_done_part != next_requested_part) {
				different_part = true;
			}
		} 
   	} catch(...) { 
      		different_part = true; 
   	} 
//	theApp.emuledlg->AddDebugLogLine(false, "Debug: User %s, last_done_part (%u) %s (%u) next_requested_part, sent %u Kbs.", GetUserName(), last_done_part, different_part? "!=": "==", next_requested_part, this->GetTransferedUp() / 1024); 

	return different_part; 
}

bool CUpDownClient::CreateNextBlockPackage(){
	// time critical
	// check if we should kick this client
	// VQB idea for fullchunks
//	if (theApp.glob_prefs->TransferFullChunks())
//	{
		// Added by Tarod -my code 100% :)
	// Disabled by Rectencle - not useful combined with Connection-Prefetching
		//if ( /*theApp.uploadqueue->CheckForTimeOver(this) &&*/ IsDifferentPartBlock())
		//{
		//	SetWaitStartTime();
		//	theApp.uploadqueue->RemoveFromUploadQueue(this);
		//	theApp.uploadqueue->AddClientToQueue(this,true);
		//	return false;
		//}
//	}
// time critical
	// check if we should kick this client
	// Changed by Rectencle! Connection-Prefetching needs calulation per volume not per time
// Normally the Client is removed in the CUploadQueue::Process() but when
// Prefetching already has started why creating a new Packet once more?
//	if (theApp.uploadqueue->CheckForTimeOver(this)){
	if (PrefetchedAlready() && !theApp.uploadqueue->GetIsOneClientAtZeroUp()) {
		// back on the waitqueue
		SetWaitStartTime();  // Added by VQB (Rectencle)
		SetAskedCount(0);  // Added by VQB (Rectencle)
		theApp.knownfiles->Save(); // Added by VQB to save stats after UL completes (Rectencle)
		ClearPrefetchedAlready(); //Rectencle Connection-Prefetching
		SetWaitStartTime() ;
		theApp.uploadqueue->RemoveFromUploadQueue(this);
		theApp.uploadqueue->AddClientToQueue(this,true);
		return false;
	}
/*	else {
		if (theApp.uploadqueue->CheckForTimeOver(this)){
			// back on the waitqueue
			SetWaitStartTime();
			theApp.uploadqueue->RemoveFromUploadQueue(this);
			theApp.uploadqueue->AddClientToQueue(this,true);
			return false;
		}
	}*/
	if (m_BlockRequests_queue.IsEmpty()){
		return false;
	}
	CFile file;
	byte* filedata = 0;
	char* fullname = 0;
	try{
		while (!m_BlockRequests_queue.IsEmpty()){
			Requested_Block_Struct* currentblock = m_BlockRequests_queue.GetHead();
			CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(currentblock->FileID);
			m_pszFileSize = srcfile->GetFileSize(); //Rectencle Connection-Prefetching (this case for small files)
			if (!srcfile)
				throw GetResString(IDS_ERR_REQ_FNF);

			if (srcfile->IsPartFile() && ((CPartFile*)srcfile)->GetStatus() != PS_COMPLETE){
				fullname = nstrdup(((CPartFile*)srcfile)->GetFullName());
				fullname[strlen(fullname)-4] = 0;			
			}
			else{
				fullname = new char[strlen(srcfile->GetPath())+strlen(srcfile->GetFileName())+10];
				sprintf(fullname,"%s\\%s",srcfile->GetPath(),srcfile->GetFileName());
			}
		
			uint32 togo;
			if (currentblock->StartOffset > currentblock->EndOffset){
				togo = currentblock->EndOffset + (srcfile->GetFileSize() - currentblock->StartOffset);
			}
			else{
				togo = currentblock->EndOffset - currentblock->StartOffset;
				if (srcfile->IsPartFile() && !((CPartFile*)srcfile)->IsComplete(currentblock->StartOffset,currentblock->EndOffset-1))
					throw GetResString(IDS_ERR_INCOMPLETEBLOCK);
			}
			
			if (!srcfile->IsPartFile()){
				if (!file.Open(fullname,CFile::modeRead|CFile::osSequentialScan|CFile::shareDenyNone))
					throw GetResString(IDS_ERR_OPEN);
				delete[] fullname;
				fullname = 0;
				file.Seek(currentblock->StartOffset,0);
				
				filedata = new byte[togo+500];
				if (uint32 done = file.Read(filedata,togo) != togo){
					file.SeekToBegin();
					file.Read(filedata + done,togo-done);
				}
				file.Close();
			}
			else{
				CPartFile* partfile = (CPartFile*)srcfile;
				delete[] fullname;
				fullname = 0;
				partfile->m_hpartfile.Seek(currentblock->StartOffset,0);
				
				filedata = new byte[togo+500];
				if (uint32 done = partfile->m_hpartfile.Read(filedata,togo) != togo){
					partfile->m_hpartfile.SeekToBegin();
					partfile->m_hpartfile.Read(filedata + done,togo-done);
				}
			}

			memcpy(reqfileid,currentblock->FileID,16);
			if (m_byDataCompVer == 1 && (!strstr(srcfile->GetFileName(),".zip")) && (!strstr(srcfile->GetFileName(),".rar")) && (!strstr(srcfile->GetFileName(),".ace")))
				CreatePackedPackets(filedata,togo,currentblock);
			else
				CreateStandartPackets(filedata,togo,currentblock);
			
			// file statistic
			srcfile->statistic.AddTransferd(togo);

			m_DoneBlocks_list.AddHead(m_BlockRequests_queue.RemoveHead());
			delete[] filedata;
			filedata = 0;
		}
	}
	catch(CString error){
		OUTPUT_DEBUG_TRACE();
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_ERR_CLIENTERRORED),GetUserName(),error.GetBuffer());
		theApp.uploadqueue->RemoveFromUploadQueue(this);
		if (filedata)
			delete filedata;
		if (fullname)
			delete[] fullname;
		return false;
	}
//	theApp.emuledlg->AddDebugLogLine(false,"Debug: Packet done. Size: %i",blockpack->GetLength());
	return true;
}

void CUpDownClient::CreateStandartPackets(byte* data,uint32 togo, Requested_Block_Struct* currentblock){
	uint32 nPacketSize;
	CMemFile memfile((BYTE*)data,togo);
	if (togo > 10240) 
		nPacketSize = togo/(uint32)(togo/10240);
	else
		nPacketSize = togo;
	while (togo){
		if (togo < nPacketSize*2)
			nPacketSize = togo;
		togo -= nPacketSize;
		Packet* packet = new Packet(OP_SENDINGPART,nPacketSize+24);
		memcpy(&packet->pBuffer[0],reqfileid,16);
		uint32 statpos = (currentblock->EndOffset - togo) - nPacketSize;
		memcpy(&packet->pBuffer[16],&statpos,4);
		uint32 endpos = (currentblock->EndOffset - togo);
		memcpy(&packet->pBuffer[20],&endpos,4);
		memfile.Read(&packet->pBuffer[24],nPacketSize);
		m_BlockSend_queue.AddTail(packet);
	}
}

void CUpDownClient::CreatePackedPackets(byte* data,uint32 togo, Requested_Block_Struct* currentblock){
	BYTE* output = new BYTE[togo+300];
	uLongf newsize = togo+300;
	uint16 result = compress2(output,&newsize,data,togo,9);
	if (result != Z_OK || togo <= newsize){
		delete[] output;
		CreateStandartPackets(data,togo,currentblock);
		return;
	}
	m_bUsedComprUp = true;
	compressiongain += (togo-newsize); // Add show compression
	notcompressed += togo;// Add show compression

	CMemFile memfile(output,newsize);
	togo = newsize;
	uint32 nPacketSize;
	if (togo > 10240) 
		nPacketSize = togo/(uint32)(togo/10240);
	else
		nPacketSize = togo;
	while (togo){
		if (togo < nPacketSize*2)
			nPacketSize = togo;
		togo -= nPacketSize;
		Packet* packet = new Packet(OP_COMPRESSEDPART,nPacketSize+24,OP_EMULEPROT);
		memcpy(&packet->pBuffer[0],reqfileid,16);
		uint32 statpos = currentblock->StartOffset;
		memcpy(&packet->pBuffer[16],&statpos,4);
		memcpy(&packet->pBuffer[20],&newsize,4);
		memfile.Read(&packet->pBuffer[24],nPacketSize);
		m_BlockSend_queue.AddTail(packet);
	}
	delete[] output;
}


void CUpDownClient::AddReqBlock(Requested_Block_Struct* reqblock){

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

}

void CUpDownClient::SetUpStartTime(uint32 dwTime){
	if (dwTime)
		m_dwUploadTime = dwTime;
	else
		m_dwUploadTime = ::GetTickCount();
}

void CUpDownClient::SetWaitStartTime(uint32 dwTime){
	if (dwTime)
		m_dwWaitTime = dwTime;
	else
		m_dwWaitTime = ::GetTickCount();
}

uint32 CUpDownClient::SendBlockData(uint32 nMaxAmmount){
	m_AvarageUDR_list.AddTail(dataratems);
	if (m_AvarageUDR_list.GetCount() > 500)
		m_AvarageUDR_list.RemoveAt(m_AvarageUDR_list.GetHeadPosition());
	m_nUpDatarate = 0;
	for (POSITION pos = m_AvarageUDR_list.GetHeadPosition();pos != 0;m_AvarageUDR_list.GetNext(pos))
		m_nUpDatarate += m_AvarageUDR_list.GetAt(pos);

	if(m_AvarageUDR_list.GetCount() > 10)
		m_nUpDatarate /= (m_AvarageUDR_list.GetCount()/10);
	else
		m_nUpDatarate = 0;

	m_cSendblock++;
	if (m_cSendblock == 30){
		m_cSendblock = 0;
		theApp.emuledlg->transferwnd.uploadlistctrl.RefreshClient(this);
	}
	dataratems = 0;
	if (socket && !socket->IsBusy()){
		
		if (m_BlockSend_queue.IsEmpty()){
			if (!CreateNextBlockPackage())
				return 0;
		}
		m_nMaxSendAllowed += nMaxAmmount;
		if (m_BlockSend_queue.GetHead()->GetRealPacketSize() > 0/*m_nMaxSendAllowed*3*/
			&& m_BlockSend_queue.GetHead()->GetRealPacketSize() > MAXFRAGSIZE*2){
			// splitting packets
				uint32 nSize = m_BlockSend_queue.GetHead()->GetRealPacketSize();
				char* pBuffer = m_BlockSend_queue.GetHead()->DetachPacket();
				delete m_BlockSend_queue.RemoveHead();
				
				uint32 nPos = nSize;
				bool bLast = true;
				while (nPos){
					uint32 nNewSize = (nPos < MAXFRAGSIZE) ? nPos : MAXFRAGSIZE;
					nPos -= nNewSize;
					char* pBuffer2 = new char[nNewSize];
					memcpy(pBuffer2,pBuffer+nPos,nNewSize);
					m_BlockSend_queue.AddHead(new Packet(pBuffer2,nNewSize,bLast));
					bLast = false;
				}
				delete[] pBuffer;
		}
		while (!m_BlockSend_queue.IsEmpty()
			&& m_BlockSend_queue.GetHead()->GetRealPacketSize() <= m_nMaxSendAllowed){
			
			Packet* tosend = m_BlockSend_queue.RemoveHead();
			uint32 nBlockSize = tosend->GetRealPacketSize();
			m_nMaxSendAllowed -= nBlockSize;
			theApp.uploadqueue->AddUpDataRateMSOverhead(24, 160);
			socket->SendPacket(tosend,true,false);
			socket->ResetTimeOutTimer(); // Added by Tarod (helps fix autocycling)
			// VQB Transfer Session Value (Added by Rectencle)
			m_nSessionUp += nBlockSize;
			// VQB End (Added by Rectencle)
			m_nTransferedUp += nBlockSize;
			theApp.UpdateSentBytes(nBlockSize);
			credits->AddUploaded(nBlockSize);
			if (m_BlockSend_queue.IsEmpty())
				CreateNextBlockPackage();
		}
		dataratems = nMaxAmmount;
		return nMaxAmmount;
	}
	return 0;
}

void CUpDownClient::FlushSendBlocks(){ // call this when you stop upload, or the socket might be not able to send
	bool bBreak = false;
	while (!m_BlockSend_queue.IsEmpty() && m_BlockSend_queue.GetHead()->IsSplitted() && socket && socket->IsConnected() && !bBreak ){	
		Packet* tosend = m_BlockSend_queue.RemoveHead();
		bool bBreak = tosend->IsLastSplitted();
		socket->SendPacket(tosend,true,false);
	}
}

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

	CMemFile* data = new CMemFile();
	data->Write(file->GetFileHash(),16);
	uint16 parts = file->GetHashCount();
	data->Write(&parts,2);
	for (int i = 0; i != parts; i++)
		data->Write(file->GetPartHash(i),16);
	Packet* packet = new Packet(data);
	packet->opcode = OP_HASHSETANSWER;
	delete data;
	theApp.uploadqueue->AddUpDataRateMSOverhead(packet->size, 160);
	socket->SendPacket(packet,true,true);
}

void CUpDownClient::ClearUploadBlockRequests(){
	FlushSendBlocks();
	for (POSITION pos = m_BlockRequests_queue.GetHeadPosition();pos != 0;m_BlockRequests_queue.GetNext(pos))
		delete m_BlockRequests_queue.GetAt(pos);
	m_BlockRequests_queue.RemoveAll();
	
	for (POSITION pos = m_DoneBlocks_list.GetHeadPosition();pos != 0;m_DoneBlocks_list.GetNext(pos))
		delete m_DoneBlocks_list.GetAt(pos);
	m_DoneBlocks_list.RemoveAll();
	
	for (POSITION pos = m_BlockSend_queue.GetHeadPosition();pos != 0;m_BlockSend_queue.GetNext(pos))
		delete m_BlockSend_queue.GetAt(pos);
	m_BlockSend_queue.RemoveAll();
}

void CUpDownClient::SendRankingInfo(){
	if (!ExtProtocolAvailable())
		return;
	uint16 nRank = theApp.uploadqueue->GetWaitingPosition(this);
	if (!nRank)
		return;
	Packet* packet = new Packet(OP_QUEUERANKING,12,OP_EMULEPROT);
	memset(packet->pBuffer,0,12);
	memcpy(packet->pBuffer+0,&nRank,2);
	theApp.uploadqueue->AddUpDataRateMSOverhead(packet->size, 160);
	socket->SendPacket(packet,true,true);
}

void CUpDownClient::SendCommentInfo(CKnownFile *file) {
	if (!m_bCommentDirty || file == NULL || !ExtProtocolAvailable() || m_byAcceptCommentVer < 1)
		return;
	m_bCommentDirty = false;

	int8 rating=file->GetFileRate();
	CString desc=file->GetFileComment();
	if(file->GetFileRate() == 0 && desc.IsEmpty())
		return;

	CMemFile *data = new CMemFile();
	data->Write(&rating,sizeof(rating));
	int length=desc.GetLength();
	if (length>128) length=128;
	data->Write(&length,sizeof(length));
	if (length>0) data->Write(desc.GetBuffer(),length);
	Packet *packet = new Packet(data,OP_EMULEPROT);
	packet->opcode = OP_FILEDESC;
	delete data;
	theApp.uploadqueue->AddUpDataRateMSOverhead(packet->size, 160);
	socket->SendPacket(packet,true);
}

void  CUpDownClient::AddRequestCount(uchar* fileid){
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos)){
		Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetAt(pos);
		if (!memcmp(cur_struct->fileid,fileid,16)){
			if (::GetTickCount() - cur_struct->lastasked < MIN_REQUESTTIME){
				if (GetDownloadState() != DS_DOWNLOADING)
					cur_struct->badrequests++;
				if (cur_struct->badrequests == BADCLIENTBAN){
					Ban();
				}
			}
			else{
				if (cur_struct->badrequests)
					cur_struct->badrequests--;
			}
			cur_struct->lastasked = ::GetTickCount();
			return;
		}
	}
	Requested_File_Struct* new_struct = new Requested_File_Struct;
	memset(new_struct,0,sizeof(Requested_File_Struct));
	memcpy(new_struct->fileid,fileid,16);
	new_struct->lastasked = ::GetTickCount();
	m_RequestedFiles_list.AddHead(new_struct);
}

void  CUpDownClient::UnBan(){
	m_bBanned = false;
	m_dwBanTime = 0;
	SetWaitStartTime();
	theApp.uploadqueue->UpdateBanCount();
	theApp.emuledlg->transferwnd.ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos)){
		Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetAt(pos);
		cur_struct->badrequests = 0;
		cur_struct->lastasked = 0;	
	}
	theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this, true, true);
}

void CUpDownClient::Ban(){
	SendMsgBeingBanned();
	m_bBanned = true;
	theApp.uploadqueue->UpdateBanCount();
	theApp.emuledlg->transferwnd.ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
	m_dwBanTime = ::GetTickCount();
	theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this);
	theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_CLIENTBLOCKED),GetUserName());
}

void CUpDownClient::UDPFileReasked(){
	AddAskedCount();
	SetLastUpRequest();
	uint16 nRank = theApp.uploadqueue->GetWaitingPosition(this);
	Packet* response = new Packet(OP_REASKACK,2,OP_EMULEPROT);
	memcpy(response->pBuffer,&nRank,2);
	theApp.clientudp->SendPacket(response,GetIP(),GetUDPPort());
}

//Rectencle
void CUpDownClient::SendMsgBeingBanned(){
	if (socket && GetUploadState()){
		char* message = "Your client is connecting too fast. It has been banned for 5 hours";
		uint16 mlen = (uint16)strlen(message);
		Packet* packet = new Packet(OP_MESSAGE,mlen+2);
		memcpy(packet->pBuffer,&mlen,2);
		memcpy(packet->pBuffer+2,message,mlen);
		socket->SendPacket(packet,true,true);
		theApp.emuledlg->AddLogLine(false,CString("Message to ")+CString(GetUserName())+CString(": ")+CString(message),GetUserName());
	}
}
// End Rectencle