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

#include "updownclient.h"                   // Needed for Module's Prototype(s) - audited 5 Nov 2004

#include "ClientCredits.h"                  // Needed for CClientCredits - audited 5 Nov 2004
#include "ClientList.h"                     // Needed for CClientList - audited 5 Nov 2004
#include "config.h"                         // Needed for PACKAGE_VERSION - audited 5 Nov 2004
#include "DownloadListCtrl.h"               // Needed for CDownloadListCtrl - audited 5 Nov 2004
#include "DownloadQueue.h"                  // Needed for CDownloadQueue - audited 5 Nov 2004
#include "Friend.h"                         // Needed for CFriend - audited 5 Nov 2004
#include "FriendList.h"                     // Needed for CFriendList - audited 5 Nov 2004
#include "IPFilter.h"                       // Needed for CIPFilter - audited 5 Nov 2004
#include "ListenSocket.h"                   // Needed for CClientReqSocket - audited 5 Nov 2004
#include "NewSockets.h"                     // Needed for NewSocket_SendPacketOP - audited 5 Nov 2004
#include "otherstructs.h"                   // Needed for Requested_Blocks_Struct - audited 5 Nov 2004
#include "packets.h"                        // Needed for CTag - audited 5 Nov 2004
#include "PartFile.h"                       // Needed for CPartFile - audited 5 Nov 2004
#include "Preferences.h"                    // Needed for CPreferences::GetUserHash
#include "SafeFile.h"                       // Needed for CSafeMemFile - audited 5 Nov 2004
#include "server.h"                         // Needed for CServer - audited 5 Nov 2004
#include "ServerListCtrl.h"                 // Needed for CServerListCtrl - audited 5 Nov 2004
#include "sockets.h"                        // Needed for CServerConnect - audited 5 Nov 2004
#include "ServerWnd.h"                      // Needed for CServerWnd - audited 5 Nov 2004
#include "TransferWnd.h"                    // Needed for CTransferWnd - audited 5 Nov 2004
#include "UploadQueue.h"                    // Needed for CUploadQueue - audited 5 Nov 2004
#include "xmule.h"                          // Needed for theApp - audited 4 Nov 2004
#include "xmuleDlg.h"                       // Needed for theApp.xmuledlg - audited 5 Nov 2004
#include "xmuleIPV4Address.h"               // Needed for xmuleIPV4Address - audited 5 Nov 2004

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

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wx/hashmap.h>
#include <wx/socket.h>                      // Needed for wxIPV4address

// some client testing variables
static wxString crash_name = "[Invalid User Name]";
static wxString empty_name = "[Empty User Name]";

//	members of CUpDownClient
//	which are used by down and uploading functions

CUpDownClient::CUpDownClient(CClientReqSocket *sender)
{
    SpecialPerson = false;
    socket = sender;
    reqfile = 0;
    Init();
}

CUpDownClient::CUpDownClient(uint16_t in_port, uint32_t in_userid, uint32_t in_serverip, uint16_t in_serverport, CPartFile *in_reqfile)
{
    SpecialPerson = false;
    socket = 0;
    Init();
    m_nUserID = in_userid;
    m_nUserPort = in_port;
    sourcesslot = 0;
    if (!HasLowID())
    sprintf(m_szFullUserIP, "%i.%i.%i.%i", (uint8_t) m_nUserID, (uint8_t)(m_nUserID >> 8), (uint8_t)(m_nUserID >> 16), (uint8_t)(m_nUserID >> 24));
    m_dwServerIP = in_serverip;
    m_nServerPort = in_serverport;
    reqfile = in_reqfile;
    ReGetClientSoft();
}

void CUpDownClient::Init()
{
    deletethis = false;
    memset(m_szFullUserIP, 0, 21);
    credits = 0;
    memset(requpfileid, 0, sizeof requpfileid);
    m_nAvDownDatarate = 0;
    m_nAvUpDatarate = 0;
    m_byChatstate = 0;
    m_cShowDR = 0;
    m_nUDPPort = 0;
    m_cFailed = 0;
    m_dwBanTime = 0;
    m_nMaxSendAllowed = 0;
    m_nTransferedUp = 0;
    m_cSendblock = 0;
    m_cAsked = 0;
    m_cDownAsked = 0;
    dataratems = 0;
    m_nUpDatarate = 0;
    m_pszUsername = 0;
    m_dwUserIP = 0;
    usedcompressiondown = false;
    //FAZ:SendSignaturePacket+ProcessSignaturePacket+SendSecIdentState to impl. for:
    m_abyPartStatus = 0;
    m_abyUpPartStatus = 0;
    m_bBanned = false;
    m_bCommentDirty = false;
    m_bCompleteSource = false;
    m_bEmuleProtocol = false;
    m_bFriendSlot = false;
    m_bGPLEvildoer = false;
    m_bHashsetRequested = false;
    m_bIsHybrid = false;
    m_bIsML = false;
    m_bIsSpammer = false;
    m_bPreviewAnsPending = false;
    m_bPreviewReqPending = false;
    m_bReaskPending = false;
    m_bRemoteQueueFull = false;
    m_bSharedDirectories = false;
    m_bSupportsPreview = false;
    m_bUDPPending = false;
    m_bUsedComprUp = false;
    m_byAcceptCommentVer = 0;
    m_byCompatibleClient = 0;
    m_byDataCompVer = 0;
    m_byEmuleVersion = 0;
    m_byExtendedRequestsVer = 0;
    m_byInfopacketsReceived = IP_NONE;
    m_bySourceExchangeVer = 0;
    m_bySupportSecIdent = 0;
    m_byUDPVer = 0;
    m_byUploadState = US_NONE;
    m_clientSoft = SO_UNKNOWN;
    m_cMessagesReceived = 0;
    m_cMessagesSend = 0;
    m_dwLastAskedTime = 0;
    m_dwLastBlockReceived = 0;
    m_dwLastSignatureIP = 0;
    m_dwLastSourceAnswer = 0;
    m_dwLastSourceRequest = 0;
    m_dwLastUpRequest = 0;
    m_dwUploadTime = 0;
    m_Friend = NULL;
    m_iFileListRequested = 0;
    m_iRate = 0;
    m_lastPartAsked = 0xffff;
    m_nClientVersion = 0;
    m_nCurSessionUp = 0;
    m_nDownDatarate = 0;
    m_nDownDataRateMS = 0;
    m_nDownloadState = DS_NONE;
    m_nPartCount = 0;
    m_nRemoteQueueRank = 0;
    m_nServerPort = 0;
    m_nSumForAvgDownDataRate = 0;
    m_nSumForAvgUpDataRate = 0;
    m_nTransferedDown = 0;
    m_nUpCompleteSourcesCount = 0;
    m_nUpPartCount = 0;
    m_nUserID = 0;
    m_nUserPort = 0;
    m_pszClientFilename = 0;
    m_SecureIdentState = IS_UNAVAILABLE;
    m_strClientFilename = "";
    m_strComment = "";
    memset(m_achUserHash, 0, 16);
    SetWaitStartTime();
    if (socket)
    {
        struct sockaddr_in sockAddr;
        memset( &sockAddr, 0, sizeof(sockAddr));

        wxIPV4address address;
        socket->GetPeer(address);
        //socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
        sockAddr.sin_addr.s_addr = GAddress_INET_GetHostAddress(address.GetAddress());
        m_dwUserIP = sockAddr.sin_addr.s_addr;
        strcpy(m_szFullUserIP, inet_ntoa(sockAddr.sin_addr));
    }
    sourcesslot = 0;
    // At the beginning, client is't a thief :)
    leechertype = 0;
    thief = false;
}

