// 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
//
// parts of this file are based on work from pan One (http://home-3.tiscali.nl/~meost/pms/)
//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"
#endif

//#include "CFile.h"                          // CFile

/*#include "wintypes.h"
#include "otherstructs.h"
#include "types.h"
#include "wx/dynarray.h"
#include "BarShader.h"
#include "MD5Sum.h"
*/

#include "CMemFile.h"                       // CMemFile - audited 5 Nov 2004
#include "ini2.h"
#include "KnownFile.h"
#include "KnownFileList.h"
#include "opcodes.h"
#include "otherfunctions.h"
#include "packets.h"                        // Packet
#include "PartFile.h"                       // PR_HIGH
#include "SharedFileList.h"
#include "SharedFilesWnd.h"
#include "updownclient.h"
#include "UploadQueue.h"
#include "xmule.h"
#include "xmuleDlg.h"

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

#include <sys/types.h>
#include <sys/stat.h>

//extern MAP * listof_sourcesKF;

// constants for MD4Transform
#define S11 3
#define S12 7
#define S13 11
#define S14 19
#define S21 3
#define S22 5
#define S23 9
#define S24 13
#define S31 3
#define S32 9
#define S33 11
#define S34 15

static void MD4Transform(uint32_t Hash[4], uint32_t x[16]);

void CFileStatistic::AddRequest()
{
    requested++;
    alltimerequested++;
    theApp.knownfiles->requested++;
    theApp.sharedfiles->UpdateItem(fileParent);
}

void CFileStatistic::AddAccepted()
{
    accepted++;
    alltimeaccepted++;
    theApp.knownfiles->accepted++;
    theApp.sharedfiles->UpdateItem(fileParent);
}

void CFileStatistic::AddTransferred(uint64_t bytes)
{
    transfered += bytes;
    alltimetransfered += bytes;
    theApp.knownfiles->transfered += bytes;
    theApp.sharedfiles->UpdateItem(fileParent);
}

CKnownFile::CKnownFile()
{
    m_iFileType = 2;
    directory = NULL;
    m_pszFileName = 0;
    m_nFileSize = 0;
    date = 0;
    m_iPermissions = PERM_ALL;
    statistic.fileParent = this;
    if (theApp.dynprefs->Get<bool>("auto-priority-share") == true)
    {
        m_iUpPriority = PR_HIGH;
        m_bAutoUpPriority = true;
    }
    else
    {
        m_iUpPriority = PR_NORMAL;
        m_bAutoUpPriority = false;
    }
    m_iQueuedCount = 0;
    m_bCommentLoaded = false;
    m_iRate = 0;
    m_strComment = "";
    m_iPartCount = 0;
}

CKnownFile::~CKnownFile()
{
    for (int i = 0 ; i != hashlist.GetSize() ; i++)
    {
        delete[] hashlist[i];
    }

    for (int i = 0 ; i != taglist.GetSize() ; i++)
    {
        delete taglist[i];

    }

    hashlist.RemoveAll();
    taglist.RemoveAll();
    delete[] directory;

    m_AvailPartFrequency.RemoveAll();
}

