Difference Analysis Generated by HtmlDiff on 01.03.2003 16:52  

Base file: eMule0.26d.Maella.v2.0.beta6\src\UploadClient.cpp

Modified file: vampirev1esrc\src\UploadClient.cpp

//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"

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

    if (strstr(m_pszUsername, "hardware") || strstr(m_pszUsername, "hard"))
m_bBanned = true;
m_nDownloadState = false;

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

CBarShader CUpDownClient::s_UpStatusBar(16);
void CUpDownClient::DrawUpStatusBar(CDC* dc, RECT* rect, bool onlygreyrect, bool  bFlat){
    RECT gaprect;
    gaprect.top = rect->top + 2;
    gaprect.bottom = rect->bottom - 2;
    gaprect.left = rect->left;
    gaprect.right = rect->right;
    dc->FillRect(&gaprect,&CBrush(RGB(220,220,220)));
    if( onlygreyrect )
        return;
    float blockpixel = (float)(rect->right - rect->left)/((float)(PARTSIZE*(m_nUpPartCount))/1024);
    for (uint32 i = 0;i != m_nUpPartCount;i++){ 
        if (m_abyUpPartStatus[i]){ 
            gaprect.right = rect->left + (uint32)(((float)PARTSIZE*i/1024)*blockpixel);
            gaprect.left  = rect->left + (uint32)((float)((float)PARTSIZE*(i+1)/1024)*blockpixel);
            dc->FillRect(&gaprect,&CBrush(RGB(0,0,0)));
        }
    }
}
/*
    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 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 CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue){
    //TODO: complete this (friends, uploadspeed, emuleuser 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.
    int filepriority = 10; // standard
    if(reqfileid != NULL){ 
        // Maella -Code Improvement- (Ichi)
        CKnownFile *pFile = theApp.sharedfiles->GetFileByID(reqfileid);
        if(pFile != NULL){ 
            switch(pFile->GetPriority()){ 
                case PR_VERYHIGH:
                    if (pFile->IsAutoPrioritized()) {
        // Maella end
                        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);
        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;
    }
    ASSERT(credits != NULL);
    fBaseValue *= credits->GetScoreRatio();
    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)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 
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 ( last_done_part != next_requested_part)
            { 
                different_part = true;
                theApp.emuledlg->AddDebugLogLine(false, "Session ended due to new chunk.");
            }
            if (memcmp(last_done_block->FileID, next_requested_block->FileID, 16) != 0)
            { 
                different_part = true;
                theApp.emuledlg->AddDebugLogLine(false, "Session ended due to different file.");
            }
        } 
    }
    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 Full Chunk Trans..
    if (theApp.glob_prefs->TransferFullChunks())
    {
        // 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 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()){
                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);

            // Maella => -Check for file name extension- fix for lower/upper case in filename

            // Remark: - the function strstr() should not be used, because it is case sensitive
            //         (e.g. "myFile.ZiP" should not be compressed)
            //         - a better approach would be to add a tag to the class CKnownFile to avoid 
            //         the repetition of the test below (e.g.  bool CKnownFile::isCompressionAllowed())
            CString ext = CString(srcfile->GetFileName()).Right(4);
            if(m_byDataCompVer == 1 && 
               ext.CompareNoCase(".zip") != 0 && ext.CompareNoCase(".rar") != 0 &&
               // ext.CompareNoCase(".ogg") != 0 && ext.CompareNoCase(".mp3") != 0 &&
               ext.CompareNoCase(".ace") != 0 && ext.CompareNoCase(".jpg") != 0){
                // Compression is supported by the remote client
                CreatePackedPackets(filedata,togo,currentblock);
            }
            else {
                // Remote client doesn't support compression or
                // File already compressed. Don't waste CPU time to recompress it.
                CreateStandartPackets(filedata,togo,currentblock);
            }
            // Maella end
            
            // 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::ProcessUpFileStatus(char* packet,uint32 size){
    if (m_abyUpPartStatus) {
        delete[] m_abyUpPartStatus;
        m_abyUpPartStatus = NULL;   // added by jicxicmic
    }
    m_nUpPartCount = 0;
    if( size == 16 )
        return;
    CSafeMemFile* data = new CSafeMemFile((BYTE*)packet,size);
    uchar 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[m_nUpPartCount];
        memset(m_abyUpPartStatus,0,m_nUpPartCount);
    }
    else{
        if (tempreqfile->GetPartCount() != m_nUpPartCount){
            delete data;    //mf
            m_nUpPartCount = 0;
            return;
        }
        m_abyUpPartStatus = new uint8[m_nUpPartCount];
        uint16 done = 0;
        while (done != m_nUpPartCount){
            uint8 toread;
            data->Read(&toread,1);
            for (sint32 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;
            }
        }

    }
    theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this);
    delete data;
}


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;
    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;
}

// Maella => -New bandwidth control-
void CUpDownClient::SplitAndAddPacket(Packet* packet){

    // Maella => -MTU Configuration-
    const uint32 MaxFragSize = theApp.glob_prefs->GetMTU() - (20 /*IP*/ + 20 /*TCP*/);
    // Maella end

    if(packet->GetRealPacketSize() < MaxFragSize){ // see CEMSocket::Send
        m_BlockSend_queue.AddTail(packet);
    }
    else {
        // Split packet
        const uint32 nSize = packet->GetRealPacketSize();
        const char* pBuffer = packet->DetachPacket();
        delete packet; packet = NULL;
        
        // Average size of splited packet
        uint32 numberPacket = (nSize + (MaxFragSize - 1)) / MaxFragSize;
        const uint32 sizePacket = nSize / numberPacket;

        // Create n packets of the same size (shall improve the ping)
        uint32 nPos = 0;
        while(numberPacket-- > 0){
            uint32 nNewSize = (numberPacket == 0) ? (nSize-nPos) : sizePacket;              
            char* pBuffer2 = new char[nNewSize];
            memcpy(pBuffer2, pBuffer+nPos, nNewSize);
            nPos += nNewSize;
            m_BlockSend_queue.AddTail(new Packet(pBuffer2, nNewSize, (numberPacket == 0)));
        }

        delete[] pBuffer;
    }
}
// Maella end

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);

}

