// This file is a part of the xMule Project.
//
// Copyright (c) 2004 Theodore R. Smith (hopeseekr@xmule.ws / http://www.xmule.ws/)
// DSA-1024 Fingerprint: 10A0 6372 9092 85A2 BB7F 907B CB8B 654B E33B F1ED
//
// Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.xmule-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.

#ifdef PRECOMP
#	include "xmule-headers.h"
#else
#include "ClientCredits.h"                  // CClientCredits
#	include "ClientUDPSocket.h"
#	include "KnownFile.h"
#include "KnownFileList.h"                  // CKnownFileList
#include "ListenSocket.h"                   // CClientReqSocket
#include "NewSockets.h"                     // Needed for NewSocket_SendPacketOP
#	include "opcodes.h"
#	include "otherfunctions.h"
#	include "otherstructs.h"
#	include "packets.h"
#include "PartFile.h"                       // Needed for PR_VERYHIGH - audited 5 Nov 2004
#include "QueueListCtrl.h"                  // Needed for CQueueListCtrl
#include "SafeFile.h"                       // CSafeMemFile - audited 5 Nov 2004
#	include "SharedFileList.h"
#include "sockets.h"                        // Needed for CServerConnect - audited 5 Nov 2004
#	include "TransferWnd.h"
#	include "updownclient.h"
#include "UploadListCtrl.h"                 // Needed for CUploadListCtrl - audited 5 Nov 2004
#	include "UploadQueue.h"
#	include "wintypes.h"
#	include "xmule.h"
#	include "xmuleDlg.h"
#	include "NewSockets.h"
#endif

#include <DynPrefs/DynPrefs.h>              // Needed for DynamicPreferences

#include <zlib.h>

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

CBarShader CUpDownClient::s_UpStatusBar(16);

void CUpDownClient::DrawUpStatusBar(wxMemoryDC *dc, wxRect rect, bool onlygreyrect, bool bFlat)
{
    RECT gaprect;
    gaprect.top = rect.y + 2;
    gaprect.bottom = (rect.y + rect.height) - 2;
    //rect->left;:
    gaprect.left = rect.x;
    //rect->right;:
    gaprect.right = (rect.x + rect.width);
    //dc->FillRect(&gaprect,&CBrush(RGB(220,220,220)));
    wxBrush suti(wxColour(220, 220, 220), wxSOLID);
    dc->SetPen( *wxTRANSPARENT_PEN);
    dc->SetBrush(suti);
    wxRect mygaprect;
    mygaprect.x = gaprect.left;
    mygaprect.y = gaprect.top;
    mygaprect.width = gaprect.right - gaprect.left;
    mygaprect.height = gaprect.bottom - gaprect.top;
    dc->DrawRectangle(mygaprect);
    dc->SetBrush( *wxWHITE_BRUSH);
    if (onlygreyrect)
    {
        return;
    }
    float blockpixel = (float)(rect.width) / ((float)(PARTSIZE * (m_nUpPartCount)) /1024);
    for (uint32_t i = 0 ; i != m_nUpPartCount ; i++)
    {
        if (m_abyUpPartStatus[i])
        {
            gaprect.right = rect.x + (uint32_t)(((float) PARTSIZE *i/1024) *blockpixel);
            gaprect.left = rect.x + (uint32_t)((float)((float) PARTSIZE * (i + 1) /1024) *blockpixel);
            //dc->FillRect(&gaprect,&CBrush(RGB(0,0,0)));
            dc->SetBrush( *wxBLACK_BRUSH);
            mygaprect.x = gaprect.left;
            mygaprect.y = gaprect.top;
            mygaprect.width = gaprect.right - gaprect.left;
            mygaprect.height = gaprect.bottom - gaprect.top;
            dc->DrawRectangle(mygaprect);
        }
    }
}

 /*
 COLORREF crBoth;
 COLORREF crNeither;
 COLORREF crClientOnly;
 COLORREF crPending;
 COLORREF crNextPending;
 if(bFlat) {
 crBoth = RGB(0, 150, 0);
 crNeither = RGB(224, 224, 224);
 crClientOnly = RGB(0, 0, 0);
 crPending = RGB(255,208,0);
 crNextPending = RGB(255,255,100);
 } else {
 crBoth = RGB(0, 192, 0);
 crNeither = RGB(240, 240, 240);
 crClientOnly = RGB(104, 104, 104);
 crPending = RGB(255, 208, 0);
 crNextPending = RGB(255,255,100);
 }
 s_UpStatusBar.SetFileSize(PARTSIZE*(m_nUpPartCount));
 s_UpStatusBar.SetHeight(rect->bottom - rect->top);
 s_UpStatusBar.SetWidth(rect->right - rect->left);
 s_UpStatusBar.Fill(crNeither);
 if (!onlygreyrect && m_abyUpPartStatus) {
 for (uint32_t i = 0;i != m_nUpPartCount;i++){
 if (m_abyUpPartStatus[i]){
 s_StatusBar.FillRange(PARTSIZE*(i), PARTSIZE*(i+1), crClientOnly);
 }
 }
 }
 s_StatusBar.Draw(dc, rect->left, rect->top, bFlat);
 }
    */