void CKnownFile::DrawShareStatusBar(wxDC *dc, wxRect rect, bool onlygreyrect, bool bFlat)
{
    static	CBarShader s_ShareStatusBar(16);

 
 /*
 DWORD crBoth;
 DWORD crNeither;
 DWORD crClientOnly;
 DWORD crPending;
 DWORD 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_ShareStatusBar.SetFileSize(GetFileSize());
    s_ShareStatusBar.SetHeight(rect.GetHeight());
    s_ShareStatusBar.SetWidth(rect.GetWidth());
    s_ShareStatusBar.Fill(RGB(255, 0, 0));
    if (!onlygreyrect && !m_AvailPartFrequency.IsEmpty())
    {
        for (int i = 0 ; i != GetPartCount() ; i++)
        if (m_AvailPartFrequency[i] > 0)
        {
            DWORD color = RGB(0, (210 - (22 * (m_AvailPartFrequency[i]
            - 1)) < 0) ? 0: 210 - (22 * (m_AvailPartFrequency[i] - 1)), 255);
            s_ShareStatusBar.FillRange(PARTSIZE * (i), PARTSIZE
            * (i + 1), color);
        }
    }
    s_ShareStatusBar.Draw(dc, rect.GetLeft(), rect.GetTop(), bFlat);
}

void CKnownFile::NewAvailPartsInfo()
{
    // Cache part count
    uint16_t partcount = GetPartCount();
    if (m_AvailPartFrequency.GetSize() < partcount)
    m_AvailPartFrequency.SetSize(partcount);
    // Reset part counters
    for (int i = 0 ; i < partcount ; i++)
    {
        m_AvailPartFrequency.Add(0);
    }
    CUpDownClient *cur_src;

    if (this->IsPartFile())
    {
        cur_src = NULL;
    }

    for (POSITION pos = m_ClientUploadList.GetHeadPosition() ; pos != 0 ;)
    {
        cur_src = m_ClientUploadList.GetNext(pos);
        for (int i = 0 ; i != partcount ; i++)
        {
            if (cur_src->IsUpPartAvailable(i))
            m_AvailPartFrequency[i] += 1;
        }
    }
    theApp.xmuledlg->sharedfileswnd->sharedfilesctrl->UpdateItem(this);
}

void CKnownFile::AddUploadingClient(CUpDownClient *client)
{
    // to be sure:
    POSITION pos = m_ClientUploadList.Find(client);
    if (pos == NULL)
    {
        m_ClientUploadList.AddTail(client);
    }
}

void CKnownFile::RemoveUploadingClient(CUpDownClient *client)
{
    // to be sure:
    POSITION pos = m_ClientUploadList.Find(client);
    if (pos != NULL)
    {
        m_ClientUploadList.RemoveAt(pos);
    }
}

void CKnownFile::SetPath(const wxString& path)
{
    if (directory)
    {
        delete[] directory;
    }

    directory = new char[path.length()];
    strcpy(directory, path.c_str());
}

bool CKnownFile::CreateFromFile(char *in_directory, char *in_filename, volatile int const *notify)
{
    // TODO Errorhandling
    //first create the filehashset
    // open file
    directory = nstrdup(in_directory);
    char *namebuffer = new char[strlen(in_directory) + strlen(in_filename) + 2];
    sprintf(namebuffer, "%s/%s", in_directory, in_filename);
    FILE *file = fopen(namebuffer, "r");
    delete[] namebuffer;
    if (!file)
    {
        printf("%s/%s ei aukea\n", in_directory, in_filename);
        return false;
    }
    // set filesize + name
    m_pszFileName = nstrdup(in_filename);
    //filesize =_filelength(file->_file);
    long curpos = ftell(file);
    fseek(file, 0, SEEK_END);
    m_nFileSize = ftell(file);
    fseek(file, curpos, SEEK_SET);
    m_AvailPartFrequency.SetSize(GetPartCount());
    for (uint32_t i = 0 ; i != GetPartCount() ; i++)
    m_AvailPartFrequency.Add(0);
    // create hashset
    uint32_t togo = m_nFileSize;
    uint16_t hashcount;
    for (hashcount = 0 ; togo >= PARTSIZE ;)
    {
        unsigned char *newhash = new unsigned char[16];
        CreateHashFromFile(file, PARTSIZE, newhash);
        hashlist.Add(newhash);
        togo -= PARTSIZE;
        hashcount++;
        if (notify && *notify)
        {
            fclose(file);
            return false;
        }
    }
    unsigned char *lasthash = new unsigned char[16];
    memset(lasthash, 0, 16);
    CreateHashFromFile(file, togo, lasthash);
    if (!hashcount)
    {
        memcpy(m_abyFileHash, lasthash, 16);
        // i_a: memleak:
        delete[] lasthash;
    }
    else
    {
        hashlist.Add(lasthash);
        unsigned char *buffer = new unsigned char[hashlist.GetCount() *16];
        for (int i = 0 ; i != hashlist.GetCount() ; i++)
        memcpy(buffer + (i *16), hashlist[i], 16);
        CreateHashFromString(buffer, hashlist.GetCount() *16, m_abyFileHash);
        delete[] buffer;
    }
    // TODO: Add filetags
    // set lastwrite date
    struct stat fileinfo;
    fstat(fileno(file), &fileinfo);
    date = fileinfo.st_mtime;
    //finished
    fclose(file);
    return true;
}

// needed for memfiles. its probably better to switch everything to CFile...
bool CKnownFile::LoadHashsetFromFile(CFile *file, bool checkhash)
{
    unsigned char checkid[16];
    file->Read( &checkid, 16);
    uint16_t parts;
    file->Read( &parts, 2);
    for (int i = 0 ; i != parts ; i++)
    {
        unsigned char *cur_hash = new unsigned char[16];
        file->Read(cur_hash, 16);
        hashlist.Add(cur_hash);
    }
    if (!checkhash)
    {
        memcpy(m_abyFileHash, checkid, 16);
        return true;
    }
    // trust noone ;-)
    if (!hashlist.IsEmpty())
    {
        unsigned char *buffer = new unsigned char[hashlist.GetCount() *16];
        for (int i = 0 ; i != hashlist.GetCount() ; i++)
        {
            memcpy(buffer + (i *16), hashlist[i], 16);
        }
        CreateHashFromString(buffer, hashlist.GetCount() *16, checkid);
        delete[] buffer;
    }
    if (!memcmp(m_abyFileHash, checkid, 16))
    {
        return true;
    }
    else
    {
        for (int i = 0 ; i != hashlist.GetSize() ; i++)
        delete[] hashlist[i];
        hashlist.RemoveAll();
        return false;
    }
}

bool CKnownFile::LoadTagsFromFile(CFile *file)
{
    try
    {
        uint32_t tagcount;
        if (4 != file->Read( &tagcount, 4))
        throw CInvalidPacket("short file reading tag count");
        for (uint32_t j = 0 ; j < tagcount ; j++)
        {
            try
            {
                CTag *newtag = new CTag(file);
                switch (newtag->tag->specialtag)
                {
                case FT_FILENAME:
                    {
                        m_pszFileName = nstrdup(newtag->tag->stringvalue);
                        delete newtag;
                        break;
                    }
                case FT_FILESIZE:
                    {
                        m_nFileSize = newtag->tag->intvalue;
                        m_AvailPartFrequency.SetSize(GetPartCount());
                        for (uint32_t i = 0 ; i != GetPartCount() ; i++)
                        m_AvailPartFrequency.Add(0);
                        delete newtag;
                        break;
                    }
                case FT_ATTRANSFERED:
                    {
                        statistic.alltimetransfered = newtag->tag->intvalue;
                        delete newtag;
                        break;
                    }
                case FT_ATREQUESTED:
                    {
                        statistic.alltimerequested = newtag->tag->intvalue;
                        delete newtag;
                        break;
                    }
                case FT_ATACCEPTED:
                    {
                        statistic.alltimeaccepted = newtag->tag->intvalue;
                        delete newtag;
                        break;
                    }
                    // for compatibility only:
                case FT_OLDDLPRIORITY:
                    // for compatibility only:
                case FT_OLDULPRIORITY:
                    // for compatibility only:
                case FT_DLPRIORITY:
                case FT_ULPRIORITY:
                    {
                        uint8_t autoprio = PR_AUTO;
                        m_iUpPriority = newtag->tag->intvalue;
                        if (m_iUpPriority == autoprio)
                        {
                            m_iUpPriority = PR_HIGH;
                            m_bAutoUpPriority = true;
                        }
                        else
                        m_bAutoUpPriority = false;
                        delete newtag;
                        break;
                    }
                case FT_PERMISSIONS:
                    {
                        m_iPermissions = newtag->tag->intvalue;
                        delete newtag;
                        break;
                    }
                default:
                    taglist.Add(newtag);
                }
            }
            catch(CStrangePacket)
            {
            }
        }
    }
    catch(CInvalidPacket e)
    {
        printf("Problem reading known file - %s\n", e.what());
        return false;
    }
    return true;
}

bool CKnownFile::LoadDateFromFile(CFile *file)
{
    return(4 == file->Read( &date, 4));
}

bool CKnownFile::LoadFromFile(CFile *file)
{
    return(LoadDateFromFile(file) &&LoadHashsetFromFile(file, false) &&LoadTagsFromFile(file));
}

bool CKnownFile::WriteToFile(FILE *file)
{
    // date
    fwrite( &date, 4, 1, file);
    // hashset
    fwrite( &m_abyFileHash, 16, 1, file);
    uint16_t parts = hashlist.GetCount();
    fwrite( &parts, 2, 1, file);
    for (int i = 0 ; i != parts ; i++)
    fwrite(hashlist[i], 16, 1, file);
    //tags
#define NR_TAGS 10
    uint32_t tagcount = taglist.GetCount() + NR_TAGS;
    // standard tags
    fwrite( &tagcount, 4, 1, file);
    CTag(FT_FILENAME, m_pszFileName) .WriteTagToFile(file);
    CTag(FT_FILESIZE, m_nFileSize) .WriteTagToFile(file);
    // statistic
    CTag(FT_ATTRANSFERED, statistic.GetAllTimeTransfered()) .WriteTagToFile(file);
    CTag(FT_ATREQUESTED, statistic.GetAllTimeRequests()) .WriteTagToFile(file);
    CTag(FT_ATACCEPTED, statistic.GetAllTimeAccepts()) .WriteTagToFile(file);
    // priority N permission
    CTag(FT_OLDDLPRIORITY, m_iUpPriority) .WriteTagToFile(file);
    CTag(FT_OLDULPRIORITY, m_iUpPriority) .WriteTagToFile(file);
    CTag(FT_ULPRIORITY, m_iUpPriority) .WriteTagToFile(file);
    // for compatibility only:
    CTag(FT_DLPRIORITY, m_iUpPriority) .WriteTagToFile(file);
    CTag(FT_PERMISSIONS, m_iPermissions) .WriteTagToFile(file);
    //other tags
    for (uint32_t j = 0 ; j < tagcount - NR_TAGS ; j++)
    taglist[j]->WriteTagToFile(file);
    return ferror(file);
#undef NR_TAGS
}

void CKnownFile::CreateHashFromInput(FILE *file, CFile *file2, int Length, unsigned char *Output, unsigned char *in_string)
{
    // time critial
    bool PaddingStarted = false;
    uint32_t Hash[4];
    Hash[0] = 0x67452301;
    Hash[1] = 0xEFCDAB89;
    Hash[2] = 0x98BADCFE;
    Hash[3] = 0x10325476;
    CMemFile *data = 0;
    if (in_string)
    {
        data = new CMemFile(in_string, Length);
    }
    uint32_t Required = Length;
    unsigned char X[64 *128];
    while (Required >= 64)
    {
        uint32_t len = Required / 64;
        if (len > sizeof(X) / (64 *sizeof(X[0])))
        len = sizeof(X) / (64 *sizeof(X[0]));
        if (in_string)
        data->Read( &X, len *64);
        else if(file)
        fread( &X, len *64, 1, file);
        else if(file2)
        file2->Read( &X, len *64);
        for (uint32_t i = 0 ; i < len ; i++)
        {
            MD4Transform(Hash, (uint32_t *)(X + i *64));
        }
        Required -= len *64;
    }
    // bytes to read
    Required = Length % 64;
    if (Required != 0)
    {
        if (in_string)
        data->Read( &X, Required);
        else if(file)
        fread( &X, Required, 1, file);
        else if(file2)
        file2->Read( &X, Required);
    }
    // in byte scale 512 = 64, 448 = 56
    if (Required >= 56)
    {
        X[Required] = 0x80;
        PaddingStarted = TRUE;
        memset( &X[Required + 1], 0, 63 - Required);
        MD4Transform(Hash, (uint32_t *) X);
        Required = 0;
    }
    if (!PaddingStarted)
    {
        X[Required++] = 0x80;
    }
    memset( &X[Required], 0, 64 - Required);
    // add size (convert to bits)
    uint32_t Length2 = Length >> 29;
    Length <<= 3;
    memcpy( &X[56], &Length, 4);
    memcpy( &X[60], &Length2, 4);
    MD4Transform(Hash, (uint32_t *) X);
    memcpy(Output, Hash, 16);
    delete data;
}

unsigned char *CKnownFile::GetPartHash(uint16_t part)
{
    if (part >= hashlist.GetCount())
    return 0;
    return hashlist[part];
}

static void MD4Transform(uint32_t Hash[4], uint32_t x[16])
{
    uint32_t a = Hash[0];
    uint32_t b = Hash[1];
    uint32_t c = Hash[2];
    uint32_t d = Hash[3];
    /* Round 1 */
    // 01:
    MD4_FF(a, b, c, d, x[ 0], S11);
    // 02:
    MD4_FF(d, a, b, c, x[ 1], S12);
    // 03:
    MD4_FF(c, d, a, b, x[ 2], S13);
    // 04:
    MD4_FF(b, c, d, a, x[ 3], S14);
    // 05:
    MD4_FF(a, b, c, d, x[ 4], S11);
    // 06:
    MD4_FF(d, a, b, c, x[ 5], S12);
    // 07:
    MD4_FF(c, d, a, b, x[ 6], S13);
    // 08:
    MD4_FF(b, c, d, a, x[ 7], S14);
    // 09:
    MD4_FF(a, b, c, d, x[ 8], S11);
    // 10:
    MD4_FF(d, a, b, c, x[ 9], S12);
    // 11:
    MD4_FF(c, d, a, b, x[10], S13);
    // 12:
    MD4_FF(b, c, d, a, x[11], S14);
    // 13:
    MD4_FF(a, b, c, d, x[12], S11);
    // 14:
    MD4_FF(d, a, b, c, x[13], S12);
    // 15:
    MD4_FF(c, d, a, b, x[14], S13);
    // 16:
    MD4_FF(b, c, d, a, x[15], S14);
    /* Round 2 */
    // 17:
    MD4_GG(a, b, c, d, x[ 0], S21);
    // 18:
    MD4_GG(d, a, b, c, x[ 4], S22);
    // 19:
    MD4_GG(c, d, a, b, x[ 8], S23);
    // 20:
    MD4_GG(b, c, d, a, x[12], S24);
    // 21:
    MD4_GG(a, b, c, d, x[ 1], S21);
    // 22:
    MD4_GG(d, a, b, c, x[ 5], S22);
    // 23:
    MD4_GG(c, d, a, b, x[ 9], S23);
    // 24:
    MD4_GG(b, c, d, a, x[13], S24);
    // 25:
    MD4_GG(a, b, c, d, x[ 2], S21);
    // 26:
    MD4_GG(d, a, b, c, x[ 6], S22);
    // 27:
    MD4_GG(c, d, a, b, x[10], S23);
    // 28:
    MD4_GG(b, c, d, a, x[14], S24);
    // 29:
    MD4_GG(a, b, c, d, x[ 3], S21);
    // 30:
    MD4_GG(d, a, b, c, x[ 7], S22);
    // 31:
    MD4_GG(c, d, a, b, x[11], S23);
    // 32:
    MD4_GG(b, c, d, a, x[15], S24);
    /* Round 3 */
    // 33:
    MD4_HH(a, b, c, d, x[ 0], S31);
    // 34:
    MD4_HH(d, a, b, c, x[ 8], S32);
    // 35:
    MD4_HH(c, d, a, b, x[ 4], S33);
    // 36:
    MD4_HH(b, c, d, a, x[12], S34);
    // 37:
    MD4_HH(a, b, c, d, x[ 2], S31);
    // 38:
    MD4_HH(d, a, b, c, x[10], S32);
    // 39:
    MD4_HH(c, d, a, b, x[ 6], S33);
    // 40:
    MD4_HH(b, c, d, a, x[14], S34);
    // 41:
    MD4_HH(a, b, c, d, x[ 1], S31);
    // 42:
    MD4_HH(d, a, b, c, x[ 9], S32);
    // 43:
    MD4_HH(c, d, a, b, x[ 5], S33);
    // 44:
    MD4_HH(b, c, d, a, x[13], S34);
    // 45:
    MD4_HH(a, b, c, d, x[ 3], S31);
    // 46:
    MD4_HH(d, a, b, c, x[11], S32);
    // 47:
    MD4_HH(c, d, a, b, x[ 7], S33);
    // 48:
    MD4_HH(b, c, d, a, x[15], S34);
    Hash[0] += a;
    Hash[1] += b;
    Hash[2] += c;
    Hash[3] += d;
}

