//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.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"
#ifdef _DEBUG
#include "DebugHelpers.h"
#endif
#include "emule.h"
#include "UpDownClient.h"
#include "FriendList.h"
#include "Clientlist.h"
#include "OtherFunctions.h"
#include "PartFile.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "Friend.h"
#include <zlib/zlib.h>
#include "Packets.h"
#include "Opcodes.h"
#include "SafeFile.h"
#include "Preferences.h"
#include "Server.h"
#include "ClientCredits.h"
#include "IPFilter.h"
#include "Statistics.h"
#include "ServerConnect.h"
#include "DownloadQueue.h"
#include "UploadQueue.h"
#include "SearchFile.h"
#include "SearchList.h"
#include "SharedFileList.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Search.h"
#include "Kademlia/Kademlia/SearchManager.h"
#include "Kademlia/Utils/UInt128.h"
#include "Kademlia/Net/KademliaUDPListener.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferWnd.h"
#include "ChatWnd.h"
#include "CxImage/xImage.h"
#include "PreviewDlg.h"
#include "Exceptions.h"
#include "Peercachefinder.h"
#include "ClientUDPSocket.h"
#include "shahashset.h"
#include "Log.h"
#include "KnownFileList.h" // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#include "Neo/NeoVersion.h" // NEO: NV - [NeoVersion] <-- Xanatos --
#include "Neo/Functions.h" // NEO: MOD  <-- Xanatos --
#include "Neo/Defaults.h" // NEO: NEO <-- Xanatos --
#include "ClientDetailDialog.h" // NEO: MLD - [ModelesDialogs] <-- Xanatos --
#include "Neo/NeoOpCodes.h"// NEO: NXI - [NeoExtraInfo] <-- Xanatos --
#include "Neo/EMBackup.h" // NEO: NB - [NeoBackup]
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
#include "Neo/SourceList.h"
#endif // NEO_CD // NEO: NCD END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
#include "Neo/Argos.h"
#endif // ARGOS // NEO: NA END <-- Xanatos --
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
#include "Neo/Lancast.h"
#include "Neo/ClientFileStatus.h"// NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
#endif //LANCAST // NEO: NLC END <-- Xanatos --
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
#include "Neo/WebCache/WebCacheSocket.h"
#endif // NEO: WC END <-- Xanatos --
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
#include "Neo/AbstractSocket.h"
#include "Neo/NATSocket.h"
#include "neo/BandwidthControl/BandwidthControl.h"
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
#include "Neo/SocketEncryption.h"
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

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


//IMPLEMENT_DYNAMIC(CClientException, CException) // NEO: MOD - [UnusedCode] <-- Xanatos --
IMPLEMENT_DYNAMIC(CUpDownClient, CObject)

CUpDownClient::CUpDownClient(CClientReqSocket* sender)
:m_AvarageDDR_list(11) // NEO: MOD - [CodeImprovement] <-- Xanatos --
,m_AvarageUDR_list(11) // NEO: MOD - [CodeImprovement] <-- Xanatos --
{
	socket = sender;
	reqfile = NULL;
	Init();
}

CUpDownClient::CUpDownClient(CPartFile* in_reqfile, uint16 in_port, uint32 in_userid,uint32 in_serverip, uint16 in_serverport, bool ed2kID)
:m_AvarageDDR_list(11) // NEO: MOD - [CodeImprovement] <-- Xanatos --
,m_AvarageUDR_list(11) // NEO: MOD - [CodeImprovement] <-- Xanatos --
{
	//Converting to the HybridID system.. The ED2K system didn't take into account of IP address ending in 0..
	//All IP addresses ending in 0 were assumed to be a lowID because of the calculations.
	socket = NULL;
	reqfile = in_reqfile;
	Init();
	m_nUserPort = in_port;
	//If this is a ED2K source, check if it's a lowID.. If not, convert it to a HyrbidID.
	//Else, it's already in hybrid form.
	if(ed2kID && !IsLowID(in_userid))
		m_nUserIDHybrid = ntohl(in_userid);
	else
		m_nUserIDHybrid = in_userid;

	//If highID and ED2K source, incoming ID and IP are equal..
	//If highID and Kad source, incoming IP needs ntohl for the IP
	if (!HasLowID() && ed2kID)
		m_nConnectIP = in_userid;
	else if(!HasLowID())
		m_nConnectIP = ntohl(in_userid);
	m_dwServerIP = in_serverip;
	m_nServerPort = in_serverport;

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	CheckOnLAN(m_nConnectIP);
#endif //LANCAST // NEO: NLC END <-- Xanatos --
}

void CUpDownClient::Init()
{
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
	oldsocket = 0;
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	credits = 0;
	m_nSumForAvgUpDataRate = 0;
	//m_bAddNextConnect = false; // NEO: MOD - [NewUploadState] <-- Xanatos --
	m_nChatstate = MS_NONE;
	m_nKadState = KS_NONE;
	//m_cShowDR = 0; // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
	m_nUDPPort = 0;
	m_nKadPort = 0;
	m_nTransferredUp = 0;
	m_cAsked = 0;
	m_cDownAsked = 0;
	m_nUpDatarate = 0;
	//m_pszUsername = 0;
	m_strUsername.Empty(); // NEO: FIX - [StabilityFix] <-- Xanatos --
	m_nUserIDHybrid = 0;
	m_dwServerIP = 0;
	m_nServerPort = 0;
    m_iFileListRequested = 0;
	// NEO: XSF - [ExtendedSharedFiles] -- Xanatos -->
	m_bRequestingFileList = false;
	m_bFileListRequested = false;
	m_bDeniesShare = false;
	// NEO: XSF END <-- Xanatos --
	m_iSourceListRequested = 0; // NEO: MCH - [ManualClientHandling] <-- Xanatos --
	// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
	m_bNotifyIdChage = false; 
	m_bWainingNotifyIdChage = false; 
	// NEO: RIC END <-- Xanatos --
	m_dwLastUpRequest = 0;
	m_bEmuleProtocol = false;
	//m_bCompleteSource = false; // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
	m_bFriendSlot = false;
	m_bCommentDirty = false;
	m_bReaskPending = false;
	m_bUDPPending = false;
	m_byEmuleVersion = 0;
	m_nUserPort = 0;
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	//m_nPartCount = 0;
	//m_nUpPartCount = 0;
	//m_abyPartStatus = 0;
	//m_abyUpPartStatus = 0;
	m_nDownloadState = DS_NONE;
	m_dwUploadTime = 0;
	m_nTransferredDown = 0;
	m_nDownDatarate = 0;
	//m_nDownDataRateMS = 0; // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
	m_nUploadState = US_NONE;
	m_dwLastBlockReceived = 0;
	m_byDataCompVer = 0;
	m_byUDPVer = 0;
	m_bySourceExchangeVer = 0;
	m_byAcceptCommentVer = 0;
	m_byExtendedRequestsVer = 0;
	m_nRemoteQueueRank = 0;
	// NEO: CQR - [CollorQueueRank] -- Xanatos -->
	m_nInitialRemoteQueueRank = 0;
	m_nDeltaRemoteQueueRank = 0;
	// NEO: CQR END <-- Xanatos --
	m_dwLastSourceRequest = 0;
	m_dwLastSourceAnswer = 0;
	m_dwLastAskedForSources = 0;
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	m_dwLastSourcesSent = 0;
#endif // ARGOS // NEO: NA END <-- Xanatos --
	m_byCompatibleClient = 0;
	m_nSourceFrom = SF_SERVER;
	m_bIsHybrid = false;
	m_bIsML=false;
	m_Friend = NULL;
	// NEO: XC - [ExtendedComments] -- Xanatos --
	//m_uFileRating=0;
	//m_strFileComment.Empty();
	m_fMessageFiltered = 0;
	m_fIsSpammer = 0;
	m_cMessagesReceived = 0;
	m_cMessagesSent = 0;
	m_nCurSessionUp = 0;
	m_nCurSessionDown = 0;
	m_nSumForAvgDownDataRate = 0;
	m_clientSoft=SO_UNKNOWN;
	m_bRemoteQueueFull = false;
	md4clr(m_achUserHash);
	SetBuddyID(NULL);
	m_nBuddyIP = 0;
	m_nBuddyPort = 0;
	if (socket){
		SOCKADDR_IN sockAddr = {0};
		int nSockAddrLen = sizeof(sockAddr);
		socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
		SetIP(sockAddr.sin_addr.S_un.S_addr);
	}
	else{
		SetIP(0);
	}
	m_fHashsetRequesting = 0;
	m_fSharedDirectories = 0;
	m_fSentCancelTransfer = 0;
	m_nClientVersion = 0;
	m_lastRefreshedDLDisplay = 0;
	m_dwDownStartTime = 0;
	m_nLastBlockOffset = 0;
	m_bUnicodeSupport = false;
	m_SecureIdentState = IS_UNAVAILABLE;
	m_dwLastSignatureIP = 0;
	m_bySupportSecIdent = 0;
	m_byInfopacketsReceived = IP_NONE;
	m_lastPartAsked = (uint16)-1;
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	//m_nUpCompleteSourcesCount= 0;
	m_fSupportsPreview = 0;
	m_fPreviewReqPending = 0;
	m_fPreviewAnsPending = 0;
	m_bTransferredDownMini = false;
    m_addedPayloadQueueSession = 0;
    m_nCurQueueSessionPayloadUp = 0; // PENDING: Is this necessary? ResetSessionUp()...
    m_lastRefreshedULDisplay = ::GetTickCount();
#ifndef ARGOS // NEO: NA -- Xanatos -->
	m_bGPLEvildoer = false;
#endif // ARGOS // NEO: NA END <-- Xanatos --
	//m_bHelloAnswerPending = false;
	m_byHelloPacketState = HP_NONE; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
	m_byFileRequestState = FR_NONE; // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
	m_byNatTraversalState = NT_NONE;
	m_uLastNatTraversalTry = 0;
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
	// NEO: FSUR - [FixStartupLoadReq] -- Xanatos -->
	m_fActiveUpReqFlag = 0;
	m_fActiveDownReqFlag = 0;
	// NEO: FSUR END <-- Xanatos --
	m_fUpIsProblematic = 0; // NEO: UPC - [UploadingProblemClient] <-- Xanatos --
	m_fKeepAlivePending = 0; // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
	m_fNoViewSharedFiles = 0;
	m_bMultiPacket = 0;
	md4clr(requpfileid);
	m_nTotalUDPPackets = 0;
	m_nFailedUDPPackets = 0;
	m_nUrlStartPos = (uint64)-1;
	m_iHttpSendState = 0;
	m_fPeerCache = 0;
	m_uPeerCacheDownloadPushId = 0;
	m_uPeerCacheUploadPushId = 0;
	m_pPCDownSocket = NULL;
	m_pPCUpSocket = NULL;
	m_uPeerCacheRemoteIP = 0;
	m_ePeerCacheDownState = PCDS_NONE;
	m_ePeerCacheUpState = PCUS_NONE;
	m_bPeerCacheDownHit = false;
	m_bPeerCacheUpHit = false;
	m_fNeedOurPublicIP = 0;
    m_random_update_wait = (uint32)(rand()/(RAND_MAX/1000));
    m_dwLastTriedToConnect = ::GetTickCount()-/*20*60*1000*/thePrefs.GetReaskIntervalsMs(true); // ZZ:DownloadManager // NEO: DR - [DownloadReask] <-- Xanatos --
	m_fQueueRankPending = 0;
	m_fUnaskQueueRankRecv = 0;
	m_fFailedFileIdReqs = 0;
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
	m_dwShieldTime = 0;
	m_bUpEndSoon = false;
#else
    m_slotNumber = 0;
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
	accupfile = NULL; // NEO: MOD - [UploadingFile] <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	m_faileddownloads = 0;

	m_fileFNF = NULL;

	m_uFastUDPCounter = 0;

	m_uFastXSCounter = 0;
	m_uXSReqs = 0;
	m_uXSAnswer = 0;

	m_uNickChanges = 0;
	m_uLastNickChage = 0;

	m_uModChanges = 0;
	m_uLastModChage = 0;
#endif // ARGOS // NEO: NA END <-- Xanatos --
    lastSwapForSourceExchangeTick = 0;
	m_pReqFileAICHHash = NULL;
	m_fSupportsAICH = 0;
	m_fAICHRequested = 0;
	m_byKadVersion = 0;
	SetLastBuddyPingPongTime();
	m_fSentOutOfPartReqs = 0;
	m_bCollectionUploadSlot = false;
	m_fSupportsLargeFiles = 0;
	m_fExtMultiPacket = 0;

	m_iIsNeoMod = SO_NULL; // NEO: MID - [ModID] <-- Xanatos --

	m_FreeDownload = FALSE; // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
	m_bLanClient = false;
#endif //LANCAST // NEO: NLC END <-- Xanatos --

	m_bDisableSwaping = false; // NEO: MCM - [ManualClientManagement] <-- Xanatos --

	m_fileStatusMap.InitHashTable(29); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --

	// NEO: NMP - [NeoModProt] -- Xanatos -->
	m_NeoModProtVersion = 0;
	m_NeoXSVersion = 0; // NEO: NMPx - [NeoModProtXS]
	m_LowIDUDPPingSupport = 0;
	//m_UnsolicitedPartStatus = 0;
	// NEO: NMP END <-- Xanatos --

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	m_SecureCommunicationVer = 0;
	m_uRequierEncryption = 0;
	m_uSupportSecureCallback = 0;
	m_uPreferUnEnCryptedPayload = 0;
	m_uSimpleXOREncryption = 0;
	m_uPKEncrpytion = 0;
	// NEO: MP - [MultiPort]
	m_nRemoteSecurePort = 0;
	m_abyRemoteDHPrime = NULL;
	m_abyRemoteDHBase = 0;
	m_nLocalSecurePort = 0;
	// NEO: MP END
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	m_uUseNATEncrpytion = 0;
	m_KeyDataOut = NULL;
 #endif //NATTUNNELING // NEO: NATT END
	// NEO: SUC - [SafeUCPCommunication]
	m_uUseUDPSecurity = 0;
	m_UDPEncryption = NULL;
	// NEO: SUC END
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
	m_uNatTraversalVersion = 0;
	m_uNatPortRelaiable = 0;
	m_uNatCharacteristic = 0;
	m_nNatPort = 0;
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --

	m_IncompletePartVer = 0; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
	m_SubChunksVer = 0; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --

	// NEO: RPS - [RealPartStatus] -- Xanatos -->
	m_HidenPartStatusVer = 0;
	m_BlockedPartStatusVer = 0;
	// NEO: RPS END <-- Xanatos --

	// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
	m_ExtraInfoVer = 0;
	m_ExtraInfo = NULL;
	// NEO: NXI END <-- Xanatos --

	// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
	m_DownloadTimeVer = 0;
	SetRemoteEDT(0, EDT_UNDEFINED);
	// NEO: EDT END <-- Xanatos --

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	m_last_l2hac_exec = 0;
	m_L2HAC_time = 0;
	m_L2HAC_support = false;
	m_l2hac_enabled = false; // lowid side
	// NEO: L2H END <-- Xanatos --

	m_uFaildCount = 0; // NEO: TCR - [TCPConnectionRetry] <-- Xanatos --
	m_uLastSeen = 0; // NEO: NSS - [NeoSourceStorage] <-- Xanatos --

	requpfile = NULL; // NEO: MFSB - [MultiFileStatusBars] <-- Xanatos --

#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
	m_uLastLoadTime = 0;
#endif // NEO_SS // NEO: NSS END <-- Xanatos --

	m_uCacheStartTime = 0; // NEO: XSC - [ExtremeSourceCache] <-- Xanatos --

	m_bAdvertisementPending = false; // NEO: ASP - [ActiveSpreading] <-- Xanatos --

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
	source = NULL;
#endif // NEO_CD // NEO: NCD END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	m_bProxy = false;
	m_bIsAcceptingOurOhcbs = true;
	m_bIsTrustedOHCBSender = true;
	m_bIsAllowedToSendOHCBs = true;
	m_uWebCacheFlags = 0;
	m_pWCDownSocket = NULL;
	m_pWCUpSocket = NULL;
	m_WA_webCacheIndex = -1;
	m_bWebcacheFailedTry = false;
	m_bWebCacheSupport = false;
	m_uWebCacheDownloadId = 0;
	m_uWebCacheUploadId = 0;
	m_eWebCacheDownState = WCDS_NONE;
	m_eWebCacheUpState = WCUS_NONE;
	//	blocksLoaded = 0; //JP blocks are counted in the WCDownSocket code now
	b_webcacheInfoNeeded = false;
	//JP trusted OHCB-Senders Start
	WebCachedBlockRequests = 0;
	SuccessfulWebCachedBlockDownloads = 0;
	//JP trusted OHCB-Senders END
	// Superlexx - encryption
	Crypt.useNewKey = true;
	Crypt.isProxy = false;
	GenerateKey(Crypt.remoteMasterKey);	// generate a key - will be done right before sending
	memset(Crypt.localMasterKey, 0, WC_KEYLENGTH);
	// TODO: WC: remove this
	lastMultiOHCBPacketSent = 0; // Superlexx - Multi-OHCB
	m_bWebCacheSupportsMultiOHCBs = false;
#endif // NEO: WC END <-- Xanatos --

	m_detailDialogInterface = new CClientDetailDialogInterface(this); // NEO: MLD - [ModelesDialogs] <-- Xanatos --

#ifdef IP2COUNTRY // NEO: IP2C - [IPtoCountry] -- Xanatos -->
	m_structUserCountry = theApp.ip2country->GetCountryFromIP(GetIP());
#endif // IP2COUNTRY // NEO: IP2C END <-- Xanatos --
}

CUpDownClient::~CUpDownClient(){
	if (IsAICHReqPending()){
		m_fAICHRequested = FALSE;
		CAICHHashSet::ClientAICHRequestFailed(this);
	}

	theApp.clientlist->RemoveClient(this, _T("Destructing client object"));
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
	LinkSource(NULL); // detach source
#endif // NEO_CD // NEO: NCD END <-- Xanatos --
	if (m_Friend)
        m_Friend->SetLinkedClient(NULL);
	if (socket){
		socket->client = 0;
		socket->Safe_Delete();
	}
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
	if(oldsocket){
		ASSERT (theApp.listensocket->IsValidSocket(oldsocket));
		oldsocket->client = 0;
		oldsocket->Safe_Delete();
	}
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	if (m_pPCDownSocket){
		m_pPCDownSocket->client = NULL;
		m_pPCDownSocket->Safe_Delete();
	}
	if (m_pPCUpSocket){
		m_pPCUpSocket->client = NULL;
		m_pPCUpSocket->Safe_Delete();
	}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if (m_pWCDownSocket){
		m_pWCDownSocket->client = NULL;
		m_pWCDownSocket->Safe_Delete();
	}
	if (m_pWCUpSocket){
		m_pWCUpSocket->client = NULL;
		m_pWCUpSocket->Safe_Delete();
	}
#endif // NEO: WC END <-- Xanatos --
	//free(m_pszUsername); // NEO: FIX - [StabilityFix] -- Xanatos --

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	delete [] m_abyRemoteDHPrime; // NEO: MP - [MultiPort]
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	delete m_KeyDataOut;
 #endif //NATTUNNELING // NEO: NATT END
	delete m_UDPEncryption; // NEO: SUC - [SafeUCPCommunication]
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
	CClientFileStatus* value;
	const CKnownFile* key;
	POSITION pos = m_fileStatusMap.GetStartPosition();
	while (pos){
		m_fileStatusMap.GetNextAssoc(pos, key, value);
		delete value;
	}
	m_fileStatusMap.RemoveAll();
	// NEO: SCFS END <-- Xanatos --

	/*
	delete[] m_abyPartStatus;
	m_abyPartStatus = NULL;
	
	delete[] m_abyUpPartStatus;
	m_abyUpPartStatus = NULL;
	*/

	// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
	delete m_ExtraInfo;
	m_ExtraInfo = NULL;
	// NEO: NXI END <-- Xanatos --

	ClearUploadBlockRequests();

	// NEO: DBR - [DynamicBlockRequest] -- Xanatos --
	//for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;)
	//	delete m_DownloadBlocks_list.GetNext(pos);
	
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;)
		delete m_RequestedFiles_list.GetNext(pos);
	
	for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;){
		Pending_Block_Struct *pending = m_PendingBlocks_list.GetNext(pos);
		delete pending->block;
		// Not always allocated
		if (pending->zStream){
			inflateEnd(pending->zStream);
			delete pending->zStream;
		}
		delete pending;
	}

	for (POSITION pos = m_WaitingPackets_list.GetHeadPosition();pos != 0;)
		delete m_WaitingPackets_list.GetNext(pos);

	DEBUG_ONLY (theApp.listensocket->Debug_ClientDeleted(this));
	SetUploadFileID(NULL);

    m_fileReaskTimes.RemoveAll(); // ZZ:DownloadManager (one resk timestamp for each file)

	delete m_pReqFileAICHHash;

	// NEO: XSF - [ExtendedSharedFiles] -- Xanatos -->
	while (!m_listFiles.IsEmpty())
		delete m_listFiles.RemoveHead();
	// NEO: XSF END <-- Xanatos --

	// NEO: XCTA - [XmanExtenedCreditTableArragement] -- Xanatos -->
	if(Credits()){
		Credits()->SetLastSeen(); //ensure we keep the credits at least 6 hours in memory, without this line our LastSeen can be outdated if we did only UDP
		if(Credits()->IsEmpty())
			Credits()->MarkToDelete();
	}
	// NEO: XCTA END  <-- Xanatos --

#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
	ClearTags();
#endif // NEO_SS // NEO: NSS END <-- Xanatos --

	delete m_detailDialogInterface;	// NEO: MLD - [ModelesDialogs] <-- Xanatos --
}

void CUpDownClient::ClearHelloProperties()
{
	m_nUDPPort = 0;
	m_byUDPVer = 0;
	m_byDataCompVer = 0;
	m_byEmuleVersion = 0;
	m_bySourceExchangeVer = 0;
	m_byAcceptCommentVer = 0;
	m_byExtendedRequestsVer = 0;
	m_byCompatibleClient = 0;
	m_nKadPort = 0;
	m_bySupportSecIdent = 0;
	m_fSupportsPreview = 0;
	m_nClientVersion = 0;
	m_fSharedDirectories = 0;
	m_bMultiPacket = 0;
	m_fPeerCache = 0;
	m_uPeerCacheDownloadPushId = 0;
	m_uPeerCacheUploadPushId = 0;
	m_byKadVersion = 0;
	m_fSupportsLargeFiles = 0;
	m_fExtMultiPacket = 0;

	// NEO: NMP - [NeoModProt] -- Xanatos -->
	m_NeoModProtVersion = 0;
	m_NeoXSVersion = 0; // NEO: NMPx - [NeoModProtXS]
	m_LowIDUDPPingSupport = 0;
	//m_UnsolicitedPartStatus = 0;
	// NEO: NMP END <-- Xanatos --

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	m_SecureCommunicationVer = 0;
	m_uSupportSecureCallback = 0;
	m_uRequierEncryption = 0;
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	m_uUseNATEncrpytion = 0;
 #endif //NATTUNNELING // NEO: NATT END
	m_uUseUDPSecurity = 0; // NEO: SUC - [SafeUCPCommunication]
	m_uPreferUnEnCryptedPayload = 0;
	m_uSimpleXOREncryption = 0;
	m_uPKEncrpytion = 0;
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
	m_uNatCharacteristic = 0;
	m_uNatPortRelaiable = 0;
	m_uNatTraversalVersion = 0;
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --

	m_IncompletePartVer = 0; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
	m_SubChunksVer = 0; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --

	// NEO: RPS - [RealPartStatus] -- Xanatos -->
	m_HidenPartStatusVer = 0;
	m_BlockedPartStatusVer = 0;
	// NEO: RPS END <-- Xanatos --

	m_ExtraInfoVer = 0; // NEO: NXI - [NeoExtraInfo] <-- Xanatos --
	m_DownloadTimeVer = 0;// NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	m_L2HAC_time = 0;
	m_L2HAC_support = false;
	// NEO: L2H END <-- Xanatos --
}