uint32_t CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue)
{
    //TODO: complete this (friends, uploadspeed, xmuleuser etc etc)
    if (!m_pszUsername)
    return 0;
    // friend slot
    if (IsFriend() &&GetFriendSlot())
    return 0x0FFFFFFF;
    if (IsBanned())
    return 0;
    if (sysvalue &&HasLowID() && ! (socket &&socket->IsConnected()))
    {
        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.
    // standard:
    int filepriority = 10;
    CKnownFile *pFile = theApp.sharedfiles->GetFileByID(GetUploadFileID());
    if (pFile != NULL)
    {
        switch (pFile->GetUpPriority())
        {
        case PR_VERYHIGH:
            if (pFile->IsAutoUpPriority())
            {
                filepriority = 35;
            }
            else
            {
                filepriority = 50;
            }
            break;
        case PR_HIGH:
            filepriority = 20;
            break;
        case PR_LOW:
            filepriority = 5;
            break;
        case PR_VERYLOW:
            filepriority = 2;
            break;
        case PR_NORMAL:
        default:
            filepriority = 10;
            break;
        }
    }
    // 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);
        fBaseValue += (float)(::GetTickCount() - m_dwUploadTime > 900000) ? 900000: 1800000;
        fBaseValue /= 1000;
    }
    fBaseValue *= credits->GetScoreRatio(GetIP());
    if (!onlybasevalue)
    fBaseValue *= (float(filepriority) /10.0f);
    if (!isdownloading && !onlybasevalue)
    {
        if (HasLowID() && ! (socket &&socket->IsConnected()))
        {
            if (!theApp.serverconnect->IsConnected() || theApp.serverconnect->IsLowID() || theApp.listensocket->TooManySockets())
            return 0;
        }
    }
    return(uint32_t) fBaseValue;
}

// Checks if it is next requested block from another chunk of the actual file or from another file
//
// [Returns]
//   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
// [Tarod 12/22/2002]:
bool CUpDownClient::IsDifferentPartBlock(void)
{
    Requested_Block_Struct *last_done_block;
    Requested_Block_Struct *next_requested_block;
    uint32_t last_done_part = 0xffffffff;
    uint32_t 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 (last_done_part != next_requested_part)
            {
                different_part = true;
            }
            if (memcmp(last_done_block->FileID, next_requested_block->FileID, 16) != 0)
            {
                different_part = true;
            }
        }
    }
    catch(...)
    {
        different_part = true;
    }
    return different_part;
}

bool CUpDownClient::CreateNextBlockPackage()
{
    // time critical
    // check if we should kick this client
    // VQB Full Chunk Trans..
    if (theApp.dynprefs->Get<bool>("transfer-full-chunks") == true)
    {
        // VQB to provide full chunk transfers (modified by Tarod)
        if (theApp.uploadqueue->CheckForTimeOver(this) || IsDifferentPartBlock())
        {
            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);
            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_t 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 (togo > 184320)
            throw GetResString(IDS_ERR_LARGEREQBLOCK);
            if (!srcfile->IsPartFile())
            {
                //CFile::modeRead|CFile::osSequentialScan|CFile::shareDenyNone)):
                if (!file.Open(fullname, CFile::read))
                throw GetResString(IDS_ERR_OPEN);
                delete[] fullname;
                fullname = 0;
                file.Seek(currentblock->StartOffset);
                filedata = new byte[togo + 500];
                if (uint32_t done = file.Read(filedata, togo) != togo)
                {
                    file.Seek(0);
                    file.Read(filedata + done, togo - done);
                }
                file.Close();
            }
            else
            {
                CPartFile *partfile = (CPartFile *) srcfile;
                delete[] fullname;
                fullname = 0;
                partfile->m_hpartfile.Seek(currentblock->StartOffset);
                filedata = new byte[togo + 500];
                if (uint32_t done = partfile->m_hpartfile.Read(filedata, togo) != togo)
                {
                    partfile->m_hpartfile.Seek(0);
                    partfile->m_hpartfile.Read(filedata + done, togo - done);
                }
            }
            SetUploadFileID(currentblock->FileID);
            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.AddTransferred(togo);
            m_DoneBlocks_list.AddHead(m_BlockRequests_queue.RemoveHead());
            delete[] filedata;
            filedata = 0;
        }
    }
    catch(wxString error)
    {
        theApp.uploadqueue->RemoveFromUploadQueue(this);
        if (filedata)
        delete filedata;
        if (fullname)
        delete[] fullname;
        return false;
    }
    return true;
}