CUpDownClient::~CUpDownClient()
{
    /* Razor 1a - Modif by MikaelB */
    if (reqfile != NULL)
    {
        reqfile->RemoveDownloadingSource(this);
    }
    /* End modif */
    theApp.clientlist->RemoveClient(this);
    if (m_Friend)
    {
        m_Friend->m_LinkedClient = NULL;
        theApp.friendlist->RefreshFriend(m_Friend);
        m_Friend = NULL;
    }
    if (m_pszClientFilename)
    {
        delete[] m_pszClientFilename;
    }
    if (socket)
    {
        socket->client = 0;
        socket->Safe_Delete();
    }
    if (m_pszUsername)
    delete[] m_pszUsername;

    if (m_abyPartStatus)
    {
        delete[] m_abyPartStatus;
        m_abyPartStatus = NULL;
    }

    if (m_abyUpPartStatus)
    {
        delete[] m_abyUpPartStatus;
        m_abyUpPartStatus = NULL;
    }

    ClearUploadBlockRequests();
    for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition() ; pos != 0 ; m_DownloadBlocks_list.GetNext(pos))
    delete m_DownloadBlocks_list.GetAt(pos);
    m_DownloadBlocks_list.RemoveAll();
    for (POSITION pos = m_RequestedFiles_list.GetHeadPosition() ; pos != 0 ; m_RequestedFiles_list.GetNext(pos))
    delete m_RequestedFiles_list.GetAt(pos);
    m_RequestedFiles_list.RemoveAll();
    for (POSITION pos = m_PendingBlocks_list.GetHeadPosition() ; pos != 0 ; m_PendingBlocks_list.GetNext(pos))
    {
        Pending_Block_Struct *pending = m_PendingBlocks_list.GetAt(pos);
        delete pending->block;
        // Not always allocated
        if (pending->zStream)
        {
            inflateEnd(pending->zStream);
            delete pending->zStream;
        }
        delete pending;
    }
    if (m_iRate > 0 || m_strComment.length() > 0)
    {
        m_iRate = 0;
        m_strComment = "";
        reqfile->UpdateFileRatingCommentAvail();
    }
    m_PendingBlocks_list.RemoveAll();
    m_AvarageUDR_list.RemoveAll();
    m_AvarageDDR_list.RemoveAll();
    SetUploadFileID(NULL);
}

bool CUpDownClient::ProcessHelloPacket(char *pachPacket, uint32_t nSize)
{
    CSafeMemFile data((BYTE *) pachPacket, nSize);
    uint8_t hashsize;
    if (1 == data.Read( &hashsize, 1))
    {
        return ProcessHelloTypePacket( &data);
    }
    else
    {
        return false;
    }
}

bool CUpDownClient::ProcessHelloAnswer(char *pachPacket, uint32_t nSize)
{
    CSafeMemFile data((BYTE *) pachPacket, nSize);
    return ProcessHelloTypePacket( &data);
}

bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile *data)
{
    m_bIsHybrid = false;
    m_bIsML = false;
    DWORD dwEmuleTags = 0;
    if (data->Read( &m_achUserHash, 16) == 16)
    {
        uint32_t nUserID;
        if (data->Read( &nUserID, 4) == 4)
        {
            //fsch2010:if (!m_nUserID || nUserID < 16777216)
            m_nUserID = nUserID;
            // hmm clientport is sent twice - why?:
            if (data->Read( &m_nUserPort, 2) == 2)
            {
                uint32_t tagcount;
                if (data->Read( &tagcount, 4) == 4)
                {
                    // TODO: Check if we get everything needed!
 /* It seems that various Mules and Donkeys send tagcount 2, Old MLDonkey sends
 tagcount 3, new mldonkeys 4. There are also some clients
    sending tagcount 5 and 7, what are those? */
                    for (uint32_t i = 0 ; i < tagcount ; i++)
                    {
                        CTag *temptag = new CTag(data);
                        if (temptag->tag->tagname && !strcmp(temptag->tag->tagname, "pr"))
                        {
                            // EDonkey hybrid does send integer 1
                        }
                        else
                        {
                            switch (temptag->tag->specialtag)
                            {
                            case CT_NAME:
                                {
                                    // Verifying username for determining a thief
                                    wxString oldusername;
                                    bool bOldUser = false;
                                    if (m_pszUsername)
                                    {
                                        bOldUser = true;
                                        oldusername.Printf("%s", m_pszUsername);
                                        delete[] m_pszUsername;
                                        m_pszUsername = NULL;
                                    }
                                    m_pszUsername = NULL;
                                    m_pszUsername = temptag->tag->stringvalue ? nstrdup(temptag->tag->stringvalue): nstrdup(crash_name);
                                    if (strcmp(m_pszUsername, "") == 0)
                                    {
                                        delete[] m_pszUsername;
                                        m_pszUsername = NULL;
                                        m_pszUsername = nstrdup(empty_name);
                                    }
                                    // If username has changed
                                    if ((bOldUser && (oldusername.CmpNoCase(m_pszUsername) != 0))
                                    && !thief)
                                    {
                                        uint64_t id = getUID();

                                        leechertype = 0;
                                        if (theApp.listensocket->offensecounter.find(id) != theApp.listensocket->offensecounter.end())
                                        theApp.listensocket->offensecounter[id]++;
                                        else
                                        theApp.listensocket->offensecounter[id] = (uint32_t) 1;
                                        theApp.listensocket->offensecounter[0]++;
                                    }
                                }
                                break;
 /*	if (m_pszUsername)
 delete[] m_pszUsername;
 m_pszUsername = nstrdup(temptag->tag->stringvalue);
    break;  */
                            case CT_VERSION:
                                {
                                    m_nClientVersion = temptag->tag->intvalue;
                                    break;
                                }
                            case ET_MOD_VERSION:
                                {
                                    if (temptag->tag->type == 2)
                                    {
                                        m_strModVersion = temptag->tag->stringvalue;
                                    }
                                    else if(temptag->tag->type == 3)
                                    {
                                        m_strModVersion.Printf("%ModID=%u", temptag->tag->intvalue);
                                    }
                                    else
                                    {
                                        m_strModVersion = "ModID=<Unknown>";
                                    }
                                    break;
                                }
                            case CT_PORT:
                                {
                                    m_nUserPort = temptag->tag->intvalue;
                                    break;
                                }
                            case CT_EMULE_UDPPORTS:
                                {
                                    m_nKadPort = (temptag->tag->intvalue >> 16) &0xffff;
                                    m_nUDPPort = temptag->tag->intvalue &0xffff;
                                    dwEmuleTags |= 1;
                                    break;
                                }
                            case CT_EMULE_MISCOPTIONS1:
                                {
                                    m_byUDPVer = (temptag->tag->intvalue >> 4 *6) &0x0f;
                                    m_byDataCompVer = (temptag->tag->intvalue >> 4 *5) &0x0f;
                                    m_bySupportSecIdent = (temptag->tag->intvalue >> 4 *4) &0x0f;
                                    m_bySourceExchangeVer = (temptag->tag->intvalue >> 4 *3) &0x0f;
                                    m_byExtendedRequestsVer = (temptag->tag->intvalue >> 4 *2) &0x0f;
                                    m_byAcceptCommentVer = (temptag->tag->intvalue >> 4 *1) &0x0f;
                                    if ((temptag->tag->intvalue >> 1 *2) &0x01)
                                    {
                                        m_bNoViewSharedFiles = true;
                                    }
                                    else
                                    {
                                        m_bNoViewSharedFiles = false;
                                    }
                                    m_bMultiPacket = (temptag->tag->intvalue >> 1 *1) &0x01;
                                    if ((temptag->tag->intvalue >> 1 *0) &0x01)
                                    {
                                        m_bSupportsPreview = true;
                                    }
                                    else
                                    {
                                        m_bSupportsPreview = false;
                                    }
                                    dwEmuleTags |= 2;
                                    break;
                                }
                            case CT_EMULE_VERSION:
                                {
                                    m_byCompatibleClient = (temptag->tag->intvalue >> 24);
                                    m_nClientVersion = temptag->tag->intvalue & 0x00ffffff;
                                    m_byEmuleVersion = 0x99;
                                    m_bSharedDirectories = true;
                                    dwEmuleTags |= 4;
                                    break;
                                }
                            case CT_FRIENDSHARING:
                                {
                                    // ignore this one
                                    break;
                                }
                            }
                        }
                        delete temptag;
                    }
                    // Make up a username if we get none
                    if (!m_pszUsername)
                    {
                        m_pszUsername = nstrdup(empty_name);
                    }
                    if (data->Read( &m_dwServerIP, 4) == 4)
                    {
                        if (data->Read( &m_nServerPort, 2) == 2)
                        {
                            // Hybrid now has an extra uint32_t.. What is it for?
                            // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
                            if (data->GetLength() - data->GetPosition() == 4)
                            {
                                uint32_t test;
                                data->Read( &test, 4);
                                if (test == (uint32_t) "KDLM")
                                {
                                    m_bIsML = true;
                                }
                                else
                                {
                                    m_bIsHybrid = true;
                                    m_bSharedDirectories = true;
                                }
                                //		if( m_nClientVersion > 10000 && m_nClientVersion < 100000 )
                                //			m_nClientVersion = m_nClientVersion - (m_nClientVersion/10000)*10000;
                                //		if( m_nClientVersion > 1000 )
                                //			m_nClientVersion = m_nClientVersion - (m_nClientVersion/1000)*1000;
                                //		if( m_nClientVersion < 100 )
                                //			m_nClientVersion *= 10;
                            }
                        }
                    }
                    // tecxx 1609 2002 - add client's servet to serverlist (Moved to uploadqueue.cpp)
                    if (socket)
                    {
                        struct sockaddr_in sockAddr;
                        memset( &sockAddr, 0, sizeof(sockAddr));

                        wxIPV4address address;
                        socket->GetPeer(address);
                        sockAddr.sin_addr.s_addr = GAddress_INET_GetHostAddress(address.GetAddress());
                        m_dwUserIP = sockAddr.sin_addr.s_addr;
                        strcpy(m_szFullUserIP, inet_ntoa(sockAddr.sin_addr));
                    }
                    if (theApp.dynprefs->Get<bool>("add-server-client") == true)
                    {
                        if (m_dwServerIP)
                        {
                            in_addr addhost;
                            addhost.s_addr = m_dwServerIP;
                            CServer *addsrv = new CServer(m_nServerPort, inet_ntoa(addhost));
                            addsrv->SetListName(addsrv->GetAddress());
                            if (!theApp.xmuledlg->serverwnd->serverlistctrl->AddServer(addsrv, true))
                            {
                                delete addsrv;
                            }
                        }
                    }
                    // get client credits
                    // key, 255.255.0.0 subnetmask
                    if (!HasLowID() || (!m_nUserID))
                    {
                        m_nUserID = m_dwUserIP;
                    }
                    unsigned char key[16];
                    md4cpy(key, m_achUserHash);
                    credits = theApp.clientcredits->GetCredit(key);
                    if ((m_Friend = theApp.friendlist->LinkFriend(key, m_dwUserIP, m_nUserPort)) != NULL)
                    {
                        m_Friend->m_LinkedClient = this;
                        m_Friend->m_dwHasHash = 1;
                        for (int i = 0 ; i < 16 ; i++)
                        m_Friend->m_abyUserhash[i] = GetUserHash() [i];
                        m_Friend->m_strName.Printf("%s", m_pszUsername);
                        m_Friend->m_dwLastUsedIP = m_dwUserIP;
                        m_Friend->m_nLastUsedPort = m_nUserPort;
                        theApp.friendlist->RefreshFriend(m_Friend);
                    }
                    ReGetClientSoft();
                    // Thief detection
                    if (!thief)
                    {
                        // Stolen Hash detection [BlackRat]
                        uint64_t id = getUID();
                        if (theApp.serverconnect->GetClientID() != m_nUserID &&memcmp(m_achUserHash, theApp.glob_prefs->GetUserHash(), 16) == 0)
                        {
                            // This is a hasl stealer !
                            thief = true;
                            leechertype = 5;

                            if (theApp.listensocket->offensecounter.find(id) != theApp.listensocket->offensecounter.end())
                            theApp.listensocket->offensecounter[id]++;
                            else
                            theApp.listensocket->offensecounter[id] = (uint32_t) 1;
                        }
                        // Detection id change [BlackRat]
 /*
 There is still something to do here
 Actually, due to problems with HashMap, everybody here is consider as id stealers...
    */
                        uint64_t lasthash;
                        uint64_t thishash = 0;
                        for (int i = 0 ; i < 8 ; i++)
                        thishash += GetUserHash() [i] << (i *8) ^ GetUserHash() [i + 8] << (i *8);
                        if ((theApp.listensocket->hashbase.find(id) != theApp.listensocket->hashbase.end()) &&
                        ((lasthash = theApp.listensocket->hashbase[id]) != thishash))
                        {
                            // id changed, this is a id stealer !
                            leechertype = 4;
                            if (theApp.listensocket->offensecounter.find(id) != theApp.listensocket->offensecounter.end())
                            theApp.listensocket->offensecounter[id]++;
                            else
                            theApp.listensocket->offensecounter[id] = (uint32_t) 1;
                            theApp.listensocket->offensecounter[0]++;
                        }
                        theApp.listensocket->hashbase[id] = thishash;
                        // Famous stolen hashs/names [BlackRat]
                        if (m_pszUsername && (
                        strcmp(m_pszUsername, "pbwll") == 0 ||
                        strcmp(m_pszUsername, "unix user") == 0 ||
                        strstr(m_pszUsername, "Odin") == m_pszUsername) &&
                        !thief)
                        {
                            // This is a thief !!!
                            thief = true;
                            leechertype = 3;
                            if (theApp.listensocket->offensecounter.find(id) != theApp.listensocket->offensecounter.end())
                            theApp.listensocket->offensecounter[id]++;
                            else
                            theApp.listensocket->offensecounter[id] = 1;
                            theApp.listensocket->offensecounter[0]++;
                        }
                        if ((theApp.listensocket->offensecounter.find(id) != theApp.listensocket->offensecounter.end()) &&
                        (theApp.listensocket->offensecounter[id] >= 3))
                        {
                            // Made suspicious actions....
                            thief = true;
                        }
                    }
                    m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
                }
            }
        }
    }
    bool bIsMule = (dwEmuleTags &0x04) == 0x04;
    if (bIsMule)
    {
        m_bEmuleProtocol = true;
        m_byInfopacketsReceived |= IP_EMULEPROTPACK;
    }
    return bIsMule;
}

void CUpDownClient::SendHelloPacket()
{
    if (socket)
    {
        struct sockaddr_in sockAddr;
        memset( &sockAddr, 0, sizeof(sockAddr));

        //socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
        wxIPV4address address;
        socket->GetPeer(address);
        sockAddr.sin_addr.s_addr = GAddress_INET_GetHostAddress(address.GetAddress());
        if (theApp.ipfilter->IsFiltered(sockAddr.sin_addr.s_addr))
        {
            Disconnected();
            theApp.stat_filteredclients++;
            return;
        }
        CMemFile *data = new CMemFile();
        uint8_t hashsize = 16;
        data->Write( &hashsize, 1);
        SendHelloTypePacket(data);
        NewSocket_SendPacketOPdata(2, OP_HELLO, data, (uint32_t) this, 0);
        delete data;
        //faz:m_bHelloAnswerPending = true;
    }
}