bool CUpDownClient::ProcessHelloPacket(const uchar* pachPacket, uint32 nSize)
{
	CSafeMemFile data(pachPacket, nSize);
	uint8 HashSize = data.ReadUInt8(); // read size of userhash
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(thePrefs.IsArgosBadProtDetection()){
		if(HashSize != 16) // read size of userhash
			theApp.argos->DoArgos(GetConnectIP(),AR_BADPROT,1);
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --
	// reset all client properties; a client may not send a particular emule tag any longer
	ClearHelloProperties();
	m_byHelloPacketState = HP_HELLO; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
	return ProcessHelloTypePacket(&data);
}

bool CUpDownClient::ProcessHelloAnswer(const uchar* pachPacket, uint32 nSize)
{
	CSafeMemFile data(pachPacket, nSize);
	bool bIsMule = ProcessHelloTypePacket(&data);
	//m_bHelloAnswerPending = false;
	m_byHelloPacketState |= HP_HELLOANSWER; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	SendAUXPortWhenNeeded();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
	return bIsMule;
}

bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data)
{
	bool bDbgInfo = thePrefs.GetUseDebugDevice();
	m_strHelloInfo.Empty();
	// clear hello properties which can be changed _only_ on receiving OP_Hello/OP_HelloAnswer
	m_bIsHybrid = false;
	m_bIsML = false;
	m_fNoViewSharedFiles = 0;
	m_bUnicodeSupport = false;

	data->ReadHash16(m_achUserHash);
	if (bDbgInfo)
		m_strHelloInfo.AppendFormat(_T("Hash=%s (%s)"), md4str(m_achUserHash), DbgGetHashTypeString(m_achUserHash));
	m_nUserIDHybrid = data->ReadUInt32();
	if (bDbgInfo)
		m_strHelloInfo.AppendFormat(_T("  UserID=%u (%s)"), m_nUserIDHybrid, ipstr(m_nUserIDHybrid));
	uint16 nUserPort = data->ReadUInt16(); // hmm clientport is sent twice - why?
	if (bDbgInfo)
		m_strHelloInfo.AppendFormat(_T("  Port=%u"), nUserPort);
	
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	CList <TOpCode*> unknownOC;
	bool bNotOfficial = false;
	uint8 uOrder = 1;
	bool bOrderViolated = false;
	bool bTypeViolated = false;
	bool bBadPort = false;
#endif // ARGOS // NEO: NA END <-- Xanatos --

	DWORD dwEmuleTags = 0;
	bool bPrTag = false;
	uint32 tagcount = data->ReadUInt32();
	if (bDbgInfo)
		m_strHelloInfo.AppendFormat(_T("  Tags=%u"), tagcount);
	for (uint32 i = 0; i < tagcount; i++)
	{
		CTag temptag(data, true);
		switch (temptag.GetNameID())
		{
			case CT_NAME:
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				if(uOrder != 1)
					bOrderViolated = true;
				uOrder = 2;
#endif // ARGOS // NEO: NA END <-- Xanatos --
				if (temptag.IsStr()) {
					m_detailDialogInterface->UpdateTree(_T("")); // NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
					//free(m_pszUsername);
					//m_pszUsername = _tcsdup(temptag.GetStr());

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->

					if(thePrefs.IsArgosNickChangerDetection() && !m_strUsername.IsEmpty())
					{
						if(m_strUsername.Compare(temptag.GetStr()) != 0)
						{
							if(::GetTickCount() - m_uLastNickChage < thePrefs.GetArgosNickChangeIntervalsMs()) //last nickchane was in less than x hours
							{
								m_uNickChanges++;
								if(m_uNickChanges >= thePrefs.GetArgosNickChangeThreshold())
									theApp.argos->DoArgos(GetConnectIP(),AR_NICKCHANGER);
							}
							m_uLastNickChage = ::GetTickCount(); 
						}
						else if(m_uNickChanges > 0) //decrease the value if it's the same nick
								m_uNickChanges--;
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --

					m_strUsername = temptag.GetStr(); // NEO: FIX - [StabilityFix] <-- Xanatos --
					if (bDbgInfo){
						/*if (m_pszUsername){//filter username for bad chars
							TCHAR* psz = m_pszUsername;
							while (*psz != _T('\0')) {
								if (*psz == _T('\n') || *psz == _T('\r'))
									*psz = _T(' ');
								psz++;
							}
						}*/
						m_strUsername.Replace(_T('\n'),_T(' '));
						m_strUsername.Replace(_T('\r'),_T(' '));
						m_strHelloInfo.AppendFormat(_T("\n  Name='%s'"), m_strUsername);
					}
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			case CT_VERSION:
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				if(uOrder != 2)
					bOrderViolated = true;
				uOrder = 3;
#endif // ARGOS // NEO: NA END <-- Xanatos --
				if (temptag.IsInt()) {
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  Version=%u"), temptag.GetInt());
					m_nClientVersion = temptag.GetInt();
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			case CT_PORT:
				if (temptag.IsInt()) {
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  Port=%u"), temptag.GetInt());
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if (nUserPort != temptag.GetInt())
						bBadPort = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					nUserPort = (uint16)temptag.GetInt();
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			case CT_MOD_VERSION:
				if (temptag.IsStr()){
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					if(thePrefs.IsArgosModChangerDetection() && !m_strUsername.IsEmpty())
					{
						if(m_strModVersion.Compare(temptag.GetStr()) != 0)
						{
							if(::GetTickCount() - m_uLastModChage < thePrefs.GetArgosModChangeIntervalsMs()) //last mod string chane was in less than x hours
							{
								m_uModChanges++;
								if(m_uModChanges >= thePrefs.GetArgosModChangeThreshold())
									theApp.argos->DoArgos(GetConnectIP(),AR_MODCHANGER);
							}
							m_uLastModChage = ::GetTickCount(); 
						}
						else if(m_uModChanges > 0) //decrease the value if it's the same mod string
								m_uModChanges--;
					}
#endif // ARGOS // NEO: NA END <-- Xanatos --

					m_strModVersion = temptag.GetStr();
					// NEO: MID - [NeoID] -- Xanatos -->
					if(StrStrI(m_strModVersion,MOD_ID))
						m_iIsNeoMod = SO_NEO;
					else
						m_iIsNeoMod = SO_NULL;
					// NEO: MID END <-- Xanatos --
				}else if (temptag.IsInt())
					m_strModVersion.Format(_T("ModID=%u"), temptag.GetInt());
				else
					m_strModVersion = _T("ModID=<Unknwon>");
				if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ModID=%s"), m_strModVersion);
#ifndef ARGOS // NEO: NA -- Xanatos -->
				CheckForGPLEvilDoer();
#endif // ARGOS // NEO: NA END <-- Xanatos --
				break;
			case CT_EMULE_UDPPORTS:
				// 16 KAD Port
				// 16 UDP Port
				if (temptag.IsInt()) {
					m_nKadPort = (uint16)(temptag.GetInt() >> 16);
					m_nUDPPort = (uint16)temptag.GetInt();
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  KadPort=%u  UDPPort=%u"), m_nKadPort, m_nUDPPort);
					dwEmuleTags |= 1;
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;

			case CT_EMULE_BUDDYUDP:
				// 16 --Reserved for future use--
				// 16 BUDDY Port
				if (temptag.IsInt()) {
					m_nBuddyPort = (uint16)temptag.GetInt();
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  BuddyPort=%u"), m_nBuddyPort);
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;

			case CT_EMULE_BUDDYIP:
				// 32 BUDDY IP
				if (temptag.IsInt()) {
					m_nBuddyIP = temptag.GetInt();
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  BuddyIP=%s"), ipstr(m_nBuddyIP));
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;

			case CT_EMULE_MISCOPTIONS1:
				//  3 AICH Version (0 = not supported)
				//  1 Unicode
				//  4 UDP version
				//  4 Data compression version
				//  4 Secure Ident
				//  4 Source Exchange
				//  4 Ext. Requests
				//  4 Comments
				//	1 PeerChache supported
				//	1 No 'View Shared Files' supported
				//	1 MultiPacket
				//  1 Preview
				if (temptag.IsInt()) {
					m_fSupportsAICH			= (temptag.GetInt() >> 29) & 0x07;
					m_bUnicodeSupport		= (temptag.GetInt() >> 28) & 0x01;
					m_byUDPVer				= (uint8)((temptag.GetInt() >> 24) & 0x0f);
					m_byDataCompVer			= (uint8)((temptag.GetInt() >> 20) & 0x0f);
					m_bySupportSecIdent		= (uint8)((temptag.GetInt() >> 16) & 0x0f);
					m_bySourceExchangeVer	= (uint8)((temptag.GetInt() >> 12) & 0x0f);
					m_byExtendedRequestsVer	= (uint8)((temptag.GetInt() >>  8) & 0x0f);
					m_byAcceptCommentVer	= (uint8)((temptag.GetInt() >>  4) & 0x0f);
					m_fPeerCache			= (temptag.GetInt() >>  3) & 0x01;
					m_fNoViewSharedFiles	= (temptag.GetInt() >>  2) & 0x01;
					m_bMultiPacket			= (temptag.GetInt() >>  1) & 0x01;
					m_fSupportsPreview		= (temptag.GetInt() >>  0) & 0x01;
					dwEmuleTags |= 2;
					if (bDbgInfo) {
						m_strHelloInfo.AppendFormat(_T("\n  PeerCache=%u  UDPVer=%u  DataComp=%u  SecIdent=%u  SrcExchg=%u")
													_T("  ExtReq=%u  Commnt=%u  Preview=%u  NoViewFiles=%u  Unicode=%u"), 
													m_fPeerCache, m_byUDPVer, m_byDataCompVer, m_bySupportSecIdent, m_bySourceExchangeVer, 
													m_byExtendedRequestsVer, m_byAcceptCommentVer, m_fSupportsPreview, m_fNoViewSharedFiles, m_bUnicodeSupport);
					}
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			case CT_EMULE_MISCOPTIONS2:
				//	26 Reserved
				//   1 Ext Multipacket (Hash+Size instead of Hash)
				//   1 Large Files (includes support for 64bit tags)
				//   4 Kad Version
				if (temptag.IsInt()) {
					m_fExtMultiPacket		= (temptag.GetInt() >>  5) & 0x01;
					m_fSupportsLargeFiles   = (temptag.GetInt() >>  4) & 0x01;
					m_byKadVersion			= (uint8)((temptag.GetInt() >>  0) & 0x0f);
					dwEmuleTags |= 8;
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  KadVersion=%u, m_fSupportsLargeFiles=%u m_fExtMultiPacket=%u"), m_byKadVersion, m_fSupportsLargeFiles, m_fExtMultiPacket);
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			case CT_EMULE_VERSION:
				//  8 Compatible Client ID
				//  7 Mjr Version (Doesn't really matter..)
				//  7 Min Version (Only need 0-99)
				//  3 Upd Version (Only need 0-5)
				//  7 Bld Version (Only need 0-99) -- currently not used
				if (temptag.IsInt()) {
					m_byCompatibleClient = (uint8)((temptag.GetInt() >> 24));
					m_nClientVersion = temptag.GetInt() & 0x00ffffff;
					m_byEmuleVersion = 0x99;
					m_fSharedDirectories = 1;
					dwEmuleTags |= 4;
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ClientVer=%u.%u.%u.%u  Comptbl=%u"), (m_nClientVersion >> 17) & 0x7f, (m_nClientVersion >> 10) & 0x7f, (m_nClientVersion >> 7) & 0x07, m_nClientVersion & 0x7f, m_byCompatibleClient);
				}
				else{
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;

			// NEO: NMP - [NeoModProt] -- Xanatos -->
			case CT_NEO_FEATURES:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					//							= (uint8)(temptag.GetInt() >> 24) & 0xff;
					//							= (uint8)(temptag.GetInt() >> 16) & 0xff;
					m_NeoXSVersion				= (uint8)(temptag.GetInt() >> 12) & 0x0f; // NEO: NMPx - [NeoModProtXS]
					//							= (uint8)(temptag.GetInt() >> 10) & 0x03;
					m_LowIDUDPPingSupport		= (uint8)(temptag.GetInt() >> 9 ) & 0x01;
					//m_UnsolicitedPartStatus	= (uint8)(temptag.GetInt() >> 8 ) & 0x01;
					//							= (uint8)(temptag.GetInt() >> 4 ) & 0x0f;
					m_NeoModProtVersion			= (uint8)(temptag.GetInt() >> 0 ) & 0x0f;
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: NMP - [NeoModProt] <-- Xanatos --

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
			case CT_ISP_BYPASS:
 #ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
 #endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					if(GetNeoModProtVersion() != 0) // NEO: NMP - [NeoModProt]
						break; // we ignore this legacy tag and wait for the new one

					m_uPreferUnEnCryptedPayload	= (uint8)(temptag.GetInt() >>  10) & 0x01;
					m_uRequierEncryption		= (uint8)(temptag.GetInt() >>  8 ) & 0x03;
					//							= (uint8)(temptag.GetInt() >>  4 ) & 0x0f;
					m_SecureCommunicationVer	= (uint8)(temptag.GetInt() >>  0 ) & 0x0f;
					
					if(m_uRequierEncryption == 0 && m_SecureCommunicationVer >= 2)
						m_uPreferUnEnCryptedPayload = TRUE; // Let the user who wants encryption choice this setting

					if(m_uPreferUnEnCryptedPayload && thePrefs.IsPreferUnEnCryptedPayload() && socket->m_Encryption)
						socket->m_Encryption->SetPlainPayload();

					if(m_SecureCommunicationVer == 1)
						m_uSimpleXOREncryption = 1; // v1 is xor only
					if(m_SecureCommunicationVer <= 2)
						m_uPKEncrpytion = 1; // v1 and v2supports this by default

				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

			// NEO: ICS - [InteligentChunkSelection] -- Xanatos -->
			case ET_INCOMPLETEPARTS:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()) {
					m_IncompletePartVer = (uint8)temptag.GetInt();
					m_SubChunksVer		= (uint8)(temptag.GetInt() >>  16); // NEO: SCT - [SubChunkTransfer]
					if(IsNeoMod() == false) // X! For compytybility only neos ise v2 and SCT, so if it isn't a neo its v1 with sct
					{
						m_IncompletePartVer = 1;
						m_SubChunksVer = 0;
					}
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: ICS END <-- Xanatos --

			// NEO: RPS - [RealPartStatus] -- Xanatos -->
			case ET_REALPARTS:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_BlockedPartStatusVer	= (uint8)(temptag.GetInt() >>  16);
					m_HidenPartStatusVer	= (uint8)(temptag.GetInt() >>  8);
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: PRS END <-- Xanatos --

			// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
			case ET_EXTRAINFO:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_ExtraInfoVer = (uint8)temptag.GetInt();
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: NXI END <-- Xanatos --

			// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
			case ET_DOWNLOADTIME:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_DownloadTimeVer = (uint8)temptag.GetInt();
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: EDT END <-- Xanatos --

			// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
			case ET_L2HAC:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_L2HAC_time = temptag.GetInt();
					m_L2HAC_support = true;
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: L2H END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
			case WC_TAG_VOODOO:
 #ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
 #endif // ARGOS // NEO: NA END
				m_bWebCacheSupport = temptag.IsInt() && temptag.GetInt() == 'ARC4';
				break;
			case WC_TAG_FLAGS:
 #ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
 #endif // ARGOS // NEO: NA END
				if (m_bWebCacheSupport && temptag.IsInt())
				{
					m_uWebCacheFlags = temptag.GetInt();
					b_webcacheInfoNeeded = m_uWebCacheFlags & WC_FLAGS_INFO_NEEDED;
					m_bWebCacheSupportsMultiOHCBs = (m_uWebCacheFlags & WC_FLAGS_MULTI_OHCBS)!=0;
				}
				break;
#endif // NEO: WC END <-- Xanatos --

			default:
				// Since eDonkeyHybrid 1.3 is no longer sending the additional Int32 at the end of the Hello packet,
				// we use the "pr=1" tag to determine them.
				if (temptag.GetName() && temptag.GetName()[0]=='p' && temptag.GetName()[1]=='r') {
					bPrTag = true;
				}
				if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkTag=%s"), temptag.GetFullInfo());
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				bNotOfficial = true;
				if (thePrefs.IsArgosOpcodeDetection()){
					TOpCode* OpCode = new TOpCode;
					OpCode->OpSource = OC_HELLO;
					OpCode->OpCode = (uint8)temptag.GetNameID();
					OpCode->OpValue = temptag.IsInt() ?  temptag.GetInt() : 0;
					unknownOC.AddTail(OpCode);
				}
#endif // ARGOS // NEO: NA END <-- Xanatos --
		}
	}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	//bool bNullNick = (m_pszUsername == NULL);

	if (thePrefs.IsArgosOpcodeDetection()){
		while(!unknownOC.IsEmpty())
			theApp.argos->AddClientToTest(this,unknownOC.RemoveHead());
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	if (!m_L2HAC_time) 
		m_L2HAC_time = L2HAC_DEFAULT_EMULE;
	if (m_L2HAC_time < L2HAC_MIN_TIME){
		uint32 tmp=(L2HAC_MIN_TIME/m_L2HAC_time);
		if(L2HAC_MIN_TIME%m_L2HAC_time) tmp++;
		m_L2HAC_time=m_L2HAC_time*tmp;
	}
	// NEO: L2H END <-- Xanatos --

	m_nUserPort = nUserPort;
	m_dwServerIP = data->ReadUInt32();
	m_nServerPort = data->ReadUInt16();
	if (bDbgInfo)
		m_strHelloInfo.AppendFormat(_T("\n  Server=%s:%u"), ipstr(m_dwServerIP), m_nServerPort);

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	bool bUnexpectedBytes = data->GetPosition() < data->GetLength();
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// Check for additional data in Hello packet to determine client's software version.
	//
	// *) eDonkeyHybrid 0.40 - 1.2 sends an additional Int32. (Since 1.3 they don't send it any longer.)
	// *) MLdonkey sends an additional Int32
	//
	if (data->GetLength() - data->GetPosition() == sizeof(uint32)){
		uint32 test = data->ReadUInt32();
		if (test == 'KDLM'){
			m_bIsML = true;
			if (bDbgInfo)
				m_strHelloInfo += _T("\n  ***AddData: \"MLDK\"");
		}
		else{
			m_bIsHybrid = true;
			if (bDbgInfo)
				m_strHelloInfo.AppendFormat(_T("\n  ***AddData: uint32=%u (0x%08x)"), test, test);
		}
	}
	else if (bDbgInfo && data->GetPosition() < data->GetLength()){
		UINT uAddHelloDataSize = (UINT)(data->GetLength() - data->GetPosition());
		if (uAddHelloDataSize == sizeof(uint32)){
			DWORD dwAddHelloInt32 = data->ReadUInt32();
			m_strHelloInfo.AppendFormat(_T("\n  ***AddData: uint32=%u (0x%08x)"), dwAddHelloInt32, dwAddHelloInt32);
		}
		else if (uAddHelloDataSize == sizeof(uint32)+sizeof(uint16)){
			DWORD dwAddHelloInt32 = data->ReadUInt32();
			WORD w = data->ReadUInt16();
			m_strHelloInfo.AppendFormat(_T("\n  ***AddData: uint32=%u (0x%08x),  uint16=%u (0x%04x)"), dwAddHelloInt32, dwAddHelloInt32, w, w);
		}
		else
			m_strHelloInfo.AppendFormat(_T("\n  ***AddData: %u bytes"), uAddHelloDataSize);
	}

	SOCKADDR_IN sockAddr = {0};
	int nSockAddrLen = sizeof(sockAddr);
	socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
	SetIP(sockAddr.sin_addr.S_un.S_addr);
#ifdef IP2COUNTRY // NEO: IP2C - [IPtoCountry] -- Xanatos -->
	m_structUserCountry = theApp.ip2country->GetCountryFromIP(GetIP());
#endif // IP2COUNTRY // NEO: IP2C END <-- Xanatos --

	if (thePrefs.GetAddServersFromClients() && m_dwServerIP && m_nServerPort){
		CServer* addsrv = new CServer(m_nServerPort, ipstr(m_dwServerIP));
		addsrv->SetListName(addsrv->GetAddress());
		if (!theApp.emuledlg->serverwnd->serverlistctrl.AddServer(addsrv, true))
			delete addsrv;
	}

	//(a)If this is a highID user, store the ID in the Hybrid format.
	//(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
	//(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
	//because they will send a ID that is the same as their IP..
	if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP ) 
		m_nUserIDHybrid = ntohl(m_dwUserIP);

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	if(socket->m_Socket->IsNatSocket())
		m_nNatPort = ntohs(sockAddr.sin_port);
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if (thePrefs.IsArgosCreditHackDetection()){
		bool bCH =  (md4cmp(m_achUserHash, thePrefs.GetUserHash())==0 && theApp.GetID()!= m_nUserIDHybrid); //if client is using my Hash ban him!
		if(thePrefs.UseArgosSystem()){
			if(bCH) 
				theApp.argos->DoArgos(GetConnectIP(),AR_CREDITHACK);
			else if(theApp.argos->IsArgos(GetConnectIP(),AR_CREDITHACK))
				theApp.argos->UnArgos(GetConnectIP(),AR_CREDITHACK);
		}else if(bCH)
			Ban(_T("Credit hack detected"));
	}

	if(thePrefs.IsClassicHashChangeDetection()){
#endif // ARGOS // NEO: NA END <-- Xanatos --

   		CClientCredits* pFoundCredits = theApp.clientcredits->GetCredit(m_achUserHash);
		if (credits == NULL){
			credits = pFoundCredits;
			//if (!theApp.clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, pFoundCredits)){
			if (!theApp.clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, m_achUserHash)){ // NEO: XCTA - [XmanExtenedCreditTableArragement] <-- Xanatos --
				if (thePrefs.GetLogBannedClients())
					AddDebugLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed (Found in TrackedClientsList)"), GetUserName(), ipstr(GetConnectIP()));
 #ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				if(thePrefs.UseArgosSystem())
					theApp.argos->DoArgos(GetConnectIP(),AR_HASHCHANGED,TRUE);
				else
 #endif // ARGOS // NEO: NA END <-- Xanatos --
					Ban();
			}	
		}
		else if (credits != pFoundCredits){
			// NEO: XCTA - [XmanExtenedCreditTableArragement] -- Xanatos -->
			credits->SetLastSeen(); //ensure to keep it at least 5 hours
			if(credits->IsEmpty())
				credits->MarkToDelete(); //check also if the old hash is used by an other client
			// NEO: XCTA END  <-- Xanatos --
			// userhash change ok, however two hours "waittime" before it can be used
			credits = pFoundCredits;
			if (thePrefs.GetLogBannedClients())
				AddDebugLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed"), GetUserName(), ipstr(GetConnectIP()));
 #ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
			if(thePrefs.UseArgosSystem())
				theApp.argos->DoArgos(GetConnectIP(),AR_HASHCHANGED,FALSE);
			else
 #endif // ARGOS // NEO: NA END <-- Xanatos --
				Ban();
		}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	}else
	   credits = theApp.clientcredits->GetCredit(m_achUserHash);
#endif // ARGOS // NEO: NA END <-- Xanatos --

	if (CFriend* new_friend = theApp.friendlist->SearchFriend(m_achUserHash, m_dwUserIP, m_nUserPort)){ // NEO: FIX <-- Xanatos --
		// Link the friend to that client 
		m_Friend=new_friend; // NEO: FIX <-- Xanatos --
		m_Friend->SetLinkedClient(this); 
	} 
	else{ 
		// avoid that an unwanted client instance keeps a friend slot 
		SetFriendSlot(false); 
		// NEO: FIX -- Xanatos -->
		if (m_Friend) 
			m_Friend->SetLinkedClient(NULL); // morph, does this help agianst chrashing due to friend slots? 
		m_Friend=NULL;//is newfriend 
		// NEO: FIX <-- Xanatos --
	} 

#ifndef ARGOS // NEO: NA -- Xanatos -->
	// check for known major gpl breaker
	CString strBuffer = m_strUsername; // NEO: FIX - [StabilityFix] <-- Xanatos --
	strBuffer.MakeUpper();
	strBuffer.Remove(_T(' '));
	if (strBuffer.Find(_T("EMULE-CLIENT")) != -1 || strBuffer.Find(_T("POWERMULE")) != -1 ){
		m_bGPLEvildoer = true;  
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --

	m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
	// check if at least CT_EMULEVERSION was received, all other tags are optional
	bool bIsMule = (dwEmuleTags & 0x04) == 0x04;
	if (bIsMule){
		m_bEmuleProtocol = true;
		m_byInfopacketsReceived |= IP_EMULEPROTPACK;
	}
	else if (bPrTag){
		m_bIsHybrid = true;
	}

	InitClientSoftwareVersion();

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
	if(thePrefs.EnableSourceList()){
		// NEO: SHM - [SourceHashMonitor]
		if(!thePrefs.UseSourceHashMonitor() // if Source Monitor is disabled
		 || theApp.sourcelist->MonitorSource(this)){ // Of source chack is OK
			LinkSource(theApp.sourcelist->GetSource(m_achUserHash)); // give a source object to this clinet
			source->Assimilate(this); // and update it
		}else
			LinkSource(NULL);
		// NEO: SHM END
	}
#endif // NEO_CD // NEO: NCD END <-- Xanatos --

	if (m_bIsHybrid)
		m_fSharedDirectories = 1;

	if (thePrefs.GetVerbose() && GetServerIP() == INADDR_NONE)
		AddDebugLogLine(false, _T("Received invalid server IP %s from %s"), ipstr(GetServerIP()), DbgGetClientInfo());

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(thePrefs.UseArgosSystem()){
		if(bUnexpectedBytes || bTypeViolated || bOrderViolated || bBadPort){
			//bNotOfficial = true; // for now lets separate this two things

			if(thePrefs.IsArgosBadHelloDetection()){
				UINT uFlag = 0;

				if(bUnexpectedBytes && GetClientSoft() == SO_EMULE) // other software may send extra bytes fo example the MLdonkey
					uFlag |= 1;
				if(bOrderViolated && GetClientSoft() == SO_EMULE) // other software may also use an other order
					uFlag |= 2;
				if(bTypeViolated) // other clinets should send us the proper tag type
					uFlag |= 4;
				if(bBadPort) // the port is sended twice i very good place to hide some datas
					uFlag |= 8;
				
				if(thePrefs.IsArgoseMCryptDetection()){
					//Xman remark: I only check for 0.44d. 
					if(m_nClientVersion == MAKE_CLIENT_VERSION(0,44,3) && m_strModVersion.IsEmpty() && m_byCompatibleClient==0 && m_bUnicodeSupport==false && bIsMule)
						uFlag |= 16;
					else if(theApp.argos->IsArgos(GetConnectIP(),AR_BADHELLO,16))
						theApp.argos->UnArgos(GetConnectIP(),AR_BADHELLO,16); //unban, it isn't any longer a emcrypt
				}

				if(uFlag)
					theApp.argos->DoArgos(GetConnectIP(),AR_BADHELLO,uFlag);
			}
		}

		theApp.argos->CheckClient(this, bNotOfficial);
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --

	return bIsMule;
}

// returns 'false', if client instance was deleted!
bool CUpDownClient::SendHelloPacket(){
	if (socket == NULL){
		ASSERT(0);
		return true;
	}

	CSafeMemFile data(128);
	data.WriteUInt8(16); // size of userhash
	SendHelloTypePacket(&data);
	Packet* packet = new Packet(&data);
	packet->opcode = OP_HELLO;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__Hello", this);
	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet,true);

	//m_bHelloAnswerPending = true;
	m_byHelloPacketState = HP_HELLO; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
	return true;
}

void CUpDownClient::SendMuleInfoPacket(bool bAnswer){
	if (socket == NULL){
		ASSERT(0);
		return;
	}

	CSafeMemFile data(128);
	data.WriteUInt8((uint8)theApp.m_uCurVersionShort);
	data.WriteUInt8(EMULE_PROTOCOL);
	// NEO: MOD -- Xanatos -->
	uint32 tagcount=7;

	bool NotMod = m_strModVersion.IsEmpty() && m_strUsername.IsEmpty() == false; // NEO: MOD <-- Xanatos --

	if(NotMod == false) // NEO: MOD <-- Xanatos --
	{
			tagcount += 1; // NEO: MID - [NeoID] <-- Xanatos -- 
		if (thePrefs.UseInteligentChunkSelection() || thePrefs.UseSubChunkTransfer()) tagcount += 1; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
		if (thePrefs.UseEstimatedDownloadTime()) tagcount += 1; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
		if (thePrefs.UseLowID2HighIDAutoCallback()) tagcount += 1; // NEO: L2H - [LowID2HighIDAutoCallback] <-- Xanatos --
	}

	data.WriteUInt32(tagcount); // nr. of tags
	// NEO: MOD END <-- Xanatos --
	CTag tag(ET_COMPRESSION,1);
	tag.WriteTagToFile(&data);
	CTag tag2(ET_UDPVER,4);
	tag2.WriteTagToFile(&data);
	CTag tag3(ET_UDPPORT,thePrefs.GetUDPPort());
	tag3.WriteTagToFile(&data);
	CTag tag4(ET_SOURCEEXCHANGE,3);
	tag4.WriteTagToFile(&data);
	CTag tag5(ET_COMMENTS,2); // NEO: XC - [ExtendedComments] <-- Xanatos --
	tag5.WriteTagToFile(&data);
	CTag tag6(ET_EXTENDEDREQUEST,2);
	tag6.WriteTagToFile(&data);

	uint32 dwTagValue = (theApp.clientcredits->CryptoAvailable() ? 3 : 0);
	if (thePrefs.UseCustomPermissions() || thePrefs.CanSeeShares() != vsfaNobody) // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
		dwTagValue |= 128; // set 'Preview supported' only if 'View Shared Files' allowed
	CTag tag7(ET_FEATURES, dwTagValue);
	tag7.WriteTagToFile(&data);

	if(NotMod == false) // NEO: MOD <-- Xanatos --
	{
		// NEO: MID - [ModID] -- Xanatos -->
		{
			CTag tag8(ET_MOD_VERSION, CString(MOD_VERSION));
			tag8.WriteTagToFile(&data);
		}
		// NEO: MID END <-- Xanatos --

		// NEO: ICS - [InteligentChunkSelection] -- Xanatos -->
		if(thePrefs.UseInteligentChunkSelection() || thePrefs.UseSubChunkTransfer()){ // NEO: SCT - [SubChunkTransfer]
			uint32 uVersions =	((thePrefs.UseSubChunkTransfer()			? 1 : 0) << 16) | // NEO: SCT - [SubChunkTransfer]
								((thePrefs.UseInteligentChunkSelection()	? 2 : 0) <<  0);
			CTag tagIncompleteParts(ET_INCOMPLETEPARTS,uVersions);
			tagIncompleteParts.WriteTagToFile(&data);
		}
		// NEO: ICS END <-- Xanatos --

		// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
		if(thePrefs.UseEstimatedDownloadTime()){
			CTag tag12(ET_DOWNLOADTIME,1);
			tag12.WriteTagToFile(&data);
		}
		// NEO: EDT END <-- Xanatos --

		// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
		if(thePrefs.UseLowID2HighIDAutoCallback()){
			CTag tag13(ET_L2HAC,GetReqFileReaskIntervals());	
			tag13.WriteTagToFile(&data); 
		}
		// NEO: L2H END <-- Xanatos --
	}

	Packet* packet = new Packet(&data,OP_EMULEPROT);
	if (!bAnswer)
		packet->opcode = OP_EMULEINFO;
	else
		packet->opcode = OP_EMULEINFOANSWER;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend(!bAnswer ? "OP__EmuleInfo" : "OP__EmuleInfoAnswer", this);
	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet,true,true);
}

void CUpDownClient::ProcessMuleInfoPacket(const uchar* pachPacket, uint32 nSize)
{
	bool bDbgInfo = thePrefs.GetUseDebugDevice();
	m_strMuleInfo.Empty();
	CSafeMemFile data(pachPacket, nSize);
	m_byCompatibleClient = 0;
	m_byEmuleVersion = data.ReadUInt8();
	if (bDbgInfo)
		m_strMuleInfo.AppendFormat(_T("EmuleVer=0x%x"), (UINT)m_byEmuleVersion);
	if( m_byEmuleVersion == 0x2B )
		m_byEmuleVersion = 0x22;
	uint8 protversion = data.ReadUInt8();
	if (bDbgInfo)
		m_strMuleInfo.AppendFormat(_T("  ProtVer=%u"), (UINT)protversion);

	//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.
		if(m_byEmuleVersion >= 0x28 && !m_bIsML) // MLdonkey currently does not support shared directories
			m_fSharedDirectories = 1;

	} else {
		return;
	}
	m_bEmuleProtocol = true;
	m_IncompletePartVer = 0; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
	m_SubChunksVer = 0; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --
	m_DownloadTimeVer = 0; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	m_L2HAC_time = 0;
	m_L2HAC_support = false;
	// NEO: L2H END <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	CList <TOpCode*> unknownOC;
	bool bNotOfficial = false;
	bool bTypeViolated = false;
#endif // ARGOS // NEO: NA END <-- Xanatos --

	uint32 tagcount = data.ReadUInt32();
	if (bDbgInfo)
		m_strMuleInfo.AppendFormat(_T("  Tags=%u"), (UINT)tagcount);
	for (uint32 i = 0; i < tagcount; i++)
	{
		CTag temptag(&data, false);
		switch (temptag.GetNameID())
		{
			case ET_COMPRESSION:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: data compression version
				if (temptag.IsInt()) {
					m_byDataCompVer = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  Compr=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_UDPPORT:
				// Bits 31-16: 0 - reserved
				// Bits 15- 0: UDP port
				if (temptag.IsInt()) {
					m_nUDPPort = (uint16)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  UDPPort=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_UDPVER:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: UDP protocol version
				if (temptag.IsInt()) {
					m_byUDPVer = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  UDPVer=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_SOURCEEXCHANGE:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: source exchange protocol version
				if (temptag.IsInt()) {
					m_bySourceExchangeVer = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  SrcExch=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_COMMENTS:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: comments version
				if (temptag.IsInt()) {
					m_byAcceptCommentVer = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  Commnts=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_EXTENDEDREQUEST:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: extended requests version
				if (temptag.IsInt()) {
					m_byExtendedRequestsVer = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ExtReq=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_COMPATIBLECLIENT:
				// Bits 31- 8: 0 - reserved
				// Bits  7- 0: compatible client ID
				if (temptag.IsInt()) {
					m_byCompatibleClient = (uint8)temptag.GetInt();
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  Comptbl=%u"), (UINT)temptag.GetInt());
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			
			case ET_FEATURES:
				// Bits 31- 8: 0 - reserved
				// Bit	    7: Preview
				// Bit   6- 0: secure identification
				if (temptag.IsInt()) {
					m_bySupportSecIdent = (uint8)((temptag.GetInt()) & 3);
					m_fSupportsPreview  = (temptag.GetInt() >> 7) & 1;
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  SecIdent=%u  Preview=%u"), m_bySupportSecIdent, m_fSupportsPreview);
				}
				else{ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
					bTypeViolated = true;
#endif // ARGOS // NEO: NA END <-- Xanatos --
					if (bDbgInfo)
						m_strMuleInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
					}
				break;
			case ET_MOD_VERSION:
				if (temptag.IsStr()){
					m_strModVersion = temptag.GetStr();
					// NEO: MID - [NeoID] -- Xanatos -->
					if(StrStrI(m_strModVersion,MOD_ID))
						m_iIsNeoMod = SO_NEO;
					else
						m_iIsNeoMod = SO_NULL;
					// NEO: MID END <-- Xanatos --
				}else if (temptag.IsInt())
					m_strModVersion.Format(_T("ModID=%u"), temptag.GetInt());
				else
					m_strModVersion = _T("ModID=<Unknwon>");
				if (bDbgInfo)
					m_strMuleInfo.AppendFormat(_T("\n  ModID=%s"), m_strModVersion);
#ifndef ARGOS // NEO: NA -- Xanatos -->
				CheckForGPLEvilDoer();
#endif // ARGOS // NEO: NA END <-- Xanatos --
				break;
			// NEO: ICS - [InteligentChunkSelection] -- Xanatos -->
			case ET_INCOMPLETEPARTS:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_IncompletePartVer = (uint8)temptag.GetInt();
					m_SubChunksVer		= (uint8)(temptag.GetInt() >>  16); // NEO: SCT - [SubChunkTransfer]
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: ICS END <-- Xanatos --
			// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
			case ET_DOWNLOADTIME:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_DownloadTimeVer = (uint8)temptag.GetInt();
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: EDT END <-- Xanatos --
			// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
			case ET_L2HAC:
#ifdef ARGOS // NEO: NA - [NeoArgos]
				bNotOfficial = true;
#endif // ARGOS // NEO: NA END
				if (temptag.IsInt()){
					m_L2HAC_time = temptag.GetInt();
					m_L2HAC_support = true;
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: L2H END <-- Xanatos --
			default:
				if (bDbgInfo)
					m_strMuleInfo.AppendFormat(_T("\n  ***UnkTag=%s"), temptag.GetFullInfo());
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				bNotOfficial = true;
				if (thePrefs.IsArgosOpcodeDetection()){
					TOpCode* OpCode = new TOpCode;
					OpCode->OpSource = OC_INFO;
					OpCode->OpCode = (uint8)temptag.GetNameID();
					OpCode->OpValue = temptag.IsInt() ?  temptag.GetInt() : 0;
					unknownOC.AddTail(OpCode);
				}
#endif // ARGOS // NEO: NA END <-- Xanatos --
		}
	}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if (thePrefs.IsArgosOpcodeDetection()){
		while(!unknownOC.IsEmpty())
			theApp.argos->AddClientToTest(this,unknownOC.RemoveHead());
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --

	// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
	if (!m_L2HAC_time) 
		m_L2HAC_time = L2HAC_DEFAULT_EMULE;
	if (m_L2HAC_time < L2HAC_MIN_TIME){
		uint32 tmp=(L2HAC_MIN_TIME/m_L2HAC_time);
		if(L2HAC_MIN_TIME%m_L2HAC_time) tmp++;
		m_L2HAC_time=m_L2HAC_time*tmp;
	}
	// NEO: L2H END <-- Xanatos --

	if( m_byDataCompVer == 0 ){
		m_bySourceExchangeVer = 0;
		m_byExtendedRequestsVer = 0;
		m_byAcceptCommentVer = 0;
		m_nUDPPort = 0;
		m_IncompletePartVer = 0; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
		m_SubChunksVer = 0; // NEO: SCT - [SubChunkTransfer] <-- Xanatos --
		m_DownloadTimeVer = 0; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
		// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
		m_L2HAC_time = 0; 
		m_L2HAC_support = false; 
		// NEO: L2H END <-- Xanatos --
	}

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	bool bUnexpectedBytes = data.GetPosition() < data.GetLength();
#endif // ARGOS // NEO: NA END <-- Xanatos --
	if (bDbgInfo && data.GetPosition() < data.GetLength()){
		m_strMuleInfo.AppendFormat(_T("\n  ***AddData: %u bytes"), data.GetLength() - data.GetPosition());
	}

	m_bEmuleProtocol = true;
	m_byInfopacketsReceived |= IP_EMULEPROTPACK;
	InitClientSoftwareVersion();

	if (thePrefs.GetVerbose() && GetServerIP() == INADDR_NONE)
		AddDebugLogLine(false, _T("Received invalid server IP %s from %s"), ipstr(GetServerIP()), DbgGetClientInfo());

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(thePrefs.UseArgosSystem()){
		if(bUnexpectedBytes || bTypeViolated){
			//bNotOfficial = true; // for now lets separate this two things

			if(thePrefs.IsArgosBadHelloDetection()){
				UINT uFlag = 0;

				if(bUnexpectedBytes && GetClientSoft() == SO_EMULE) // other software may send extra bytes
					uFlag |= 1;
				if(bTypeViolated) // even other clinets should send us the proper tag type
					uFlag |= 4;
				
				if(uFlag)
					theApp.argos->DoArgos(GetConnectIP(),AR_BADHELLO,uFlag);
			}
		}

		theApp.argos->CheckClient(this, bNotOfficial, true);
	}
#endif // ARGOS // NEO: NA END <-- Xanatos --

}

void CUpDownClient::SendHelloAnswer(){
	if (socket == NULL){
		ASSERT(0);
		return;
	}

	CSafeMemFile data(128);
	SendHelloTypePacket(&data);
	Packet* packet = new Packet(&data);
	packet->opcode = OP_HELLOANSWER;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__HelloAnswer", this);
	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet,true);

	m_byHelloPacketState |= HP_HELLOANSWER; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
	SendAUXPortWhenNeeded();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
}

void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
{
	data->WriteHash16(thePrefs.GetUserHash());
	uint32 clientid;
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	if( socket && socket->m_Socket->IsNatSocket() && theApp.IsFirewalled())
		clientid = 1; // that's our kad LowID
	else
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
		clientid = theApp.GetID();

	data->WriteUInt32(clientid);
	data->WriteUInt16(thePrefs.GetPort());

	uint32 tagcount = 6;

	if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
		tagcount += 2;

	bool NotMod = m_strModVersion.IsEmpty() && m_strUsername.IsEmpty() == false; // NEO: MOD <-- Xanatos --

	if(NotMod == false) // NEO: MOD <-- Xanatos --
	{
		{
			tagcount += 1; // NEO: MID - [NeoID] <-- Xanatos -- 
			tagcount += 1; // NEO: NMP - [NeoModProt] <-- Xanatos --
		}

		// NEO: NMP - [NeoModProt] -- Xanatos -->
		if(GetNeoModProtVersion() == 0) // X! for backwards compatybility
		{

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			if (thePrefs.IsSupportISPBypass()) 
				tagcount += 1;
#endif // ISPBYPASS // NEO: SCC END
			if (thePrefs.UseInteligentChunkSelection() || thePrefs.UseSubChunkTransfer()) // NEO: ICS - [InteligentChunkSelection]
				tagcount += 1;
			if (thePrefs.UseRealPartStatus()) // NEO: RPS - [RealPartStatus]
				tagcount += 1;
			if (thePrefs.SendExtraInfo()) // NEO: NXI - [NeoExtraInfo]
				tagcount += 1;
		}
		// NEO: NMP END <-- Xanatos --

		if (thePrefs.UseEstimatedDownloadTime()) tagcount += 1; // NEO: EDT - [EstimatedDownloadTime] <-- Xanatos --
		if (thePrefs.UseLowID2HighIDAutoCallback()) tagcount += 1; // NEO: L2H - [LowID2HighIDAutoCallback] <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		if(thePrefs.IsWebCacheEnabled())
			tagcount+=(1/*WC_VOODOO*/+1/*WC_FLAGS*/); // MORPH - Modified by Commander, WebCache 1.2e
#endif // NEO: WC END <-- Xanatos --
	}

	data->WriteUInt32(tagcount);

	// eD2K Name

	// TODO implement multi language website which informs users of the effects of bad mods
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	CTag tagName(CT_NAME, thePrefs.IsArgosNickThiefDetection() ? theApp.argos->GetAntiNickThiefNick() : thePrefs.GetUserNick() );
#else // NEO: NA END
	CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? thePrefs.GetUserNick() : _T("Please use a GPL-conform version of eMule") );
#endif // ARGOS <-- Xanatos --
	tagName.WriteTagToFile(data, utf8strRaw);

	// eD2K Version
	CTag tagVersion(CT_VERSION,EDONKEYVERSION);
	tagVersion.WriteTagToFile(data);

	// eMule UDP Ports
	uint32 kadUDPPort = 0;
	if(Kademlia::CKademlia::IsConnected())
	{
		kadUDPPort = thePrefs.GetKADPort(); // NEO: KAX - [KadAuxPort] <-- Xanatos --
	}
	CTag tagUdpPorts(CT_EMULE_UDPPORTS, 
				((uint32)kadUDPPort			   << 16) |
				((uint32)thePrefs.GetUDPPort() <<  0)
				); 
	tagUdpPorts.WriteTagToFile(data);

	if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
	{
		CTag tagBuddyIP(CT_EMULE_BUDDYIP, theApp.clientlist->GetBuddy()->GetIP() ); 
		tagBuddyIP.WriteTagToFile(data);
	
		CTag tagBuddyPort(CT_EMULE_BUDDYUDP, 
//					( RESERVED												)
					((uint32)theApp.clientlist->GetBuddy()->GetUDPPort()  ) 
					);
		tagBuddyPort.WriteTagToFile(data);
	}

	// eMule Misc. Options #1
	const UINT uUdpVer				= 4;
	const UINT uDataCompVer			= 1;
	const UINT uSupportSecIdent		= theApp.clientcredits->CryptoAvailable() ? 3 : 0;
	const UINT uSourceExchangeVer	= 3;
	const UINT uExtendedRequestsVer	= 2;
	const UINT uAcceptCommentVer	= 2; // NEO: XC - [ExtendedComments] <-- Xanatos --
	const UINT uNoViewSharedFiles	= (!thePrefs.UseCustomPermissions() && thePrefs.CanSeeShares() == vsfaNobody) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
	const UINT uMultiPacket			= 1;
	const UINT uSupportPreview		= (thePrefs.UseCustomPermissions() || thePrefs.CanSeeShares() != vsfaNobody) ? 1 : 0; // set 'Preview supported' only if 'View Shared Files' allowed // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
	const UINT uPeerCache			= 1;
	const UINT uUnicodeSupport		= 1;
	const UINT nAICHVer				= 1;
	CTag tagMisOptions1(CT_EMULE_MISCOPTIONS1, 
				(nAICHVer				<< 29) |
				(uUnicodeSupport		<< 28) |
				(uUdpVer				<< 24) |
				(uDataCompVer			<< 20) |
				(uSupportSecIdent		<< 16) |
				(uSourceExchangeVer		<< 12) |
				(uExtendedRequestsVer	<<  8) |
				(uAcceptCommentVer		<<  4) |
				(uPeerCache				<<  3) |
				(uNoViewSharedFiles		<<  2) |
				(uMultiPacket			<<  1) |
				(uSupportPreview		<<  0)
				);
	tagMisOptions1.WriteTagToFile(data);

	// eMule Misc. Options #2
	const UINT uKadVersion			= KADEMLIA_VERSION;
	const UINT uSupportLargeFiles	= (OLD_MAX_EMULE_FILE_SIZE < MAX_EMULE_FILE_SIZE) ? 1 : 0;
	const UINT uExtMultiPacket		= 1;

	CTag tagMisOptions2(CT_EMULE_MISCOPTIONS2, 
//				(RESERVED				     )
				(uExtMultiPacket		<<  5) |
				(uSupportLargeFiles		<<  4) |
				(uKadVersion			<<  0) 
				);
	tagMisOptions2.WriteTagToFile(data);

	// eMule Version
	CTag tagMuleVersion(CT_EMULE_VERSION, 
				//(uCompatibleClientID		<< 24) |
				(CemuleApp::m_nVersionMjr	<< 17) |
				(CemuleApp::m_nVersionMin	<< 10) |
				(CemuleApp::m_nVersionUpd	<<  7) 
//				(RESERVED			     ) 
				);
	tagMuleVersion.WriteTagToFile(data);

	if(NotMod == false) // NEO: MOD <-- Xanatos --
	{
		{
			// NEO: MID - [ModID] -- Xanatos -->
			CTag tagMODVersion(CT_MOD_VERSION, CString(MOD_VERSION));
			tagMODVersion.WriteTagToFile(data);
			// NEO: MID END <-- Xanatos --

			// NEO: NMP - [NeoModProt] -- Xanatos -->
			uint32 uNeoFeatures =	
						//	((0 & 0xff)		<< 24) | // Unused
						//	((0 & 0xff)		<< 16) | // Reserved
							((1 & 0x0f)		<< 12) | // NEO: NMPx - [NeoModProtXS]
						//	((0 & 0x03)		<< 10  | // Reserved
							((1 & 0x01)		<< 9 ) | // LowID UDP Ping Support (notifyes a fix form xman1 that allow the remote low ID to use udp reasks)
							((1 & 0x01)		<< 8 ) | // Unsolicited Part Status (allows our client ro recieve filestatus at any time)
						//	((0 & 0x0f)		<< 4 ) | // Reserved
							((1	& 0x0f)		<< 0 );  // support for Neo Mod Prot / Neo Mod Multi Packet / Neo Mod Info Packet
			CTag tagETMODF(CT_NEO_FEATURES, uNeoFeatures);	
			tagETMODF.WriteTagToFile(data); 
			// NEO: NMP - [NeoModProt] <-- Xanatos --
		}

		// NEO: NMP - [NeoModProt] -- Xanatos -->
		if(GetNeoModProtVersion() == 0) // X! for backwards compatybility
		{
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			if(thePrefs.IsSupportISPBypass()){
				uint32 Pref = thePrefs.GetNeedISPBypass();
				uint32 uepl = (Pref && thePrefs.IsPreferUnEnCryptedPayload()); // set this flag only when we need ecryption
				uint32 uVersions =	
									(0x00			<<  24) | // unused
									(0xD2			<<  16) | // identyfy our current encryption model // DX2
									((0x00 & 0x0f)	<<  12) | // reserved
									((uepl & 0x01)	<<  11) | // Prefer Encrypt only protocoll but not file data
									((Pref & 0x07)	<<  8 ) | // Is encryption needed
									(3				<<  0); 
				CTag tagRealParts(CT_ISP_BYPASS,uVersions);
				tagRealParts.WriteTagToFile(data);
			}
#endif // ISPBYPASS // NEO: SCC END

			// NEO: ICS - [InteligentChunkSelection]
			if(thePrefs.UseInteligentChunkSelection() || thePrefs.UseSubChunkTransfer()){ // NEO: SCT - [SubChunkTransfer]
				uint32 uVersions =	((thePrefs.UseSubChunkTransfer()			? 1 : 0) << 16) | // NEO: SCT - [SubChunkTransfer]
									((thePrefs.UseInteligentChunkSelection()	? 2 : 0) <<  0);
				CTag tagIncompleteParts(ET_INCOMPLETEPARTS,uVersions);
				tagIncompleteParts.WriteTagToFile(data);
			}
			// NEO: ICS END

			// NEO: RPS - [RealPartStatus]
			if(thePrefs.UseRealPartStatus()){
				uint32 uVersions =	(1 << 16) |
									(1 <<  8) |
									(0 <<  0); // the old mono RPS version does not support the new format and would cause an error
				CTag tagRealParts(ET_REALPARTS,uVersions);
				tagRealParts.WriteTagToFile(data);
			}
			// NEO: PRS END
			// NEO: NXI - [NeoExtraInfo]
			if(thePrefs.SendExtraInfo()){
				CTag tagExtraInfo(ET_EXTRAINFO,1);
				tagExtraInfo.WriteTagToFile(data);
			}
			// NEO: NXI END
		}
		// NEO: NMP END <-- Xanatos --

		// NEO: EDT - [EstimatedDownloadTime] -- Xanatos -->
		if (thePrefs.UseEstimatedDownloadTime()){
			CTag tagEDT(ET_DOWNLOADTIME,1);
			tagEDT.WriteTagToFile(data);
		}
		// NEO: EDT END <-- Xanatos --

		// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
		if(thePrefs.UseLowID2HighIDAutoCallback()){
			CTag tagL2H(ET_L2HAC,GetReqFileReaskIntervals());	
			tagL2H.WriteTagToFile(data); 
		}
		// NEO: L2H END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		if(thePrefs.IsWebCacheEnabled()){
			CTag tagWebCacheVoodoo( WC_TAG_VOODOO, (uint32)'ARC4' );
			tagWebCacheVoodoo.WriteTagToFile(data);
			uint32 flags = WC_FLAGS_UDP | WC_FLAGS_NO_OHCBS | WC_FLAGS_MULTI_OHCBS;
			bool localMasterKeyNeeded = true;
			for(int i=0; localMasterKeyNeeded && i < WC_KEYLENGTH; i++)
			localMasterKeyNeeded = (Crypt.localMasterKey[i]==0);
			if (b_webcacheInfoNeeded || m_WA_webCacheIndex == -1 || localMasterKeyNeeded)
				flags |= WC_FLAGS_INFO_NEEDED;
			CTag tagWebCacheFlags( WC_TAG_FLAGS, flags);
			tagWebCacheFlags.WriteTagToFile(data);
		}
#endif // NEO: WC END <-- Xanatos --
	}

	uint32 dwIP;
	uint16 nPort;
	if (theApp.serverconnect->IsConnected()){
		dwIP = theApp.serverconnect->GetCurrentServer()->GetIP();
		nPort = theApp.serverconnect->GetCurrentServer()->GetPort();
#ifdef _DEBUG
		if (dwIP == theApp.serverconnect->GetLocalIP()){
			dwIP = 0;
			nPort = 0;
		}
#endif
	}
	else{
		nPort = 0;
		dwIP = 0;
	}
	data->WriteUInt32(dwIP);
	data->WriteUInt16(nPort);
//	data->WriteUInt32(dwIP); //The Hybrid added some bits here, what ARE THEY FOR?
}

// NEO: XC - [ExtendedComments] -- Xanatos -->
void CUpDownClient::ProcessMuleCommentPacket(const uchar* pachPacket, uint32 nSize){
	CSafeMemFile data(pachPacket,nSize);
	CKnownFile *file;
	Comment_Struct cs;

	if(m_byAcceptCommentVer >= 2) {
		uchar filehash[16];
		if (nSize<16)
			return;
		data.Read(&filehash,16);
		file = theApp.sharedfiles->GetFileByID(filehash);
		if (!file)
			file = theApp.downloadqueue->GetFileByID(filehash);
		if (!file)
			return;
	}
	else {
		file = reqfile;
		if (!file || !file->IsPartFile())
			return;
	}
	CClientFileStatus* status = GetFileStatus(file,true); // NEO: SCFS - [SmartClientFileStatus]

	cs.m_strFileName = status->GetFileName();
	if (data.GetLength() - data.GetPosition()<(sizeof(cs.m_uRating)+sizeof(UINT)))
		return;
	cs.m_uRating = data.ReadUInt8();
	ULONGLONG uLength = data.ReadUInt32();
	if (thePrefs.GetLogRatingDescReceived() && cs.m_uRating > 0)
		AddDebugLogLine(false, GetResString(IDS_RATINGRECV), cs.m_strFileName, cs.m_uRating);
	if (uLength > data.GetLength() - data.GetPosition())
		uLength = data.GetLength() - data.GetPosition();
	if (uLength > MAXFILECOMMENTLEN*3)
		uLength = MAXFILECOMMENTLEN*3;
	if (uLength > 0){
		cs.m_strComment = data.ReadString(GetUnicodeSupport()!=utf8strNone, (UINT)uLength);
		if (thePrefs.GetLogRatingDescReceived() && !cs.m_strComment.IsEmpty())
			AddDebugLogLine(false, GetResString(IDS_DESCRIPTIONRECV), cs.m_strFileName, cs.m_strComment);

		// test if comment is filtered
		if (!thePrefs.GetCommentFilter().IsEmpty())
		{
			CString strCommentLower(cs.m_strComment);
			strCommentLower.MakeLower();

			int iPos = 0;
			CString strFilter(thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos));
			while (!strFilter.IsEmpty())
			{
				// comment filters are already in lowercase, compare with temp. lowercased received comment
				if (strCommentLower.Find(strFilter) >= 0)
				{
					cs.m_strComment.Empty();
					break;
				}
				strFilter = thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos);
			}
		}
	}
	if (cs.m_uRating <= 0 && cs.m_strComment.IsEmpty())
		return;

	// NEO: SCFS - [SmartClientFileStatus]
	status->SetFileComment(cs.m_strComment);
	status->SetFileRating(cs.m_uRating);
	// NEO: SCFS END

	if (HasValidHash())
		md4cpy(cs.m_achUserHash, GetUserHash());
	cs.m_strUserName = m_strUsername; // NEO: FIX - [StabilityFix] <-- Xanatos --
	file->AddComment(cs);
}
// NEO: XC END <-- Xanatos --

/*void CUpDownClient::ProcessMuleCommentPacket(const uchar* pachPacket, uint32 nSize)
{
	if (reqfile && reqfile->IsPartFile())
	{
		CSafeMemFile data(pachPacket, nSize);
		uint8 uRating = data.ReadUInt8();
		if (thePrefs.GetLogRatingDescReceived() && uRating > 0)
			AddDebugLogLine(false, GetResString(IDS_RATINGRECV), m_strClientFilename, uRating);
		CString strComment;
		UINT uLength = data.ReadUInt32();
		if (uLength > 0)
		{
			// we have to increase the raw max. allowed file comment len because of possible UTF8 encoding.
			if (uLength > MAXFILECOMMENTLEN*3)
				uLength = MAXFILECOMMENTLEN*3;
			strComment = data.ReadString(GetUnicodeSupport()!=utf8strNone, uLength);
			if (thePrefs.GetLogRatingDescReceived() && !strComment.IsEmpty())
				AddDebugLogLine(false, GetResString(IDS_DESCRIPTIONRECV), m_strClientFilename, strComment);

			// test if comment is filtered
			if (!thePrefs.GetCommentFilter().IsEmpty())
			{
				CString strCommentLower(strComment);
				strCommentLower.MakeLower();

				int iPos = 0;
				CString strFilter(thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos));
				while (!strFilter.IsEmpty())
				{
					// comment filters are already in lowercase, compare with temp. lowercased received comment
					if (strCommentLower.Find(strFilter) >= 0)
					{
						strComment.Empty();
						uRating = 0;
						break;
					}
					strFilter = thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos);
				}
			}
		}
		if (!strComment.IsEmpty() || uRating > 0)
		{
			m_strFileComment = strComment;
			m_uFileRating = uRating;
			reqfile->UpdateFileRatingCommentAvail();
		}
	}
}*/

bool CUpDownClient::Disconnected(LPCTSTR pszReason, bool bFromSocket)
{
	ASSERT( theApp.clientlist->IsValidClient(this) );

	//If this is a KAD client object, just delete it!
	SetKadState(KS_NONE);

#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack]
    if (GetUploadState() == US_UPLOADING || GetUploadState() == US_CONNECTING || GetUploadState() == US_WAITCALLBACK || GetUploadState() == US_WAITCALLBACKKAD)
#else
    if (GetUploadState() == US_UPLOADING || GetUploadState() == US_CONNECTING)
#endif //NATTUNNELING // NEO: LUC END
	{
		if (thePrefs.GetLogUlDlEvents() && GetUploadState()==US_UPLOADING && m_fSentOutOfPartReqs==0 && !theApp.uploadqueue->IsOnUploadQueue(this))
			DebugLog(_T("Disconnected client removed from upload queue and waiting list: %s"), DbgGetClientInfo());
		theApp.uploadqueue->RemoveFromUploadQueue(this, pszReason);
	}

	// 28-Jun-2004 [bc]: re-applied this patch which was in 0.30b-0.30e. it does not seem to solve the bug but
	// it does not hurt either...
	if (m_BlockRequests_queue.GetCount() > 0 || m_DoneBlocks_list.GetCount()){
		// Although this should not happen, it seems(?) to happens sometimes. The problem we may run into here is as follows:
		//
		// 1.) If we do not clear the block send requests for that client, we will send those blocks next time the client
		// gets an upload slot. But because we are starting to send any available block send requests right _before_ the
		// remote client had a chance to prepare to deal with them, the first sent blocks will get dropped by the client.
		// Worst thing here is, because the blocks are zipped and can therefore only be uncompressed when the first block
		// was received, all of those sent blocks will create a lot of uncompress errors at the remote client.
		//
		// 2.) The remote client may have already received those blocks from some other client when it gets the next
		// upload slot.
        DebugLogWarning(_T("Disconnected client with non empty block send queue; %s reqs: %s doneblocks: %s"), DbgGetClientInfo(), m_BlockRequests_queue.GetCount() > 0 ? _T("true") : _T("false"), m_DoneBlocks_list.GetCount() ? _T("true") : _T("false"));
		ClearUploadBlockRequests();
	}

	if (GetDownloadState() == DS_DOWNLOADING){
		if (m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY || m_ePeerCacheDownState == PCDS_DOWNLOADING)
			theApp.m_pPeerCache->DownloadAttemptFailed();
		SetDownloadState(DS_ONQUEUE, CString(_T("Disconnected: ")) + pszReason);
	}
	else{
		// ensure that all possible block requests are removed from the partfile
		ClearDownloadBlockRequests();
		// NEO: MOD - [CodeImprovement] -- Xanatos -->
		/*if(GetDownloadState() == DS_CONNECTED){
		//Xman Code Imrpovement moved down
			theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
			if(reqfile ? reqfile->PartPrefs.EnableSourceKeeper() : thePrefs.EnableSourceKeeper())
				SetDownloadState(DS_ERROR); // X?
			else
#endif // NEO_SK // NEO: NSK END <-- Xanatos --
				theApp.downloadqueue->RemoveSource(this);
	    }*/
		// NEO: MOD END <-- Xanatos --
	}

	// we had still an AICH request pending, handle it
	if (IsAICHReqPending()){
		m_fAICHRequested = FALSE;
		CAICHHashSet::ClientAICHRequestFailed(this);
	}

	// The remote client does not have to answer with OP_HASHSETANSWER *immediatly* 
	// after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client 
	// is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
	if (((GetDownloadState() == DS_REQHASHSET) || m_fHashsetRequesting) && (reqfile)){
#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
		if(reqfile ? reqfile->PartPrefs.EnableSourceKeeper() : thePrefs.EnableSourceKeeper())
			SetDownloadState(DS_ERROR);
#endif // NEO_SK // NEO: NSK END <-- Xanatos --
        reqfile->hashsetneeded = true;
	}

	ASSERT( theApp.clientlist->IsValidClient(this) );

	//check if this client is needed in any way, if not delete it
	bool bDelete = true;

	// Dead Soure Handling
	//
	// If we failed to connect to that client, it is supposed to be 'dead'. Add the IP
	// to the 'dead sources' lists so we don't waste resources and bandwidth to connect
	// to that client again within the next hour.
	//
	// But, if we were just connecting to a proxy and failed to do so, that client IP
	// is supposed to be valid until the proxy itself tells us that the IP can not be
	// connected to (e.g. 504 Bad Gateway)
	//

	// NEO: MOD - [CodeImprovement] -- Xanatis -->

	bool bAddDeadSource = true;
	bool bFaild = false;
	switch(m_nUploadState){
		case US_PENDING: // NEO: MOD - [NewUploadState]
		case US_NONEEDEDPARTS: // NEO: SCT - [SubChunkTransfer]
		case US_ONUPLOADQUEUE:
			bDelete = false;
			break;

#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack]
		case US_WAITCALLBACKKAD: // Note: the user may be still there just with an other buddy so reset the buddy IP/Port, and we try to get new one over his BuddyID
			SetNatPort(0); // NEO: NATT - [NatTraversal]

			SetBuddyPort(0);
			SetBuddyIP(0);

#endif //NATTUNNELING // NEO: LUC END
		case US_CONNECTING:
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
			if (socket->m_Socket->IsAsyncSocket() && ((CTCPSocket*)socket->m_Socket)->GetProxyConnectFailed())
#else
			if (socket && socket->GetProxyConnectFailed())
#endif //NATTUNNELING // NEO: UTCP END
				bAddDeadSource = false;
			//if (thePrefs.GetLogUlDlEvents())
            //    AddDebugLogLine(DLP_VERYLOW, true,_T("Removing connecting client from upload list: %s Client: %s"), pszReason, DbgGetClientInfo());

			// NEO: UPC - [UploadingProblemClient]
			theApp.uploadqueue->RemoveFromUploadQueue(this,pszReason);
			m_fUpIsProblematic = 1;
			//back to queue
			theApp.uploadqueue->AddClientDirectToQueue(this);
			bDelete = false;
			break;
			// NEO: UPC END
		case US_WAITCALLBACK:
			bFaild = true; // NEO: TCR - [TCPConnectionRetry]
		case US_ERROR:
		case US_BANNED: // NEO: MOD //Xman 5.1 why we should keep it ?
//			if (bAddDeadSource)
//				theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
			bDelete = true;
	}

	bAddDeadSource = true;
	// NEO: TCR - [TCPConnectionRetry]
	bool bRetry = false;
	bool bForceDelete = false;
	if(m_uFaildCount == (uint16)-1){
		bForceDelete = true;
		m_uFaildCount = 0; // reset
	}
	// NEO: TCR END
	switch(m_nDownloadState){
		case DS_ONQUEUE:
		case DS_TOOMANYCONNS:
		case DS_NONEEDEDPARTS:
		case DS_LOWTOLOWIP:
			bDelete = false;
			break;

		// NEO: TCR - [TCPConnectionRetry]
		case DS_WAITCALLBACKKAD: // Note: the user may be still there just with an other buddy so reset the buddy IP/Port, and we try to get new one over his BuddyID
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
			SetNatPort(0);
#endif //NATTUNNELING // NEO: NATT END 

			SetBuddyPort(0);
			SetBuddyIP(0);

		case DS_CONNECTING:{
#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP]
			if (socket && socket->m_Socket->IsAsyncSocket() && ((CTCPSocket*)socket->m_Socket)->GetProxyConnectFailed())
#else
			if (socket && socket->GetProxyConnectFailed())
#endif //NATTUNNELING // NEO: UTCP END
				bAddDeadSource = false;

			if(!thePrefs.UseTCPConnectionRetry() || bForceDelete /*|| IsBanned()*/) // X?: hmm....
			{
				bRetry=false;
			}
#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage]
			else if(!IsActive(true) && GetFaildCount() < thePrefs.GetTCPStoredConnectionRetry()){
				SetNextAskedTime(SEC2MS(100));
				bRetry = true;
			}
#endif // NEO_SS // NEO: NSS END
			else if (IsSourceConfirmed() && GetFaildCount() < thePrefs.GetTCPConnectionRetry())
			{
				SetNextAskedTime(SEC2MS(50));
				bRetry = true;
			}
			else if (GetFaildCount() < thePrefs.GetTCPNewConnectionRetry())
			{
				SetNextAskedTime(SEC2MS(70));
				bRetry = true;
			}

			if(bRetry){
				SetDownloadState(DS_CONNECTIONRETRY);
				bDelete = false;
			}
		}
		case DS_WAITCALLBACK: // Note: the uset may be still there just other server unfortunytla we can't find out his new server so we drop him
			bFaild = true; // NEO: TCR - [TCPConnectionRetry]
		case DS_ERROR:
		case DS_BANNED: // NEO: MOD
//			if(!bRetry){
//				if (bAddDeadSource)
//					theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
				bDelete = true;
//			}
		// NEO: TCR END
	}

	if(bFaild){
		if(!bRetry && bAddDeadSource){
			theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
		}
		IncrementFaildCount(); // NEO: TCR - [TCPConnectionRetry]
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
		m_nRemoteSecurePort = 0; // reset AUX port we want a new one
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
	}

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase]
	if(bFaild || m_nDownloadState == DS_ERROR || m_nUploadState == US_ERROR)
		if(source)
			source->ConnectionFaild(m_nDownloadState == DS_ERROR || m_nUploadState == US_ERROR);
#endif // NEO_CD // NEO: NCD END

	// NEO: MOD END <-- Xanatis --

#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
	if(bDelete && (reqfile ? reqfile->PartPrefs.EnableSourceKeeper() : thePrefs.EnableSourceKeeper()) // Do we want to delete this client? // is the Keeper enabled?
	 && bForceDelete == false // Delete only sources that are filtered by the firewall
	 && IsSourceConfirmed() // Client must be Real, we must had contact to him, at least onece
	 && m_nDownloadState != DS_NONE // Only if this client is an Download Source
	 && reqfile //theApp.downloadqueue->IsPartFile(reqfile) // Only if the req partfile is valid // X?
	){
		ASSERT(theApp.downloadqueue->IsPartFile(reqfile));
		if(m_nDownloadState != DS_ERROR // The error state must stay separatly
		 && m_nDownloadState != DS_BANNED) // Banned Clients will be currcntly also keept
			SetDownloadState(DS_UNREACHABLE);
		bDelete = false;
	}
#endif // NEO_SK // NEO: NSK END <-- Xanatos --

	if (GetChatState() != MS_NONE){
		// NEO: MOD - [CodeImprovement] -- Xanatos -->
		if(bDelete==true)
			theApp.downloadqueue->RemoveSource(this);
		// NEO: MOD END <-- Xanatos --
		bDelete = false;
		theApp.emuledlg->chatwnd->chatselector.ConnectingResult(this,false);
	}

	// NEO: MLD - [ModelesDialogs] -- Xanatos -->
	if (GetDetailDialogInterface()->IsDialogOpen())
		bDelete = false;
	// NEO: MLD <-- Xanatos --

#ifdef ISPBYPASS // NEO: SUC - [SafeUCPCommunication] -- Xanatos -->
	if(bDelete == false && UseUDPSecurity() && thePrefs.IsSupportISPBypass() == 1 // if we dont remove the client
	 && socket->m_Encryption && socket->m_Encryption->IsSecure() // we save the last used TCP key for furder UDP reask pings
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	 && socket->m_Socket->IsAsyncSocket() // only if this was a TCP connection if it was a nat one we will agree on a new kay also for udp ping
#endif //NATTUNNELING // NEO: NATT END
	){
		delete m_UDPEncryption; // if there was an old one delete it
		m_UDPEncryption = socket->m_Encryption;
		socket->m_Encryption = NULL;
		m_UDPEncryption->ShutDown(); // delete some not longer used objects 
	}
	else // for nat it's important to cleanup this here
	{
		delete m_UDPEncryption;
		m_UDPEncryption = NULL;
	}
#endif // ISPBYPASS // NEO: SUC END <-- Xanatos --

	if (!bFromSocket && socket){
		ASSERT (theApp.listensocket->IsValidSocket(socket));
		socket->Safe_Delete();
	}
	socket = 0;
#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
	if(oldsocket){
		ASSERT (theApp.listensocket->IsValidSocket(oldsocket));
		oldsocket->Safe_Delete();
	}
	oldsocket = 0;
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --

    if (m_iFileListRequested || m_bRequestingFileList){	// NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
		LogWarning(LOG_STATUSBAR, GetResString(IDS_SHAREDFILES_FAILED), GetUserName());
        m_iFileListRequested = 0;
		m_bRequestingFileList = false; // NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
	}

	m_iSourceListRequested = 0; // NEO: MCH - [ManualClientHandling] <-- Xanatos --

	// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
	m_bNotifyIdChage = false;
	m_bWainingNotifyIdChage = false;
	// NEO: RIC END <-- Xanatos --

	if (m_Friend)
		theApp.friendlist->RefreshFriend(m_Friend);

	//Xman Code Improvement: don't refresh list-item on deletion
	if(bDelete==false) // NEO: MOD - [CodeImprovement] <-- Xanatos --
		theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(this);

	if (bDelete)
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			Debug(_T("--- Deleted client            %s; Reason=%s\n"), DbgGetClientInfo(true), pszReason);
		return true;
	}
	else
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			Debug(_T("--- Disconnected client       %s; Reason=%s\n"), DbgGetClientInfo(true), pszReason);
		m_fHashsetRequesting = 0;
		SetSentCancelTransfer(0);
		//m_bHelloAnswerPending = false;
		m_byHelloPacketState = HP_NONE; // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
		m_byFileRequestState = FR_NONE; // NEO: USPS - [UnSolicitedPartStatus] <-- Xanatos --
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
		m_byNatTraversalState = NT_NONE;
		m_uLastNatTraversalTry = 0;
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
		m_fQueueRankPending = 0;
		m_fFailedFileIdReqs = 0;
		m_fActiveDownReqFlag = 0; // NEO: FSUR - [FixStartupLoadReq] <-- Xanatos --
		m_fKeepAlivePending = 0; // NEO: DKA - [DownloadKeepAlive] <-- Xanatos --
		m_fUnaskQueueRankRecv = 0;
		m_bAdvertisementPending = false; // NEO: ASP - [ActiveSpreading] <-- Xanatos --
		m_uPeerCacheDownloadPushId = 0;
		m_uPeerCacheUploadPushId = 0;
		m_uPeerCacheRemoteIP = 0;
		SetPeerCacheDownState(PCDS_NONE);
		SetPeerCacheUpState(PCUS_NONE);
		if (m_pPCDownSocket){
			m_pPCDownSocket->client = NULL;
			m_pPCDownSocket->Safe_Delete();
		}
		if (m_pPCUpSocket){
			m_pPCUpSocket->client = NULL;
			m_pPCUpSocket->Safe_Delete();
		}
#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
		SetWebCacheDownState(WCDS_NONE);
		SetWebCacheUpState(WCUS_NONE);
		if (m_pWCDownSocket){
			m_pWCDownSocket->client = NULL;
			m_pWCDownSocket->Safe_Delete();
		}
		if (m_pWCUpSocket){
			m_pWCUpSocket->client = NULL;
			m_pWCUpSocket->Safe_Delete();
		}
#endif // NEO: WC END <-- Xanatos --
		m_fSentOutOfPartReqs = 0;
		return false;
	}
}

//Returned bool is not if the TryToConnect is successful or not..
//false means the client was deleted!
//true means the client was not deleted!
bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon, CRuntimeClass* pClassSocket)
{
   // NEO: FCCP - [FixConnectionCollision] -- Xanatos -->
   bool socketnotinitiated = (socket == NULL || socket->GetConState() == ES_DISCONNECTED);
   if (socketnotinitiated) 
   {
    if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon /*&& !(socket && socket->IsConnected())*/ )
   // NEO: FCCP END <-- Xanatos --
	//if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon && !(socket && socket->IsConnected()))
	{
		if(Disconnected(_T("Too many connections")))
		{
			delete this;
			return false;
		}
		return true;
	}

	uint32 uClientIP = GetIP();
	if (uClientIP == 0 && !HasLowID())
		uClientIP = ntohl(m_nUserIDHybrid);
	if (uClientIP)
	{
		// although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
		// we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
		if (
#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
		 !theApp.lancast->IsLanIP(uClientIP) &&
#endif //LANCAST // NEO: NLC END <-- Xanatos --
		 theApp.ipfilter->IsFiltered(uClientIP)
		){
			theStats.filteredclients++;
			if (thePrefs.GetLogFilteredIPs())
				AddDebugLogLine(true, GetResString(IDS_IPFILTERED), ipstr(uClientIP), theApp.ipfilter->GetLastHit());
			SetForDelete(); // NEO: TCR - [TCPConnectionRetry] <-- Xanatos --
			if (Disconnected(_T("IPFilter")))
			{
				delete this;
				return false;
			}
			return true;
		}

		// for safety: check again whether that IP is banned
		if (theApp.clientlist->IsBannedClient(uClientIP))
		{
			if (thePrefs.GetLogBannedClients())
				AddDebugLogLine(false, _T("Refused to connect to banned client %s"), DbgGetClientInfo());
			SetForDelete(); // NEO: TCR - [TCPConnectionRetry] <-- Xanatos --
			if (Disconnected(_T("Banned IP")))
			{
				delete this;
				return false;
			}
			return true;
		}
	}

	if( GetKadState() == KS_QUEUED_FWCHECK )
		SetKadState(KS_CONNECTING_FWCHECK);

	if ( HasLowID() )
	{
		if(!theApp.DoCallback(this))
		{
			//We cannot do a callback!
			if (GetDownloadState() == DS_CONNECTING)
				SetDownloadState(DS_LOWTOLOWIP);
			else if (GetDownloadState() == DS_REQHASHSET)
			{
				SetDownloadState(DS_ONQUEUE);
				reqfile->hashsetneeded = true;
			}
			if (GetUploadState() == US_CONNECTING)
			{
				if(Disconnected(_T("LowID->LowID and US_CONNECTING")))
				{
					delete this;
					return false;
				}
			}
			return true;
		}

		//We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
		//If ANYTHING changes with the "if(!theApp.DoCallback(this))" above that will let you fall through 
		//with the condition that the source is firewalled and we are firewalled, we must
		//recheck it before the this check..
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
		if( HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && (!theApp.serverconnect->IsLocalServer(GetServerIP(), GetServerPort()) || theApp.IsFirewalled()))
#else
		if( HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp.serverconnect->IsLocalServer(GetServerIP(), GetServerPort()))
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
		{
			//This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
			if( Kademlia::CKademlia::IsConnected() )
			{
				//We are connect to Kad
				if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID())))
				{
					//There are too many source lookups already or we are already searching this key.
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
//					if (GetDownloadState() == US_CONNECTING)
//						SetUploadState(US_TOOMANYCONNSKAD);

					if (GetDownloadState() == DS_CONNECTING)
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
						SetDownloadState(DS_TOOMANYCONNSKAD);
					return true;
				}
			}
		}
	}

	// NEO: FCCP - [FixConnectionCollision] -- Xanatos --
	//Xman: Useless check with socketnotinitiated
	//if (!socket || !socket->IsConnected()){

	if (socket) 
		socket->Safe_Delete(); 

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->
	// if we are going to establish a nat tunel than create the proper nat socket
	if(thePrefs.IsNATTraversalEnabled() && GetNatTraversalVersion() > 0 && (HasLowID() && theApp.IsFirewalled() || GetUserPort() == 0)) // The GetUserPort() is for manual added UDP sources
	{
		socket = new CClientReqSocket(this,true);
	}
	else
#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --
	{
		if (pClassSocket == NULL)
			pClassSocket = RUNTIME_CLASS(CClientReqSocket);
		socket = static_cast<CClientReqSocket*>(pClassSocket->CreateObject());
		socket->SetClient(this);
	}

	if (!socket->Create())
	{
		socket->Safe_Delete();
		return true;
	}

	// NEO: FCCP - [FixConnectionCollision] -- Xanatos --
	//Xman: Useless check with socketnotinitiated
	//}else
	//{
	//	ConnectionEstablished();
	//	return true;
	//}

	// MOD Note: Do not change this part - Merkur
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
	if (HasLowID() || GetUserPort() == 0 && GetNatTraversalVersion() > 0) // The GetUserPort() is for manual added UDP sources
#else
	if (HasLowID()) 
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
	{
		if (GetDownloadState() == DS_CONNECTING)
			SetDownloadState(DS_WAITCALLBACK);

		if (GetUploadState() == US_CONNECTING)
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
			SetUploadState(US_WAITCALLBACK);
#else
		{
			if(Disconnected(_T("LowID and US_CONNECTING")))
			{
				delete this;
				return false;
			}
			return true;
		}
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --

		CServerSocket* server;
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
		if ((server = theApp.serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) != NULL && !theApp.IsFirewalled()) // NEO: NEW - [NewCoded]
#else
		if ((server = theApp.serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) != NULL) // NEO: NEW - [NewCoded]
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
		{
			Packet* packet = new Packet(OP_CALLBACKREQUEST,4);
			PokeUInt32(packet->pBuffer, m_nUserIDHybrid);
			if (thePrefs.GetDebugServerTCPLevel() > 0 || thePrefs.GetDebugClientTCPLevel() > 0)
				DebugSend("OP__CallbackRequest", this);
			theStats.AddUpDataOverheadServer(packet->size);
			theApp.serverconnect->SendPacket(packet,true,server); // NEO: NEW - [NewCoded] <-- Xanatos --
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
			if( GetUploadState() == US_WAITCALLBACK )
				SetUploadState(US_WAITCALLBACKKAD);

			if( GetDownloadState() == DS_WAITCALLBACK )
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
				SetDownloadState(DS_WAITCALLBACKKAD);
		}
		else
		{
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
			if ( GetUploadState() == US_WAITCALLBACK || !GetRemoteQueueRank() || m_bReaskPending) // NEO: LUC - [LowIDUplaodCallBack]
#else
			if ( GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending) )
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
			{
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
				if( !HasValidBuddyID() && (GetUserPort() != 0 || GetNatTraversalVersion() == 0)) // The GetUserPort() is for manual added UDP sources
#else
				if( !HasValidBuddyID() )
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
				{
					theApp.downloadqueue->RemoveSource(this);
					if(Disconnected(_T("LowID and US_NONE and QR=0")))
					{
						delete this;
						return false;
					}
					return true;
				}
				
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
				if( !Kademlia::CKademlia::IsConnected() && (GetUserPort() != 0 || GetNatTraversalVersion() == 0)) // The GetUserPort() is for manual added UDP sources
#else
				if( !Kademlia::CKademlia::IsConnected() )
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
				{
					//We are not connected to Kad and this is a Kad Firewalled source..
					theApp.downloadqueue->RemoveSource(this);
					{
						if(Disconnected(_T("Kad Firewalled source but not connected to Kad.")))
						{
							delete this;
							return false;
						}
						return true;
					}
				}
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
                if( GetDownloadState() == DS_WAITCALLBACK || GetUploadState() == US_WAITCALLBACK )
#else
                if( GetDownloadState() == DS_WAITCALLBACK )
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
				{
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
					// Note: if we are arrived at this point we already checked do the client support nat traversal
					if(thePrefs.IsNATTraversalEnabled() && (theApp.IsFirewalled() || GetUserPort() == 0) && IsFullConeNat() && IsNATPortRelaiable()) // The GetUserPort() is for manual added UDP sources
					{
						// Note: This nat type allows incomming packets form all hosts so no need for a bidirectional udp tunneling
						// we can skip the buddy sync and use immidetly direct communication
						ResetNatTraversalState();
						AddNatTraversalState(NT_INITIALIZER); // this tell us to send a hello after we have a open tunel
						SetLastNatTraversalTry();
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
						if(UseNATEncrpytion() && (thePrefs.IsSupportISPBypass() == 1 || thePrefs.IsSupportISPBypass() == 2) && (thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1)){
							PrepareNATEncryption(false); // this is to be send in a packet so we add trash to scramble the size
							SendSecurePing(); // sen a ping with the kay agreement
						}else
 #endif // ISPBYPASS // NEO: SCC END
							SendNatPing();
						// NEO: LUC - [LowIDUplaodCallBack]
						if( GetUploadState() == US_WAITCALLBACK )
							SetUploadState(US_WAITCALLBACKKAD);

						if( GetDownloadState() == DS_WAITCALLBACK )
						// NEO: LUC END
							SetDownloadState(DS_WAITCALLBACKKAD);
					}
					else
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
					if( GetBuddyIP() && GetBuddyPort())
					{
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
						// we are firewalled and want to connect an other firewalled cleint
						// here we need a other callback method that will iniciate a UDP tunel
						if(thePrefs.IsNATTraversalEnabled() && (theApp.IsFirewalled() || GetUserPort() == 0)) // The GetUserPort() is for manual added UDP sources
						{
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
							if(UseNATEncrpytion() && (thePrefs.IsSupportISPBypass() == 1 || thePrefs.IsSupportISPBypass() == 2) && (thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1))
								PrepareNATEncryption();
 #endif // ISPBYPASS // NEO: SCC END
							TryToSyncOverBuddy();
							// NEO: LUC - [LowIDUplaodCallBack]
							if( GetUploadState() == US_WAITCALLBACK )
								SetUploadState(US_WAITCALLBACKKAD);

							if( GetDownloadState() == DS_WAITCALLBACK )
							// NEO: LUC END
								SetDownloadState(DS_WAITCALLBACKKAD);
						}
						else
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
						{
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
							if(thePrefs.IsSupportISPBypass() && SupportSecureCallback() && (thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1))
								RequestSecureCallback();
							else
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
							{
								CSafeMemFile bio(34);
								bio.WriteUInt128(&Kademlia::CUInt128(GetBuddyID()));
								bio.WriteUInt128(&Kademlia::CUInt128(reqfile->GetFileHash()));
								bio.WriteUInt16(thePrefs.GetPort());
								if (thePrefs.GetDebugClientKadUDPLevel() > 0 || thePrefs.GetDebugClientUDPLevel() > 0)
									DebugSend("KadCallbackReq", this);
								Packet* packet = new Packet(&bio, OP_KADEMLIAHEADER);
								packet->opcode = KADEMLIA_CALLBACK_REQ;
								theStats.AddUpDataOverheadKad(packet->size);
								theApp.clientkad->SendPacket(packet, GetBuddyIP(), GetBuddyPort()); // NEO: KAX - [KadAuxPort] <-- Xanatos --
							}
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
							if( GetUploadState() == US_WAITCALLBACK )
								SetUploadState(US_WAITCALLBACKKAD);

							if( GetDownloadState() == DS_WAITCALLBACK )
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
								SetDownloadState(DS_WAITCALLBACKKAD);
						}
					}
					else
					{
						//Create search to find buddy.
						Kademlia::CSearch *findSource = new Kademlia::CSearch;
						findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
						findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
						findSource->AddFileID(Kademlia::CUInt128(reqfile->GetFileHash()));
						if(Kademlia::CSearchManager::StartSearch(findSource))
						{
							//Started lookup..
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
							if( GetUploadState() == US_WAITCALLBACK )
								SetUploadState(US_WAITCALLBACKKAD);

							if( GetDownloadState() == DS_WAITCALLBACK )
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
								SetDownloadState(DS_WAITCALLBACKKAD);
						}
						else
						{
							//This should never happen..
							ASSERT(0);
						}
					}
				}
			}
			else
			{
				if (GetDownloadState() == DS_WAITCALLBACK)
				{
					m_bReaskPending = true;
					SetDownloadState(DS_ONQUEUE);
				}
			}
		}
	}
	// MOD Note - end
	else
	{
		if (!Connect())
			return false; // client was deleted!
	}

   // NEO: FCCP - [FixConnectionCollision] -- Xanatos -->
   }
   else if(IsBanned()) //call this only with my fix inside!
   {
      //Xman first check for banned clients. Could occur during our communication
      if (thePrefs.GetLogBannedClients()) 
         AddDebugLogLine(false, _T("Refused to connect to banned client %s"), DbgGetClientInfo());
      SetForDelete(); // NEO: TCR - [TCPConnectionRetry]
      if (Disconnected(_T("Banned IP")))
      {
         delete this;
         return false;
      }
   }
   else if (CheckHandshakeFinished()) {
      ConnectionEstablished();
      return true;
   }
   else if (m_byHelloPacketState == HP_NONE) {
      if (!SendHelloPacket())
         return false; // client was deleted!
      DebugLog(LOG_SUCCESS, _T("[FIX CONNECTION COLLISION] Already initiated socket, OP_HELLO have been sent to client: %s"), DbgGetClientInfo());
   }
   // NEO: FCCP END <-- Xanatos --

	return true;
}

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
/**
* TryToSyncOverBuddy sends a NAT ping request over a KAD buddy to teh target client,
*  It may also request a remote TryToSyncOverBuddy to get the actual port of the target
*
* @param bPasive: is set to true when its an answer on a requested TryToSyncOverBuddy
*/
void CUpDownClient::TryToSyncOverBuddy(bool bPasive)
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"Pasive %u",(uint8)bPasive);

	if(!bPasive){
		ResetNatTraversalState();
		AddNatTraversalState(NT_INITIALIZER); // this tell us to send a hello after we have a open tunel
		SetLastNatTraversalTry();
	}

	CSafeMemFile data(128);
	data.WriteHash16(GetBuddyID());

	// Since here all datas are pased unparsed to the buddy (our target)
	uchar hash[16]; md4clr(&hash[0]);
	data.WriteHash16(&hash[0]); // a invalid NULL indicates this is a Mod Prot Packet, not a file reask

	// write mod opcode
	data.WriteUInt8(OP_NAT_SYNC);

	// We may relay on the udp port published by the cleint and send our direct ping immidetly
	// or we can ask the remote client to send us his actual valid udp port and send the sync ping when we recive his OP_NAT_SYNC over our buddy
	// if we are behind a Full Cone NAT we send the sync and just wait for the remote ping to arrive 
	if(!bPasive && Kademlia::CKademlia::IsConnected() && theApp.clientlist->GetBuddy() && (!IsNATPortRelaiable() || thePrefs.DontTrustNatPorts()) && !thePrefs.IsFullConeNat())
	{
		NATTrace((uint32)socket,NLE_OTHER,__FUNCTION__,"Remote sync requested");

		data.WriteUInt8(OP_NAT_SYNC_REQ); // request OP_NAT_SYNC
		data.WriteUInt8(16+4+2); // length to can skipp unknown entries, max 255 bytes should be enough

		// write our buddyID
		Kademlia::CUInt128 uBuddyID(true);
		uBuddyID.Xor(Kademlia::CKademlia::GetPrefs()->GetKadID());
		byte cID[16];
		uBuddyID.ToByteArray(cID);
		data.WriteHash16(cID); // my kad id

		// write the ip/udpport of our buddy
		data.WriteUInt32(theApp.clientlist->GetBuddy()->GetIP());
		data.WriteUInt16(theApp.clientlist->GetBuddy()->GetKadPort());
	}

 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	if(m_KeyDataOut)
	{
		NATTrace((uint32)socket,NLE_OTHER,__FUNCTION__,"send Security config over buddy");

		m_KeyDataOut->Seek(1, CFile::begin); // feom 1 drop the dummy opcode
		uint8 len = (uint8)m_KeyDataOut->GetLength()-1;

		data.WriteUInt8(OP_NAT_SECURITY); // request OP_NAT_SYNC
		data.WriteUInt8(len); // length to can skipp unknown entries, max 255 bytes should be enough

		byte buff[48]; // the data can be 32 or 48 bytes long
		m_KeyDataOut->Read(&buff[0],len);
		data.Write(buff,len);

		if(m_UDPEncryption->IsSending())
			m_UDPEncryption->SendingDone();
		// se send it only once anyway
		delete m_KeyDataOut;
		m_KeyDataOut = NULL;
	}
 #endif // ISPBYPASS // NEO: SCC END

	NATTrace((uint32)socket,NLE_SENT,__FUNCTION__,"Sync Request");

	// send packet over buddy
	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP__ReaskCallbackUDP (MOD)", this, NULL);
	Packet* packet = new Packet(&data, OP_EMULEPROT);
	packet->opcode = OP_REASKCALLBACKUDP;
	theStats.AddUpDataOverheadFileRequest(packet->size);
	theApp.clientkad->SendPacket(packet, GetBuddyIP(), GetBuddyPort() ); // NEO: KAX - [KadAuxPort]

	if(!bPasive)
	{
		theApp.downloadqueue->AddUDPFileReasks();
		m_nTotalUDPPackets++; // X?

		// if we don't have a buddy or the remote port is relaiable, ping now
		// if we are behind a Full Cone NAT don't ping just wait for the remote ping
		if((!theApp.clientlist->GetBuddy() || (IsNATPortRelaiable() && !thePrefs.DontTrustNatPorts())) && !thePrefs.IsFullConeNat())
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			if(UseNATEncrpytion() && (thePrefs.IsSupportISPBypass() == 1 || thePrefs.IsSupportISPBypass() == 2) && (thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1))
				SendDummyPing();
			else
 #endif // ISPBYPASS // NEO: SCC END
				SendNatPing();
	}

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}

 #ifdef ISPBYPASS // NEO: SUC - [SafeUCPCommunication]
void CUpDownClient::PrepareNATEncryption(bool bNoTrash) // Note: we establishc a new nat security on every connection also for file reask pings
{
	//ASSERT(m_UDPEncryption == NULL);
	delete m_UDPEncryption; // thay may be an old one from a UDP file reask ping

	m_UDPEncryption = new CSocketCryptor();

	// yet we have only one udp port, may change in future
	//if(m_abyRemoteDHPrime && m_nRemoteSecurePort)
	//	m_UDPEncryption->SetDH(m_abyRemoteDHPrime,m_abyRemoteDHBase);

	delete m_KeyDataOut;
	m_KeyDataOut = new CSafeMemFile();
	if(UsePKEncrpytion() && theApp.clientcredits->CryptoAvailable() && credits && credits->GetSecIDKeyLen()){
		m_KeyDataOut = SecureConnection(false); // PK
		m_UDPEncryption->SetSending(true); // after we sent this first packet the socket will be set to secure state
		m_UDPEncryption->SetA(); // DX2
	}else
		m_KeyDataOut = m_UDPEncryption->SecureConnection(false,NULL,bNoTrash); // DH
}

void CUpDownClient::SendSecurePing() // try not so sen the key data to buddy and over ping use always only onw way
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");
	NATTrace((uint32)socket,NLE_SENT,__FUNCTION__,"Nat Kay Ping");

	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP__Nat_Ping", this, NULL);

	m_KeyDataOut->Seek(0, CFile::begin); // from 0 with the dummy opcode
	uint8 uDummy = m_KeyDataOut->ReadUInt8();
	Packet* ping = new Packet((uint8)(rand()%256), (UINT)m_KeyDataOut->GetLength(), uDummy);
	m_KeyDataOut->Read(ping->pBuffer, (UINT)m_KeyDataOut->GetLength()-1);

	if(m_UDPEncryption->IsSending())
		m_UDPEncryption->SendingDone();
	// se send it only once anyway
	delete m_KeyDataOut;
	m_KeyDataOut = NULL;

	theStats.AddUpDataOverheadFileRequest(ping->size);
	theApp.clientkad->SendPacket(ping, GetConnectIP(), GetNatPort());

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}