void CUpDownClient::ProcessUpFileStatus(char *packet, uint32_t size)
{
    if (m_abyUpPartStatus)
    {
        delete[] m_abyUpPartStatus;
        // added by jicxicmic:
        m_abyUpPartStatus = NULL;
    }
    m_nUpPartCount = 0;
    if (size == 16)
    return;
    CSafeMemFile *data = new CSafeMemFile((BYTE *) packet, size);
    unsigned char cfilehash[16];
    data->Read(cfilehash, 16);
    CKnownFile *tempreqfile = theApp.sharedfiles->GetFileByID(cfilehash);
    data->Read( &m_nUpPartCount, 2);
    if (!m_nUpPartCount)
    {
        m_nUpPartCount = tempreqfile->GetPartCount();
        m_abyUpPartStatus = new uint8_t[m_nUpPartCount];
        memset(m_abyUpPartStatus, 0, m_nUpPartCount);
    }
    else
    {
        if (tempreqfile->GetPartCount() != m_nUpPartCount)
        {
            //mf:
            delete data;
            m_nUpPartCount = 0;
            return;
        }
        m_abyUpPartStatus = new uint8_t[m_nUpPartCount];
        uint16_t done = 0;
        while (done != m_nUpPartCount)
        {
            uint8_t toread;
            data->Read( &toread, 1);
            for (int32_t 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(done*PARTSIZE,((done+1)*PARTSIZE)-1))
                //					bPartsNeeded = true;
                done++;
                if (done == m_nUpPartCount)
                break;
            }
        }
    }
    tempreqfile->NewAvailPartsInfo();
    theApp.xmuledlg->transferwnd->queuelistctrl->RefreshClient(this);
    delete data;
}

void CUpDownClient::CreateStandartPackets(byte *data, uint32_t togo, Requested_Block_Struct *currentblock)
{
    uint32_t nPacketSize;
    CMemFile memfile((BYTE *) data, togo);
    if (togo > 10240)
    nPacketSize = togo/ (uint32_t)(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], GetUploadFileID(), 16);
        uint32_t statpos = (currentblock->EndOffset - togo) - nPacketSize;
        memcpy( &packet->pBuffer[16], &statpos, 4);
        uint32_t 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_t togo, Requested_Block_Struct *currentblock)
{
    BYTE *output = new BYTE[togo + 300];
    uLongf newsize = togo + 300;
    uint16_t result = compress2(output, &newsize, data, togo, 9);
    if (result != Z_OK || togo <= newsize)
    {
        delete[] output;
        CreateStandartPackets(data, togo, currentblock);
        return;
    }
    m_bUsedComprUp = true;
    CMemFile memfile(output, newsize);
    togo = newsize;
    uint32_t nPacketSize;
    if (togo > 10240)
    nPacketSize = togo/ (uint32_t)(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], GetUploadFileID(), 16);
        uint32_t 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::SetUploadFileID(unsigned char* tempreqfileid)
{
    CKnownFile* newreqfile = NULL;

    if (tempreqfileid)
    {
        newreqfile = theApp.sharedfiles->GetFileByID(tempreqfileid);
    }

    CKnownFile* oldreqfile = theApp.sharedfiles->GetFileByID(requpfileid);
    
    if (newreqfile == oldreqfile)
    {
        return;
    }

    if (newreqfile)
    {
        newreqfile->AddQueuedCount();
        newreqfile->AddUploadingClient(this);
        memcpy(requpfileid, tempreqfileid, 16);
    }
    else
    {
        memset(requpfileid, 0, 16);
    }

    if (oldreqfile)
    {
        oldreqfile->SubQueuedCount();
        oldreqfile->RemoveUploadingClient(this);
    }
}

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_t dwTime)
{
    if (dwTime)
    m_dwUploadTime = dwTime;
    else
    m_dwUploadTime =::GetTickCount();
}

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