void CUpDownClient::SendMuleInfoPacket(bool bAnswer)
{
    if (socket)
    {
        CMemFile *data = new CMemFile();
        uint8_t version = CURRENT_VERSION_SHORT;
        data->Write( &version, 1);
        uint8_t protversion = EMULE_PROTOCOL;
        data->Write( &protversion, 1);
//        uint32_t tagcount = 7;
        uint32_t tagcount = 8;

/*        if (!newprefs01_opt[3])
        {
            tagcount++;
        }*/

        data->Write( &tagcount, 4);
        CTag tag(ET_COMPRESSION, 1);
        tag.WriteTagToFile(data);
        CTag tag2(ET_UDPVER, 3);
        tag2.WriteTagToFile(data);
        CTag tag3(ET_UDPPORT, static_cast<uint16_t>(theApp.dynprefs->Get<long>("tcp-port")));
        tag3.WriteTagToFile(data);
        CTag tag4(ET_SOURCEEXCHANGE, 2);
        tag4.WriteTagToFile(data);
        CTag tag5(ET_COMMENTS, 1);
        tag5.WriteTagToFile(data);
        CTag tag6(ET_EXTENDEDREQUEST, 2);
        tag6.WriteTagToFile(data);
        uint32_t dwTagValue = (theApp.clientcredits->CryptoAvailable() ? 3: 0);
        CTag tag7(ET_FEATURES, dwTagValue);
        tag7.WriteTagToFile(data);

        CTag tag8(ET_COMPATIBLECLIENT, SO_XMULE);
        tag8.WriteTagToFile(data);

        CTag tag9(ET_MOD_VERSION, (char *)wxString::Format(wxT("%s v%s"), wxT(PACKAGE_NAME), wxT(PACKAGE_VERSION)).c_str());
        tag9.WriteTagToFile(data);
        // Maella end
        Packet *packet = new Packet(data, OP_EMULEPROT);
        delete data;

        if (!bAnswer)
        {
            NewSocket_SendPacketOP(2, OP_EMULEINFO, packet, (uint32_t) this, 1);
        }
        else
        {
            NewSocket_SendPacketOP(2, OP_EMULEINFOANSWER, packet, (uint32_t) this, 1);
        }
    }
}

void CUpDownClient::ProcessMuleInfoPacket(char *pachPacket, uint32_t nSize)
{
    CSafeMemFile *data = new CSafeMemFile((BYTE *) pachPacket, nSize);
    //The version number part of this packet will soon be useless since it is only able to go to v.99.
    //Why the version is a uint8_t and why it was not done as a tag like the eDonkey hello packet is not known..
    //Therefore, sooner or later, we are going to have to switch over to using the eDonkey hello packet to
    //set the version.
    //No sense making a third value sent for versions..
    m_byCompatibleClient = 0;
    if (data->Read( &m_byEmuleVersion, 1) == 1)
    {
        if (m_byEmuleVersion == 0x2B)
        {
            m_byEmuleVersion = 0x22;
        }
        uint8_t protversion;
        if (data->Read( &protversion, 1) == 1)
        {
            //implicitly supported options by older clients
            if (protversion == EMULE_PROTOCOL)
            {
                //in the future do not use version to guess about new features
                if (m_byEmuleVersion < 0x25 &&m_byEmuleVersion > 0x22)
                m_byUDPVer = 1;
                if (m_byEmuleVersion < 0x25 &&m_byEmuleVersion > 0x21)
                m_bySourceExchangeVer = 1;
                if (m_byEmuleVersion == 0x24)
                m_byAcceptCommentVer = 1;
                // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
                // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
                // directory which has a trailing backslash.
                // MLdonkey currently does not support shared directories:
                if (m_byEmuleVersion >= 0x28 && !m_bIsML) m_bSharedDirectories = true;
                m_bEmuleProtocol = true;
                uint32_t tagcount;
                if (data->Read( &tagcount, 4) == 4)
                {
                    for (unsigned int i = 0 ; i < tagcount ; i++)
                    {
                        CTag *temptag = new CTag(data);
                        switch (temptag->tag->specialtag)
                        {
                        case ET_COMPRESSION:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: data compression version
                            m_byDataCompVer = temptag->tag->intvalue;
                            break;
                        case ET_UDPPORT:
                            // Bits 31-16: 0 - reserved
                            // Bits 15- 0: UDP port
                            m_nUDPPort = temptag->tag->intvalue;
                            break;
                        case ET_UDPVER:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: UDP protocol version
                            m_byUDPVer = temptag->tag->intvalue;
                            break;
                        case ET_SOURCEEXCHANGE:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: source exchange protocol version
                            m_bySourceExchangeVer = temptag->tag->intvalue;
                            break;
                        case ET_COMMENTS:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: comments version
                            m_byAcceptCommentVer = temptag->tag->intvalue;
                            break;
                        case ET_EXTENDEDREQUEST:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: extended requests version
                            m_byExtendedRequestsVer = temptag->tag->intvalue;
                            break;
                        case ET_COMPATIBLECLIENT:
                            // Bits 31- 8: 0 - reserved
                            // Bits  7- 0: compatible client ID
                            m_byCompatibleClient = temptag->tag->intvalue;
                            break;
                        case ET_FEATURES:
                            // Bits 31- 8: 0 - reserved
                            // Bit	    7: Preview
                            // Bit   6- 0: secure identification
                            m_bySupportSecIdent = temptag->tag->intvalue &3;
                            m_bSupportsPreview = (temptag->tag->intvalue &128) > 0;
                            break;
                            //orig emule30e:
                        case ET_MOD_VERSION:
                            m_clientModString = temptag->tag->stringvalue;
                            break;
                            //for the future, i will prepare the use of sivka-ET_MOD_VERSION
                                case CT_EMULE_VERSION:
                                        m_byCompatibleClient = (temptag->tag->intvalue >> 24);
                                        m_nClientVersion = temptag->tag->intvalue & 0x00ffffff;
					break;
                        }
                        delete temptag;
                    }
                    if (m_byDataCompVer == 0)
                    {
                        m_bySourceExchangeVer = 0;
                        m_byExtendedRequestsVer = 0;
                        m_byAcceptCommentVer = 0;
                        m_nUDPPort = 0;
                    }
                    ReGetClientSoft();
                    m_byInfopacketsReceived |= IP_EMULEPROTPACK;
                    if (m_byInfopacketsReceived == IP_BOTH)
                    {
                        InfoPacketsReceived();
                    }
                }
            }
        }
    }
    delete data;
}

void CUpDownClient::SendHelloAnswer()
{
    CMemFile *data = new CMemFile();
    SendHelloTypePacket(data);
    if (socket)
    {
        NewSocket_SendPacketOPdata(2, OP_HELLOANSWER, data, (uint32_t) this, 0);
    }
    delete data;
}