void CUpDownClient::SendPacketUDP(Packet* packet, bool bKad, uint16 port)
{
	ASSERT(!m_UDPEncryption || m_UDPEncryption->IsSecure());

	if(socket && socket->m_Socket->IsNatSocket() && ((CNATSocket*)socket->m_Socket)->IsSecure()) // we have a "tcp" connection why do we try to send somethink over udp?
	{
		ASSERT(0);
		return;
	}

	if(m_UDPEncryption && m_UDPEncryption->IsSecure()){
		// Note: we need a way to encrypt securely packets sent over UDP, without fails on changed order or missing packets
		// for this we reset the key shudling alghorytm for every packet, and as kay we use the SHA256 hash of the real key and a 16 bit rundom number
		// for practival reasone i have excluded come values form the first byte so we have only 63488 combinations instad of 65536, but thats stillenough
		Packet* oldpacket = packet;
		byte randomizer[2];
		randomizer[0] = CSocketCryptor::GetDummy(); // here we have 8 reserved values of valid prot id's
		randomizer[1] = (uint8)(rand()%256); // here we have the full range

		packet = new Packet(randomizer[1], oldpacket->size+2, randomizer[0]);
		packet->pBuffer[0] = oldpacket->prot;
		packet->pBuffer[1] = oldpacket->opcode;
		memcpy(packet->pBuffer+2,oldpacket->pBuffer,oldpacket->size);

		delete oldpacket;

		CSocketCryptor::EnCodeBufferUDP(packet->pBuffer,packet->size,m_UDPEncryption->abyKey,m_UDPEncryption->uKeyLen,&randomizer[0],(uint8)m_UDPEncryption->eSide);
	}

	if(bKad){
		if(port == 0)
			port = GetKadPort();
		theApp.clientkad->SendPacket(packet, GetConnectIP(), port);
	}else{
		if(port == 0)
			port = GetUDPPort();
		theApp.clientudp->SendPacket(packet, GetConnectIP(), port);
	}
}