// Adde by Tarod [Juanjo]
void CAbstractFile::SetFileName(char *NewName)
{
    if (m_pszFileName != NULL)
    {
        delete[] m_pszFileName;
        m_pszFileName = new char[strlen(NewName) + 1];
        wxString filenametemp;
        //.Printf("%s",NewName);:
        filenametemp = NewName;
        filenametemp.Replace("\\", "-");
        filenametemp.Replace(">", "-");
        filenametemp.Replace("<", "-");
        filenametemp.Replace("*", "-");
        filenametemp.Replace(":", "-");
        filenametemp.Replace("?", "-");
        sprintf(m_pszFileName, "%s", filenametemp.GetData());
    }
}

//End by Tarod

Packet* CKnownFile::CreateSrcInfoPacket(CUpDownClient* forClient)
{
    CTypedPtrList<CPtrList, CUpDownClient *> srclist;
    //should we use "filehash"?:
    theApp.uploadqueue->FindSourcesForFileById(&srclist, forClient->GetUploadFileID());

    if (srclist.IsEmpty())
    {
        return NULL;
    }

    CMemFile data;
    uint16_t nCount = 0;
    data.Write(forClient->GetUploadFileID(), 16);
    data.Write( &nCount, 2);

    //we are only taking 30 random sources since we can't be sure if they have parts we need
    //this is hard coded because its a temp solution until next(?) version
    srand(time(NULL));

    for (int i=0; i<30; ++i)
    {
        int victim = ((rand() >> 7) % srclist.GetSize());
        POSITION pos = srclist.FindIndex(victim);
        CUpDownClient *cur_src = srclist.GetAt(pos);

        if (!cur_src->HasLowID() && cur_src != forClient)
        {
            nCount++;
            uint32_t dwID = cur_src->GetUserID();
            uint16_t nPort = cur_src->GetUserPort();
            uint32_t dwServerIP = cur_src->GetServerIP();
            uint16_t nServerPort = cur_src->GetServerPort();
            data.Write( &dwID, 4);
            data.Write( &nPort, 2);
            data.Write( &dwServerIP, 4);
            data.Write( &nServerPort, 2);
            if (forClient->GetSourceExchangeVersion() > 1)
            {
                data.Write(cur_src->GetUserHash(), 16);
            }
        }

        srclist.RemoveAt(pos);
        
        if (srclist.GetSize() == 0)
        {
            break;
        }
    }

    if (!nCount)
    {
        return NULL;
    }

    data.Seek(16);
    data.Write(&nCount, 2);
    Packet* result = new Packet( &data, OP_EMULEPROT);
    result->opcode = OP_ANSWERSOURCES;

    if (nCount > 28)
    {
        result->PackPacket();
    }

    return result;
}