void CUpDownClient::SendHelloTypePacket(CMemFile *data)
{
/*
unsigned char *uh;
uh=(unsigned char *)theApp.glob_prefs->GetUserHash();
for(int i=0;i<16;i++) {
printf("  %02x",uh[i]);
}
printf("\n");
*/

    data->Write(theApp.glob_prefs->GetUserHash(), 16);
    uint32_t clientid = theApp.serverconnect->GetClientID();
    data->Write( &clientid, 4);
    uint16_t nPort = static_cast<uint16_t>(theApp.dynprefs->Get<long>("tcp-port"));
    data->Write( &nPort, 2);
    uint32_t tagcount = 5;
    data->Write( &tagcount, 4);
    ////////START adding by sivka [xrmb: -HashThief Protection-]
    //to change from 1 to 5 -->theApp.glob_prefs->IsHashThiefProtectionEnabled()):
    if (theApp.dynprefs->Get<bool>("secure-ident"))
    {
        //IceCream, added counter measure for leecher-mod :p START
        if (m_pszUsername && (strstr(m_pszUsername, "G@m3r") == m_pszUsername ||strstr(m_pszUsername, "$WAREZ$") == m_pszUsername ||strstr(m_pszUsername, "Chief") == m_pszUsername))
        {
            // try to make the user of GPL-breaking clients read our info-site without spamming them in any way:
            if (m_bGPLEvildoer)
            {
                char *strUsedName;
                strUsedName = "Lies Mich! http://ReadMe.xmule-project.net <- Please use a GPL-conform version";
                CTag tagName(CT_NAME, strUsedName);
                tagName.WriteTagToFile(data);
            }
            else
            {
                CTag tagName(CT_NAME, m_pszUsername);
                tagName.WriteTagToFile(data);
            }
        }
        else
        {
            char *strUsedName;
            // try to make the user of GPL-breaking clients read our info-site without spamming them in any way:
            if (m_bGPLEvildoer)
            {
                strUsedName = "Lies Mich! http://ReadMe.xmule-project.net <- Please use a GPL-conform version";
            }
            else
            {
                strUsedName = const_cast<char *>(theApp.dynprefs->Get<wxString>("nickname").c_str());
            }

            CTag tagName(CT_NAME, strUsedName);
            tagName.WriteTagToFile(data);
        }
        //IceCream, added counter measure for leecher-mod :p END
    }
    else
    {
        char *strUsedName;
        // try to make the user of GPL-breaking clients read our info-site without spamming them in any way:
        if (m_bGPLEvildoer)
        {
            strUsedName = "Lies Mich! http://ReadMe.xmule-project.net <- Please use a GPL-conform version";
        }
        else
        {
            strUsedName = const_cast<char *>(theApp.dynprefs->Get<wxString>("nickname").c_str());
        }

        CTag tagName(CT_NAME, strUsedName);
        tagName.WriteTagToFile(data);
    }
        //CTag tagName(CT_NAME, theApp.glob_prefs->GetUserNick());
        //tagName.WriteTagToFile(data);
    ////////STOP adding by sivka [xrmb: -HashThief Protection-]
    CTag tagVersion(CT_VERSION, EDONKEYVERSION);
    tagVersion.WriteTagToFile(data);
    CTag tagUDPports(CT_EMULE_UDPPORTS, static_cast<uint32_t>(theApp.dynprefs->Get<long>("udp-port")));
    tagUDPports.WriteTagToFile(data);
    uint32_t uUdpVer;
    const uint32_t uDataCompVer = 1;
    const uint32_t uSupportSecIdent = theApp.clientcredits->CryptoAvailable() ? 3: 0;
    const uint32_t uSourceExchangeVer = 2;
    uint32_t uExtendedRequestsVer;
/*    if (newprefs02_opt[1])
    {
        uUdpVer = 4;
        uExtendedRequestsVer = 2;
    }
    else
    {*/
        uUdpVer = 3;
        uExtendedRequestsVer = 0;
//    }
    const uint32_t uAcceptCommentVer = 1;
    CTag tagMiscOptions(CT_EMULE_MISCOPTIONS1,
    (uUdpVer << 4 *6) | (uDataCompVer << 4 *5) | (uSupportSecIdent << 4 *4) | (uSourceExchangeVer << 4 *3) |
    (uExtendedRequestsVer << 4 *2) | (uAcceptCommentVer << 4));
    tagMiscOptions.WriteTagToFile(data);

    uint32_t dwIP;
/*  
    10     0000001 0001001 010     0000001 base 2
    client maj v   minor v release revision
*/
    CTag tagMuleVersion(CT_EMULE_VERSION, 
            (SO_XMULE << 26 - 2) + (MAJOR_VERSION << 26 - 7 - 2) +
            (MINOR_VERSION << 26 - 7 - 7 - 2) +
            (RELEASE_VERSION << 26 - 3 - 7 - 7 - 2) +
            REVISION_VERSION);
    tagMuleVersion.WriteTagToFile(data);
    if (theApp.serverconnect->IsConnected())
    {
        dwIP = theApp.serverconnect->GetCurrentServer()->GetIP();
        nPort = theApp.serverconnect->GetCurrentServer()->GetPort();
    }
    else
    {
        nPort = 0;
        dwIP = 0;
    }
    data->Write( &dwIP, 4);
    data->Write( &nPort, 2);
}

void CUpDownClient::ProcessMuleCommentPacket(char *pachPacket, uint32_t nSize)
{
    if (reqfile)
    {
        if (reqfile->IsPartFile())
        {
            unsigned int length;
            if (nSize > (sizeof(m_iRate) + sizeof(length) - 1))
            {
                CSafeMemFile data((BYTE *) pachPacket, nSize);
                if (sizeof(m_iRate) == data.Read( &m_iRate, sizeof(m_iRate)))
                {
                    if (sizeof(length) == data.Read( &length, sizeof(length)))
                    {
                        reqfile->SetHasRating(true);
                        if (length > data.GetLength() - data.GetPosition())
                        {
                            length = data.GetLength() - data.GetPosition();
                        }
                        if (length > 50) length = 50;
                        if (length > 0)
                        {
                            char *desc = new char[length + 1];
                            memset(desc, 0, length + 1);
                            length == data.Read(desc, length);
                            m_strComment.Printf("%s", desc);
                            reqfile->SetHasComment(true);
                            delete[] desc;
#if 0
                            if (0/*theApp.glob_prefs->GetCommentFilter() .GetLength() >0*/)
                            {
                                wxString resToken;
                                wxString strlink = theApp.glob_prefs->GetCommentFilter();
                                strlink.MakeLower();

                                ///resToken= strlink.Tokenize("|",curPos);
                                while (resToken != "")
                                {
                                    if (m_strComment.MakeLower() .Find(resToken) > - 1)
                                    {
                                        m_strComment = "";
                                        m_iRate = 0;
                                        reqfile->SetHasRating(false);
                                        reqfile->SetHasComment(false);
                                        break;
                                    }
                                    ///resToken= strlink.Tokenize("|",curPos);
                                }
                            }
#endif
                        }
                    }
                }
            }
            if (reqfile->HasRating() || reqfile->HasComment())
            {
                theApp.xmuledlg->transferwnd->downloadlistctrl->UpdateItem(reqfile);
            }
        }
    }
}

void CUpDownClient::Disconnected()
{
    if (GetUploadState() == US_UPLOADING)
    {
        theApp.uploadqueue->RemoveFromUploadQueue(this);
    }
    if (GetDownloadState() == DS_DOWNLOADING)
    {
        SetDownloadState(DS_ONQUEUE);
    }
    if (((GetDownloadState() == DS_REQHASHSET) ||m_bHashsetRequested) &&reqfile)
    {
        reqfile->hashsetneeded = true;
    }
    bool bDelete = true;
    switch (m_nDownloadState)
    {
    case DS_TOOMANYCONNS:
    case DS_NONEEDEDPARTS:
    case DS_LOWTOLOWIP:
        break;
    }
    switch (m_byUploadState)
    {
    case US_CONNECTING:
    case US_ONUPLOADQUEUE:
        bDelete = false;
        break;
    case US_WAITCALLBACK:
    case US_ERROR:
        bDelete = true;
        break;
    }
    switch (m_nDownloadState)
    {
    case DS_CONNECTING:
    case DS_ONQUEUE:
    case DS_CONNECTED:
    case DS_REQHASHSET:
        bDelete = false;
        break;
    case DS_WAITCALLBACK:
        {
            case DS_ERROR:
            bDelete = true;
        }
    }
    if (GetChatState())
    {
        bDelete = false;
    }
    if (socket)
    {
        socket->Safe_Delete();
    }
    socket = NULL;
    if (m_iFileListRequested)
    {
        m_iFileListRequested = 0;
    }
    if (m_Friend)
    {
        theApp.friendlist->RefreshFriend(m_Friend);
    }
    if (GetUploadState() == US_NONE)
    {
        if (GetDownloadState() == DS_NONE)
        {
            bDelete = false;
        }
    }
    if (!bDelete) {
        m_bHashsetRequested = false;
        m_dwEnteredConnectedState = 0;
        //faz:m_bHelloAnswerPending = 0;
    }
}

bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon)
{
    if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon && ! (socket &&socket->IsConnected()))
    {
        Disconnected();
        SetDownloadState(DS_ERROR);
        //socket->Safe_Delete();
        return false;
    }
    if ((theApp.serverconnect->GetClientID() < 16777216) &&HasLowID())
    {
        if (GetDownloadState() == DS_CONNECTING)
        {
            SetDownloadState(DS_LOWTOLOWIP);
        }
        else if(GetDownloadState() == DS_REQHASHSET)
        {
            SetDownloadState(DS_ONQUEUE);
            reqfile->hashsetneeded = true;
        }
        if (GetUploadState() == US_CONNECTING)
        {
            Disconnected();
            SetUploadState(DS_ERROR);
            //socket->Safe_Delete();
            return false;
        }
    }
    if (!socket)
    {
        socket = new CClientReqSocket(theApp.glob_prefs, this);
        if (!socket->Create())
        {
            socket->Safe_Delete();
            return false;
        }
    }
    else if(!socket->IsConnected())
    {
        SetDownloadState(DS_ERROR);
        SetUploadState(DS_ERROR);
        //socket->Safe_Delete();
        socket = new CClientReqSocket(theApp.glob_prefs, this);
        if (!socket->Create())
        {
            socket->Safe_Delete();
            return false;
        }
    }
    else
    {
        ConnectionEstablished();
        return true;
    }
    if (HasLowID())
    {
        if (GetDownloadState() == DS_CONNECTING)
        SetDownloadState(DS_WAITCALLBACK);
        if (GetUploadState() == US_CONNECTING)
        {
            Disconnected();
            SetUploadState(DS_ERROR);
            //socket->Safe_Delete();
            return false;
        }
        if (theApp.serverconnect->IsLocalServer(m_dwServerIP, m_nServerPort))
        {
            Packet *packet = new Packet(OP_CALLBACKREQUEST, 4);
            memcpy(packet->pBuffer, &m_nUserID, 4);
            theApp.uploadqueue->AddUpDataOverheadServer(packet->size);
#if defined(__DEBUG__)
//            printf("CUpDownClient::TryToConnect: OP_CALLBACKREQUEST size=%ld\n", packet->size);
#endif
            theApp.serverconnect->SendPacket(packet);
        }
        else
        {
            if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending))
            {
                theApp.downloadqueue->RemoveSource(this);
                Disconnected();
                return false;
            }
            else
            {
                if (GetDownloadState() == DS_WAITCALLBACK)
                {
                    m_bReaskPending = true;
                    SetDownloadState(DS_ONQUEUE);
                }
            }
        }
    }
    else
    {
        xmuleIPV4Address tmp;
        tmp.Hostname(GetFullIP());
        tmp.Service(GetUserPort());
#if defined(__DEBUG__)
        //printf("CUpDownClient::TryToConnect %s:%d  %s\n", (const char *) tmp->IPAddress(), tmp->Service(), GetFullIP());
#endif
        socket->Connect(tmp, FALSE);
        SendHelloPacket();
    }
    return true;
}

void CUpDownClient::ConnectionEstablished()
{
    m_cFailed = 0;
    // ok we have a connection, lets see if we want anything from this client
    if (GetChatState() == MS_CONNECTING)
    {
        //theApp.xmuledlg->chatwnd.chatselector.ConnectingResult(this,true);
        //arning CHATSELECTOR MISSING
    }
    switch (GetDownloadState())
    {
    case DS_CONNECTING:
    case DS_WAITCALLBACK:
        m_bReaskPending = false;
        SetDownloadState(DS_CONNECTED);
        SendFileRequest();
    }
    if (m_bReaskPending)
    {
        m_bReaskPending = false;
        if ((GetDownloadState() != DS_NONE) && (GetDownloadState() != DS_DOWNLOADING))
        {
            SetDownloadState(DS_CONNECTED);
            SendFileRequest();
        }
    }
    switch (GetUploadState())
    {
    case US_CONNECTING:
    case US_WAITCALLBACK:
        if (theApp.uploadqueue->IsDownloading(this))
        {
            SetUploadState(US_UPLOADING);
            NewSocket_SendPacketOPdata(2, OP_ACCEPTUPLOADREQ, NULL, (uint32_t) this, 0);
        }
    }
    if (m_iFileListRequested == 1)
    {
        if (m_bSharedDirectories)
        {
            NewSocket_SendPacketOPdata(2, OP_ASKSHAREDDIRS, NULL, (uint32_t) this, 0);
        }
        else
        {
            NewSocket_SendPacketOPdata(2, OP_ASKSHAREDFILES, NULL, (uint32_t) this, 0);
        }
    }
}