void CUpDownClient::SendDummyPing() // Note: This ping is expected to be dropepd by the NAT, howeever if it arrives it will be dropped by us.
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");
	NATTrace((uint32)socket,NLE_SENT,__FUNCTION__,"Nat dummy Ping");

	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP__Nat_Ping", this, NULL);

	//CSafeMemFile trashData(15);

	//uint8 trash = (uint8)(rand()%16);
	//for(;trash>0;trash--)
	//	trashData.WriteUInt8((uint8)(rand()%256));
	// we should get 0 to 15 random chars, more would collide with the SUI key size, 

	//trashData.Seek(0, CFile::begin); // from 0 with the dummy opcode
	//Packet* ping = new Packet((uint8)(rand()%256), (UINT)trashData.GetLength(), CSocketCryptor::GetDummy());
	//trashData.Read(ping->pBuffer, (UINT)trashData.GetLength());
	Packet* ping = new Packet((uint8)(rand()%256), 0, CSocketCryptor::GetDummy());

	theStats.AddUpDataOverheadFileRequest(ping->size);
	theApp.clientkad->SendPacket(ping, GetConnectIP(), GetNatPort());

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}
 #endif // ISPBYPASS // NEO: SUC END

/**
* SendNatPing sendd a nat ping or ping ack, the packet does not contain any data
*
* @param bAck: if true than an ping ACK is sent
*/
void CUpDownClient::SendNatPing()
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");
	NATTrace((uint32)socket,NLE_SENT,__FUNCTION__,"Nat Ping");

	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP__Nat_Ping", this, NULL);
	Packet* ping = new Packet(OP_NAT_PING, 0, OP_MODPROT);
	theStats.AddUpDataOverheadFileRequest(ping->size);
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	SendPacketUDP(ping,true,GetNatPort());
 #else
	theApp.clientkad->SendPacket(ping, GetConnectIP(), GetNatPort());
 #endif // ISPBYPASS // NEO: SCC END

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}

/**
* The Function SendNatConfig sends the needed configuration informations
* 1. Nat Traversal Version
* 2. The Maximal Segment Size, this value is obtional
*
*/
void CUpDownClient::SendNatConfig()
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");

	CSafeMemFile data(128);

	uint32 tagcount = 4;
	data.WriteUInt32(tagcount); // nr. of tags

	// version
	CTag tagVersion(NTT_VERSION,1);
	tagVersion.WriteTagToFile(&data);

	CTag tagNatType(NTT_NAT_TYPE,thePrefs.GetNatType()); // obtional, default if restricted cone
	tagNatType.WriteTagToFile(&data);

	CTag tagFixPort(NTT_FIX_PORT,thePrefs.IsNATPortRelaiable()); // obtional
	tagFixPort.WriteTagToFile(&data);

	// max segment size (obtional but should be sent)
	CTag tagMssSize(NTT_MSS_SIZE,MAXFRAGSIZE);
	tagMssSize.WriteTagToFile(&data);

	NATTrace((uint32)socket,NLE_SENT,__FUNCTION__,"Nat Configurations");

	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP_Nat_Config", this, NULL);
	Packet* config = new Packet(&data, OP_MODPROT);
	config->opcode = OP_NAT_CONFIG;
	theStats.AddUpDataOverheadFileRequest(config->size);
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	SendPacketUDP(config,true,GetNatPort());
 #else
	theApp.clientkad->SendPacket(config, GetConnectIP(), GetNatPort());
 #endif // ISPBYPASS // NEO: SCC END

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}

/**
* The Function ProcessNatConfigPacket reads all konfiguration and configures the Nat Socket
*   Note: the NAT Socket is not operative untill it has been configured.
* 
* @param pachPacket: A pointer to the recive buffer
*
* @param nSize: Recieve buffer size
*/
void CUpDownClient::ProcessNatConfigPacket(const uchar* pachPacket, uint32 nSize)
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");

	CString m_strNatInfo;
	bool bDbgInfo = thePrefs.GetUseDebugDevice();
	bool bDbgInfoPrint = false;

	if(bDbgInfo)
		m_strNatInfo.AppendFormat(_T("--> Nat Config Packet Info, cleint %s: "), GetUserName());

	CSafeMemFile data(pachPacket, nSize);

	sUserModeTCPConfig* UserModeTCPConfig = new sUserModeTCPConfig(GetConnectIP(), GetNatPort()); // NEO: UTCP - [UserModeTCP]

	uint32 tagcount = data.ReadUInt32();

	if (bDbgInfo)
		m_strNatInfo.AppendFormat(_T("  Tags=%u"), (UINT)tagcount);
	for (uint32 i = 0; i < tagcount; i++)
	{
		CTag temptag(&data, false);
		switch (temptag.GetNameID())
		{
			case NTT_VERSION:
			{
				ASSERT( temptag.IsInt() );
				m_uNatTraversalVersion = (uint8) temptag.GetInt();
				UserModeTCPConfig->Version = (uint8) temptag.GetInt(); // NEO: UTCP - [UserModeTCP]
				break;
			}
			case NTT_NAT_TYPE:
			{
				ASSERT( temptag.IsInt() );
				m_uNatCharacteristic = temptag.IsInt();
				break;
			}
			case NTT_FIX_PORT: 
			{
				ASSERT( temptag.IsInt() );
				m_uNatPortRelaiable = temptag.IsInt();
				break;
			}
			// NEO: UTCP - [UserModeTCP]
			case NTT_MSS_SIZE:
			{
				ASSERT( temptag.IsInt() );
				UserModeTCPConfig->MaxSegmentSize = temptag.GetInt();
				break;
			}
			// NEO: UTCP END
			default:
				if (bDbgInfo){
					m_strNatInfo.AppendFormat(_T("\n  ***UnkTag=%s"), temptag.GetFullInfo());
					bDbgInfoPrint = true;
				}
		}
	}

	((CNATSocket*)socket->m_Socket)->SetConfig(UserModeTCPConfig); // NEO: UTCP - [UserModeTCP]

	if (bDbgInfo && data.GetPosition() < data.GetLength()){
		m_strNatInfo.AppendFormat(_T("\n  ***AddData: %u bytes"), data.GetLength() - data.GetPosition());
		bDbgInfoPrint = true;
	}

	if(bDbgInfo)
		m_strNatInfo.Append(_T("\n <--"));

	if(bDbgInfoPrint)
		DebugLog(LOG_WARNING, m_strNatInfo);

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
}

/**
* ResetNatTraversalState is ment to keep the stuff clean, it conditionaly resets the state to none.
* It can also delete the old socket this happens wen we recive an sync or ping again, this means the remote socket is already resetet
* 
* @param bFromSocket: reset from socket means we also
*
*/
bool CUpDownClient::ResetNatTraversalState(bool bFromSocket)
{ 
	ASSERT(m_uLastNatTraversalTry != 0 || m_byNatTraversalState == NT_NONE || m_byNatTraversalState == NT_ACCEPTOR || m_byNatTraversalState == NT_INITIALIZER);

	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");

	if(socket && socket->m_Socket->IsNatSocket() && ((CNATSocket*)socket->m_Socket)->IsConfig()){ // re reset the connection so that a secundyry conneciton attempt will success
		socket->client = 0;
		socket->Safe_Delete();
		socket = 0;
		m_byNatTraversalState &= ~ (NT_TUNEL | NT_COMPLETE);
		NATTrace((uint32)socket,NLE_OTHER,__FUNCTION__,"clearing socket");
	}
	if(bFromSocket == false || (::GetTickCount() - m_uLastNatTraversalTry) > SEC2MS(20)){ // X-ToDo: is this time ok
		m_byNatTraversalState = NT_NONE; 
		m_uLastNatTraversalTry = 0;
		NATTrace((uint32)socket,NLE_OTHER,__FUNCTION__,"reseting state");
	} 
	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");
	return m_byNatTraversalState == NT_NONE; // reseted
}

/**
* CheckNatTraversalState take care of connunicating only when we have a valid state, and a proper socket.
* If we don't have a valid state the state will be reset and the connection dropped.
* 
* @param port: give's a source port to check it must always be == GetNatPort() otherwice our answers want arrive
*/
bool CUpDownClient::CheckNatTraversalState(uint16 port)
{
	NATTrace((uint32)socket,NLE_FUNCTION,__FUNCTION__,"");
	if(GetNatTraversalState() == NT_NONE)
	{
		DebugLogWarning(_T("Recived nat config for a cleint without an activ nat state!; cleint: %s"),GetUserName());
		NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"no nat state");
		//ASSERT(0);
		return false;
	}

	uint8 uRet = 0x00;
	if(socket && !socket->m_Socket->IsNatSocket()){
		DebugLogError(_T("Resived nat traversal packet for a client who have a *tcp* socket; cleint: %s"),GetUserName());
		uRet |= socket ? 0x02 : 0x01;
	}

	if(port)
	{
		if(port != GetNatPort()){ // this should nevver happen unless the remote nat is not RFC conform
			DebugLogError(_T("!!! NAT UDP port mismatch %u - %u, cleint: %s"),(UINT)port,(UINT)GetNatPort(),GetUserName());
			uRet |= 0x04; // we can't continue as our packets want arrive
		}
	}

	if(uRet != 0x00){
		NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"no socket %i, bad socket %i, port mismatch %i, no config %i"
							, (int)(uRet & 0x01), (int)(uRet & 0x02), (int)(uRet & 0x04), (int)(uRet & 0x08));
		ResetNatTraversalState();
		ASSERT(0);
		return false;
	}

	NATTrace((uint32)socket,NLE_RESULT,__FUNCTION__,"done");

	return true;
}
#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --

#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
bool CUpDownClient::SwapSocket()
{
	//socket->client = NULL; // don't set NULL we want still recive packets it thay come

 #ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler]
	bool onDownQueue = false;
	if (socket && socket->onDownQueue)
	{
		theApp.downloadBandwidthThrottler->RemoveFromStandardList(socket);
		theApp.downloadqueue->RemoveFromProcessQueue(socket);
		socket->onDownQueue = false; // for Direct Download
		onDownQueue = true;
	}
 #endif // NEO_DBT // NEO: NDBT END

	//socket->client = NULL;  // Note: from this monet we can't recive anythink from the other cleint untill he swaps his socket to, 
	//						  //		in the cases where we swap the socket we don't expect to get any additional packets
	oldsocket = socket; // keep trace on the dropped socket, so we can still reciev packets from it

	// we create a new socket and let the old one simply timeout

	// create new socket
	socket = static_cast<CClientReqSocket*>(RUNTIME_CLASS(CClientReqSocket)->CreateObject());
	socket->SetClient(this);
	if (!socket->Create())
	{
		socket->Safe_Delete();
		return false;
	}

	// stablish new secure connection
	Connect(true);

 #ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler]
	if (onDownQueue)
	{
		if(!thePrefs.IsDirectDownload())
		{
			theApp.downloadBandwidthThrottler->AddToStandardList(socket);
			theApp.downloadqueue->AddToProcessQueue(socket);
		}
		else
			socket->onDownQueue = true;
	}
 #endif // NEO_DBT // NEO: NDBT END

	// send swap request
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__Swap_Socket", this);
	Packet* packet = new Packet(OP_SWAP_SOCKET, 2, GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
	PokeUInt16(packet->pBuffer, thePrefs.GetPort());
	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet,true);

	return true;
}
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --

#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
bool CUpDownClient::Connect(bool bSwap)
#else
bool CUpDownClient::Connect()
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
{
	//Try to always tell the socket to WaitForOnConnect before you call Connect.
	socket->WaitForOnConnect();
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	bool bSecureConnection = 
		(thePrefs.IsSupportISPBypass() && (thePrefs.GetNeedISPBypass() == 3 ||
		GetSecureCommunicationVersion() && (
		(thePrefs.GetNeedISPBypass() > 1 || DoRequierEncryption() > 1)
		// Note: The case below wont work properly when the client we want upload to is a low id
		//        In this case the remote low id will hotswap the connection when he recives accept upload
		|| ((thePrefs.GetNeedISPBypass() > 0 || DoRequierEncryption() > 0) && GetUploadState() == US_CONNECTING)
		)));
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

	SOCKADDR_IN sockAddr = {0};
	sockAddr.sin_family = AF_INET;
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	if(bSecureConnection && m_nRemoteSecurePort /*&& (m_uFaildCount == 0 || thePrefs.GetNeedISPBypass() == 3)*/)
		sockAddr.sin_port = htons(m_nRemoteSecurePort);
	else
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --
		sockAddr.sin_port = htons(GetUserPort());
	sockAddr.sin_addr.S_un.S_addr = GetConnectIP();
	socket->Connect((SOCKADDR*)&sockAddr, sizeof sockAddr);
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
	if(bSecureConnection){
		bool bXorOnly = I2B(UseSimpleXOREncryption());

		ASSERT(socket->m_Encryption == NULL);
		if(socket->m_Encryption == NULL)
			socket->m_Encryption = new CSocketCryptor();

		if(m_abyRemoteDHPrime && m_nRemoteSecurePort)
			socket->m_Encryption->SetDH(m_abyRemoteDHPrime,m_abyRemoteDHBase);

		CSafeMemFile* keyData;
		if(UsePKEncrpytion() && theApp.clientcredits->CryptoAvailable() && credits && credits->GetSecIDKeyLen())
			keyData = SecureConnection(bXorOnly); // PK
		else
			keyData = socket->m_Encryption->SecureConnection(bXorOnly); // DH

		if(keyData){
			ASSERT(socket->HasQueues() == false); // It should be the first packet we send
			// Send initialisation packet
			Packet* packet = new Packet(new char[(UINT)keyData->GetLength()], (UINT)keyData->GetLength(), true, false);
			keyData->Seek(0, CFile::begin);
			keyData->Read(packet->GetPacket(), (UINT)keyData->GetLength());
			delete keyData;
			socket->SendPacket(packet);
		}else
			return false;

		if(PreferUnencryptedPayload() && thePrefs.IsPreferUnEnCryptedPayload() && socket->m_Encryption)
			socket->m_Encryption->SetPlainPayload();
	}
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

#ifdef ISPBYPASS // NEO: CHS - [ConnectionHotSwap] -- Xanatos -->
	if(bSwap == false)
#endif // ISPBYPASS // NEO: CHS END <-- Xanatos --
	{
		if (!SendHelloPacket())
			return false; // client was deleted!
	}
	return true;
}

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
void CUpDownClient::RequestSecureCallback()
{
	CSafeMemFile data(128);
	data.WriteHash16(GetBuddyID());

	// Since here all datas are pased unparsed to the buddy (our target)
	uchar hash[16]; md4clr(&hash[0]);
	data.WriteHash16(&hash[0]); // a invalid NULL indicates this is a Mod Prot Packet, not a file reask

	// write mod opcode
	data.WriteUInt8(OP_SECURE_CALLBACK_REQ);

	data.WriteUInt128(&Kademlia::CUInt128(GetBuddyID()));
	data.WriteUInt128(&Kademlia::CUInt128(reqfile->GetFileHash()));
	data.WriteUInt16(theApp.listensocket->GetSecretPort(true)); // this connection is not sae so we give only the default secret port not the top secret port ;)

	// more data may be added later

	// send packet over buddy
	if (thePrefs.GetDebugClientUDPLevel() > 0)
		DebugSend("OP__ReaskCallbackUDP (MOD)", this, NULL);
	Packet* packet = new Packet(&data, OP_EMULEPROT);
	packet->opcode = OP_REASKCALLBACKUDP;
	theStats.AddUpDataOverheadFileRequest(packet->size);
	theApp.clientkad->SendPacket(packet, GetBuddyIP(), GetBuddyPort() );
}

CSafeMemFile* CUpDownClient::SecureConnection(bool bXorOnly) // PK
{
	srand( (unsigned)time( NULL ) );

	// generate rundom session key
	char abyConnectionKey[SOCKET_KEY_SIZE];
	for (int i = 0; i < SOCKET_KEY_SIZE; i ++)
		abyConnectionKey[i] = (byte)(rand()%256);

	// Note: We use currently 32 bytes for the kay, but the maximal amount we can encript is 37 bytes, so we have 5 bytes left for 

	byte* abyCryptedKey = NULL; // Encrypt the session kay with the public kay of the remote clinet
	VERIFY(theApp.clientcredits->EncryptData(credits,(uchar*)abyConnectionKey,SOCKET_KEY_SIZE,abyCryptedKey) == KEY_PACKET_SIZE);
	if(abyCryptedKey == NULL)
		return NULL;

	CSafeMemFile* keyData = new CSafeMemFile(49);
	keyData->WriteUInt8(CSocketCryptor::GetDummy()); // dummy opcode

	keyData->Write(abyCryptedKey,KEY_PACKET_SIZE);

	// Secure socket
	socket->m_Encryption->uKeyLen = SOCKET_KEY_SIZE;
	ASSERT(socket->m_Encryption->abyKey == NULL);
	socket->m_Encryption->abyKey = new byte[SOCKET_KEY_SIZE];
	memcpy(socket->m_Encryption->abyKey,abyConnectionKey,SOCKET_KEY_SIZE);
	if(bXorOnly)
		socket->m_Encryption->SetXor(); // XOR
	else
		socket->m_Encryption->SetA(); // DX2

	socket->m_Encryption->SetSending(true); // after we sent this first packet the socket will be set to secure state

	if(m_abyRemoteDHPrime) // in PK mode we secure the sonnection with hashing the set kay with the DH prime
		socket->m_Encryption->CrossKeys(m_abyRemoteDHPrime,SOCKET_KEY_SIZE);

	delete [] abyCryptedKey;
	return keyData;
}
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