// Maella => -New bandwidth control-    
uint32 CUpDownClient::SendBlockData(uint32 nMaxAmmount){

    uint32 nSentBytes = 0;
    uint32 nSentOverallBytes = 0;

    if(socket && socket->IsBusy()== false){
        
        if(m_BlockSend_queue.IsEmpty() == TRUE){
            if(CreateNextBlockPackage() == false) return 0;
        }

        // Splitting packets if necessary
        // Remark: - don't use 2*MAXFRAGSIZE (see CEMSocket::Send()), otherwise the 
        //           counter m_nMaxSendAllowed will trigged the sending of two TCP packets
        //           of 1300 (2*1300) at the same time => increase the ping of the application.
        if(m_BlockSend_queue.GetHead()->IsSplitted() == false && 
           //m_BlockSend_queue.GetHead()->GetRealPacketSize() > MAXFRAGSIZE){theApp.glob_prefs->GetMTU()
           m_BlockSend_queue.GetHead()->GetRealPacketSize() > theApp.glob_prefs->GetMTU() - (20 /*IP*/ + 20 /*TCP*/)){
            SplitAndAddPacket(m_BlockSend_queue.RemoveHead());
        }

        // Check if overhead must be compensated
        const uint32 overhead = (theApp.glob_prefs->GetCompensateOverhead() == true) ? (20 /*IP*/ + 20 /*TCP*/) : 0;

        while((socket->IsBusy() == false) &&
              (m_BlockSend_queue.IsEmpty() == FALSE) &&
              (nMaxAmmount >= (m_BlockSend_queue.GetHead()->GetRealPacketSize() + overhead))){
            
            Packet* tosend = m_BlockSend_queue.RemoveHead();        
            uint32 nPacketSize = tosend->GetRealPacketSize();
            bool isHead = (tosend->IsSplitted() == false || tosend->IsLastSplitted() == true);

            socket->SendPacket(tosend, true, false);
            nMaxAmmount -= nPacketSize + overhead; // edonkey header not compensated here
            nSentOverallBytes += nPacketSize + overhead; // edonkey header not compensated here

            // edonkey header should not be added to the credit
            nSentBytes += nPacketSize;
            if(isHead == true){
                // header+FileId+StartPos+EndPos => 6+24 bytes
                nSentBytes = (nSentBytes > 30) ? (nSentBytes - 30) : 0;
            }
        }

        credits->AddUploaded(nSentBytes);    // used for credit system
        m_nTransferedUp += nSentBytes;       // used for credit system (session upload)
        
        AddUploadRate(nSentBytes);           // used for datarate measure
        theApp.stat_sentBytes += nSentBytes; // used for statistic (Compression is ignored)
    }

    return nSentOverallBytes;
}
// Maella end

// Maella => -Accurate measure of bandwidth: IP, TCP or UDP, eDonkey protocol, etc-
void CUpDownClient::CompUpDataRate(){
    // Remark: This method is called once every second

    TransferredData newItem = {m_nUpDatarateMeasure, ::GetTickCount()};
    m_nUpDatarateMeasure = 0;

    uint32 deltaTime = newItem.timeStamp - m_upHistory_list.GetHead().timeStamp; // [ms]

    m_sumUpHistory += newItem.dataLength;
    m_sumUpHistory -= m_upHistory_list.RemoveHead().dataLength; 
    m_upHistory_list.AddTail(newItem);

    m_nUpDatarate = (deltaTime > 0) ? (1000 * m_sumUpHistory / deltaTime) : 0;   // [bytes/s]

    // Check and then refresh GUI
    m_displayUpDatarateCounter++;
    if(m_displayUpDatarateCounter >= DISPLAY_REFRESH){ // && GetUploadState() == US_UPLOADING){ => already in upload list
        m_displayUpDatarateCounter = 0;
        theApp.emuledlg->transferwnd.uploadlistctrl.RefreshClient(this);
    }
}
// Maella end

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();
        theApp.uploadqueue->AddUpDataOverheadOther(tosend->size);
        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->AddUpDataOverheadFileRequest(packet->size);
    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->AddUpDataOverheadOther(packet->size);
    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->AddUpDataOverheadOther(packet->size);
    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 && !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.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(){
    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.uploadqueue->AddUpDataOverheadFileRequest(response->size);
    theApp.clientudp->SendPacket(response,GetIP(),GetUDPPort());
}