// Updates priority of file if autopriority is activated
void CKnownFile::UpdateAutoUpPriority(void)
{
    if (!this->IsAutoUpPriority())
    return;
    if (GetQueuedCount() > 20)
    {
        if (GetUpPriority() != PR_LOW)
        {
            SetUpPriority(PR_LOW);
            theApp.xmuledlg->sharedfileswnd->sharedfilesctrl->UpdateItem(this);
        }
        return;
    }
    if (GetQueuedCount() > 1)
    {
        if (GetUpPriority() != PR_NORMAL)
        {
            SetUpPriority(PR_NORMAL);
            theApp.xmuledlg->sharedfileswnd->sharedfilesctrl->UpdateItem(this);
        }
        return;
    }
    if (GetUpPriority() != PR_HIGH)
    {
        SetUpPriority(PR_HIGH);
        theApp.xmuledlg->sharedfileswnd->sharedfilesctrl->UpdateItem(this);
    }
}

//For File Comment //
void CKnownFile::LoadComment()
{
    char buffer[100];
//    char *fullpath = new char[theApp.dynprefs->Get<wxString>("app-directory").length() + 13];
//    sprintf(fullpath, "%sfileinfo.ini", theApp.glob_prefs->GetAppDir());
    buffer[0] = 0;
    for (uint16_t i = 0 ; i != 16 ; i++)
    sprintf(buffer, "%s%02X", buffer, m_abyFileHash[i]);
    CIni ini(theApp.dynprefs->Get<wxString>("app-directory") + wxT("fileinfo.ini"), buffer);
    m_strComment = ini.GetString("Comment") .GetData();
    //For rate:
    m_iRate = ini.GetInt("Rate", 0);
    m_bCommentLoaded = true;
//    delete[] fullpath;
}