void CUpDownClient::ConnectionEstablished()
{
	// ok we have a connection, lets see if we want anything from this client
	
	ResetFaildCount(); // NEO: TCR - [TCPConnectionRetry] <-- Xanatos --
	SetLastSeen(); // NEO: NSS - [NeoSourceStorage] <-- Xanatos --
	// We need to keep this separated, new clinets does not have an hash -> thay dont have an source object
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
	if(source)
		source->ConnectionEstablished();
#endif // NEO_CD // NEO: NCD END <-- Xanatos --

	// check if we should use this client to retrieve our public IP
	if (theApp.GetPublicIP() == 0 /*&& theApp.serverconnect->IsConnected()*/ && m_fPeerCache) // NEO: SO - [StandAlone] -- Xanatos --
		SendPublicIPRequest();

	switch(GetKadState())
	{
		case KS_CONNECTING_FWCHECK:
            SetKadState(KS_CONNECTED_FWCHECK);
			break;
		case KS_CONNECTING_BUDDY:
		case KS_INCOMING_BUDDY:
			SetKadState(KS_CONNECTED_BUDDY);
			break;
	}

	if (GetChatState() == MS_CONNECTING || GetChatState() == MS_CHATTING)
		theApp.emuledlg->chatwnd->chatselector.ConnectingResult(this,true);

	switch(GetDownloadState())
	{
		case DS_CONNECTING:
		case DS_WAITCALLBACK:
		case DS_WAITCALLBACKKAD:
			m_bReaskPending = false;
			SetDownloadState(DS_CONNECTED);
			SendFileRequest();
			break;
	}

	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:
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
		case US_WAITCALLBACKKAD:
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
			if (theApp.uploadqueue->IsDownloading(this))
			{
#ifdef NEO_DBT // NEO: NDBT - [NeoDownloadBandwidthThrottler] -- Xanatos -->
				socket->SetPriorityReceive(true);
#endif // NEO_DBT // NEO: NDBT END <-- Xanatos --
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
				socket->SetPrioritySend(true);
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
				SetUploadState(US_UPLOADING);
				SendAcceptUpload(); // NEO: PTM - [PrivatTransferManagement] <-- Xanatos --
			}
			// NEO: ASP - [ActiveSpreading] -- Xanatos -->
			else if(m_bAdvertisementPending)
			{
				m_bAdvertisementPending = false;
				if(CKnownFile* partfile = theApp.sharedfiles->GetFileByID(GetUploadFileID()))
				{
					SendFileAdvertisement(partfile);
					SetUploadFileID(NULL);
					SetUploadState(US_NONE);
				}
			}
			// NEO: ASP END <-- Xanatos --
	}

	//if (m_iFileListRequested == 1)
	// NEO: XSF - [ExtendedSharedFiles] -- Xanatos -->
	if (m_bRequestingFileList)
	{
		m_bRequestingFileList = false;
		m_iFileListRequested++;
	// NEO: XSF END <-- Xanatos --
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend(m_fSharedDirectories ? "OP__AskSharedDirs" : "OP__AskSharedFiles", this);
		Packet* packet = new Packet(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES,0);
		theStats.AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true,true);
	}

	// NEO: MCH - [ManualClientHandling] -- Xanatos -->
	if (m_iSourceListRequested == 1 && theApp.downloadqueue->IsPartFile(reqfile)) // just to be sure
	{
		m_iSourceListRequested--;

		if (thePrefs.GetDebugClientTCPLevel() > 0){
			DebugSend("OP__RequestSources", this, reqfile->GetFileHash());
			if (GetLastAskedForSources() == 0)
				Debug(_T("  first source request\n"));
			else
				Debug(_T("  last source request was before %s\n"), CastSecondsToHM((GetTickCount() - GetLastAskedForSources())/1000));
		}
		reqfile->SetLastAnsweredTimeTimeout();
		Packet* packet = new Packet(OP_REQUESTSOURCES,16,OP_EMULEPROT);
		md4cpy(packet->pBuffer,reqfile->GetFileHash());
		theStats.AddUpDataOverheadSourceExchange(packet->size);
		socket->SendPacket(packet,true,true);
		SetLastAskedForSources();
		if (thePrefs.GetDebugSourceExchange())
			AddDebugLogLine( false, _T("Send:Source Request User(%s) File(%s)"), GetUserName(), reqfile->GetFileName() );
	}
	// NEO: MCH END <-- Xanatos --

	// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
	/* Xanatos:
	* This solution is much beter that the normal "Maella -Inform sources of an ID change-",
	* by using this opcode instad of an compleer reask we can save some overhead
	* and avoid to be banned...
	*/
	if(m_bNotifyIdChage){
		m_bNotifyIdChage = false;
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__Change_Client_Id", this);
		Packet* packet = new Packet(OP_CHANGE_CLIENT_ID, 8);
		PokeUInt32(packet->pBuffer, theApp.GetPublicIP()); // New ID
		PokeUInt32(packet->pBuffer + 4, theApp.serverconnect->IsConnected() ? theApp.serverconnect->GetCurrentServer()->GetIP() : 0x00000000); // New Server IP
		theStats.AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
	}
	// NEO: RIC END <-- Xanatos --

	while (!m_WaitingPackets_list.IsEmpty())
	{
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("Buffered Packet", this);
		socket->SendPacket(m_WaitingPackets_list.RemoveHead());
	}

}

void CUpDownClient::InitClientSoftwareVersion()
{
	// NEO: FIX - [StabilityFix] -- Xanatos --
	//if (m_pszUsername == NULL){ 
	//	m_clientSoft = SO_UNKNOWN;
	//	return;
	//}

	int iHashType = GetHashType();
	if (m_bEmuleProtocol || iHashType == SO_EMULE){
		LPCTSTR pszSoftware;
		switch(m_byCompatibleClient){
			case SO_CDONKEY:
				m_clientSoft = SO_CDONKEY;
				pszSoftware = _T("cDonkey");
				break;
			case SO_XMULE:
				m_clientSoft = SO_XMULE;
				pszSoftware = _T("xMule");
				break;
			case SO_AMULE:
				m_clientSoft = SO_AMULE;
				pszSoftware = _T("aMule");
				break;
			case SO_SHAREAZA:
			// NEO: ECR - [EnhancedClientRecognization] -- Xanatos -->
			case SO_SHAREAZA2:
			case SO_SHAREAZA3:
			case SO_SHAREAZA4:
			// NEO: ECR END <-- Xanatos --
				m_clientSoft = SO_SHAREAZA;
				pszSoftware = _T("Shareaza");
				break;
			case SO_LPHANT:
				m_clientSoft = SO_LPHANT;
				pszSoftware = _T("lphant");
				break;
			// NEO: ECR - [EnhancedClientRecognization] -- Xanatos -->
			case SO_EMULEPLUS:
				m_clientSoft = SO_EMULEPLUS;
				pszSoftware = _T("eMule Plus");
				break;
			case SO_HYDRANODE:
				m_clientSoft = SO_HYDRANODE;
				pszSoftware = _T("Hydranode");
				break;
			case SO_TRUSTYFILES:
				m_clientSoft = SO_TRUSTYFILES;
				pszSoftware = _T("TrustyFiles");
				break;
			// NEO: ECR END <-- Xanatos --
			default:
				if (m_bIsML || m_byCompatibleClient == SO_MLDONKEY || m_byCompatibleClient == SO_MLDONKEY2 || m_byCompatibleClient == SO_MLDONKEY3){ // NEO: ECR - [EnhancedClientRecognization] <-- Xanatos --
				//if (m_bIsML || m_byCompatibleClient == SO_MLDONKEY){
					m_clientSoft = SO_MLDONKEY;
					pszSoftware = _T("MLdonkey");
				}
				else if (m_bIsHybrid || m_byCompatibleClient == SO_EDONKEYHYBRID){ // NEO: ECR - [EnhancedClientRecognization] <-- Xanatos --
				//else if (m_bIsHybrid){
					m_clientSoft = SO_EDONKEYHYBRID;
					pszSoftware = _T("eDonkeyHybrid");
				}
				else if (m_byCompatibleClient != 0){
					// NEO: ECR - [EnhancedClientRecognization] -- Xanatos -->
					if (StrStrI(m_strUsername,_T("shareaza")))
					{
						m_clientSoft = SO_SHAREAZA;
						pszSoftware = _T("Shareaza");
					}
					else if (StrStr(m_strModVersion,_T("Plus 1")))
					{
						m_clientSoft = SO_EMULEPLUS;
						pszSoftware = _T("eMule Plus");
					}
					else
					{
						m_clientSoft = SO_XMULE; // means: 'eMule Compatible'
						pszSoftware = _T("eMule Compat");
					}
					// NEO: ECR END <-- Xanatos --
					//m_clientSoft = SO_XMULE; // means: 'eMule Compatible'
					//pszSoftware = _T("eMule Compat");
				}
				else{
					m_clientSoft = SO_EMULE;
					pszSoftware = _T("eMule");
				}
		}

		int iLen;
		TCHAR szSoftware[128];
		if (m_byEmuleVersion == 0){
			m_nClientVersion = MAKE_CLIENT_VERSION(0, 0, 0);
			iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s"), pszSoftware);
		}
		else if (m_byEmuleVersion != 0x99){
			UINT nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f);
			m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
			iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v0.%u"), pszSoftware, nClientMinVersion);
		}
		else{
			UINT nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
			UINT nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
			UINT nClientUpVersion  = (m_nClientVersion >>  7) & 0x07;
			m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
			if (m_clientSoft == SO_EMULE)
				iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u%c"), pszSoftware, nClientMajVersion, nClientMinVersion, _T('a') + nClientUpVersion);
			// NEO: ECR - [EnhancedClientRecognization] -- Xanatos -->
			else if (m_clientSoft == SO_EMULEPLUS)
			{
				if(nClientMinVersion == 0)
				{
					if(nClientUpVersion == 0)
						iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u"), pszSoftware, nClientMajVersion);
					else
						iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u%c"), pszSoftware, nClientMajVersion, _T('a') + nClientUpVersion - 1);
				}
				else
				{
					if(nClientUpVersion == 0)
						iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion);
					else
						iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u%c"), pszSoftware, nClientMajVersion, nClientMinVersion, _T('a') + nClientUpVersion - 1);
				}
			}
			// NEO: ECR END <-- Xanatos --
			else if (m_clientSoft == SO_AMULE || nClientUpVersion != 0)
				iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion, nClientUpVersion);
			else if (m_clientSoft == SO_LPHANT)
			{
				if (nClientMinVersion < 10)
				    iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.0%u"), pszSoftware, (nClientMajVersion-1), nClientMinVersion);
				else
					iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, (nClientMajVersion-1), nClientMinVersion);
			}
			else
				iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion);
		}
		if (iLen > 0){
			memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
			m_strClientSoftware.ReleaseBuffer(iLen);
		}
		return;
	}

	if (m_bIsHybrid){
		m_clientSoft = SO_EDONKEYHYBRID;
		// seen:
		// 105010	0.50.10
		// 10501	0.50.1
		// 10300	1.3.0
		// 10201	1.2.1
		// 10103	1.1.3
		// 10102	1.1.2
		// 10100	1.1
		// 1051		0.51.0
		// 1002		1.0.2
		// 1000		1.0
		// 501		0.50.1

		UINT nClientMajVersion;
		UINT nClientMinVersion;
		UINT nClientUpVersion;
		if (m_nClientVersion > 100000){
			UINT uMaj = m_nClientVersion/100000;
			nClientMajVersion = uMaj - 1;
			nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100;
			nClientUpVersion = m_nClientVersion % 100;
		}
		else if (m_nClientVersion >= 10100 && m_nClientVersion <= 10309){
			UINT uMaj = m_nClientVersion/10000;
			nClientMajVersion = uMaj;
			nClientMinVersion = (m_nClientVersion - uMaj*10000) / 100;
			nClientUpVersion = m_nClientVersion % 10;
		}
		else if (m_nClientVersion > 10000){
			UINT uMaj = m_nClientVersion/10000;
			nClientMajVersion = uMaj - 1;
			nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10;
			nClientUpVersion = m_nClientVersion % 10;
		}
		else if (m_nClientVersion >= 1000 && m_nClientVersion < 1020){
			UINT uMaj = m_nClientVersion/1000;
			nClientMajVersion = uMaj;
			nClientMinVersion = (m_nClientVersion - uMaj*1000) / 10;
			nClientUpVersion = m_nClientVersion % 10;
		}
		else if (m_nClientVersion > 1000){
			UINT uMaj = m_nClientVersion/1000;
			nClientMajVersion = uMaj - 1;
			nClientMinVersion = m_nClientVersion - uMaj*1000;
			nClientUpVersion = 0;
		}
		else if (m_nClientVersion > 100){
			UINT uMin = m_nClientVersion/10;
			nClientMajVersion = 0;
			nClientMinVersion = uMin;
			nClientUpVersion = m_nClientVersion - uMin*10;
		}
		else{
			nClientMajVersion = 0;
			nClientMinVersion = m_nClientVersion;
			nClientUpVersion = 0;
		}
		m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);

		int iLen;
		TCHAR szSoftware[128];
		if (nClientUpVersion)
			iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkeyHybrid v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
		else
			iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkeyHybrid v%u.%u"), nClientMajVersion, nClientMinVersion);
		if (iLen > 0){
			memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
			m_strClientSoftware.ReleaseBuffer(iLen);
		}
		return;
	}

	if (m_bIsML || iHashType == SO_MLDONKEY){
		m_clientSoft = SO_MLDONKEY;
		UINT nClientMinVersion = m_nClientVersion;
		m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
		TCHAR szSoftware[128];
		int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("MLdonkey v0.%u"), nClientMinVersion);
		if (iLen > 0){
			memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
			m_strClientSoftware.ReleaseBuffer(iLen);
		}
		return;
	}

	if (iHashType == SO_OLDEMULE){
		m_clientSoft = SO_OLDEMULE;
		UINT nClientMinVersion = m_nClientVersion;
		m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
		TCHAR szSoftware[128];
		int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("Old eMule v0.%u"), nClientMinVersion);
		if (iLen > 0){
			memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
			m_strClientSoftware.ReleaseBuffer(iLen);
		}
		return;
	}

	m_clientSoft = SO_EDONKEY;
	UINT nClientMinVersion = m_nClientVersion;
	m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
	TCHAR szSoftware[128];
	int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkey v0.%u"), nClientMinVersion);
	if (iLen > 0){
		memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
		m_strClientSoftware.ReleaseBuffer(iLen);
	}
}

int CUpDownClient::GetHashType() const
{
	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;
}

// NEO: FIX - [StabilityFix] -- Xanatos --
/*void CUpDownClient::SetUserName(LPCTSTR pszNewName)
{
	free(m_pszUsername);
	if (pszNewName)
		m_pszUsername = _tcsdup(pszNewName);
	else
		m_pszUsername = NULL;
	m_detailDialogInterface->UpdateTree(_T("")); // NEO: XSF - [ExtendedSharedFiles] <-- Xanatos --
}*/

// NEO: XSF - [ExtendedSharedFiles] -- Xanatos -->
bool CUpDownClient::RequestSharedFileList(bool bForce){
	if (!GetViewSharedFilesSupport())
		return false;
	if (!bForce && m_bFileListRequested)
		return false;
	if (m_bRequestingFileList) {
		ModLogWarning(LOG_STATUSBAR, GetResString(IDS_X_REQUESTING_SHARED_FILES), GetUserName(), GetUserIDHybrid());
		return false;
	}
	m_bRequestingFileList = true;
	m_bFileListRequested = true;
	AddLogLine(true, GetResString(IDS_SHAREDFILES_REQUEST), GetUserName());
	if (!TryToConnect(true))
		return false;
	return true;
}

bool CUpDownClient::SendDirRequest(CString path, bool bForce)
{
	bool requested;
	if (!m_listDirs.Lookup(path, requested))
		return false;
	if (!bForce && requested)
		return false;

	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__AskSharedFilesInDirectory", this);
	CSafeMemFile tempfile(80);
	tempfile.WriteString(path, GetUnicodeSupport());
	Packet* replypacket = new Packet(&tempfile);
	replypacket->opcode = OP_ASKSHAREDFILESDIR;
	theStats.AddUpDataOverheadOther(replypacket->size);
	if (!socket || !socket->IsConnected())
		if (!TryToConnect(true)) {
			return false;
		}
	SetFileListRequested(GetFileListRequested()+1);
	socket->SendPacket(replypacket, true, true);
	m_listDirs.SetAt(path, true);
	return true;
}

void CUpDownClient::ProcessSharedFileList(const uchar* pachPacket, uint32 nSize, LPCTSTR pszDirectory)
{
	if (m_iFileListRequested > 0)
	{
		m_iFileListRequested--;
		CString dir;
		if (pszDirectory)
			dir = pszDirectory;
		else
			m_listDirs.SetAt(_T(""), true);

		for (POSITION pos = m_listFiles.GetHeadPosition(); pos != NULL; ) {
			POSITION pos1 = pos;
			CSearchFile *curfile = m_listFiles.GetNext(pos);
			if (curfile->GetDirectory() == dir) {
				delete curfile;
				m_listFiles.RemoveAt(pos1);
			}
		}

		uint32 nSearchID = (uint32)this;
		CSafeMemFile data(pachPacket, nSize);
		UINT results = data.ReadUInt32();

		for (UINT i = 0; i < results; i++){
			CSearchFile* toadd = new CSearchFile(&data, GetUnicodeSupport()!=utf8strNone, nSearchID, 0, 0, dir);
			toadd->SetClientID(GetIP());
			toadd->SetClientPort(GetUserPort());
			toadd->SetClientServerIP(GetServerIP());
			toadd->SetClientServerPort(GetServerPort());
			if (GetServerIP() && GetServerPort()){
				CSearchFile::SServer server(GetServerIP(), GetServerPort());
				server.m_uAvail = 1;
				toadd->AddServer(server);
			}
			toadd->SetPreviewPossible( GetPreviewSupport() && ED2KFT_VIDEO == GetED2KFileTypeID(toadd->GetFileName()) );
			m_listFiles.AddTail(toadd);
			// NEO: SSC - [SearchCatch]
			CPartFile *file = theApp.downloadqueue->GetFileByID(toadd->GetFileHash());
			if (file){
				if (toadd->GetClientID() && toadd->GetClientPort()){
					// pre-filter sources which would be dropped in CPartFile::AddSources
					if (CPartFile::CanAddSource(toadd->GetClientID(), toadd->GetClientPort(), toadd->GetClientServerIP(), toadd->GetClientServerPort())){
						CSafeMemFile sources(1+4+2);
						sources.WriteUInt8(1);
						sources.WriteUInt32(toadd->GetClientID());
						sources.WriteUInt16(toadd->GetClientPort());
						sources.SeekToBegin();
						file->AddSources(&sources,toadd->GetClientServerIP(),toadd->GetClientServerPort());
					}
				}
				// NEO: XUC - [ExtendedUdpCache]
				if(thePrefs.UseUDPCache()){
					CPartFile::SServer tmpServer(toadd->GetClientServerIP(), toadd->GetClientServerPort());
					tmpServer.m_uAvail = toadd->GetIntTagValue(FT_SOURCES);
					file->AddAvailServer(tmpServer);
					Debug(_T("Caching server with %i sources for %s"), toadd->GetIntTagValue(FT_SOURCES), file->GetFileName());
				}
				// NEO: XUC END
			}
			// NEO: SSC END
		}
		data.Close();
		m_detailDialogInterface->UpdateTree(dir);
	}
}

void CUpDownClient::ProcessSharedDirsList(const uchar* pachPacket, uint32 nSize)
{
	bool requested;
	if (m_iFileListRequested > 0)
	{
		m_iFileListRequested--;
		CSafeMemFile data(pachPacket, nSize);
		UINT uDirs = data.ReadUInt32();
		if (uDirs > 0)
			m_listDirs.RemoveAll();
		for (UINT i = 0; i < uDirs; i++)
		{
			CString strDir = data.ReadString(GetUnicodeSupport()!=utf8strNone);
			AddDebugLogLine(true, GetResString(IDS_SHAREDANSW), GetUserName(), GetUserIDHybrid(), strDir);
			if (!m_listDirs.Lookup(strDir, requested))
				m_listDirs.SetAt(strDir, false);
		}
		ASSERT( data.GetPosition() == data.GetLength() );
		for (POSITION pos = m_listFiles.GetHeadPosition(); pos != NULL; ) {
			POSITION pos1 = pos;
			CSearchFile *curfile = m_listFiles.GetNext(pos);
			if (!m_listDirs.Lookup(curfile->GetDirectory(), requested)) {
				delete curfile;
				m_listFiles.RemoveAt(pos1);
			}
		}
		m_detailDialogInterface->UpdateTree(_T(""));
	}
	else
		AddLogLine(true, GetResString(IDS_SHAREDANSW2), GetUserName(), GetUserIDHybrid());
}

void CUpDownClient::SetDeniesShare(bool in, bool updateTree)
{
	m_bDeniesShare = in;
	if (in) {
		m_listDirs.RemoveAll();
		while (!m_listFiles.IsEmpty())
			delete m_listFiles.RemoveHead();
	}
	if (updateTree) 
		m_detailDialogInterface->UpdateTree(_T(""));
}
// NEO: XSF END <-- Xanatos --

/*void CUpDownClient::RequestSharedFileList()
{
	if (m_iFileListRequested == 0){
		AddLogLine(true, GetResString(IDS_SHAREDFILES_REQUEST), GetUserName());
    	m_iFileListRequested = 1;
		TryToConnect(true);
	}
	else{
		LogWarning(LOG_STATUSBAR, _T("Requesting shared files from user %s (%u) is already in progress"), GetUserName(), GetUserIDHybrid());
	}
}

void CUpDownClient::ProcessSharedFileList(const uchar* pachPacket, uint32 nSize, LPCTSTR pszDirectory)
{
	if (m_iFileListRequested > 0)
	{
        m_iFileListRequested--;
		theApp.searchlist->ProcessSearchAnswer(pachPacket,nSize,this,NULL,pszDirectory);
	}
}*/

// NEO: MCH - [ManualClientHandling] -- Xanatos -->
void CUpDownClient::RequestSourceList()
{
	if (m_iSourceListRequested == 0){
		m_iSourceListRequested = 1;
		TryToConnect(true);
	}
}
// NEO: MCH END <-- Xanatos --

// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
bool CUpDownClient::NotifyIdChage()
{
	if (theApp.listensocket->TooManySockets() && !(socket && socket->IsConnected()) )
	{
		m_bWainingNotifyIdChage = true;
		return true;
	}
	m_bWainingNotifyIdChage = false;

	m_bNotifyIdChage = true;
	return TryToConnect();
}
// NEO: RIC END <-- Xanatos --

void CUpDownClient::SetUserHash(const uchar* pucUserHash)
{
	if( pucUserHash == NULL ){
		md4clr(m_achUserHash);
		return;
	}

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->

	//************* Neo Mule User Hash *******************************//
	// 00  01  02  03  04  05  06  07  08  09  10  11  12  13  14  15 //
	// ??  ??  ??  ??  ??  14  ??  'N' 'M' !!  !!  !!  !!  ??  111 ?? //
	//****************************************************************//

	if(m_achUserHash[7] == 'N' && m_achUserHash[8] == 'M')
	{
		uint32* uNeoHashFlagPool = (uint32*)&m_achUserHash[9];

		// 1st byte

		// 2st byte
		//				  (*uNeoHashFlagPool	>> 12) & 0x0f;
		uint32 secport	= (*uNeoHashFlagPool	>> 11) & 0x01; // is a secure port attached
		uint32 need		= (*uNeoHashFlagPool	>> 10) & 0x01; // only when mode is implicit or higher
		uint32 support	= (*uNeoHashFlagPool	>> 8 ) & 0x02; // in what extend do we support TCP is always but NAT(relevant) and UDP(irrelevant) is obtional

		if(support)
		{
			SetSecureCommunicationSupport();
			SetSupportSecureCallback();
			SetRequierEncryption(need ? 2 : 0);

 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
			SetNATEncrpytion(support < 3); // "< 3" ~ TCP & NAT & [UDP], 3 ~ TCP only
 #endif //NATTUNNELING // NEO: NATT END

			if(secport)
			{
				// 3rd and 4th secure port
				if(secport && GetRemoteSecurePort() == 0) // if we have a port it is already this one or a more secure onw
					SetRemoteSecurePort((uint16)((*uNeoHashFlagPool >> 16) & 0xffff));
			}
		}
	}
#endif // ISPBYPASS // NEO: SCC END <-- Xanatos --

	md4cpy(m_achUserHash, pucUserHash);
}

void CUpDownClient::SetBuddyID(const uchar* pucBuddyID)
{
	if( pucBuddyID == NULL ){
		md4clr(m_achBuddyID);
		m_bBuddyIDValid = false;
		return;
	}
//#ifdef NATTUNNELING // NEO: NATT - [NatTraversal] -- Xanatos -->
//	if(isnulmd4(pucBuddyID))
//		return;
//#endif //NATTUNNELING // NEO: NATT END <-- Xanatos --
	m_bBuddyIDValid = true;
	md4cpy(m_achBuddyID, pucBuddyID);
}

void CUpDownClient::SendPublicKeyPacket()
{
	// send our public key to the client who requested it
	if (socket == NULL || credits == NULL || m_SecureIdentState != IS_KEYANDSIGNEEDED){
		ASSERT ( false );
		return;
	}
	if (!theApp.clientcredits->CryptoAvailable())
		return;

    Packet* packet = new Packet(OP_PUBLICKEY,theApp.clientcredits->GetPubKeyLen() + 1,OP_EMULEPROT);
	theStats.AddUpDataOverheadOther(packet->size);
	memcpy(packet->pBuffer+1,theApp.clientcredits->GetPublicKey(), theApp.clientcredits->GetPubKeyLen());
	packet->pBuffer[0] = theApp.clientcredits->GetPubKeyLen();
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__PublicKey", this);
	socket->SendPacket(packet,true,true);
	m_SecureIdentState = IS_SIGNATURENEEDED;
}

void CUpDownClient::SendSignaturePacket()
{
	// signate the public key of this client and send it
	if (socket == NULL || credits == NULL || m_SecureIdentState == 0){
		ASSERT ( false );
		return;
	}

	if (!theApp.clientcredits->CryptoAvailable())
		return;
	if (credits->GetSecIDKeyLen() == 0)
		return; // We don't have his public key yet, will be back here later
	// do we have a challenge value received (actually we should if we are in this function)
	if (credits->m_dwCryptRndChallengeFrom == 0){
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("Want to send signature but challenge value is invalid ('%s')"), GetUserName());
		return;
	}
	// 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 byChaIPKind = 0;
	uint32 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
	uchar achBuffer[250];
	uint8 siglen = theApp.clientcredits->CreateSignature(credits, achBuffer,  250, ChallengeIP, byChaIPKind );
	if (siglen == 0){
		ASSERT ( false );
		return;
	}
	Packet* packet = new Packet(OP_SIGNATURE,siglen + 1+ ( (bUseV2)? 1:0 ),OP_EMULEPROT);
	theStats.AddUpDataOverheadOther(packet->size);
	memcpy(packet->pBuffer+1,achBuffer, siglen);
	packet->pBuffer[0] = siglen;
	if (bUseV2)
		packet->pBuffer[1+siglen] = byChaIPKind;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__Signature", this);
	socket->SendPacket(packet,true,true);
	m_SecureIdentState = IS_ALLREQUESTSSEND;
}

void CUpDownClient::ProcessPublicKeyPacket(const uchar* pachPacket, uint32 nSize)
{
	theApp.clientlist->AddTrackClient(this);

	if (socket == NULL || credits == NULL || pachPacket[0] != nSize-1
		|| nSize == 0 || nSize > 250){
		ASSERT ( false );
		return;
	}
	if (!theApp.clientcredits->CryptoAvailable())
		return;
	// 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
			if (thePrefs.GetLogSecureIdent())
				AddDebugLogLine(false, _T("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket"));
		}
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
		SendAUXPortWhenNeeded();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
	}
	else
	{
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("Failed to use new received public key"));
	}
}

void CUpDownClient::ProcessSignaturePacket(const uchar* pachPacket, uint32 nSize)
{
	// here we spread the good guys from the bad ones ;)

	if (socket == NULL || credits == NULL || nSize == 0 || nSize > 250){
		ASSERT ( false );
		return;
	}

	uint8 byChaIPKind;
	if (pachPacket[0] == nSize-1)
		byChaIPKind = 0;
	else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2
		byChaIPKind = pachPacket[nSize-1];
	else{
		ASSERT ( false );
		return;
	}

	if (!theApp.clientcredits->CryptoAvailable())
		return;
	
	// we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
	if (m_dwLastSignatureIP == GetIP())
	{
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("received multiple signatures from one client"));
		return;
	}
	
	// also make sure this client has a public key
	if (credits->GetSecIDKeyLen() == 0)
	{
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("received signature for client without public key"));
		return;
	}
	
	// and one more check: did we ask for a signature and sent a challange packet?
	if (credits->m_dwCryptRndChallengeFor == 0)
	{
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("received signature for client with invalid challenge value ('%s')"), GetUserName());
		return;
	}

	if (theApp.clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ){
		// result is saved in function abouve
		//if (thePrefs.GetLogSecureIdent())
		//	AddDebugLogLine(false, _T("'%s' has passed the secure identification, V2 State: %i"), GetUserName(), byChaIPKind);
#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
		SendAUXPortWhenNeeded();
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --
#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
		if(source)
			source->SUIPassed(this);
#endif // NEO_CD // NEO: NCD END <-- Xanatos --
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
		if (thePrefs.UseArgosSystem())
			theApp.argos->SUIPassed(this);
#endif // ARGOS // NEO: NA END <-- Xanatos --
	}
	else
	{
		if (thePrefs.GetLogSecureIdent())
			AddDebugLogLine(false, _T("'%s' has failed the secure identification, V2 State: %i"), GetUserName(), byChaIPKind);
	}
	m_dwLastSignatureIP = GetIP(); 

	// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
	if(thePrefs.SendExtraInfo() && GetExtraInfoVersion())
		SendExtraInfoPacket(NIX_SUI);
	// NEO: NXI END <-- Xanatos --
}

void CUpDownClient::SendSecIdentStatePacket()
{
	// check if we need public key and signature
	uint8 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 == 0){
			//if (thePrefs.GetLogSecureIdent())
			//	AddDebugLogLine(false, _T("Not sending SecIdentState Packet, because State is Zero"));
			return;
		}
		// crypt: send random data to sign
		uint32 dwRandom = rand()+1;
		credits->m_dwCryptRndChallengeFor = dwRandom;
		Packet* packet = new Packet(OP_SECIDENTSTATE,5,OP_EMULEPROT);
		theStats.AddUpDataOverheadOther(packet->size);
		packet->pBuffer[0] = nValue;
		PokeUInt32(packet->pBuffer+1, dwRandom);
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__SecIdentState", this);
		socket->SendPacket(packet,true,true);
	}
	else
		ASSERT ( false );
}

void CUpDownClient::ProcessSecIdentStatePacket(const uchar* pachPacket, uint32 nSize)
{
	if (nSize != 5)
		return;
	if (!credits){
		ASSERT ( false );
		return;
	}
	switch(pachPacket[0]){
		case 0:
			m_SecureIdentState = IS_UNAVAILABLE;
			break;
		case 1:
			m_SecureIdentState = IS_SIGNATURENEEDED;
			break;
		case 2:
			m_SecureIdentState = IS_KEYANDSIGNEEDED;
			break;
	}
	credits->m_dwCryptRndChallengeFrom = PeekUInt32(pachPacket+1);
}

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

	// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
	if(thePrefs.SendExtraInfo() && GetExtraInfoVersion())
		SendExtraInfoPacket(NIX_HELLO | NIX_SUI, true); 
	// NEO: NXI END <-- Xanatos --

	if (m_bySupportSecIdent){
		SendSecIdentStatePacket();
	}
}

#ifdef ISPBYPASS // NEO: MP - [MultiPort] -- Xanatos -->
void CUpDownClient::SendAUXPortWhenNeeded(bool bOnProcess)
{
	if(socket == NULL){
		ASSERT(0);
		return;
	}

	// we or he dont support aux ports
	if(!thePrefs.UseEncryptedPorts() || GetSecureCommunicationVersion() == 0)
		return;

	// nider we nor the other one requirers encryption
	//if(!thePrefs.GetNeedISPBypass() && !DoRequierEncryption()) // X-ToDo
	//	return;

	// in the new version 3 we send our secret ports only to cleints we trust, 
	// this are client that have requested a valid file form us or that are a source for a file
	if(!reqfile && isnulmd4(requpfileid)) // we dont trust him yet 
		return;	// so we don't tell him our secret ports

	// check do we still listen on this port
	if(theApp.listensocket->IsListening(m_nLocalSecurePort) == false)
		m_nLocalSecurePort = 0;

	// if the connection is already secure there is no need for port exchange
	if(!bOnProcess && m_nLocalSecurePort != 0) // if we sent already a port dont send if again unless the cleint requests it or have the wrong one
		return;

	bool unSafe = (!credits || credits->GetCurrentIdentState(GetIP()) != IS_IDENTIFIED); // we need a SUI identification
	if(unSafe && SupportSecIdent() && theApp.clientcredits->CryptoAvailable()) // we mess teh key but we expect to get it soon, don't sen yet
		return;

	// Note: give only one port to a clinet to avoid compromysing all ports
	if(m_nLocalSecurePort == 0)
		m_nLocalSecurePort = theApp.listensocket->GetSecretPort(unSafe || GetSecureCommunicationVersion() < 3); // get a rundom not default port
	
	SendAUXPort();
}

void CUpDownClient::SendAUXPort()
{
	CSafeMemFile data(48);

	data.WriteUInt16(m_nLocalSecurePort);
	data.WriteUInt16(m_nRemoteSecurePort); // we send the port we have to let the remote side verify is it still valid
	
	// write the port secret
	if(GetSecureCommunicationVersion() >= 3){
		byte* abyPrime;
		byte abyBase;
		if(theApp.listensocket->GetSecretPortDH(m_nLocalSecurePort,abyPrime,abyBase)){
			data.Write(abyPrime,SOCKET_KEY_SIZE);
			data.WriteUInt8(abyBase);
		}
	}

	UINT size = (UINT)data.GetLength();
	ASSERT(size <= 37); // this is the max plain text length the SUI key can handle
	byte* PlainData = data.Detach();
	byte* SecureData = NULL;
	uint8 len = 0;

	if(theApp.clientcredits->CryptoAvailable() && credits 
		&& credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED){
		len = theApp.clientcredits->EncryptData(credits,PlainData,size,SecureData);
		ASSERT(len == 48); // the encrypted length must always be 48 bytes
	}else
		len = (uint8)size;

	Packet* packet = new Packet(OP_AUX_PORT,len,GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
	memcpy(packet->pBuffer,SecureData ? SecureData : PlainData,len);
	delete [] SecureData;
	free(PlainData);

	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet);
}

void CUpDownClient::ProcessAUXPort(const uchar* pachPacket, UINT nSize)
{
	uint8 len = 0;
	byte* PlainData = NULL;
	
	if(nSize == 48){
		if(theApp.clientcredits->CryptoAvailable() && credits 
		 && (credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED
		 || credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY))
			len = theApp.clientcredits->DecryptData(pachPacket,nSize,PlainData);
	}else
		len = (uint8)nSize;

	if(len >= 4)
	{
		CSafeMemFile data(PlainData ? PlainData : pachPacket, len);

		m_nRemoteSecurePort = data.ReadUInt16();
		uint16 LocalSecurePort = data.ReadUInt16(); // this is send to let the other cleint know do our port is still valid

		if(len > 4){ // custom DH parameters
			if(m_abyRemoteDHPrime == NULL)
				m_abyRemoteDHPrime = new byte[SOCKET_KEY_SIZE];
			data.Read(m_abyRemoteDHPrime,SOCKET_KEY_SIZE);
			m_abyRemoteDHBase = data.ReadUInt8();
		}else{ // default DH parameters
			delete [] m_abyRemoteDHPrime;
			m_abyRemoteDHPrime = NULL;
			m_abyRemoteDHBase = 0;
		}

		// the client have an wrong port update it
		SendAUXPortWhenNeeded(LocalSecurePort == 0 || LocalSecurePort != m_nLocalSecurePort);
	}

	delete [] PlainData;
}