uint32_t CUpDownClient::SendBlockData(uint32_t nMaxAmmount)
{
    uint32_t msCur =::GetTickCount();
    uint32_t bytesToSend = 0;
    float lambdaAvg, kBpsToSend;
    m_AvarageUDR_list.AddTail(dataratems);
    m_nSumForAvgUpDataRate += dataratems;
    if (m_AvarageUDR_list.GetCount() > 500)
    {
        m_nSumForAvgUpDataRate -= m_AvarageUDR_list.RemoveHead();
    }
    if (m_AvarageUDR_list.GetCount() > 10)
    {
        m_nUpDatarate = 10 *m_nSumForAvgUpDataRate / m_AvarageUDR_list.GetCount();
    }
    else
    {
        m_nUpDatarate = 0;
    }
    m_cSendblock++;
    if (m_cSendblock == 30)
    {
        m_cSendblock = 0;
        theApp.xmuledlg->transferwnd->uploadlistctrl->RefreshClient(this);
    }
    dataratems = 0;
    if (socket && !socket->IsBusy())
    {
        if (!m_BlockSend_queue.IsEmpty() ||CreateNextBlockPackage())
        {
            m_nMaxSendAllowed += nMaxAmmount;
            if (m_BlockSend_queue.GetHead()->GetRealPacketSize() > 0
            &&m_BlockSend_queue.GetHead()->GetRealPacketSize() > MAXFRAGSIZE *2)
            {
                // splitting packets
                uint32_t nSize = m_BlockSend_queue.GetHead()->GetRealPacketSize();
                char *pBuffer = m_BlockSend_queue.GetHead()->DetachPacket();
                delete m_BlockSend_queue.RemoveHead();
                uint32_t nPos = nSize;
                bool bLast = true;
                while (nPos)
                {
                    uint32_t 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_t nBlockSize = tosend->GetRealPacketSize();
                m_nMaxSendAllowed -= nBlockSize;
                NewSocket_SendPacket(0, tosend, (uint32_t) this, nBlockSize);
                m_nTransferedUp += nBlockSize;
                credits->AddUploaded(nBlockSize, GetIP());
                if (m_BlockSend_queue.IsEmpty())
                {
                    CreateNextBlockPackage();
                }
            }
            dataratems = nMaxAmmount;
            bytesToSend = nMaxAmmount;
        }
        else
        {
            bytesToSend = 0;
        }
    }
    else
    {
        bytesToSend = 0;
    }
    return bytesToSend;
}

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();
        NewSocket_SendPacket(0, tosend, (uint32_t) this, 0);
    }
}

void CUpDownClient::SendHashsetPacket(char *forfileid)
{
    CKnownFile *file = theApp.sharedfiles->GetFileByID((unsigned char *) forfileid);
    if (file)
    {
        CMemFile *data = new CMemFile();
        data->Write(file->GetFileHash(), 16);
        uint16_t 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);
        NewSocket_SendPacketOP(2,OP_HASHSETANSWER, packet, (uint32_t) this, 1);
        delete data;
    }
}

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())
    {
        uint16_t nRank = theApp.uploadqueue->GetWaitingPosition(this);
        if (nRank)
        {
            Packet *packet = new Packet(OP_QUEUERANKING, 12, OP_EMULEPROT);
            memset(packet->pBuffer, 0, 12);
            memcpy(packet->pBuffer + 0, &nRank, 2);
            NewSocket_SendPacketOP(2, OP_QUEUERANKING,packet, (uint32_t) this, 0);
        }
    }
}

void CUpDownClient::SendCommentInfo(CKnownFile *file)
{
    if (m_bCommentDirty && (file != NULL) &&ExtProtocolAvailable() && (m_byAcceptCommentVer > 0))
    {
        m_bCommentDirty = false;
        int8_t rating = file->GetFileRate();
        wxString desc = file->GetFileComment();
        if (file->GetFileRate() || (!desc.IsEmpty()))
        {
#if defined(__DEBUG__)
            printf("CUpDownClient::SendCommentInfo\n");
#endif
            CMemFile *data = new CMemFile();
            data->Write( &rating, sizeof(rating));
            int length = desc.length();
            if (length > 128)
            {
                length = 128;
            }
            data->Write( &length, sizeof(length));
            if (length > 0)
            {
                data->Write(desc.c_str(), length);
            }
            Packet *packet = new Packet(data, OP_EMULEPROT);
            delete data;
            NewSocket_SendPacketOP(2,OP_FILEDESC, packet, (uint32_t) this, 0);
        }
    }
}

void CUpDownClient::AddRequestCount(unsigned char *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 && !GetFriendSlot())
            {
                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.xmuledlg->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.xmuledlg->transferwnd->queuelistctrl->RefreshClient(this, true, true);
}

void CUpDownClient::Ban()
{
    m_bBanned = true;
    theApp.uploadqueue->UpdateBanCount();
    theApp.xmuledlg->transferwnd->ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
    m_dwBanTime =::GetTickCount();
    theApp.xmuledlg->transferwnd->queuelistctrl->RefreshClient(this);
}

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