// modified by sivka [Maella: -Support for tag ET_MOD_VERSION 0x55-]
void CUpDownClient::ReGetClientSoft()
{
    int iHashType = GetHashType();

    if (m_pszUsername == NULL)
    {
        m_clientSoft = SO_UNKNOWN;
    }
    else if(iHashType == SO_OLDEMULE)
    {
        m_clientSoft = SO_OLDEMULE;
    }
    else if(iHashType == SO_EMULE)
    {
        switch (m_byCompatibleClient)
        {
        case SO_CDONKEY:
            m_clientSoft = SO_CDONKEY;
            break;
        case SO_AMULE:
            m_clientSoft = SO_AMULE;
            break;
        case SO_XMULE:
            m_clientSoft = SO_XMULE;
            break;
        case SO_SHAREAZA:
            m_clientSoft = SO_SHAREAZA;
            break;
        default:
            if (m_bIsML)
            {
                m_clientSoft = SO_MLDONKEY;
            }
            else if (m_bIsHybrid)
            {
                m_clientSoft = SO_EDONKEYHYBRID;
            }
            else
            {
                m_clientSoft = SO_EMULE;
            }
        }
        //return;
    }
    else if(m_bIsML || iHashType == SO_MLDONKEY)
    {
        m_clientSoft = SO_MLDONKEY;
    }
    else if(m_bIsHybrid)
    {
        m_clientSoft = SO_EDONKEYHYBRID;
    }
    else
    {
        m_clientSoft = SO_EDONKEY;
    }

    // Format name of client
    switch (GetClientSoft())
    {
        case SO_EDONKEY:
            m_clientVerString.Printf(wxT("eDonkey v%.1f"), static_cast<float>(GetVersion()) / 10.0f);
            break;
        case SO_EDONKEYHYBRID:
            m_clientVerString.Printf(wxT("eDonkeyHybrid v%.1f"), static_cast<float>(GetVersion()) / 10.0f);
            break;
        case SO_OLDEMULE:
            m_clientVerString.Printf(wxT("old eMule v%.2f"), static_cast<float>(GetVersion()) / 1000.0f);
            break;
        case SO_EMULE:
            m_clientVerString = wxT("eMule");
            break;
        case SO_CDONKEY:
            m_clientVerString.Printf(wxT("cDonkey v%.2f"), static_cast<float>(GetVersion()) / 1000.0f);
            break;
        case SO_AMULE:
            m_clientVerString = wxT("aMule");
            break;
        case SO_XMULE:
            m_clientVerString = wxT("xMule");
            break;
        case SO_MLDONKEY:
            m_clientVerString = _T("Old MlDonkey");
            break;
        case SO_SHAREAZA:
            m_clientVerString = wxT("Shareaza");
            break;
        default:
            m_clientVerString = GetResString(IDS_UNKNOWN);
    }
    
    if (iHashType == SO_EMULE)
    {
        if (m_byEmuleVersion != 0x99)
        {
            if (m_clientModString.IsEmpty() == false)
            {
                m_clientVerString += _T(" [");
                m_clientVerString += m_clientModString;
                m_clientVerString += _T("]");
                return;
            }

            wxString temp;
            long tmp_version;
            temp.Printf(wxT("%02X"), m_byEmuleVersion);
            temp.ToLong(&tmp_version);
            m_nClientVersion = tmp_version;
            m_nClientVersion *= 10;
            m_clientVerString.Printf(m_clientVerString + wxT(" v0.%02X"), GetMuleVersion());
        }
        else
        {
            uint32_t nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
            uint32_t nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
            uint32_t nClientUpVersion  = (m_nClientVersion >>  7) & 0x07;
            m_nClientVersion = form_version(nClientMajVersion, nClientMinVersion, nClientUpVersion);
            
            if (m_clientSoft == SO_EMULE)
            {
                m_clientVerString.Printf(m_clientVerString + wxT(" v%u.%u%c"), nClientMajVersion, nClientMinVersion, _T('a') + nClientUpVersion);
            }
            else if (m_clientSoft == SO_AMULE || nClientUpVersion != 0 || m_clientSoft == SO_XMULE)
            {
                m_clientVerString.Printf(m_clientVerString + wxT(" v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
            }
            else
            {
                m_clientVerString.Printf(m_clientVerString + wxT(" v%u.%u"), nClientMajVersion, nClientMinVersion);
            }
        }
    }
}

// Maella end

int CUpDownClient::GetHashType()
{
    if (m_achUserHash[5] == 13 &&m_achUserHash[14] == 110)
    return SO_OLDEMULE;
    else if(m_achUserHash[5] == 14 &&m_achUserHash[14] == 111)
    return SO_EMULE;
    else if(m_achUserHash[5] == 'M' &&m_achUserHash[14] == 'L')
    return SO_MLDONKEY;
    else
    return SO_UNKNOWN;
}

void CUpDownClient::SetUserName(char *pszNewName)
{
    if (m_pszUsername)
    delete[] m_pszUsername;
    if (pszNewName)
    m_pszUsername = nstrdup(pszNewName);
    else
    m_pszUsername = NULL;
}

void CUpDownClient::RequestSharedFileList()
{
    m_iFileListRequested = 1;
    (void) TryToConnect(true);
}

void CUpDownClient::ProcessSharedFileList(char *pachPacket, uint32_t nSize)
{
    if (m_iFileListRequested > 0)
    {
        m_iFileListRequested--;
        //FAZtheApp.searchlist->ProcessSearchanswer(pachPacket,nSize,this);
    }
}

wxString CUpDownClient::GetUploadFileInfo()
{
    if (this == NULL) return "";
    wxString sRet;
    // build info text and display it
    sRet.Printf(GetResString(IDS_USERINFO), GetUserName(), GetUserID());
    if (reqfile)
    {
        sRet += GetResString(IDS_SF_REQUESTED) + wxString(reqfile->GetFileName()) + "\n";
        wxString stat;
        stat.Printf(GetResString(IDS_FILESTATS_SESSION) + GetResString(IDS_FILESTATS_TOTAL),
        reqfile->statistic.GetAccepts(), reqfile->statistic.GetRequests(), CastItoXBytes(reqfile->statistic.GetTransfered()) .GetData(),
        reqfile->statistic.GetAllTimeAccepts(),
        reqfile->statistic.GetAllTimeRequests(), CastItoXBytes(reqfile->statistic.GetAllTimeTransfered()) .GetData());
        sRet += stat;
    }
    else
    {
        sRet += GetResString(IDS_REQ_UNKNOWNFILE);
    }
    return sRet;
    return "";
}

void CUpDownClient::Destroy()
{
    socket->Destroy();
}

void CUpDownClient::SetUserHash(unsigned char *m_achTempUserHash)
{
    if (m_achTempUserHash == NULL)
    {
        md4clr(m_achUserHash);
        return;
    }
    md4cpy(m_achUserHash, m_achTempUserHash);
}

void CUpDownClient::SendPublicKeyPacket()
{
    // delete this line later
    // send our public key to the client who requested it
    if (socket &&credits && (m_SecureIdentState == IS_KEYANDSIGNEEDED))
    {
        if (theApp.clientcredits->CryptoAvailable())
        {
            Packet *packet = new Packet(OP_PUBLICKEY, theApp.clientcredits->GetPubKeyLen() + 1, OP_EMULEPROT);
            memcpy(packet->pBuffer + 1, theApp.clientcredits->GetPublicKey(), theApp.clientcredits->GetPubKeyLen());
            packet->pBuffer[0] = theApp.clientcredits->GetPubKeyLen();
            NewSocket_SendPacketOP(2, OP_PUBLICKEY, packet, (uint32_t) this, 0);
            m_SecureIdentState = IS_SIGNATURENEEDED;
        }
    }
}

void CUpDownClient::ProcessSecIdentStatePacket(unsigned char *pachPacket, uint32_t nSize)
{
    if (nSize == 5)
    {
        if (credits)
        {
            switch (pachPacket[0])
            {
            case 0:
                m_SecureIdentState = IS_UNAVAILABLE;
                break;
            case 1:
                m_SecureIdentState = IS_SIGNATURENEEDED;
                break;
            case 2:
                m_SecureIdentState = IS_KEYANDSIGNEEDED;
                break;
            }
            uint32_t dwRandom;
            memcpy( &dwRandom, pachPacket+1, 4);
            credits->m_dwCryptRndChallengeFrom = dwRandom;
        }
    }
}

void CUpDownClient::SendSignaturePacket()
{
    // signate the public key of this client and send it
    if (socket &&credits &&m_SecureIdentState)
    {
        if (theApp.clientcredits->CryptoAvailable())
        {
            // We don't have his public key yet, will be back here later:
            if (credits->GetSecIDKeyLen())
            {
                // delete this line later
                // do we have a challenge value recieved (actually we should if we are in this function)
                if (credits->m_dwCryptRndChallengeFrom)
                {
                    // v2
                    // we will use v1 as default, except if only v2 is supported
                    bool bUseV2;
                    if ((m_bySupportSecIdent &1) == 1)
                    {
                        bUseV2 = false;
                    }
                    else
                    {
                        bUseV2 = true;
                    }
                    uint8_t byChaIPKind = 0;
                    uint32_t ChallengeIP = 0;
                    if (bUseV2)
                    {
                        if (theApp.serverconnect->GetClientID() == 0 || theApp.serverconnect->IsLowID())
                        {
                            // we cannot do not know for sure our public ip, so use the remote clients one
                            ChallengeIP = GetIP();
                            byChaIPKind = CRYPT_CIP_REMOTECLIENT;
                        }
                        else
                        {
                            ChallengeIP = theApp.serverconnect->GetClientID();
                            byChaIPKind = CRYPT_CIP_LOCALCLIENT;
                        }
                    }
                    //end v2
                    unsigned char achBuffer[250];
                    uint8_t siglen = theApp.clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP,byChaIPKind);
                    (void)theApp.clientcredits->VerifyIdent(credits, achBuffer, siglen, GetIP(),byChaIPKind);
                    if (siglen)
                    {
                        Packet *packet = new Packet(OP_SIGNATURE, siglen + 1 + ((bUseV2) ? 1: 0), OP_EMULEPROT);
                        packet->pBuffer[0] = siglen;
                        memcpy(packet->pBuffer + 1, achBuffer, siglen);
                        if (bUseV2)
                        {
                            packet->pBuffer[1 + siglen] = byChaIPKind;
                        }
                        NewSocket_SendPacketOP(2, OP_SIGNATURE, packet, (uint32_t) this, 0);
                        m_SecureIdentState = IS_ALLREQUESTSSEND;
                    }
                }
            }
        }
    }
}

void CUpDownClient::ResetFileStatusInfo()
{
    if (m_abyPartStatus)
    {
        delete[] m_abyPartStatus;
        m_abyPartStatus = NULL;
    }

    if (m_abyUpPartStatus)
    {
        delete[] m_abyPartStatus;
        m_abyPartStatus = NULL;
    }

    m_nPartCount = 0;
    m_strClientFilename = "";
    m_bCompleteSource = false;
    m_dwLastAskedTime = 0;
    m_iRate = 0;
    m_strComment = "";
}

 /*
 bool CUpDownClient::IsBanned() {
 return ((theApp.clientlist->IsBannedClient(GetIP()))&& m_nDownloadState != DS_DOWNLOADING);
 }
    */

void CUpDownClient::ProcessPublicKeyPacket(unsigned char *pachPacket, uint32_t nSize)
{
    //fsch2010removedtheApp.clientlist->AddTrackClient(this);
    /// delete this line later
    if (socket == NULL || credits == NULL || pachPacket[0] != nSize - 1
    || nSize == 0 || nSize > 250)
    {
        return;
    }
    if (theApp.clientcredits->CryptoAvailable())
    {
        // the function will handle everything (mulitple key etc)
        if (credits->SetSecureIdent(pachPacket + 1, pachPacket[0]))
        {
            // if this client wants a signature, now we can send him one
            if (m_SecureIdentState == IS_SIGNATURENEEDED)
            {
                SendSignaturePacket();
            }
            else if(m_SecureIdentState == IS_KEYANDSIGNEEDED)
            {
                // something is wrong
            }
        }
    }
}

void CUpDownClient::SendSecIdentStatePacket()
{
    // check if we need public key and signature
    uint8_t nValue = 0;
    if (credits)
    {
        if (theApp.clientcredits->CryptoAvailable())
        {
            if (credits->GetSecIDKeyLen() == 0)
            {
                nValue = IS_KEYANDSIGNEEDED;
            }
            else if(m_dwLastSignatureIP != GetIP())
            {
                nValue = IS_SIGNATURENEEDED;
            }
        }
        if (nValue)
        {
            // crypt: send random data to sign
            uint32_t dwRandom = rand() + 1;
            credits->m_dwCryptRndChallengeFor = dwRandom;
            Packet *packet = new Packet(OP_SECIDENTSTATE, 5, OP_EMULEPROT);
            packet->pBuffer[0] = nValue;
            memcpy(packet->pBuffer + 1, &dwRandom, sizeof(dwRandom));
            NewSocket_SendPacketOP(2, OP_SECIDENTSTATE, packet, (uint32_t) this, 0);
        }
    }
}

void CUpDownClient::ProcessSignaturePacket(unsigned char *pachPacket, uint32_t nSize)
{
    /// delete this line later
    // here we spread the good guys from the bad ones ;)
    if (socket == NULL || credits == NULL || nSize == 0 || nSize > 250)
    {
        return;
    }
    uint8_t byChaIPKind;
    if (pachPacket[0] == nSize - 1)
    {
        byChaIPKind = 0;
        //v2:
    }
    else if(pachPacket[0] == nSize - 2 && (m_bySupportSecIdent &2) > 0)
    {
        byChaIPKind = pachPacket[nSize - 1];
    }
    else
    {
        return;
    }
    if (theApp.clientcredits->CryptoAvailable())
    {
        // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
        if (m_dwLastSignatureIP != GetIP())
        {
            // also make sure this client has a public key
            if (credits->GetSecIDKeyLen())
            {
                // and one more check: did we ask for a signature and sent a challange packet?
                if (credits->m_dwCryptRndChallengeFor)
                {
                    (void)theApp.clientcredits->VerifyIdent(credits, pachPacket + 1, pachPacket[0], GetIP(),byChaIPKind);
                    m_dwLastSignatureIP = GetIP();
                }
            }
        }
    }
}

void CUpDownClient::InfoPacketsReceived()
{
    // indicates that both Information Packets has been received
    // needed for actions, which process data from both packets
    m_byInfopacketsReceived = IP_NONE;
    if (m_bySupportSecIdent)
    {
        SendSecIdentStatePacket();
    }
}

 /*
 void CUpDownClient::SendPreviewRequest(CAbstractFile* pForFile) {
 if (!m_bPreviewReqPending) {
 m_bPreviewReqPending = true;
 Packet* packet = new Packet(OP_REQUESTPREVIEW,16,OP_EMULEPROT);
 memcpy(packet->pBuffer,pForFile->GetFileHash(),16);
 printf("CUpDownClient::SendPreviewRequest: OP_REQUESTPREVIEW size=%ld\n",packet->size);
 SafeSendPacket(packet);
 } else {
 //to res table - later
 AddLogLine(true, GetResString(IDS_ERR_PREVIEWALREADY));
 }
 }
 void CUpDownClient::SendPreviewAnswer(CKnownFile* pForFile, CxImage** imgFrames, uint8_t nCount) {
 m_bPreviewAnsPending = false;
 CSafeMemFile data(1024);
 if (pForFile) {
 data.Write(pForFile->GetFileHash(),16);
 } else {
 char ZeroHash[16];
 md4clr(ZeroHash);
 data.Write(ZeroHash,16);
 }
 data.Write(&nCount,1);
 for (int i = 0; i != nCount; i++) {
 if (imgFrames == NULL) {
 wxASSERT (false);
 return;
 }
 CxImage* cur_frame = imgFrames[i];
 if (cur_frame == NULL) {
 wxASSERT (false);
 return;
 }
 BYTE* abyResultBuffer = NULL;
 long nResultSize = 0;
 if (!cur_frame->Encode(abyResultBuffer, nResultSize, CXIMAGE_FORMAT_PNG)) {
 wxASSERT (false);
 return;
 }
 data.Write(&nResultSize,4);
 data.Write(abyResultBuffer, nResultSize);
 free(abyResultBuffer);
 }
 Packet* packet = new Packet(&data, OP_EMULEPROT);
 packet->opcode = OP_PREVIEWANSWER;
 printf("CUpDownClient::SendPreviewAnswer: OP_PREVIEWANSWER size=%ld\n",packet->size);
 SafeSendPacket(packet);//okdeb
 }
 void CUpDownClient::ProcessPreviewReq(char* pachPacket, uint32_t nSize) {
 if (nSize < 16)
 throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
 if (m_bPreviewAnsPending|| theApp.glob_prefs->ServePreview() ==2|| (theApp.glob_prefs->ServePreview() ==1&& !IsFriend()))
 return;
 m_bPreviewAnsPending = true;
 CKnownFile* previewFile = theApp.sharedfiles->GetFileByID((unsigned char*) pachPacket);
 if (previewFile == NULL) {
 SendPreviewAnswer(NULL, NULL, 0);
 } else {
 previewFile->GrabImage(4,0,true,450,this);
 }
 }
 void CUpDownClient::ProcessPreviewAnswer(char* pachPacket, uint32_t nSize) {
 if (!m_bPreviewReqPending)
 return;
 m_bPreviewReqPending = false;
 CSafeMemFile data((BYTE*) pachPacket,nSize);
 unsigned char Hash[16];
 data.Read(Hash,16);
 uint8_t nCount;
 data.Read(&nCount,1);
 if (nCount == 0) {
 // to res table -later
 AddLogLine(true, GetResString(IDS_ERR_PREVIEWFAILED),GetUserName());
 return;
 }
 CSearchFile* sfile = theApp.searchlist->GetSearchFileByHash(Hash);
 if (sfile == NULL) {
 //already deleted
 return;
 }
 for (int i = 0; i != nCount; i++) {
 long nSize;
 data.Read(&nSize,4);
 BYTE* pBuffer = new BYTE[nSize];
 data.Read(pBuffer,nSize);
 CxImage* image = new CxImage(pBuffer, nSize,CXIMAGE_FORMAT_PNG);
 delete[] pBuffer;
 if (image->IsValid()) {
 sfile->AddPreviewImg(image);
 }
 }
 (new PreviewDlg())->SetFile(sfile);
 }
 // sends a packet, if needed it will establish a connection before
 // options used: ignore max connections, control packet, delete packet
 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
    */

bool CUpDownClient::SafeSendPacket(Packet *packet)
{
    if (socket)
    {
        if (socket->IsConnected())
        {
            NewSocket_SendPacket(4, packet, (uint32_t) this, 0);
        }
        else
        {
            m_WaitingPackets_list.AddTail(packet);
            return TryToConnect(true);
        }
    }
    else
    {
        m_WaitingPackets_list.AddTail(packet);
        return TryToConnect(true);
    }

    return false;
}