void CUpDownClient::SetRemoteDHPrime(const byte* abyRemoteDHPrime)
{
	if(m_abyRemoteDHPrime == NULL)
		m_abyRemoteDHPrime = new byte[SOCKET_KEY_SIZE];
	memcpy(m_abyRemoteDHPrime, abyRemoteDHPrime, SOCKET_KEY_SIZE);
}
#endif // ISPBYPASS // NEO: MP END <-- Xanatos --

void CUpDownClient::ResetFileStatusInfo()
{
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	/*
	delete[] m_abyPartStatus;
	m_abyPartStatus = NULL;

	m_nPartCount = 0;
	m_bCompleteSource = false;

	m_strClientFilename.Empty();
	*/

	m_nRemoteQueueRank = 0;

	// NEO: XC - [ExtendedComments] -- Xanatos --
	//m_uFileRating = 0;
	//m_strFileComment.Empty();
	delete m_pReqFileAICHHash;
	m_pReqFileAICHHash = NULL;
}

bool CUpDownClient::IsBanned() const
{
	return GetConnectIP() != 0 && theApp.clientlist->IsBannedClient(GetConnectIP()); //Xman official bugfix, was: //GetIP());  // NEO: FIX <-- Xanatos --
}

void CUpDownClient::SendPreviewRequest(const CAbstractFile* pForFile)
{
	if (m_fPreviewReqPending == 0){
		m_fPreviewReqPending = 1;
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__RequestPreview", this, pForFile->GetFileHash());
		Packet* packet = new Packet(OP_REQUESTPREVIEW,16,OP_EMULEPROT);
		md4cpy(packet->pBuffer,pForFile->GetFileHash());
		theStats.AddUpDataOverheadOther(packet->size);
		SafeSendPacket(packet);
	}
	else{
		LogWarning(LOG_STATUSBAR, GetResString(IDS_ERR_PREVIEWALREADY));
	}
}

void CUpDownClient::SendPreviewAnswer(const CKnownFile* pForFile, CxImage** imgFrames, uint8 nCount)
{
	m_fPreviewAnsPending = 0;
	CSafeMemFile data(1024);
	if (pForFile){
		data.WriteHash16(pForFile->GetFileHash());
	}
	else{
		static const uchar _aucZeroHash[16] = {0};
		data.WriteHash16(_aucZeroHash);
	}
	data.WriteUInt8(nCount);
	for (int i = 0; i != nCount; i++){
		if (imgFrames == NULL){
			ASSERT ( false );
			return;
		}
		CxImage* cur_frame = imgFrames[i];
		if (cur_frame == NULL){
			ASSERT ( false );
			return;
		}
		BYTE* abyResultBuffer = NULL;
		long nResultSize = 0;
		if (!cur_frame->Encode(abyResultBuffer, nResultSize, CXIMAGE_FORMAT_PNG)){
			ASSERT ( false );			
			return;
		}
		data.WriteUInt32(nResultSize);
		data.Write(abyResultBuffer, nResultSize);
		free(abyResultBuffer);
	}
	Packet* packet = new Packet(&data, OP_EMULEPROT);
	packet->opcode = OP_PREVIEWANSWER;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__PreviewAnswer", this, (uchar*)packet->pBuffer);
	theStats.AddUpDataOverheadOther(packet->size);
	SafeSendPacket(packet);
}

void CUpDownClient::ProcessPreviewReq(const uchar* pachPacket, uint32 nSize)
{
	if (nSize < 16)
		throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
	
	if ((m_fPreviewAnsPending || thePrefs.CanSeeShares()==vsfaNobody 
	|| (thePrefs.CanSeeShares()==vsfaFriends && !IsFriend())
	|| (thePrefs.CanSeeShares()==vsfaCommunity && !IsCommunity()) // NEO: NC - [NiceCommunity] <-- Xanatos --
	) && !thePrefs.UseCustomPermissions()) // NEO: SSP - [ShowSharePermissions] <-- Xanatos --
		return;
	
	m_fPreviewAnsPending = 1;
	CKnownFile* previewFile = theApp.sharedfiles->GetFileByID(pachPacket);
	if (previewFile == NULL){
		SendPreviewAnswer(NULL, NULL, 0);
	}
	else{
		// NEO: SSP - [ShowSharePermissions] -- Xanatos -->
		int Perm = ((previewFile->GetPermissions() == PERM_DEFAULT) ? thePrefs.CanSeeShares() : previewFile->GetPermissions());
		if (thePrefs.UseCustomPermissions() && (
			Perm == PERM_NONE ||
			(Perm == PERM_FRIENDS && !IsFriend()) ||
			(Perm == PERM_COMMUNITY && !IsCommunity()) // NEO: NC - [NiceCommunity]
			)) return;
		// NEO: SSP END <-- Xanatos --

		previewFile->GrabImage(4,0,true,450,this);
	}
}