void CKnownFile::SetFileComment(wxString strNewComment)
{
    char buffer[100];
//    char* fullpath = new char[strlen(theApp.glob_prefs->GetAppDir()) + 13];
//    sprintf(fullpath, "%sfileinfo.ini", theApp.glob_prefs->GetAppDir());
    buffer[0] = 0;

    for (uint16_t i=0; i!=16; ++i)
    {
        sprintf(buffer, "%s%02X", buffer, m_abyFileHash[i]);
    }

    CIni ini(theApp.dynprefs->Get<wxString>("app-directory") + wxT("fileinfo.ini"), buffer);
    ini.WriteString("Comment", strNewComment);
    m_strComment = strNewComment;
//    delete[] fullpath;

    CTypedPtrList < CPtrList, CUpDownClient *> srclist;
    theApp.uploadqueue->FindSourcesForFileById( &srclist, this->GetFileHash());
    
    for (POSITION pos = srclist.GetHeadPosition(); pos != 0; srclist.GetNext(pos))
    {
        CUpDownClient* cur_src = srclist.GetAt(pos);
        cur_src->SetCommentDirty();
    }
}

void CKnownFile::SetFileRate(int8_t iNewRate)
{
    char buffer[100];
//    char* fullpath = new char[strlen(theApp.glob_prefs->GetAppDir()) + 13];
//    sprintf(fullpath, "%sfileinfo.ini", theApp.glob_prefs->GetAppDir());
    buffer[0] = 0;
    
    for (uint16_t i=0; i!=16; ++i)
    {
        sprintf(buffer, "%s%02X", buffer, m_abyFileHash[i]);
    }
    
    CIni ini(theApp.dynprefs->Get<wxString>("app-directory") + wxT("fileinfo.ini"), buffer);
    ini.WriteInt("Rate", iNewRate);
    m_iRate = iNewRate;
//    delete[] fullpath;

    CTypedPtrList < CPtrList, CUpDownClient *> srclist;
    theApp.uploadqueue->FindSourcesForFileById( &srclist, this->GetFileHash());

    for (POSITION pos = srclist.GetHeadPosition() ; pos != 0 ; srclist.GetNext(pos))
    {
        CUpDownClient* cur_src = srclist.GetAt(pos);
        cur_src->SetCommentDirty();
    }
}

void CKnownFile::SetUpPriority(uint8_t iNewUpPriority, bool m_bsave)
{
    m_iUpPriority = iNewUpPriority;
    if (this->IsPartFile() && m_bsave)
    {
        ((CPartFile *) this)->SavePartFile();
    }
}