void CUpDownClient::ProcessPreviewAnswer(const uchar* pachPacket, uint32 nSize)
{
	if (m_fPreviewReqPending == 0)
		return;
	m_fPreviewReqPending = 0;
	CSafeMemFile data(pachPacket, nSize);
	uchar Hash[16];
	data.ReadHash16(Hash);
	uint8 nCount = data.ReadUInt8();
	if (nCount == 0){
		LogError(LOG_STATUSBAR, GetResString(IDS_ERR_PREVIEWFAILED), GetUserName());
		return;
	}
	CSearchFile* sfile = theApp.searchlist->GetSearchFileByHash(Hash);
	// NEO: XSF - [ExtendedSharedFiles] -- Xanatos -->
	if (sfile == NULL && !m_listFiles.IsEmpty())
		for (POSITION pos = m_listFiles.GetHeadPosition(); pos != NULL; ) {
			CSearchFile *item = m_listFiles.GetNext(pos);
			if (!md4cmp(Hash, item->GetFileHash())) {
				sfile = item;
				break;
			}
		}
	// NEO: XSF END <-- Xanatos --
	if (sfile == NULL){
		//already deleted
		return;
	}

	BYTE* pBuffer = NULL;
	try{
		for (int i = 0; i != nCount; i++){
			uint32 nImgSize = data.ReadUInt32();
			if (nImgSize > nSize)
				throw CString(_T("CUpDownClient::ProcessPreviewAnswer - Provided image size exceeds limit"));
			pBuffer = new BYTE[nImgSize];
			data.Read(pBuffer, nImgSize);
			CxImage* image = new CxImage(pBuffer, nImgSize, CXIMAGE_FORMAT_PNG);
			delete[] pBuffer;
			pBuffer = NULL;
			if (image->IsValid()){
				sfile->AddPreviewImg(image);
			}
		}
	}
	catch(...){
		delete[] pBuffer;
		throw;
	}
	(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 that client object was deleted because the connection try failed and the object wasn't needed anymore.
bool CUpDownClient::SafeSendPacket(Packet* packet){
	if (socket && socket->IsConnected()){
		socket->SendPacket(packet);
		return true;
	}
	else{
		m_WaitingPackets_list.AddTail(packet);
		return TryToConnect(true);
	}
}

#ifdef _DEBUG
void CUpDownClient::AssertValid() const
{
	CObject::AssertValid();

	CHECK_OBJ(socket);
	CHECK_PTR(credits);
	CHECK_PTR(m_Friend);
	CHECK_OBJ(reqfile);
	//(void)m_abyUpPartStatus; // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
	m_OtherRequests_list.AssertValid();
	m_OtherNoNeeded_list.AssertValid();
	(void)m_lastPartAsked;
	(void)m_cMessagesReceived;
	(void)m_cMessagesSent;
	(void)m_dwUserIP;
	(void)m_dwServerIP;
	(void)m_nUserIDHybrid;
	(void)m_nUserPort;
	(void)m_nServerPort;
	(void)m_nClientVersion;
	(void)m_nUpDatarate;
	(void)m_byEmuleVersion;
	(void)m_byDataCompVer;
	CHECK_BOOL(m_bEmuleProtocol);
	CHECK_BOOL(m_bIsHybrid);
	//(void)m_pszUsername; // NEO: FIX - [StabilityFix] <-- Xanatos --
	(void)m_achUserHash;
	(void)m_achBuddyID;
	(void)m_nBuddyIP;
	(void)m_nBuddyPort;
	(void)m_nUDPPort;
	(void)m_nKadPort;
	(void)m_byUDPVer;
	(void)m_bySourceExchangeVer;
	(void)m_byAcceptCommentVer;
	(void)m_byExtendedRequestsVer;
	(void)m_IncompletePartVer; // NEO: ICS - [InteligentChunkSelection] <-- Xanatos --
	(void)m_SubChunksVer; // NEO: SCT - [SubChunkTransfer]
	// NEO: RPS - [RealPartStatus] -- Xanatos -->
	(void)m_HidenPartStatusVer;
	(void)m_BlockedPartStatusVer;
	// NEO: RPS END <-- Xanatos --
	(void)m_ExtraInfoVer; // NEO: NXI - [NeoExtraInfo] <-- Xanatos --
	CHECK_BOOL(m_bFriendSlot);
	CHECK_BOOL(m_bCommentDirty);
	CHECK_BOOL(m_bIsML);
	//ASSERT( m_clientSoft >= SO_EMULE && m_clientSoft <= SO_SHAREAZA || m_clientSoft == SO_MLDONKEY || m_clientSoft >= SO_EDONKEYHYBRID && m_clientSoft <= SO_UNKNOWN );
	(void)m_strClientSoftware;
	(void)m_dwLastSourceRequest;
	(void)m_dwLastSourceAnswer;
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	(void)m_dwLastSourcesSent;
#endif // ARGOS // NEO: NA END <-- Xanatos --
	(void)m_dwLastAskedForSources;
    (void)m_iFileListRequested;
	(void)m_iSourceListRequested; // NEO: MCH - [ManualClientHandling] <-- Xanatos --
	// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
	(void)m_bNotifyIdChage;
	(void)m_bWainingNotifyIdChage;
	// NEO: RIC END <-- Xanatos --
	(void)m_byCompatibleClient;
	m_WaitingPackets_list.AssertValid();
	m_DontSwap_list.AssertValid();
	(void)m_lastRefreshedDLDisplay;
	ASSERT( m_SecureIdentState >= IS_UNAVAILABLE && m_SecureIdentState <= IS_KEYANDSIGNEEDED );
	(void)m_dwLastSignatureIP;
	ASSERT( (m_byInfopacketsReceived & ~IP_BOTH) == 0 );
	(void)m_bySupportSecIdent;
	(void)m_nTransferredUp;
	ASSERT( m_nUploadState >= US_UPLOADING && m_nUploadState <= US_NONE );
	(void)m_dwUploadTime;
	(void)m_cAsked;
	(void)m_dwLastUpRequest;
	(void)m_nCurSessionUp;
    (void)m_nCurQueueSessionPayloadUp;
    (void)m_addedPayloadQueueSession;
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	//(void)m_nUpPartCount;
	//(void)m_nUpCompleteSourcesCount;
	(void)s_UpStatusBar;
	(void)requpfileid;
    (void)m_lastRefreshedULDisplay;
	m_AvarageUDR_list.AssertValid();
	m_BlockRequests_queue.AssertValid();
	m_DoneBlocks_list.AssertValid();
	m_RequestedFiles_list.AssertValid();
	ASSERT( m_nDownloadState >= DS_DOWNLOADING && m_nDownloadState <= DS_NONE );
	(void)m_cDownAsked;
	// NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	//(void)m_abyPartStatus;
	//(void)m_strClientFilename;
	(void)m_nTransferredDown;
	(void)m_dwDownStartTime;
	(void)m_nLastBlockOffset;
	(void)m_nDownDatarate;
	//(void)m_nDownDataRateMS; // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
	(void)m_nSumForAvgDownDataRate;
	//(void)m_cShowDR; // NEO: ASM - [AccurateSpeedMeasure] <-- Xanatos --
	(void)m_nRemoteQueueRank;
	// NEO: CQR - [CollorQueueRank] -- Xanatos -->
	(void) m_nInitialRemoteQueueRank;
	(void) m_nDeltaRemoteQueueRank;
	// NEO: CQR END <-- Xanatos --
	(void)m_dwLastBlockReceived;
	//(void)m_nPartCount; // NEO: SCFS - [SmartClientFileStatus] -- Xanatos --
	ASSERT( m_nSourceFrom >= SF_SERVER && m_nSourceFrom <= SF_LINK );
	CHECK_BOOL(m_bRemoteQueueFull);
	//CHECK_BOOL(m_bCompleteSource); // NEO: SCFS - [SmartClientFileStatus] <-- Xanatos --
	CHECK_BOOL(m_bReaskPending);
	CHECK_BOOL(m_bUDPPending);
	CHECK_BOOL(m_bTransferredDownMini);
	CHECK_BOOL(m_bUnicodeSupport);
	ASSERT( m_nKadState >= KS_NONE && m_nKadState <= KS_CONNECTED_BUDDY );
	m_AvarageDDR_list.AssertValid();
	(void)m_nSumForAvgUpDataRate;
	m_PendingBlocks_list.AssertValid();
	//m_DownloadBlocks_list.AssertValid(); // NEO: DBR - [DynamicBlockRequest] <-- Xanatos --
	(void)s_StatusBar;
	ASSERT( m_nChatstate >= MS_NONE && m_nChatstate <= MS_UNABLETOCONNECT );
	// NEO: XC - [ExtendedComments] -- Xanatos --
	//(void)m_strFileComment;
	//(void)m_uFileRating;
	CHECK_BOOL(m_bAdvertisementPending); // NEO: ASP - [ActiveSpreading] <-- Xanatos --
	(void)m_ExtraInfo; // NEO: NXI - [NeoExtraInfo] <-- Xanatos --
#undef CHECK_PTR
#undef CHECK_BOOL
}
#endif

#ifdef _DEBUG
void CUpDownClient::Dump(CDumpContext& dc) const
{
	CObject::Dump(dc);
}
#endif

LPCTSTR CUpDownClient::DbgGetDownloadState() const
{
	const static LPCTSTR apszState[] =
	{
		_T("Downloading"),
		_T("OnQueue"),
		_T("Connected"),
		_T("Connecting"),
		_T("WaitCallback"),
		_T("WaitCallbackKad"),
		_T("ReqHashSet"),
		_T("NoNeededParts"),
		_T("TooManyConns"),
		_T("TooManyConnsKad"),
		_T("LowToLowIp"),
		_T("Banned"),
		_T("Error"),
		_T("None"),
		_T("RemoteQueueFull")
	};
	if (GetDownloadState() >= ARRSIZE(apszState))
		return _T("*Unknown*");
	return apszState[GetDownloadState()];
}

LPCTSTR CUpDownClient::DbgGetUploadState() const
{
	const static LPCTSTR apszState[] =
	{
		_T("Uploading"),
		_T("OnUploadQueue"),
		_T("WaitCallback"),
		_T("Connecting"),
		_T("Pending"),
		_T("LowToLowIp"),
		_T("Banned"),
		_T("Error"),
		_T("None")
	};
	if (GetUploadState() >= ARRSIZE(apszState))
		return _T("*Unknown*");
	return apszState[GetUploadState()];
}

LPCTSTR CUpDownClient::DbgGetKadState() const
{
	const static LPCTSTR apszState[] =
	{
		_T("None"),
		_T("FwCheckQueued"),
		_T("FwCheckConnecting"),
		_T("FwCheckConnected"),
		_T("BuddyQueued"),
		_T("BuddyIncoming"),
		_T("BuddyConnecting"),
		_T("BuddyConnected")
	};
	if (GetKadState() >= ARRSIZE(apszState))
		return _T("*Unknown*");
	return apszState[GetKadState()];
}

CString CUpDownClient::DbgGetFullClientSoftVer() const
{
	if (GetClientModVer().IsEmpty())
		return GetClientSoftVer();
	return GetClientSoftVer() + _T(" [") + GetClientModVer() + _T(']');
}

CString CUpDownClient::DbgGetClientInfo(bool bFormatIP) const
{
	CString str;
	if (this != NULL)
	{
		try{
			if (HasLowID())
			{
				if (GetConnectIP())
				{
					str.Format(_T("%u@%s (%s) '%s' (%s,%s/%s/%s)"),
						GetUserIDHybrid(), ipstr(GetServerIP()),
						ipstr(GetConnectIP()),
						GetUserName(),
						DbgGetFullClientSoftVer(),
						DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
				}
				else
				{
					str.Format(_T("%u@%s '%s' (%s,%s/%s/%s)"),
						GetUserIDHybrid(), ipstr(GetServerIP()),
						GetUserName(),
						DbgGetFullClientSoftVer(),
						DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
				}
			}
			else
			{
				str.Format(bFormatIP ? _T("%-15s '%s' (%s,%s/%s/%s)") : _T("%s '%s' (%s,%s/%s/%s)"),
					ipstr(GetConnectIP()),
					GetUserName(),
					DbgGetFullClientSoftVer(),
					DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
			}
		}
		catch(...){
			str.Format(_T("%08x - Invalid client instance"), this);
		}
	}
	return str;
}

bool CUpDownClient::CheckHandshakeFinished() const
{
	//if (m_bHelloAnswerPending)
	if (m_byHelloPacketState != HP_BOTH) // NEO: FCCP - [FixConnectionCollision] <-- Xanatos --
	{
		// 24-Nov-2004 [bc]: The reason for this is that 2 clients are connecting to each other at the same..
		//if (thePrefs.GetVerbose())
		//	AddDebugLogLine(DLP_VERYLOW, false, _T("Handshake not finished - while processing packet: %s; %s"), DbgGetClientTCPOpcode(protocol, opcode), DbgGetClientInfo());
		return false;
	}

	return true;
}

#ifndef ARGOS // NEO: NA -- Xanatos -->
void CUpDownClient::CheckForGPLEvilDoer()
{
	if (!m_strModVersion.IsEmpty()){
		LPCTSTR pszModVersion = (LPCTSTR)m_strModVersion;

		// skip leading spaces
		while (*pszModVersion == _T(' '))
			pszModVersion++;

		// check for known major gpl breaker
		if (_tcsnicmp(pszModVersion, _T("LH"), 2)==0 || _tcsnicmp(pszModVersion, _T("LIO"), 3)==0 || _tcsnicmp(pszModVersion, _T("PLUS PLUS"), 9)==0)
			m_bGPLEvildoer = true;
	}
}
#endif // ARGOS // NEO: NA END <-- Xanatos --

void CUpDownClient::OnSocketConnected(int /*nErrorCode*/)
{
}

CString CUpDownClient::GetDownloadStateDisplayString() const
{
	CString strState;
	switch (GetDownloadState())
	{
		case DS_CONNECTING:
			strState = GetResString(IDS_CONNECTING);
			break;
		case DS_CONNECTED:
			strState = GetResString(IDS_ASKING);
			break;
		// NEO: SD - [StandByDL] -- Xanatos -->
		case DS_HALTED:
			strState = GetResString(IDS_X_STANDBY);
			break;
		// NEO: SD - [StandByDL] <-- Xanatos --
		// NEO: MDR - [ManualDownloadReask] -- Xanatos -->
		case DS_CONNECTINGWAITING:
			strState = GetResString(IDS_X_CONNECTINGWAITING);
			break;
		// NEO: MDR - [ManualDownloadReask] <-- Xanatos --
#if defined(NEO_SK) || defined(NEO_SS) // NEO: NSK - [NeoSourceKeeper] // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
		case DS_REVIVAL:
			strState = GetResString(IDS_X_REVIVAL);
			break;
#endif // NEO_SK // NEO_SS // NEO: NSK END // NEO: NSS END <-- Xanatos --
		// NEO: TCR - [TCPConnectionRetry] -- Xanatos -->
		case DS_CONNECTIONRETRY:
			strState = GetResString(IDS_X_CONNECTIONRETRY);
			break;
		// NEO: TCR END <-- Xanatos --
		// NEO: XSC - [ExtremeSourceCache] -- Xanatos -->
		case DS_CACHED:
			strState = GetResString(IDS_X_CACHED);
			break;
		// NEO: XSC END <-- Xanatos --
#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
		case DS_LOADED:
			strState = GetResString(IDS_X_LOADED);
			break;
		case DS_LOADEDWAITING:
			strState = GetResString(IDS_X_LOADEDWAITING);
			break;
		case DS_RESERVE:
			strState = GetResString(IDS_X_RESERVE);
			break;
		case DS_RETIRED:
			strState = GetResString(IDS_X_RETIRED);
			break;
#endif // NEO_SS // NEO: NSS END <-- Xanatos --
		case DS_WAITCALLBACK:
			strState = GetResString(IDS_CONNVIASERVER);
			break;
		case DS_ONQUEUE:
			if (IsRemoteQueueFull())
				strState = GetResString(IDS_QUEUEFULL);
			else
				strState = GetResString(IDS_ONQUEUE);
			break;
		case DS_DOWNLOADING:
			strState = GetResString(IDS_TRANSFERRING);
			break;
		case DS_REQHASHSET:
			strState = GetResString(IDS_RECHASHSET);
			break;
		case DS_NONEEDEDPARTS:
			strState = GetResString(IDS_NONEEDEDPARTS);
			break;
		case DS_LOWTOLOWIP:
			strState = GetResString(IDS_NOCONNECTLOW2LOW);
			break;
		case DS_TOOMANYCONNS:
			strState = GetResString(IDS_TOOMANYCONNS);
			break;
		case DS_ERROR:
			strState = GetResString(IDS_ERROR);
			break;
		case DS_WAITCALLBACKKAD:
			strState = GetResString(IDS_KAD_WAITCBK);
			break;
		case DS_TOOMANYCONNSKAD:
			strState = GetResString(IDS_KAD_TOOMANDYKADLKPS);
			break;
#ifdef NEO_SK // NEO: NSK - [NeoSourceKeeper] -- Xanatos -->
		case DS_UNREACHABLE:
			strState = GetResString(IDS_X_UNREACHABLE);
			break;
#endif // NEO_SK // NEO: NSK END <-- Xanatos --
	}

	if (thePrefs.GetPeerCacheShow())
	{
		switch (m_ePeerCacheDownState)
		{
		case PCDS_WAIT_CLIENT_REPLY:
			strState += _T(" ")+GetResString(IDS_PCDS_CLIENTWAIT);
			break;
		case PCDS_WAIT_CACHE_REPLY:
			strState += _T(" ")+GetResString(IDS_PCDS_CACHEWAIT);
			break;
		case PCDS_DOWNLOADING:
			strState += _T(" ")+GetResString(IDS_CACHE);
			break;
		}
		if (m_ePeerCacheDownState != PCDS_NONE && m_bPeerCacheDownHit)
			strState += _T(" Hit");
	}

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if (thePrefs.GetWebCacheShow())
	{
		switch (m_eWebCacheDownState)
		{
		case WCDS_WAIT_CLIENT_REPLY:
			strState += _T(" ")+GetResString(IDS_X_PROXY_WAIT);
			break;
		case WCDS_WAIT_CACHE_REPLY:
			strState += _T(" ")+GetResString(IDS_X_CACHE_WAIT); // not needed...
			break;
		case WCDS_DOWNLOADINGVIA:
			strState += _T(" ")+GetResString(IDS_X_VIA_PROXY);
			break;
		case WCDS_DOWNLOADINGFROM:
			strState += _T(" ")+GetResString(IDS_X_FROM_PROXY);
			break;
		}
	}
#endif // NEO: WC END <-- Xanatos --

/*#if !defined DONT_USE_SOCKET_BUFFERING && (defined _DEBUG || defined _DEBUG_NEO)// NEO: DSB - [DynamicSocketBuffer] -- Xanatos -->
	CEMSocket* s = socket;
	if (s != NULL) {
		if (m_pPCDownSocket)
			s = m_pPCDownSocket;
		else if (m_pWCDownSocket)
			s = m_pWCDownSocket;

		strState.AppendFormat(_T(", BUF: %u"), socket->GetRecvBufferSize());

		DWORD RTT = s->GetRTT();
		if (RTT!=(DWORD)-1)
			strState.AppendFormat(_T(", RTT: %ims"), RTT);
		else
			strState.Append(_T(", RTT: ?")); 
	}
#endif // NEO: DSB - [DynamicSocketBuffer] <-- Xanatos --*/

	return strState;
}

CString CUpDownClient::GetUploadStateDisplayString() const
{
	CString strState;
	switch (GetUploadState()){
		case US_ONUPLOADQUEUE:
			strState = GetResString(IDS_ONQUEUE);
			break;
		// NEO: SCT - [SubChunkTransfer] -- Xanatos -->
		case US_NONEEDEDPARTS:
			strState = GetResString(IDS_NONEEDEDPARTS);
			break;
		// NEO: SCT END <-- Xanatos --
		case US_PENDING:
			strState = GetResString(IDS_CL_PENDING);
			break;
		case US_LOWTOLOWIP:
			strState = GetResString(IDS_CL_LOW2LOW);
			break;
		case US_BANNED:
			strState = GetResString(IDS_BANNED);
			break;
		case US_ERROR:
			strState = GetResString(IDS_ERROR);
			break;
		case US_CONNECTING:
			strState = GetResString(IDS_CONNECTING);
			break;
		case US_WAITCALLBACK:
#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
		case US_WAITCALLBACKKAD:
#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
			strState = GetResString(IDS_CONNVIASERVER);
			break;
//#ifdef NATTUNNELING // NEO: LUC - [LowIDUplaodCallBack] -- Xanatos -->
//		case US_TOOMANYCONNSKAD: 
//			strState = GetResString(IDS_KAD_TOOMANDYKADLKPS);
//			break;
//#endif //NATTUNNELING // NEO: LUC END <-- Xanatos --
		case US_UPLOADING:
#ifdef NEO_UBT // NEO: NUBT - [NeoUploadBandwidthThrottler] -- Xanatos -->
			if (!HaveTrickleSlot()){
#else
            if (GetSlotNumber() <= theApp.uploadqueue->GetActiveUploadsCount()) {
#endif // NEO_UBT // NEO: NUBT END <-- Xanatos --
				strState = GetResString(IDS_TRANSFERRING);
            } else {
                strState = GetResString(IDS_TRICKLING);
            }
            //CString strStateTemp = strState;
            //strState.Format(_T("%i: %s"), GetSlotNumber(), strStateTemp);
			break;
	}

	if (thePrefs.GetPeerCacheShow())
	{
		switch (m_ePeerCacheUpState)
		{
		case PCUS_WAIT_CACHE_REPLY:
			strState += _T(" CacheWait");
			break;
		case PCUS_UPLOADING:
			strState += _T(" Cache");
			break;
		}
		if (m_ePeerCacheUpState != PCUS_NONE && m_bPeerCacheUpHit)
			strState += _T(" Hit");
	}

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
	if (thePrefs.GetWebCacheShow())
	{
		if( m_eWebCacheUpState == WCUS_UPLOADING )
			strState += _T(" ")+GetResString(IDS_X_VIA_PROXY);
	}
#endif // NEO: WC END <-- Xanatos --

/*#if !defined DONT_USE_SOCKET_BUFFERING && (defined _DEBUG || defined _DEBUG_NEO)// NEO: DSB - [DynamicSocketBuffer] -- Xanatos -->
	CEMSocket* s = socket;
	if (s != NULL) {
		if (m_pPCUpSocket)
			s = m_pPCUpSocket;
		else if (m_pWCUpSocket)
			s = m_pWCUpSocket;

		strState.AppendFormat(_T(", BUF:%u"), s->GetSendBufferSize());		
		DWORD RTT = s->GetRTT();
		if (RTT!=(DWORD)-1)
			strState.AppendFormat(_T(", RTT: %ims"), RTT);
		else
			strState.Append(_T(", RTT: ?"));
		DWORD RTTo = s->GetRTTo();
		if (RTTo!=(DWORD)-1)
			strState.AppendFormat(_T(", RTTo: %ims"), RTTo);
		else
			strState.Append(_T(", RTTo: ?"));

		DWORD busySince = s->GetBusyTimeSince();
		if (s->GetBusyRatioTime() > 0)
			strState.AppendFormat(_T(", BusyRatio: %0.2f"), s->GetBusyRatioTime());
		if (busySince > 0)
			strState.AppendFormat(_T(", BusyTime: %ums"), GetTickCount() - busySince);
	}
#endif // NEO: DSB - [DynamicSocketBuffer] <-- Xanatos --*/

	return strState;
}

void CUpDownClient::SendPublicIPRequest(){
	if (socket && socket->IsConnected()){
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__PublicIPReq", this);
		Packet* packet = new Packet(OP_PUBLICIP_REQ,0,OP_EMULEPROT);
		theStats.AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
		m_fNeedOurPublicIP = 1;
	}
}

void CUpDownClient::ProcessPublicIPAnswer(const BYTE* pbyData, UINT uSize){
	if (uSize != 4)
		throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
	uint32 dwIP = PeekUInt32(pbyData);
	if (m_fNeedOurPublicIP == 1){ // did we?
		m_fNeedOurPublicIP = 0;
		if (theApp.GetPublicIP() == 0 && !::IsLowID(dwIP) ){
			theApp.SetPublicIP(dwIP);
			// NEO: RIC - [ReaskOnIDChange] -- Xanatos -->
			if(thePrefs.IsCheckIPChange())
				theApp.CheckIDChange(dwIP);
			// NEO: RIC END <-- Xanatos --
		}
	}	
}

void CUpDownClient::CheckFailedFileIdReqs(const uchar* aucFileHash)
{
	if ( aucFileHash != NULL && (theApp.sharedfiles->IsUnsharedFile(aucFileHash) || theApp.downloadqueue->GetFileByID(aucFileHash)) )
		return;
	//if (GetDownloadState() != DS_DOWNLOADING) // filereq floods are never allowed!
	{
		if (m_fFailedFileIdReqs < 6)// NOTE: Do not increase this nr. without increasing the bits for 'm_fFailedFileIdReqs'
			m_fFailedFileIdReqs++;
		if (m_fFailedFileIdReqs == 6)
		{
			if (theApp.clientlist->GetBadRequests(this) < 2)
				theApp.clientlist->TrackBadRequest(this, 1);
			if (theApp.clientlist->GetBadRequests(this) >= 2){
				theApp.clientlist->TrackBadRequest(this, -2); // reset so the client will not be rebanned right after the ban is lifted
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
				if(thePrefs.IsFileScannerDetection())
					if(thePrefs.UseArgosSystem())
						theApp.argos->DoArgos(GetConnectIP(),AR_FILESCANNER);
					else
#endif // ARGOS // NEO: NA END <-- Xanatos --
				Ban(_T("FileReq flood"));
			}
			throw CString(thePrefs.GetLogBannedClients() ? _T("FileReq flood") : _T(""));
		}
	}
}

EUtf8Str CUpDownClient::GetUnicodeSupport() const
{
	if (m_bUnicodeSupport)
		return utf8strRaw;
	return utf8strNone;
}

void CUpDownClient::SetSpammer(bool bVal){ 
#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
	if(thePrefs.IsArgosSpamDetection())
		if(thePrefs.UseArgosSystem()){
			if(bVal) 
				theApp.argos->DoArgos(GetConnectIP(),AR_SPAM);
			else if(theApp.argos->IsArgos(GetConnectIP(),AR_SPAM))
				theApp.argos->UnArgos(GetConnectIP(),AR_SPAM);
		}else
#endif // ARGOS // NEO: NA END <-- Xanatos --
		{
			if (bVal)
				Ban(_T("Identified as Spammer"));
			else if (IsBanned() && m_fIsSpammer)
				UnBan();
		}
	m_fIsSpammer = bVal ? 1 : 0;
}

void  CUpDownClient::SetMessageFiltered(bool bVal)	{
	m_fMessageFiltered = bVal ? 1 : 0;
}

void CUpDownClient::SetLastAskedTime()
{ 
	m_fileReaskTimes.SetAt(reqfile, ::GetTickCount());
	// NEO: SR - [SpreadReask] -- Xanatos -->
	if(thePrefs.UseSpreadReask())
		SetSpreadReaskModyfier();
	// NEO: SR END <-- Xanatos --
}

// NEO: SR - [SpreadReask] -- Xanatos -->
void CUpDownClient::SetSpreadReaskModyfier()
{ 
	m_uSpreadReaskModyfier = ((uint32)(((float)(rand()%100))/100.0f*thePrefs.GetSpreadReaskValueMs()));
}
// NEO: SR END <-- Xanatos --

// NEO: DR - [DownloadReask] -- Xanatos -->
uint32 CUpDownClient::GetReqFileReaskIntervals()
{
	uint32 FileReaskTime;

	if(reqfile && reqfile->IsPartFile()){
		if (GetDownloadState() == DS_ONQUEUE){
			if(IsRemoteQueueFull()){
				FileReaskTime = reqfile->PartPrefs.GetFullQReaskIntervalsMs();
			}else{
				FileReaskTime = reqfile->PartPrefs.GetReaskIntervalsMs();
			}
		}else if(GetDownloadState() == DS_NONEEDEDPARTS){
			FileReaskTime = reqfile->PartPrefs.GetNnPReaskIntervalsMs();
		}else{
			FileReaskTime = reqfile->PartPrefs.GetReaskIntervalsMs();
		}
	}else
		FileReaskTime = thePrefs.GetReaskIntervalsMs();

	return FileReaskTime;
}

void CUpDownClient::SetNextAskedTime(uint32 uNextReask)
{ 
	m_fileReaskTimes.SetAt(reqfile, uNextReask ? ((::GetTickCount() - GetReqFileReaskIntervals()) + uNextReask) : 0); // MDR - [ManualDownloadReask]
	// We reset this time so the clinet don't stuck for 20mins.
	m_dwLastTriedToConnect = ::GetTickCount()-/*20*60*1000*/(reqfile ? reqfile->PartPrefs.GetReaskIntervalsMs(true) : thePrefs.GetReaskIntervalsMs(true)) /*+ uNextReask*/; // ZZ:DownloadManager
}

bool CUpDownClient::SetSafeReAskTime(bool bManual)
{
	if(!reqfile)
		return false;

	if (GetLastAskedTime() == 0)
		return true;

	const uint32 uAllowedInterval = (bManual ? MAN_REQUESTTIME : MIN_REQUESTTIME);
	if(::GetTickCount() - GetLastAskedTime(reqfile) > uAllowedInterval){
		SetNextAskedTime(); // to now
		return true;
	}
	SetNextAskedTime(uAllowedInterval);
	return false;
}
// NEO: DR END <-- Xanatos --

// NEO: MOD -- Xanatos -->
void CUpDownClient::ClearWhenNeeded()
{
	ASSERT(theApp.clientlist->IsValidClient(this));

	//Check wheter object is still used somewhere else

	if (GetUploadState() != US_NONE && GetUploadState() != US_ERROR && GetUploadState() != US_BANNED) //Object is on Upload Queue
		return;

	if (GetChatState() != MS_NONE) //Used on chat
		return;

	if (GetKadState() != KS_NONE) //Kad
		return;

	if(GetDetailDialogInterface()->IsDialogOpen()) //Client page is open // NEO: MLD - [ModelesDialogs]
		return;

	//End check

	if (socket){
		ASSERT (theApp.listensocket->IsValidSocket(socket));
		socket->Safe_Delete();
		socket = NULL;
	}

    if (m_iFileListRequested){
		DebugLog(GetResString(IDS_SHAREDFILES_FAILED),GetUserName());
        m_iFileListRequested = 0;
	}

	if (m_Friend)
		theApp.friendlist->RefreshFriend(m_Friend);

	delete this;
}
// NEO: MOD END <-- Xanatos --

// NEO: L2H - [LowID2HighIDAutoCallback] -- Xanatos -->
uint32 CUpDownClient::GetL2HACTime() const
{
	return m_L2HAC_time ? (m_L2HAC_time - L2HAC_CALLBACK_PRECEDE) : 0;
} 
// NEO: L2H END <-- Xanatos --

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase] -- Xanatos -->
void CUpDownClient::LinkSource(CKnownSource* Source)
{
	ASSERT(!source || source->IsUsed());
	if(source){
		source->UnUse();
		source->Detach(this);
	}
	source = Source;
	if(Source)
		Source->Use();
}

void CUpDownClient::AttachSource(CKnownSource* Source, bool bAssimilate)
{
	LinkSource(Source);

	if(!bAssimilate)
		return;

	SetIP(source->GetIP()); // m_nConnectIP = m_dwUserIP
	m_nUserPort = source->GetUserPort();

	m_nUserIDHybrid = source->GetUserIDHybrid();
	m_nUDPPort = source->GetUDPPort();
	m_nKadPort = source->GetKadPort();

	m_strUsername = source->GetUserName(); // NEO: FIX - [StabilityFix]
	m_strClientSoftware = source->GetClientSoftVer();
	m_strModVersion = source->GetClientModVer();
	m_clientSoft = source->GetClientSoft();

}
#endif // NEO_CD // NEO: NCD END <-- Xanatos --

#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->
bool CUpDownClient::IsActive(bool bNewActive){
	ASSERT(reqfile);
	return GetLastSeen() ? ((time(NULL) - GetLastSeen()) < reqfile->PartPrefs.GetReaskIntervalsS() * 2) : bNewActive; // Note: *2 is for NnP sources
}
#endif // NEO_SS // NEO: NSS END <-- Xanatos --

#ifdef LANCAST // NEO: NLC - [NeoLanCast] -- Xanatos -->
void CUpDownClient::CheckOnLAN( uint32 val )
{
	if (!thePrefs.IsLancastEnabled() || !val)
		return;
	m_bLanClient = theApp.lancast->IsLanIP(val);

	ASSERT(!m_bLanClient || socket == NULL || socket->IsLanSocket()); // LanSocket state is set on create and on connection accept so it should be always done at this point
	//if(m_bLanClient){
		//m_nUserIDHybrid = ntohl(m_dwUserIP); // X-ToDo: is this sensefull
		//if(socket)
		//	socket->SetOnLan();
	//}
}
#endif //LANCAST // NEO: NLC END <-- Xanatos --

// NEO: SCFS - [SmartClientFileStatus] -- Xanatos -->
CClientFileStatus* CUpDownClient::GetFileStatus(const CKnownFile* File, bool bAdd) const
{
	CClientFileStatus* Status;
	if(m_fileStatusMap.Lookup(File,Status))
		return Status;
	else if(bAdd){
		Status = new CClientFileStatus((const_cast<CKnownFile*>(File)));
		(const_cast<CUpDownClient*>(this))->m_fileStatusMap.SetAt(File,Status);
		return Status;
	}else
		return NULL;
}

void CUpDownClient::ClearFileStatus(const CKnownFile* File)
{
	CClientFileStatus* Status = GetFileStatus(File);
	if(Status == NULL)
		return;
	m_fileStatusMap.RemoveKey(File);
	delete Status;
}
// NEO: SCFS END <-- Xanatos --

// NEO: NMPi - [NeoModProtInfo] -- Xanatos -->
void CUpDownClient::SendModInfoPacket(){
	if (socket == NULL){
		ASSERT(0);
		return;
	}

	CSafeMemFile data(128);

	uint32 tagcount=1;

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	if (thePrefs.IsSupportISPBypass()) 
		tagcount += 1;
#endif // ISPBYPASS // NEO: SCC END

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	if (thePrefs.IsNATTraversalEnabled()) 
		tagcount += 1;
#endif //NATTUNNELING // NEO: NATT END

	// NEO: NATS - [NatSupport]
	if(theApp.IsFirewalled() && Kademlia::CKademlia::IsConnected())
		tagcount += 1; 
	// NEO: NATS END

	// NEO: NXI - [NeoExtraInfo]
	if (thePrefs.SendExtraInfo())
		tagcount += 1;
	// NEO: NXI END

	data.WriteUInt32(tagcount); // nr. of tags

	// NEO: XCFS - [ExtendedClientFileStatus]
	uint32 nSCT		= thePrefs.UseSubChunkTransfer()			? 1 : 0; // version 4 bit
	uint32 ICSv2	= thePrefs.UseInteligentChunkSelection()	? 2 : 0; // version 3 bit
	uint32 RPS		= thePrefs.UseRealPartStatus()				? 1 : 0; // version 3 bit
	uint32 HPS		= thePrefs.UseRealPartStatus()				? 1 : 0; // flag 1 bit
	uint32 BPS		= thePrefs.UseRealPartStatus()				? 1 : 0; // flag 1 bit

	uint32 uFileStatus =	
					//	((0     & 0xff)	<< 24) | // unused
					//	((0     & 0xff)	<< 16) | // reserved
						((BPS   & 0x01)	<< 15) | // RPS Flag Blocked Parts
						((HPS   & 0x01)	<< 14) | // RPS Flag Hiden Parts
						((RPS   & 0x07)	<< 11) | // RPS VErsion
						((ICSv2 & 0x07)	<< 8 ) | // ICSv2 Version
					//	((0     & 0x0f)	<< 4 ) | // reserved
						((nSCT  & 0x0f)	<< 0 );  // SCT version
	CTag tagRealParts(CT_EXT_FILESTATUS,uFileStatus);
	tagRealParts.WriteNewEd2kTag(&data);
	// NEO: XCFS END

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	if(thePrefs.IsSupportISPBypass()){
		uint32 Pref = thePrefs.GetNeedISPBypass();
		uint32 uepl = (Pref && thePrefs.IsPreferUnEnCryptedPayload()); // set this flag only when we need ecryption
		uint32 pk = theApp.clientcredits->CryptoAvailable();
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
		uint32 nat = (thePrefs.GetNeedISPBypass() == 1 ||  thePrefs.GetNeedISPBypass() == 2);
 #endif //NATTUNNELING // NEO: NATT END
		uint32 udp = thePrefs.GetNeedISPBypass() == 1;

		uint32 uVersions =	
						//	((0x00 & 0xff)	<< 24) | // unused
						//	((0x00 & 0xff)	<< 16) | // reserved
						//	((0x00 & 0x01)	<< 15) | // reserved
							((1    & 0x01)	<< 14) | // cleint supports secure TCP callback
							((udp  & 0x01)	<< 13) | // Use UDP Secureity
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
							((nat  & 0x01)	<< 12) | // Use NAT Encrpytion
 #endif //NATTUNNELING // NEO: NATT END
							((pk   & 0x01)	<< 11) | // support PK connections
							((uepl & 0x01)	<< 10) | // Prefer Encrypt only protocoll but not file data
							((Pref & 0x03)	<< 8 ) | // Is encryption needed
						//	((0    & 0x0f)	<< 4 ) | // reserved
							((3    & 0x0f)	<< 0 );
		CTag tagRealParts(CT_ISP_BYPASS,uVersions);
		tagRealParts.WriteNewEd2kTag(&data);
	}
#endif // ISPBYPASS // NEO: SCC END

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	if (thePrefs.IsNATTraversalEnabled()){
		uint32 fix = thePrefs.IsNATPortRelaiable() ? TRUE : FALSE;
		uint32 type = thePrefs.GetNatType();

		uint32 uVersions =	
						//	((0x00 & 0xff)	<< 24) | // unused
						//	((0x00 & 0xff)	<< 16) | // reserved
						//	((0x00 & 0x1f)	<< 11) | // reserved
							((type & 0x03)	<< 9 ) | // nat type 0-restricted 1-full 2-simetric 3-
							((fix  & 0x01)	<< 8 ) | // fix port hardware FW
						//	((0    & 0x0f)	<< 4 ) | // reserved
							((1    & 0x0f)	<< 0 );
		CTag tag(CT_NAT_TUNNELING, uVersions);
		tag.WriteNewEd2kTag(&data);
	}
#endif //NATTUNNELING // NEO: NATT END

	// NEO: NATS - [NatSupport]
	if(theApp.IsFirewalled() && Kademlia::CKademlia::IsConnected())
	{
		// Note: to connect a cleint over his buddy or to request a calback we need not only his buddy IP/Port but also his Buddy ID
		// So to get this realy to work we need to transmitt the buddy ID to
		Kademlia::CUInt128 uBuddyID(true);
		uBuddyID.Xor(Kademlia::CKademlia::GetPrefs()->GetKadID());
		byte cID[16];
		uBuddyID.ToByteArray(cID);
		CTag tagBuddyID(CT_EMULE_BUDDYID, cID);
		tagBuddyID.WriteNewEd2kTag(&data);
	}
	// NEO: NATS END

	// NEO: NXI - [NeoExtraInfo]
	if(thePrefs.SendExtraInfo()){
		CTag tagExtraInfo(ET_EXTRAINFO,1);
		tagExtraInfo.WriteNewEd2kTag(&data);
	}
	// NEO: NXI END

	Packet* packet = new Packet(&data,OP_MODPROT);
	packet->opcode = OP_MODINFOPACKET;
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__ModInfoPacket", this);
	theStats.AddUpDataOverheadOther(packet->size);
	socket->SendPacket(packet,true,true);
}

void CUpDownClient::ProcessModInfoPacket(const uchar* pachPacket, uint32 nSize)
{
	bool bDbgInfo = thePrefs.GetUseDebugDevice();
	CString m_strModInfo;
	CSafeMemFile data(pachPacket, nSize);

#ifdef ARGOS // NEO: NA - [NeoArgos]
	CList <TOpCode*> unknownOC;
#endif // ARGOS // NEO: NA END

	uint32 tagcount = data.ReadUInt32();
	if (bDbgInfo)
		m_strModInfo.AppendFormat(_T("  Tags=%u"), (UINT)tagcount);
	for (uint32 i = 0; i < tagcount; i++)
	{
		CTag temptag(&data, false);
		switch (temptag.GetNameID())
		{
			// NEO: XCFS - [ExtendedClientFileStatus]
			case CT_EXT_FILESTATUS:
				if (temptag.IsInt()){

					//							= (uint8)(temptag.GetInt() >> 24) & 0xff;
					//							= (uint8)(temptag.GetInt() >> 16) & 0xff;
					uint8 BlockedPartStatus		= (uint8)(temptag.GetInt() >> 15) & 0x01;
					uint8 HidenPartStatus		= (uint8)(temptag.GetInt() >> 14) & 0x01;
					uint8 RealPartStatusVer		= (uint8)(temptag.GetInt() >> 11) & 0x07;
					m_IncompletePartVer			= (uint8)(temptag.GetInt() >> 8 ) & 0x07;
					//							= (uint8)(temptag.GetInt() >> 4 ) & 0x0f;
					m_SubChunksVer				= (uint8)(temptag.GetInt() >> 0 ) & 0x0f;

					ASSERT(BlockedPartStatus || HidenPartStatus || !RealPartStatusVer);
					// Note: RPC version without one or booth RPS flags is invalid, 
					//       the cleint must always say wha is he doint gith the parts 'blocking and hiding' or 'only hiding', 
					//       or he can booth depanding on the situation
					// Booth RPS versions have always teh same version as the writing functions are identical 
					//		 just other opcodes are used and other part states notifyed
					if(BlockedPartStatus)
						m_BlockedPartStatusVer = RealPartStatusVer;
					if(HidenPartStatus)
						m_HidenPartStatusVer = RealPartStatusVer;
					
				}else if (bDbgInfo)
					m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
				// NEO: XCFS END

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			case CT_ISP_BYPASS:
				if (temptag.IsInt()){
					uint32 oldSecureCommunicationVer = m_SecureCommunicationVer;
					//							= (uint8)(temptag.GetInt() >>  24) & 0xff;
					//							= (uint8)(temptag.GetInt() >>  16) & 0xff;
					//							= (uint8)(temptag.GetInt() >>  15) & 0x01;
					m_uSupportSecureCallback	= (uint8)(temptag.GetInt() >>  14) & 0x01;
					m_uUseUDPSecurity			= (uint8)(temptag.GetInt() >>  13) & 0x01;
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
					m_uUseNATEncrpytion			= (uint8)(temptag.GetInt() >>  12) & 0x01;
 #endif //NATTUNNELING // NEO: NATT END
					m_uPKEncrpytion				= (uint8)(temptag.GetInt() >>  11) & 0x01;
					m_uPreferUnEnCryptedPayload	= (uint8)(temptag.GetInt() >>  10) & 0x01;
					m_uRequierEncryption		= (uint8)(temptag.GetInt() >>  8 ) & 0x03;
					//							= (uint8)(temptag.GetInt() >>  4 ) & 0x0f;
					m_SecureCommunicationVer	= (uint8)(temptag.GetInt() >>  0 ) & 0x0f;
					
					if(m_uRequierEncryption == 0 && m_SecureCommunicationVer >= 2)
						m_uPreferUnEnCryptedPayload = TRUE; // Let the user who wants encryption choice this setting

					if(m_uPreferUnEnCryptedPayload && thePrefs.IsPreferUnEnCryptedPayload() && socket->m_Encryption)
						socket->m_Encryption->SetPlainPayload();

					if(m_SecureCommunicationVer == 1)
						m_uSimpleXOREncryption = 1; // v1 is xor only

					// for compytybility to v1 and v2
					if(oldSecureCommunicationVer < 3 && m_SecureCommunicationVer >= 3)
						m_nRemoteSecurePort = 0; // we must reset the port the remote cleint may now requirer nonstandard DH parameters
					else if(oldSecureCommunicationVer >= 3 && m_SecureCommunicationVer < 3)
					{
						// its a old version without DH parameters
						delete [] m_abyRemoteDHPrime;
						m_abyRemoteDHPrime = NULL;
						m_abyRemoteDHBase = 0;
					}

				}else if (bDbgInfo)
					m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
#endif // ISPBYPASS // NEO: SCC END

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
			case CT_NAT_TUNNELING:
				if (temptag.IsInt()){
					//						= (uint8)(temptag.GetInt() >> 24) & 0xff;
					//						= (uint8)(temptag.GetInt() >> 16) & 0xff;
					//						= (uint8)(temptag.GetInt() >> 11) & 0x1f;
					m_uNatCharacteristic	= (uint8)(temptag.GetInt() >> 9 ) & 0x03;
					m_uNatPortRelaiable		= (uint8)(temptag.GetInt() >> 8 ) & 0x01;
					//						= (uint8)(temptag.GetInt() >> 4 ) & 0x0f;
					m_uNatTraversalVersion  = (uint8)(temptag.GetInt() >> 0 ) & 0x0f;
				}else if (bDbgInfo)
					m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
#endif //NATTUNNELING // NEO: NATT END

			// NEO: NATS - [NatSupport]
			case CT_EMULE_BUDDYID:
				if(temptag.IsHash())
				{
					SetBuddyID(temptag.GetHash());
				}
				else{
					if (bDbgInfo)
						m_strModInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				}
				break;
			// NEO: NATS END

			// NEO: NXI - [NeoExtraInfo]
			case ET_EXTRAINFO:
				if (temptag.IsInt()){
					m_ExtraInfoVer = (uint8)temptag.GetInt() & 0x0f; // i may use thsi tag for many more statistic extensions
				}else if (bDbgInfo)
					m_strHelloInfo.AppendFormat(_T("\n  ***UnkType=%s"), temptag.GetFullInfo());
				break;
			// NEO: NXI END

			default:
				if (bDbgInfo)
					m_strModInfo.AppendFormat(_T("\n  ***UnkTag=%s"), temptag.GetFullInfo());
#ifdef ARGOS // NEO: NA - [NeoArgos]
				if (thePrefs.IsArgosOpcodeDetection()){
					TOpCode* OpCode = new TOpCode;
					OpCode->OpSource = OC_MODINFO;
					OpCode->OpCode = (uint8)temptag.GetNameID();
					OpCode->OpValue = temptag.IsInt() ?  temptag.GetInt() : 0;
					unknownOC.AddTail(OpCode);
				}
#endif // ARGOS // NEO: NA END
		}
	}

	if (bDbgInfo && data.GetPosition() < data.GetLength()){
		m_strModInfo.AppendFormat(_T("\n  ***AddData: %u bytes"), data.GetLength() - data.GetPosition());
	}

#ifdef ARGOS // NEO: NA - [NeoArgos]
	if(thePrefs.UseArgosSystem())
	{
		if (thePrefs.IsArgosOpcodeDetection()){
			while(!unknownOC.IsEmpty())
				theApp.argos->AddClientToTest(this,unknownOC.RemoveHead());
		}
		if(thePrefs.IsArgosBadHelloDetection())
		{
			if(data.GetPosition() < data.GetLength()) // extra bytes
				theApp.argos->DoArgos(GetConnectIP(),AR_BADHELLO,1);
		}
	}
#endif // ARGOS // NEO: NA END
}
// NEO: NMPi END <-- Xanatos --

// NEO: XCFS - [ExtendedClientFileStatus] -- Xanatos -->
void CUpDownClient::SendExtendedFileStatus(CKnownFile* file, bool bReq) 
{
	// NEO: ICS - [InteligentChunkSelection]
	if (thePrefs.UseInteligentChunkSelection() && GetIncompletePartVersion() >= (bReq ? 2 : 1) && file->IsPartFile())
	{
		CSafeMemFile data(16+16);
		data.WriteHash16(file->GetFileHash());
		((CPartFile*)file)->WriteIncPartStatus(&data);
		Packet* packet = new Packet(&data, GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
		if(bReq && GetVersion() < MAKE_CLIENT_VERSION(0, 47, 0)) // only older clients should us the old opcode
			packet->opcode = OP_UPFILEINCSTATUS; // X!: for backwards compatybility
		else
			packet->opcode = OP_FILEINCSTATUS;
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__FileIncompleteStatus", this, file->GetFileHash());
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet,true);
	}
	// NEO: ICS END

	// NEO: RPS - [RealPartStatus]
	if (thePrefs.UseRealPartStatus() && GetHidenPartStatusVersion() && file->HaveRealInfo(PR_PART_HIDEN))
	{
		CSafeMemFile data(16+16);
		data.WriteHash16(file->GetFileHash());
		file->WriteRealPartStatus(&data, PR_PART_HIDEN);
		Packet* packet = new Packet(&data, GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
		packet->opcode = OP_FILEHIDENSTATUS;
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__FileHidenStatus", this, file->GetFileHash());
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet,true);
	}
	if (thePrefs.UseRealPartStatus() && GetBlockedPartStatusVersion() && file->HaveRealInfo(PR_PART_OFF))
	{
		CSafeMemFile data(16+16);
		data.WriteHash16(file->GetFileHash());
		file->WriteRealPartStatus(&data, PR_PART_OFF);
		Packet* packet = new Packet(&data, GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
		packet->opcode = OP_FILEBLOCKEDSTATUS;
		if (thePrefs.GetDebugClientTCPLevel() > 0)
			DebugSend("OP__FileBlockedStatus", this, file->GetFileHash());
		theStats.AddUpDataOverheadFileRequest(packet->size);
		socket->SendPacket(packet,true);
	}
	// NEO: PRS END
}
// NEO: XCFS END <-- Xanatos --

// NEO: NMPm - [NeoModProtMultiPacket] -- Xanatos -->
// Every entry is identyfyed by an uint8 opcode and have a uint16 size field
// This Multi Packet is designed to be used with file reask retated stuff as it contains a file hash on the very begin
//
void CUpDownClient::WriteModMultiPacket(CSafeMemFile* data_out, CKnownFile* file, CClientFileStatus* status, bool bReq, bool bUDP)
{
	bool bWriteSize = GetNeoModProtVersion() > 0;

	// NEO: EDT - [EstimatedDownloadTime]
	if (bReq == false && bUDP == true // we send this only on udp answers, tcp have an own 
	 && thePrefs.UseEstimatedDownloadTime() && GetDownloadTimeVersion() && GetNeoModProtVersion()) 
	{
		data_out->WriteUInt8(OP_EDT_STATUS);
		data_out->WriteUInt16(4+4);

		uint32 avg_value;
		uint32 err_value;
		EstimateDownloadTime(avg_value, err_value);
		data_out->WriteUInt32(avg_value);
		data_out->WriteUInt32(err_value);
	}
	// NEO: EDT END

	// NEO: SCT - [SubChunkTransfer]
	if(bReq == false // send the map only whe it's an answer
	 && thePrefs.UseSubChunkTransfer() && GetSubChunksVer() 
	 && file->IsPartFile() 
	 && (bUDP ? status->m_uSCTpos // send in udp packet only when we are in progress sending out map, when the map is out the pos will be reseted to 0
			  : GetUploadState() == US_NONEEDEDPARTS) ) // the cleint does not need any full part but he may need some blocks of incomplete parts
	{
		data_out->WriteUInt8(OP_SUBCHUNKMAPS);
		uint16 pos = (uint16)data_out->GetPosition();
		if(bWriteSize)
			data_out->WriteUInt16(0);
		((CPartFile*)file)->WriteSubChunkMaps(data_out, status);
		if(bWriteSize){
			data_out->Seek(pos, CFile::begin);
			data_out->WriteUInt16((uint16)(data_out->GetLength() - (data_out->GetPosition()+2)));
			data_out->Seek(0, CFile::end);
		}
	}
	// NEO: SCT END

	uint16 PartStatusSize = 0;
	if(bWriteSize){
		PartStatusSize = 2 + (file->GetED2KPartCount()/8);
		if(file->GetED2KPartCount()%8)
			PartStatusSize += 1;
	}

	// NEO: ICS - [InteligentChunkSelection]
	if (thePrefs.UseInteligentChunkSelection() && GetIncompletePartVersion() >= ((bReq || bUDP) ? 2 : 1) && file->IsPartFile())
	{
		if(bReq && GetVersion() < MAKE_CLIENT_VERSION(0, 47, 0) && GetNeoModProtVersion() == 0) // only older neo clients should use the old opcode
			data_out->WriteUInt8(OP_UPFILEINCSTATUS); // X!: for backwards compatybility
		else
			data_out->WriteUInt8(OP_FILEINCSTATUS);
		if(bWriteSize)
			data_out->WriteUInt16(PartStatusSize);
		((CPartFile*)file)->WriteIncPartStatus(data_out);
	}
	// NEO: ICS END

	// NEO: RPS - [RealPartStatus]
	if (thePrefs.UseRealPartStatus() && GetHidenPartStatusVersion() && file->HaveRealInfo(PR_PART_HIDEN))
	{
		data_out->WriteUInt8(OP_FILEHIDENSTATUS);
		if(bWriteSize)
			data_out->WriteUInt16(PartStatusSize);
		file->WriteRealPartStatus(data_out, PR_PART_HIDEN);
	}
	if (thePrefs.UseRealPartStatus() && GetBlockedPartStatusVersion() && file->HaveRealInfo(PR_PART_OFF))
	{
		data_out->WriteUInt8(OP_FILEBLOCKEDSTATUS);
		if(bWriteSize)
			data_out->WriteUInt16(PartStatusSize);
		file->WriteRealPartStatus(data_out, PR_PART_OFF);
	}
	// NEO: PRS END

#ifdef WEBCACHE // NEO: WC - [WebCache]
	if( bUDP == false && thePrefs.IsWebCacheEnabled() && SupportsWebCache() && WebCacheInfoNeeded())
	{	
		data_out->WriteUInt8(WC_TAG_WEBCACHENAME);
		uint16 pos = (uint16)data_out->GetPosition();
		if(bWriteSize)
			data_out->WriteUInt16(0);
		data_out->WriteString(thePrefs.GetWebCacheName()); // the WriteString writes a proper uint16 length entry
		if(bWriteSize){
			data_out->Seek(pos, CFile::begin);
			data_out->WriteUInt16((uint16)(data_out->GetLength() - (data_out->GetPosition()+2)));
			data_out->Seek(0, CFile::end);
		}

		/*data_out->WriteUInt8(WC_TAG_WEBCACHEID);
		if(bWriteSize)
		data_out->WriteUInt16(4);
		m_uWebCacheUploadId = GetRandomUInt32();
		data_out->WriteUInt32(m_uWebCacheUploadId);*/

		data_out->WriteUInt8(WC_TAG_MASTERKEY);
		if(bWriteSize)
			data_out->WriteUInt16(WC_KEYLENGTH);
		data_out->Write( Crypt.remoteMasterKey, WC_KEYLENGTH );

		byte tmpID[4];
		for (int i=0; i<4; i++)
			tmpID[i] = Crypt.remoteMasterKey[i] ^ (thePrefs.GetUserHash())[i];
		m_uWebCacheUploadId = *((uint32*)tmpID);

		SetWebCacheInfoNeeded(false);
	}
#endif // NEO: WC END
}

void CUpDownClient::ReadModMultiPacket(CSafeMemFile* data_in, CKnownFile* file, CClientFileStatus* status, uint8 opcode)
{
	bool bReadSize = GetNeoModProtVersion() > 0;

	while (data_in->GetLength() - data_in->GetPosition())
	{
		// Note: opcode it != 0 only when we cone from the official multi packet // for backwards compatybility
		uint8 opcode_in = opcode ? opcode : data_in->ReadUInt8(); // read the Entry ID
		uint16 size_in = bReadSize ? data_in->ReadUInt16() : 0; // every mod multi packet entry have a size information, so it can be skipped 
		uint16 pos = (uint16)data_in->GetPosition();
		try{
			switch (opcode_in)
			{
				case NULL: // kill opcode to exit the loop if you want place datas below this entry list you must send the kill opcode first
					return;
				// NEO: EDT - [EstimatedDownloadTime]
				case OP_EDT_STATUS:
				{
					uint32 avg_time = data_in->ReadUInt32();
					uint32 err_time = data_in->ReadUInt32();
					SetRemoteEDT(avg_time, err_time);
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				}
				// NEO: EDT END
				// NEO: SCT - [SubChunkTransfer]
				case OP_SUBCHUNKMAPS:
					status->ReadSubChunkMaps(data_in); // NEO: SCFS - [SmartClientFileStatus]
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				// NEO: SCT END
				// NEO: ICS - [InteligentChunkSelection]
				case OP_FILEINCSTATUS:
				case OP_UPFILEINCSTATUS:  // X!: for backwards compatybility
					status->ReadFileStatus(data_in, CFS_Incomplete);
					file->UpdatePartsInfoEx(CFS_Incomplete);
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				// NEO: ICS END
				// NEO: RPS - [RealPartStatus]
				case OP_FILEHIDENSTATUS:
					status->ReadFileStatus(data_in, CFS_Hiden);
					file->UpdatePartsInfoEx(CFS_Hiden);
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				case OP_FILEBLOCKEDSTATUS:
					status->ReadFileStatus(data_in, CFS_Blocked);
					file->UpdatePartsInfoEx(CFS_Blocked);
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				// NEO: RPS END
#ifdef WEBCACHE // NEO: WC - [WebCache]
				case WC_TAG_WEBCACHENAME:
				{
					CString webcachename = data_in->ReadString(false);
					if( SupportsWebCache() )
					{
						webcachename.Trim();
						webcachename.MakeLower();
						if ( webcachename.IsEmpty() )
							m_WA_webCacheIndex = -1;
						else
						{
							int index = GetWebCacheIndex(webcachename);
							m_WA_webCacheIndex = (index >= 0) ? index : AddWebCache(webcachename);
						}
					}
					ASSERT( !bReadSize || pos + size_in == data_in->GetPosition());
					break;
				}
				/*case WC_TAG_WEBCACHEID:
				{
				ASSERT(!bReadSize || size_in == 4);
				m_uWebCacheDownloadId = data_in.ReadUInt32();
				if( !SupportsWebCache() )
				m_uWebCacheDownloadId = 0;
				break;
				}*/
				case WC_TAG_MASTERKEY:
				{
					ASSERT(!bReadSize || size_in == WC_KEYLENGTH);
					byte tmpKey[WC_KEYLENGTH];
					data_in->Read( tmpKey, WC_KEYLENGTH );
					if( SupportsWebCache() )
					{
						for(int i=0;i<WC_KEYLENGTH;i++)
							Crypt.localMasterKey[i] = tmpKey[i];

						byte tmpID[4];
						for (int i=0; i<4; i++)
							tmpID[i] = Crypt.localMasterKey[i] ^ (GetUserHash())[i];
						m_uWebCacheDownloadId = *((uint32*)tmpID);
					}
					break;
				}
#endif // NEO: WC END
				default:
				{
					// Note: when we arrived at this point there is a bug in the mod capability detection/notification!
					//			The remote client shall send only segments that we know.
					if(bReadSize == 0 || data_in->GetPosition() + size_in > data_in->GetLength())
						AfxThrowFileException(CFileException::endOfFile, 0, _T("MemoryFile"));
					DebugLog(_T("Unknown MOD sub opcode 0x%02x received"), opcode_in);
					data_in->Seek(size_in, CFile::current);
				}
			} // switch
		}
		catch(CFileException* error) // we handle them here to know what sub opcode caused that error
		{
			error->Delete();
			CString strError;
			strError.Format(_T("Invalid Mod sub opcode 0x%02x received, size %i, pos %i"), opcode_in, size_in, (int)pos);
			throw strError;
		}
		if(opcode) // for backwards compatybility
			return; // in this mode we read only one entry at the time
	} // while
}
// NEO: NMPm END <-- Xanatos --

// NEO: NMPx - [NeoModProtXS] -- Xanatos -->
void CUpDownClient::WriteNeoXSTags(CSafeMemFile* data, const CUpDownClient* forClient) const
{
	byte byValue[255];
	ZeroMemory(&byValue[0],sizeof(byValue));
	byte* bValue = &byValue[0];
	uint8 uLength = 0;

	if(HasLowID() && GetServerIP() && GetServerPort())
	{
		WriteNanoTagIDLen(bValue,NT_ServerIPPort,4+2); uLength+=2; // len = 2
		*((uint32*)bValue) = GetServerIP();
		bValue+=4; uLength+=4; // len = 6
		*((uint16*)bValue) = GetServerPort();
		bValue+=2; uLength+=2; // len = 8
	}

	if(HasLowID() && HasValidBuddyID())
	{
		WriteNanoTagIDLen(bValue,NT_BuddyID,16); uLength+=2; // len = 10
		memcpy(bValue,GetBuddyID(),16);
		bValue+=16; uLength+=16; // len = 26

		if(GetBuddyIP() && GetBuddyPort())
		{
			WriteNanoTagIDLen(bValue,NT_BuddyIPPort,4+2); uLength+=2; // len = 28
			*((uint32*)bValue) = GetBuddyIP();
			bValue+=4; uLength+=4; // len = 32
			*((uint16*)bValue) = GetBuddyPort();
			bValue+=2; uLength+=2; // len = 34
		}

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
		if(GetNatTraversalVersion() > 0)
		{
			WriteNanoTagIDLen(bValue,NT_NATT); uLength++; // len = 35

			uint32 ver = GetNatTraversalVersion();
			uint32 fix = IsNATPortRelaiable() ? TRUE : FALSE;
			uint32 type = GetNatType();

			(byte&)*bValue |=	((0x00 & 0x01)	<< 7); // 1 bits reserved for future flags 0-1
			(byte&)*bValue |=	((type & 0x03)	<< 5); // nat type 0-3
			(byte&)*bValue |=	((fix  & 0x01)	<< 4); // fix port 0-1
			(byte&)*bValue |=	((ver  & 0x0f)	<< 0); // version 0-15
			bValue++; uLength++; // len = 36

			if(fix || type == 1) // fix or full cone 
			{
				WriteNanoTagIDLen(bValue,NT_NATPort,2); uLength+=1; // len = 37
				*((uint16*)bValue) = GetNatPort();
				bValue+=2; uLength+=2; // len = 39
			}
		}
#endif //NATTUNNELING // NEO: NATT END
	}

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	if(GetSecureCommunicationVersion() >= 3 && forClient->GetSecureCommunicationVersion() >= 3 
	 && (DoRequierEncryption() > 1 || forClient->DoRequierEncryption() > 1) ) // send the info only when one or booth cleints requirer encryption
	{
		WriteNanoTagIDLen(bValue,NT_ISPT); uLength++; // len = 40

		uint32 ver = GetSecureCommunicationVersion();
		uint32 need = (DoRequierEncryption() > 1); // only when mode is implicit or higher
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
		uint32 nat = UseNATEncrpytion();
 #endif //NATTUNNELING // NEO: NATT END
		uint32 scb = SupportSecureCallback();

		(byte&)*bValue |=	((0x00 & 0x01)	<< 7); // 1 bits resetved for future flags 0-1
		(byte&)*bValue |=	((scb  & 0x01)	<< 6); // secure callback enabled
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
		(byte&)*bValue |=	((nat  & 0x01)	<< 5); // is encryptio needed by this side
 #endif //NATTUNNELING // NEO: NATT END
		(byte&)*bValue |=	((need & 0x01)	<< 4); // is encryptio needed by this side
		(byte&)*bValue |=	((ver  & 0x0f)	<< 0); // version 0-15
		bValue++; uLength++; // len = 41

		if(GetRemoteSecurePort()) // do we provide AUX ports
		{
			bool bSecure = GetRemoteDHPrime() && theApp.clientcredits->CryptoAvailable() && forClient->Credits()
				&& (forClient->Credits()->GetCurrentIdentState(forClient->GetIP()) == IS_IDENTIFIED
				 || forClient->Credits()->GetCurrentIdentState(forClient->GetIP()) == IS_IDBADGUY);

			ASSERT(SOCKET_KEY_SIZE == 32);
			if(bSecure){
				WriteNanoTagIDLen(bValue,NT_SecPort,48); uLength+=2; // len = 43
			}else{
				WriteNanoTagIDLen(bValue,NT_SecPort,GetRemoteDHPrime() ? (2 + SOCKET_KEY_SIZE + 1) : 2); uLength+=2; // len = 43
			}

			byte* beginPtr = bValue;
			uint8 prevLen = uLength;

			*((uint16*)bValue) = GetRemoteSecurePort();
			bValue+=2; uLength+=2; // len = 45

			if(GetRemoteDHPrime())
			{
				memcpy(bValue,GetRemoteDHPrime(),SOCKET_KEY_SIZE);
				bValue+=SOCKET_KEY_SIZE; uLength+=SOCKET_KEY_SIZE; // len = 77
				*((byte*)bValue) = GetRemoteDHBase();
				bValue+=1; uLength+=1; // len = 78
			}

			if(bSecure)
			{
				byte* bfrValue = NULL;
				VERIFY(theApp.clientcredits->EncryptData(forClient->Credits(),beginPtr,2 + SOCKET_KEY_SIZE + 1,bfrValue) == 48); // the encrypted length must always be 48 bytes
				if(bfrValue)
					memcpy(beginPtr,bfrValue,48);
				delete [] bfrValue;
				bValue = beginPtr + 48;	uLength = prevLen + 48; // len = 91
			}
		}
	}
#endif // ISPBYPASS // NEO: SCC END

	ASSERT(uLength <= 91);
	data->WriteUInt8(uLength);
	if(uLength)
		data->Write(&byValue[0],uLength);
}

CUpDownClient::tNeoXSTags::tNeoXSTags()
{
	dwServerIP = 0;
	nServerPort = 0;

	bBuddyID = false;

	dwBuddyIP = 0;
	nBuddyPort = 0;

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	uNatTraversalVersion = 0;
	uNatCharacteristic = 0;
	uNatPortRelaiable = 0;
	nNatPort = 0;
#endif //NATTUNNELING // NEO: NATT END

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	uIspTraversalVersion = 0;
	uEncryptionNeeded = 0;
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	uUseNATEncrpytion = 0;
 #endif //NATTUNNELING // NEO: NATT END
	uSecurePort = 0;
	abyRemoteDHBase = 0;
#endif // ISPBYPASS // NEO: SCC END
}

void CUpDownClient::tNeoXSTags::Attach(CUpDownClient* newcleint)
{
	newcleint->SetServerIP(dwServerIP);
	newcleint->SetServerPort(nServerPort);

	if(bBuddyID){
		newcleint->SetBuddyID(&abyBuddyID[0]);

		newcleint->SetBuddyIP(dwBuddyIP);
		newcleint->SetBuddyPort(nBuddyPort);
	}

#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	newcleint->SetNatTraversalSupport(uNatTraversalVersion);
	newcleint->SetNatType(uNatCharacteristic);
	newcleint->SetNatPortRelaiable(uNatPortRelaiable);
	newcleint->SetNatPort(nNatPort);
#endif //NATTUNNELING // NEO: NATT END

#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	newcleint->SetSecureCommunicationSupport(uIspTraversalVersion);
	newcleint->SetRequierEncryption(uEncryptionNeeded);
	newcleint->SetSupportSecureCallback(uSupportSecureCallback);
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	newcleint->SetNATEncrpytion(uUseNATEncrpytion);
 #endif //NATTUNNELING // NEO: NATT END
	newcleint->SetRemoteSecurePort(uSecurePort);
	if(abyRemoteDHBase){
		newcleint->SetRemoteDHPrime(&abyRemoteDHPrime[0]);
        newcleint->SetRemoteDHBase(abyRemoteDHBase);
	}
#endif // ISPBYPASS // NEO: SCC END
}

CUpDownClient::tNeoXSTags *CUpDownClient::ReadNeoXSTags(CSafeMemFile* sources, const CUpDownClient* pClient)
{
	UINT len = sources->ReadUInt8();
	if(len == 0xFF) // just in cas for future versions
		len = sources->ReadUInt16();

	if(len)
	{
		if(sources->GetPosition() + len > sources->GetLength())
			throw CString(_T("Wrong Neo XS Tag List size !!!"));

		tNeoXSTags* NeoXSTags = new tNeoXSTags;

		byte byValue[256];
		sources->Read(&byValue[0],min(len,sizeof(byValue)));
		byte* pBuffer = &byValue[0];
		byte* pBuffEnd = &byValue[0] + len; // last valid adress

		if(len > sizeof(byValue)) // just in cas for future versions
			sources->Seek(len-sizeof(byValue),CFile::current);

		while(pBuffEnd >= pBuffer + 1) // we need to have one byte in peto, the GetNanoTagLen may want read 2 of tham, and besides entries without content are not valid anyway
		{
			uint8 uID = GetNanoTagID(pBuffer);
			uint8 uLength = GetNanoTagLen(pBuffer);
			if(pBuffer + uLength > pBuffEnd || uLength == 0){
				delete NeoXSTags;
				throw CString(_T("Wrong Neo XS Tag Entry size !!!"));
			}

			byte* bValue = pBuffer;
			pBuffer += uLength;

			switch(uID)
			{
			case NT_ServerIPPort:
				ASSERT(uLength == 6);
				NeoXSTags->dwServerIP = *((uint32*)bValue);
				bValue += 4;
				NeoXSTags->nServerPort = *((uint16*)bValue);
				break;
			case NT_BuddyID:
				ASSERT(uLength == 16);
				NeoXSTags->bBuddyID = true;
				memcpy(&NeoXSTags->abyBuddyID[0],bValue,16);
				break;
			case NT_BuddyIPPort:
				ASSERT(uLength == 6);
				NeoXSTags->dwBuddyIP = *((uint32*)bValue);
				bValue += 4;
				NeoXSTags->nBuddyPort = *((uint16*)bValue);
				break;
#ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
			case NT_NATT:
				NeoXSTags->uNatCharacteristic	= ((byte)*bValue >> 5) & 0x03;
				NeoXSTags->uNatPortRelaiable	= ((byte)*bValue >> 4) & 0x01;
				NeoXSTags->uNatTraversalVersion = ((byte)*bValue >> 0) & 0x0f;
				break;
			case NT_NATPort:
				ASSERT(NeoXSTags->uNatTraversalVersion);
				ASSERT(uLength == 2);
				NeoXSTags->nNatPort = *((uint16*)bValue);
				break;
#endif //NATTUNNELING // NEO: NATT END
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			case NT_ISPT:
				NeoXSTags->uSupportSecureCallback	= ((byte)*bValue >> 6) & 0x01;
 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
				NeoXSTags->uUseNATEncrpytion		= ((byte)*bValue >> 5) & 0x01;
 #endif //NATTUNNELING // NEO: NATT END
				NeoXSTags->uEncryptionNeeded		=(((byte)*bValue >> 4) & 0x01) ? 2 : 0;
				NeoXSTags->uIspTraversalVersion		= ((byte)*bValue >> 0) & 0x0f;
				break;
			case NT_SecPort:
				ASSERT(NeoXSTags->uIspTraversalVersion);
				if(uLength == 48)
				{
					if(theApp.clientcredits->CryptoAvailable() && pClient->Credits() 
					 && (pClient->Credits()->GetCurrentIdentState(pClient->GetIP()) == IS_IDENTIFIED
					 || pClient->Credits()->GetCurrentIdentState(pClient->GetIP()) == IS_IDBADGUY))
					{
						byte* bfrValue = NULL;
						uLength = theApp.clientcredits->DecryptData(bValue,48,bfrValue);
						if(bfrValue)
							memcpy(bValue,bfrValue,uLength);
						delete [] bfrValue;
					}
					else
						continue; // the data couldn't be decryptes
				}

				if(uLength >= 2){
					NeoXSTags->uSecurePort = *((uint16*)bValue);
					bValue += 2;
					if(uLength > 2){
						memcpy(&NeoXSTags->abyRemoteDHPrime[0],bValue,32);
						bValue += 32;
						NeoXSTags->abyRemoteDHBase = *((byte*)bValue);
					}
				}
				break;
#endif // ISPBYPASS // NEO: SCC END
			default:
				DebugLog(_T("Unknown Neo XS Tag sub opcode 0x%02x received, size %i"), uID, uLength);
			} // switch
		} // while

		return NeoXSTags;
	}

	return NULL;
}
// NEO: NMPx END <-- Xanatos --

// NEO: NXI - [NeoExtraInfo] -- Xanatos -->
void CUpDownClient::SendExtraInfoPacket(DWORD dwInfos, bool bViaUDP, uint32 dwIP, uint16 nPort){

	if(bViaUDP){
		if(socket && socket->IsConnected())
			bViaUDP = false; // We have a TCP connection so we use it...
		else if(GetUDPPort() == 0 || thePrefs.GetUDPPort() == 0 || theApp.IsFirewalled())
			return;

		if(!dwIP || !nPort){
			dwIP = GetIP();
			nPort = GetUDPPort();
		}
	}else if (socket == NULL){
		ASSERT(0);
		return;
	}

	CSafeMemFile data(128);

	//data.WriteUInt8(EXTRAINFO_PROTOCOL);

	uint32 uTagCount = 0;
	ULONG uTagCountFilePos = (ULONG)data.GetPosition();
	data.WriteUInt32(uTagCount);

	if(dwInfos & NIX_HELLO){
		uint8 uCreditSystem = REMOTE_CS_NONE;
		// NEO: NCS - [NeoCreditSystem]
		if(thePrefs.UseCreditSystem())
			if (thePrefs.UseNeoCreditSystem())
				uCreditSystem = REMOTE_CS_NEO;
			else
				switch(thePrefs.GetCreditSystem()){
					case 0: uCreditSystem = REMOTE_CS_OFFICIAL; break;
					case 1: uCreditSystem = REMOTE_CS_EASTSHARE; break;
					case 2: uCreditSystem = REMOTE_CS_LOVELACE; break;
					case 3: uCreditSystem = REMOTE_CS_PAWCIO; break;
					case 4: uCreditSystem = REMOTE_CS_PEACE; break;
					case 5: uCreditSystem = REMOTE_CS_RT; break;
					case 6: uCreditSystem = REMOTE_CS_SIVKA; break;
					case 7: uCreditSystem = REMOTE_CS_SWAT; break;
					case 8: uCreditSystem = REMOTE_CS_TK4; break;
					case 9: uCreditSystem = REMOTE_CS_XTREME; break;
					case 10: uCreditSystem = REMOTE_CS_ZZUL; break;
				}
		// NEO: NCS END
		CTag tagCS(EI_CREDIT_SYSTEM,uCreditSystem); 
		tagCS.WriteTagToFile(&data);
		uTagCount++;

		DWORD dwQueleSystem = NULL;
		if(thePrefs.SaveUploadQueueWaitTime()) // NEO: SQ - [SaveUploadQueue]
			dwQueleSystem |= REMOTE_QS_SAVE_WAIT_TIME;
		if(thePrefs.UseMultiQueue()) // NEO: MQ - [MultiQueue]
			dwQueleSystem |= REMOTE_QS_ONE_PER_FILE;
		if(thePrefs.UseNeoScoreSystem()) // NEO: NFS - [NeoScoreSystem]
			dwQueleSystem |= REMOTE_QS_EXPONENTIAL;
		if(thePrefs.UseRandomQueue()) // NEO: RQ - [RandomQueue]
			dwQueleSystem |= REMOTE_QS_PROBABILISTIC;
		if(thePrefs.UseInfiniteQueue()) // NEO: TQ - [TweakUploadQueue]
			dwQueleSystem |= REMOTE_QS_INFINITE;
		//dwQueleSystem |= REMOTE_QS_PAYBACK_FIRST;
		if(thePrefs.UseOldPrioritySystem())// NEO: TQ - [TweakUploadQueue]
			dwQueleSystem |= REMOTE_QS_OLD_PRIO_SYS;
		CTag tagQS(EI_QUELE_SYSTEM,dwQueleSystem);
		tagQS.WriteTagToFile(&data);
		uTagCount++;

		if(thePrefs.SendExtraInfoBandwidth()){
			CTag tagUC(EI_MAX_UL_CAPACITY,thePrefs.GetMaxUpload());
			tagUC.WriteTagToFile(&data);
			uTagCount++;

			CTag tagDC(EI_MAX_DL_CAPACITY,thePrefs.GetMaxDownload());
			tagDC.WriteTagToFile(&data);
			uTagCount++;
		}

		if(thePrefs.SendExtraInfoUpTime()){
			uint32 uUpTime = (GetTickCount()-theStats.starttime)/1000; // in seconds
			CTag tagUC(EI_UP_TIMR,uUpTime);
			tagUC.WriteTagToFile(&data);
			uTagCount++;
		}

		if(thePrefs.SendExtraInfoUpTime() == 1){
			if(theApp.GetLastIDChange() > 0){
				uint32 uIdAge = (GetTickCount()-theApp.GetLastIDChange())/1000; // in seconds
				CTag tagDC(EI_ID_AGE,uIdAge);
				tagDC.WriteTagToFile(&data);
				uTagCount++;
			}
		}

		if(!thePrefs.SendExtraInfoString().IsEmpty()){
			CTag tagSI(EI_STRING_INFO,thePrefs.SendExtraInfoString().GetLength());
			tagSI.WriteTagToFile(&data);
			uTagCount++;
		}
	}
	if(dwInfos & NIX_SUI){
		if(credits){
			CTag tagSUI(EI_SUI_STATE, credits->GetCurrentIdentState(GetIP()));
			tagSUI.WriteTagToFile(&data);
			uTagCount++;
		}
	}
	if(dwInfos & NIX_REQUP){
		CKnownFile* currequpfile = theApp.sharedfiles->GetFileByID(requpfileid);
		if(currequpfile)
		{
			CTag tagUP(EI_UL_PRIO,currequpfile->GetUpPriority());
			tagUP.WriteTagToFile(&data);
			uTagCount++;

			CTag tagREL(EI_UL_RELEASE,currequpfile->GetReleasePriority());
			tagREL.WriteTagToFile(&data);
			uTagCount++;

			if(thePrefs.SendExtraInfoUlFile()){
				uint32 uLastSeen = currequpfile->IsPartFile() ? (UINT)((CPartFile*)currequpfile)->lastseencomplete.GetTime() : (UINT)CTime::GetCurrentTime().GetTime();
				CTag tagLC(EI_LAST_SEEN_REQ_FILE,uLastSeen);
				tagLC.WriteTagToFile(&data);
				uTagCount++;
			}

			if(thePrefs.SendExtraInfoUlFile() == 1){
				UINT uSourceCount = currequpfile->IsPartFile() ? ((CPartFile*)currequpfile)->GetSourceCount() : currequpfile->GetQueuedCount();
				CTag tagSC(EI_REQ_FILE_SOURCES,uSourceCount);
				tagSC.WriteTagToFile(&data);
				uTagCount++;

				CTag tagCS(EI_REQ_FILE_COMP_SOURCES,currequpfile->m_nCompleteSourcesCount);
				tagCS.WriteTagToFile(&data);
				uTagCount++;
			}

		}
	}
	if(dwInfos & NIX_REQDOWN){
		if(reqfile){
			CTag tagDP(EI_DL_PRIO,reqfile->GetDownPriority());
			tagDP.WriteTagToFile(&data);
			uTagCount++;

			if(thePrefs.SendExtraInfoDlFile()){
				CTag tagSC(EI_UP_REQ_FILE_SOURCES,reqfile->GetSourceCount());
				tagSC.WriteTagToFile(&data);
				uTagCount++;

				CTag tagCS(EI_UP_REQ_FILE_COMP_SOURCES,reqfile->m_nCompleteSourcesCount);
				tagCS.WriteTagToFile(&data);
				uTagCount++;
			}
		}
	}
	if(dwInfos & NIX_RANKING){
		if(credits){
			float modif = 1.0F;
			// NEO: NCS - [NeoCreditSystem]
			if(thePrefs.UseCreditSystem())
				if (thePrefs.UseNeoCreditSystem())
					modif = credits->GetNeoScoreRatio(GetRequestFile() != NULL /*GetDownloadState() == DS_ONQUEUE*/,GetIP());
				else
					modif = credits->GetScoreRatio(GetIP()); 
			// NEO: NCS END

			uint32 uScore = (uint32)(modif*1000);
			CTag tagS(EI_CREDIT_SCORE, uScore);
			tagS.WriteTagToFile(&data);
			uTagCount++;
		}

		CTag tagWT(EI_WAITING_TIME, (::GetTickCount()-GetWaitStartTime())/1000);
		tagWT.WriteTagToFile(&data);
		uTagCount++;

		CTag tagQR(EI_QUEUE_RATING,GetScore(false,IsDownloading(),true));
		tagQR.WriteTagToFile(&data);
		uTagCount++;

		CTag tagQS(EI_QUEUE_SCORE,GetScore(false,IsDownloading(),false));
		tagQS.WriteTagToFile(&data);
		uTagCount++;
		
		CTag tagFS(EI_PRIVATE_SLOT,IsPrivatUpload()); // NEO: PTM - [PrivatTransferManagement]
		tagFS.WriteTagToFile(&data);
		uTagCount++;

		if(thePrefs.SendExtraInfoWaitingUsers()){
			CTag tagQS(EI_WAITING_USERS,theApp.uploadqueue->GetWaitingUserCount());
			tagQS.WriteTagToFile(&data);
			uTagCount++;
		}
	}

	if(!uTagCount) // we dont have any tags writen so we dont send the packet
		return;

	data.Seek(uTagCountFilePos, CFile::begin);
	data.WriteUInt32(uTagCount);
	data.Seek(0, CFile::end);

	Packet* packet = new Packet(&data,GetNeoModProtVersion() ? OP_MODPROT : OP_EMULEPROT); // NEO: NMP - [NeoModProt]
	packet->opcode = OP_EXTRAINFO; 
	if (thePrefs.GetDebugClientTCPLevel() > 0)
		DebugSend("OP__ExtraInfo", this);
	theStats.AddUpDataOverheadOther(packet->size);

	if(bViaUDP)
 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
		SendPacketUDP(packet);
 #else
		theApp.clientudp->SendPacket(packet,dwIP,nPort);
 #endif // ISPBYPASS // NEO: SCC END
	else
		socket->SendPacket(packet,true,true);
}

void CUpDownClient::ProcessExtraInfoPacket(CSafeMemFile* data, bool bFromUDP)
{
	ASSERT(GetExtraInfoVersion());

	//uint8 protversion = data->ReadUInt8();
	//if (protversion != EXTRAINFO_PROTOCOL){
	//	if (thePrefs.GetVerbose())
	//		AddDebugLogLine(false,_T("Bad EXTRAINFO_PROTOCOL packet revived from client %s, HelloInfo:%s, MuleInfo:%s"),DbgGetFullClientSoftVer(),DbgGetHelloInfo(),DbgGetMuleInfo());
	//	return;
	//}

	if(!m_ExtraInfo){
		m_ExtraInfo = new Extra_Info_Struct;
		
		// Unfortunatly the  0 is a part of valid valuses
		// so we take -1 for indeterminates
		memset(m_ExtraInfo,0xff,sizeof Extra_Info_Struct);

		m_ExtraInfo->CreditScore = 0;
		m_ExtraInfo->SomeInfosLen = 0;
	}

	uint32 tagcount = data->ReadUInt32();
	for (uint32 i = 0;i < tagcount; i++){
		CTag temptag(data, true);
		switch (temptag.GetNameID()){
			case EI_SUI_STATE:
				if(bFromUDP) break;
				m_ExtraInfo->SUIState = (uint8)temptag.GetInt();
				break;

			// File Priorities
			case EI_UL_PRIO:
				m_ExtraInfo->FileULPriority = (uint8)temptag.GetInt();
				break;
			case EI_UL_RELEASE:
				m_ExtraInfo->FileULReleasePriority = (uint8)temptag.GetInt();
				break;
			case EI_DL_PRIO:
				m_ExtraInfo->FileDLPriority = (uint8)temptag.GetInt();
				break;

			// Credit system
			case EI_CREDIT_SCORE:{
				uint32 uScore = temptag.GetInt();
				m_ExtraInfo->CreditScore = ((float)uScore)/1000;
				break;
			}
			case EI_CREDIT_SYSTEM:
				if(bFromUDP) break;
				m_ExtraInfo->CreditSystem = (uint8)temptag.GetInt();
				break;

			// Score Informations
			case EI_QUELE_SYSTEM:
				if(bFromUDP) break;
				m_ExtraInfo->QueueSystem = temptag.GetInt();
				break;
			case EI_WAITING_TIME:
				m_ExtraInfo->WaitingTime = temptag.GetInt();
				break;
			case EI_QUEUE_RATING:
				m_ExtraInfo->QueueRating = temptag.GetInt();
				break;
			case EI_QUEUE_SCORE:
				m_ExtraInfo->QueueScore = temptag.GetInt();
				break;
			case EI_PRIVATE_SLOT:
				m_ExtraInfo->PrivatSlot = (uint8)temptag.GetInt();
				break;
			case EI_WAITING_USERS:
				m_ExtraInfo->WaitingUsers = temptag.GetInt();
				break;

			// Bandwidth infos
			case EI_MAX_UL_CAPACITY:
				if(bFromUDP) break;
				m_ExtraInfo->UploadCapacity = (uint16)temptag.GetInt();
				break;
			case EI_MAX_DL_CAPACITY:
				if(bFromUDP) break;
				m_ExtraInfo->DownloadCapacity = (uint16)temptag.GetInt();
				break;

			// Other File infos
			case EI_LAST_SEEN_REQ_FILE:
				m_ExtraInfo->lastseencompletereqfile = temptag.GetInt();
				break;

			case EI_REQ_FILE_SOURCES:
				m_ExtraInfo->ReqFileSources = (uint16)temptag.GetInt();
				break;
			case EI_REQ_FILE_COMP_SOURCES:
				m_ExtraInfo->ReqFileCompleteSources = (uint16)temptag.GetInt();
				break;

			case EI_UP_REQ_FILE_SOURCES:
				m_ExtraInfo->UpReqFileSources = (uint16)temptag.GetInt();
				break;
			case EI_UP_REQ_FILE_COMP_SOURCES:
				m_ExtraInfo->UpReqFileCompleteSources = (uint16)temptag.GetInt();
				break;

			// Other infos
			case EI_UP_TIMR:
				m_ExtraInfo->UpTime = temptag.GetInt();
				break;
			case EI_ID_AGE:
				m_ExtraInfo->IDAge = temptag.GetInt();
				break;

			case EI_STRING_INFO:{
				if(bFromUDP) break;
				m_ExtraInfo->SomeInfosLen = temptag.GetInt();

				break;
			}
#ifdef _DEBUG
			default:
				DebugLogWarning(_T("Unknown Tag in Extra Info Packet: %s"), temptag.GetFullInfo());
#endif
		}
	}
}
// NEO: NXI END <-- Xanatos --

#ifdef ARGOS // NEO: NA - [NeoArgos] -- Xanatos -->
void CUpDownClient::IncXSReqs(){
	if(m_uXSReqs > 128){
		m_uXSAnswer /= 2;
		m_uXSReqs /= 2;
	}
	m_uXSReqs++;
}

void CUpDownClient::IncXSAnswer(){
	if(m_uXSAnswer > 128){
		m_uXSAnswer /= 2;
		m_uXSReqs /= 2;
	}
	m_uXSAnswer++;
}

bool CUpDownClient::CheckXSAsk()
{
	// Check for XS exploid, asking without answering
	// WARNING: official clients do this an accepted but not answered request is already being counted !!!
	// for proper operation "unsigned int nTimePassedClient = dwTickCount - GetLastAskedForSources(); // GetLastSrcAnswerTime();" is nessesery !!!
	if(m_uXSReqs > 2 && (!m_uXSAnswer || (m_uXSReqs / m_uXSAnswer > 2)))
		theApp.argos->DoArgos(GetConnectIP(),AR_XSEXPLOIT,TRUE);

	// check for fast XS, to fast asking
	// WARNING: official clients do this due to a inconsistent implementation of the reask roules !!!
	// Bevoure we can count the ask we must go sure the client had got our last answer "GetLastSourcesSent()" !!
	if(GetLastSourcesSent() && ::GetTickCount() - GetLastSourcesSent() > CONNECTION_LATENCY){
		if(::GetTickCount() - GetLastSrcReqTime() < thePrefs.GetArgosXSExploitIntervalsMs()){
			m_uFastXSCounter++;
			if(m_uFastXSCounter > thePrefs.GetArgosXSExploitThreshold())
				theApp.argos->DoArgos(GetConnectIP(),AR_XSEXPLOIT);
		}
	}

	// don't answer to exploiters
	return theApp.argos->IsArgos(GetConnectIP(),AR_XSEXPLOIT);
}
#endif // ARGOS // NEO: NA END <-- Xanatos --

// NEO: MOD -- Xanatos -->
bool CUpDownClient::SUIFaild() const{
	if(credits)
		return ( theApp.clientcredits->CryptoAvailable() 
		 && ( credits->GetCurrentIdentState(GetIP()) == IS_IDFAILED 
		   || credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY 
		   || credits->GetCurrentIdentState(GetIP()) == IS_IDNEEDED) 
		 );
	return false;
}

bool CUpDownClient::IsFriend() const
{
	if(SUIFaild())
		return false;

#ifdef ARGOS // NEO: NA - [NeoArgos]
	if(thePrefs.IsArgosHashThiefDetection()
	 && theApp.argos->IsArgos(GetConnectIP(),AR_HASHTHIEF))
		return false;
#endif // ARGOS // NEO: NA END

	return m_Friend != NULL; 
}
// NEO: MOD END <-- Xanatos --

// NEO: NC - [NiceCommunity] -- Xanatos -->
/* Name:     IsCommunity
   Function: Test if client is community member
   Return:   true  - if one of the community tags occur in the name of the actual client
					 and community sharing is enabled
			 false - otherwise
   Remarks:  All strings will be treated case-insensitive. There can be more than one
			 community tag in the community tag string - all these strings must be separated
			 by "|". Spaces around community tags are trimmed.
   Author:   Mighty Knife
*/
bool CUpDownClient::IsCommunity() const 
{
	if (!thePrefs.IsCommunityEnabled() || m_strUsername.IsEmpty()) // NEO: FIX - [StabilityFix] <-- Xanatos --
		return false;

#ifdef ARGOS // NEO: NA - [NeoArgos]
	if(thePrefs.IsArgosNickThiefDetection()
	 && theApp.argos->IsArgos(GetConnectIP(),AR_NICKTHIEF))
		return false;
#endif // ARGOS // NEO: NA END

	CString Communities = thePrefs.GetCommunityName(); 
	for(int pos = 0; pos >= 0;){
		CString Community = Communities.Tokenize (_T("|"),pos).Trim();
		if (Community.IsEmpty())
			continue;
		if(StrStrI(m_strUsername,Community)) // NEO: FIX - [StabilityFix] <-- Xanatos --
			return true;
	}
	return false;
}
// NEO: NC END <-- Xanatos --

// NEO: PTM - [PrivatTransferManagement] -- Xanatos -->
uint8 CUpDownClient::IsPrivatUpload()
{
	uint8 PrivateUpload = GetFriendSlot() ? 1 : 0;
	return PrivateUpload;
}

uint8 CUpDownClient::IsPrivatDownload()
{
	if(m_FreeDownload)
		return m_FreeDownload;

	if(m_ExtraInfo && m_ExtraInfo->PrivatSlot != 0xFF)
		return m_ExtraInfo->PrivatSlot;

	return FALSE;
}
// NEO: PTM END <-- Xanatos --

#ifdef IP2COUNTRY // NEO: IP2C - [IPtoCountry] -- Xanatos -->
CString	CUpDownClient::GetCountryName(bool longName) const {
	return theApp.ip2country->GetCountryNameFromRef(m_structUserCountry,longName);
}

int CUpDownClient::GetCountryFlagIndex() const {
	return m_structUserCountry->FlagIndex;
}

void CUpDownClient::ResetIP2Country(uint32 m_dwIP){
	m_structUserCountry = theApp.ip2country->GetCountryFromIP((m_dwIP)?m_dwIP:m_dwUserIP);
}
#endif // IP2COUNTRY // NEO: IP2C END <-- Xanatos --

// NEO: NTT - [NewToolTips] -- Xanatos -->
void CUpDownClient::GetTooltipBaseInfo(CString &info)
{
	if(!GetUserName().IsEmpty())
		info.Format(GetResString(IDS_X_USERINFO), GetUserName(), m_nUserIDHybrid, GetResString(HasLowID() ? IDS_IDLOW : IDS_IDHIGH), DbgGetFullClientSoftVer());
	else
		info.Format(GetResString(IDS_X_USERINFO2));
	if (m_dwServerIP)
	{
		in_addr server;
		server.S_un.S_addr = m_dwServerIP;
		info.AppendFormat(GetResString(IDS_X_SERVER), ipstr(server), m_nServerPort);
	}
}

void CUpDownClient::GetTooltipDownloadInfo(CString &info, bool a4af, CPartFile* file, bool base) 
{
	if (IsEd2kClient())
	{
		if(base)
			GetTooltipBaseInfo(info);

		if (file == NULL)
			file = this->reqfile;

		info.AppendFormat(GetResString(IDS_X_LASTASK), CastSecondsToHM((::GetTickCount() - (DWORD)this->GetLastAskedTime())/1000));
		info.AppendFormat(GetResString(IDS_X_LASTASK2), CastSecondsToHM((::GetTickCount() - (DWORD)this->getLastTriedToConnectTime())/1000));
		info.AppendFormat(GetResString(IDS_X_NEXTASK),	CastSecondsToHM(this->GetTimeUntilReask(this->reqfile)/1000),CastSecondsToHM(this->GetTimeUntilReask(file)/1000)); // ZZ:DownloadManager

		info.AppendFormat(GetResString(IDS_X_SOURCEINFO), GetAskedCountDown());
		info.AppendFormat(GetResString(IDS_X_SOURCEINFO2), GetAvailablePartCount());
		if (reqfile)
		{
			if (a4af)
				info.AppendFormat(GetResString(IDS_X_ASKEDFAF), reqfile->GetFileName());
			
			// NEO: SCFS - [SmartClientFileStatus]
			if (CClientFileStatus* status = GetFileStatus(file,false))
				info.AppendFormat(GetResString(IDS_X_CLIENTSOURCENAME), status->GetFileName());
			// NEO: SCFS END
			
			// NEO: XC - [ExtendedComments]
			CPartFile* file = (CPartFile*)reqfile;
			for (POSITION pos = file->GetCommentList().GetHeadPosition(); pos != NULL;)
			{					
				Comment_Struct* cur_cs = file->GetCommentList().GetNext(pos);
				if (!md4cmp(cur_cs->m_achUserHash,GetUserHash()))
				{
					if (cur_cs->m_strComment.IsEmpty())
						info.AppendFormat(GetResString(IDS_X_CMT_NONE)); 	//No comment entered
					else
						info.AppendFormat(GetResString(IDS_X_CMT_READ), cur_cs->m_strComment);

					info.AppendFormat(GetResString(IDS_X_CMT_RATING), GetRateString(cur_cs->m_uRating));
					break;
				} 					
			}
			// NEO: XC END	
		}

		// ZZ:DownloadManager -->
		if (thePrefs.IsExtControlsEnabled() && !this->m_OtherRequests_list.IsEmpty()){
			info.AppendFormat(GetResString(IDS_X_A4AF));
			for (POSITION pos3 = this->m_OtherRequests_list.GetHeadPosition(); pos3!=NULL; this->m_OtherRequests_list.GetNext(pos3))
				info.AppendFormat(_T("<br>%s"),this->m_OtherRequests_list.GetAt(pos3)->GetFileName());
		}
		// ZZ:DownloadManager <--
	}
	else
		info.AppendFormat(GetResString(IDS_X_AVAIL_PARTS), this->GetUserName(), this->GetAvailablePartCount());
}

void CUpDownClient::GetTooltipUploadInfo(CString &info, bool base)
{
	if (base) GetTooltipBaseInfo(info);

	if(CKnownFile* file = theApp.sharedfiles->GetFileByID(requpfileid))
	{
		info.AppendFormat(GetResString(IDS_X_REQUESTED), file->GetFileName());
		info.AppendFormat(GetResString(IDS_X_FILESTATS_SESSION), file->statistic.GetAccepts(), file->statistic.GetRequests(), CastItoXBytes(file->statistic.GetTransferred(), false, false));
		info.AppendFormat(GetResString(IDS_X_FILESTATS_TOTAL), file->statistic.GetAllTimeAccepts(), file->statistic.GetAllTimeRequests(), CastItoXBytes(file->statistic.GetAllTimeTransferred(), false, false));
	}
	else
		info.AppendFormat(GetResString(IDS_REQ_UNKNOWNFILE));
}

void CUpDownClient::GetTooltipQueueInfo(CString &info, bool base)
{
	if (base) GetTooltipBaseInfo(info);
	if(CKnownFile* file = theApp.sharedfiles->GetFileByID(requpfileid))
		info.AppendFormat(GetResString(IDS_X_REQUESTED), file->GetFileName());

	info.AppendFormat(GetResString(IDS_X_QL_RATING), GetScore(false,false,true));
	info.AppendFormat(GetResString(IDS_X_QL_SCORE), GetScore(false));
	info.AppendFormat(GetResString(IDS_X_SOURCEINFO), GetAskedCount());
	info.AppendFormat(GetResString(IDS_X_QL_LASTSEEN), CastSecondsToHM((GetTickCount() - GetLastUpRequest())/1000));
	info.AppendFormat(GetResString(IDS_X_ENTEREDQUEUE), CastSecondsToHM((GetTickCount() - GetWaitStartTime())/1000));
}

void CUpDownClient::GetTooltipClientInfo(CString &info)
{
	GetTooltipBaseInfo(info);
	if(reqfile)
	{
		info.AppendFormat(GetResString(IDS_X_DOWNLOAD_INFO));
		info.AppendFormat(GetResString(IDS_X_REQUESTED), reqfile->GetFileName());
		GetTooltipDownloadInfo(info, false, false);
	}

	switch(GetUploadState())
	{
		case US_UPLOADING:
			info.AppendFormat(GetResString(IDS_X_UPLOAD_INFO));
			GetTooltipQueueInfo(info, false);
			break;
		case US_ONUPLOADQUEUE:
			info.AppendFormat(GetResString(IDS_X_QUEUE_INFO));
			GetTooltipUploadInfo(info, false);
			break;
	}

}
// NEO: NTT END <-- Xanatos --

#ifdef WEBCACHE // NEO: WC - [WebCache] -- Xanatos -->
bool CUpDownClient::IsBehindOurWebCache() const {
	// WC-TODO: make this more efficient
	return( thePrefs.GetWebCacheName() == GetWebCacheName() );
}
#endif // NEO: WC END <-- Xanatos --