//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "StdAfx.h"
#include "updownclient.h"
#include "emule.h"
#include "uploadqueue.h"
#include "Clientlist.h"

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


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

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

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

void CUpDownClient::Init(){
	memset(m_szFullUserIP,0,21);
	credits = 0;
	m_nAvDownDatarate = 0;
	m_nAvUpDatarate = 0;
	m_byChatstate = 0;
	//m_cShowDR = 0;
	m_nUDPPort = 0;
	m_cFailed = 0;
	m_dwBanTime = 0;
	m_nMaxSendAllowed = 0;
	m_nTransferedUp = 0;
	//m_cSendblock = 0;
	m_cAsked = 0;
	m_cDownAsked = 0;
	//dataratems = 0;
	m_nUpDatarate = -1;
	m_pszUsername = 0;
	m_dwUserIP = 0;
	m_nUserID = 0;
	m_nServerPort = 0;
	m_bBanned = false;
	m_bFileListRequested = false;
	m_dwLastUpRequest = 0;
	m_bEmuleProtocol = false;
	usedcompressiondown = false;
	m_bUsedComprUp = false;
	m_bCompleteSource = false;
	m_bFriendSlot = false;
	m_bCommentDirty = false;
	m_bReaskPending = false;
	m_bUDPPending = false;
	m_byEmuleVersion = 0;
	m_nUserPort = 0;
	m_nPartCount = 0;
	m_nUpPartCount = 0;
	m_abyPartStatus = 0;
	m_abyUpPartStatus = 0;
	m_dwLastAskedTime = 0;
	m_nDownloadState = DS_NONE;
	m_pszClientFilename = 0;
	m_dwUploadTime = 0;
	m_nTransferedDown = 0;
	m_nDownDatarate = 0;
	//m_nDownDataRateMS = 0;
	m_byUploadState = US_NONE;
	m_dwLastBlockReceived = 0;
	m_byEmuleVersion = 0;
	m_byDataCompVer = 0;
	m_byUDPVer = 0;
	m_bySourceExchangeVer = 0;
	m_byAcceptCommentVer = 0;
	m_byExtendedRequestsVer = 0;
	m_nRemoteQueueRank = 0;
	m_dwLastSourceRequest = 0;
	m_dwLastSourceAnswer = 0;
	m_byCompatableClient = 0;
	m_bIsHybrid = false;
	m_Friend = NULL;
	m_iRate=0;
	m_strComment="";
	//m_nCurSessionUp = 0;
    m_LastGotULData = 0;
	m_nSumForAvgDownDataRate = 0;
	//m_nSumForAvgUpDataRate = 0;
	m_clientSoft=SO_UNKNOWN;
	m_bRemoteQueueFull = false;
	memset( m_achUserHash, 0, 16);
	SetWaitStartTime();
	if (socket){
		SOCKADDR_IN sockAddr;
		memset(&sockAddr, 0, sizeof(sockAddr));
		uint32 nSockAddrLen = sizeof(sockAddr);
		socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
		m_dwUserIP = sockAddr.sin_addr.S_un.S_addr;
		strcpy(m_szFullUserIP,inet_ntoa(sockAddr.sin_addr));
	}
	sourcesslot=0;

    m_lastRefreshedULDisplay = ::GetTickCount();
    //m_lastRefreshedDLDisplay = ::GetTickCount();
    m_lastCalculatedDownloadRate = ::GetTickCount();

    m_bHasPriorPart = false;
    m_iPriorPartNumber = 0;
}

CUpDownClient::~CUpDownClient(){
	//Beep(400,5);
	theApp.clientlist->RemoveClient(this);
	if (m_Friend){
		m_Friend->m_LinkedClient = NULL;
		theApp.friendlist->RefreshFriend(m_Friend);
		m_Friend = NULL;
	}
	if (m_pszClientFilename)
		delete[] m_pszClientFilename;
	if (socket){
		socket->client = 0;
		socket->Safe_Delete();
	}
	if (m_pszUsername)
		delete[] m_pszUsername;
	if (m_abyPartStatus)
		delete[] m_abyPartStatus;
	if (m_abyUpPartStatus)
		delete[] m_abyUpPartStatus;
	ClearUploadBlockRequests();

	for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;m_DownloadBlocks_list.GetNext(pos))
		delete m_DownloadBlocks_list.GetAt(pos);
	m_DownloadBlocks_list.RemoveAll();
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos))
		delete m_RequestedFiles_list.GetAt(pos);
	m_RequestedFiles_list.RemoveAll();
	for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;m_PendingBlocks_list.GetNext(pos)){
		Pending_Block_Struct *pending = m_PendingBlocks_list.GetAt(pos);
		delete pending->block;
		// Not always allocated
		if (pending->zStream) delete pending->zStream;
		delete pending;
	}

	if (m_iRate>0 || m_strComment.GetLength()>0) {
		m_iRate=0; m_strComment="";
		reqfile->UpdateFileRatingCommentAvail();
	}

	m_PendingBlocks_list.RemoveAll();
	m_AvarageUDR_list.RemoveAll();
	m_AvarageDDR_list.RemoveAll();
	DEBUG_ONLY (theApp.listensocket->Debug_ClientDeleted(this));
}

void CUpDownClient::ProcessHelloPacket(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	uint8 hashsize;
	data->Read(&hashsize,1);
	this->ProcessHelloTypePacket(data);
	delete data;
}

void CUpDownClient::ProcessHelloAnswer(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	this->ProcessHelloTypePacket(data);
	delete data;
}

void CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data){
	
	m_bIsHybrid = false;
	data->Read(&m_achUserHash,16);
	uint32 nUserID;
	data->Read(&nUserID,4);
	if (!m_nUserID)
		m_nUserID = nUserID;
	data->Read(&m_nUserPort,2); // hmm clientport is sent twice - why?
	uint32	tagcount;
	data->Read(&tagcount,4);
	for (int i = 0;i != tagcount; i++){
		CTag* temptag = new CTag(data);
		switch(temptag->tag->specialtag){
			case CT_NAME:
				if (m_pszUsername)
					delete[] m_pszUsername;
				if( temptag->tag->stringvalue )
					m_pszUsername = nstrdup(temptag->tag->stringvalue);
				else
					m_pszUsername=NULL;
				break;
			case CT_VERSION:
				m_nClientVersion = temptag->tag->intvalue;
				break;
			case CT_PORT:
				m_nUserPort = temptag->tag->intvalue;
				break;
		}
		delete temptag;
	}
	data->Read(&m_dwServerIP,4);
	data->Read(&m_nServerPort,2);
	// Hybrid now has an extra uint32.. What is it for?
	// Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
	if ( data->GetLength() - data->GetPosition() == 4 ){
//		uint32 test;
//		data->Read(&test,4);
		m_bIsHybrid = true;
//		if( m_nClientVersion > 10000 && m_nClientVersion < 100000 )
//			m_nClientVersion = m_nClientVersion - (m_nClientVersion/10000)*10000;
//		if( m_nClientVersion > 1000 )
//			m_nClientVersion = m_nClientVersion - (m_nClientVersion/1000)*1000;
//		if( m_nClientVersion < 100 )
//			m_nClientVersion *= 10;
	}
	// tecxx 1609 2002 - add client's servet to serverlist (Moved to uploadqueue.cpp)

	SOCKADDR_IN sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	uint32 nSockAddrLen = sizeof(sockAddr);
	socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
	m_dwUserIP = sockAddr.sin_addr.S_un.S_addr;
	strcpy(m_szFullUserIP,inet_ntoa(sockAddr.sin_addr));

	// get client credits
	// key, 255.255.0.0 subnetmask

	if (theApp.glob_prefs->AddServersFromClient()){
		in_addr addhost;
		addhost.S_un.S_addr = m_dwServerIP;
		CServer* addsrv = new CServer(m_nServerPort, inet_ntoa(addhost));
		addsrv->SetListName(addsrv->GetAddress());

		if (!theApp.emuledlg->serverwnd.serverlistctrl.AddServer(addsrv, true))
			delete addsrv;
		/*else
			theApp.emuledlg->AddLogLine(false,"Added new server: %s:%d", srv->GetFullIP(), srv->GetPort());*/
	}
	if(!HasLowID() && m_nUserID != m_dwUserIP)
		m_nUserID = m_dwUserIP;

	uchar key[16];
	memcpy(key,m_achUserHash,16);
	credits = theApp.clientcredits->GetCredit(key);
	if ( (m_Friend = theApp.friendlist->LinkFriend(key, m_dwUserIP, m_nUserPort) ) != NULL){
		m_Friend->m_LinkedClient = this;
		m_Friend->m_dwHasHash = 1;
		for( int i = 0; i < 16; i++ )
			m_Friend->m_abyUserhash[i] = GetUserHash()[i];
		m_Friend->m_strName.Format("%s", m_pszUsername);
		m_Friend->m_dwLastUsedIP = m_dwUserIP;
		m_Friend->m_nLastUsedPort = m_nUserPort;
		theApp.friendlist->RefreshFriend(m_Friend);
	}
	ReGetClientSoft();
}

void CUpDownClient::SendHelloPacket(){
	// if IP is filtered, dont greet him but disconnect...
	if (socket){
		SOCKADDR_IN sockAddr;
		memset(&sockAddr, 0, sizeof(sockAddr));
		uint32 nSockAddrLen = sizeof(sockAddr);
		socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
		if ( theApp.ipfilter->IsFiltered(sockAddr.sin_addr.S_un.S_addr)) {
			theApp.emuledlg->AddDebugLogLine(true,GetResString(IDS_IPFILTERED),GetFullIP(),theApp.ipfilter->GetLastHit());
			Disconnected();
			theApp.stat_filteredclients++;
			return;
		}
	}

	CMemFile* data = new CMemFile();
	uint8 hashsize = 16;
	data->Write(&hashsize,1);
	SendHelloTypePacket(data);
	Packet* packet = new Packet(data);
	delete data;
	packet->opcode = OP_HELLO;
	if (socket){
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
	}
}

void CUpDownClient::SendMuleInfoPacket(bool bAnswer){
	CMemFile* data = new CMemFile();
	uint8 version = CURRENT_VERSION_SHORT;
	data->Write(&version,1);
	uint8 protversion = EMULE_PROTOCOL;
	data->Write(&protversion,1);
	uint32 tagcount = 6;
	data->Write(&tagcount,4);
	CTag tag(ET_COMPRESSION,1);
	tag.WriteTagToFile(data);
	CTag tag2(ET_UDPVER,2);
	tag2.WriteTagToFile(data);
	CTag tag3(ET_UDPPORT,theApp.glob_prefs->GetUDPPort());
	tag3.WriteTagToFile(data);
	CTag tag4(ET_SOURCEEXCHANGE,1);
	tag4.WriteTagToFile(data);
	CTag tag5(ET_COMMENTS,1);
	tag5.WriteTagToFile(data);
	CTag tag6(ET_EXTENDEDREQUEST,1);
	tag6.WriteTagToFile(data);
	Packet* packet = new Packet(data,OP_EMULEPROT);
	delete data;
	if (!bAnswer)
		packet->opcode = OP_EMULEINFO;
	else
		packet->opcode = OP_EMULEINFOANSWER;
	if (socket){
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true,true);
	}
}

void CUpDownClient::ProcessMuleInfoPacket(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	m_byCompatableClient = 0;
	data->Read(&m_byEmuleVersion,1);
	if( m_byEmuleVersion == 0x2B )
		m_byEmuleVersion = 0x22;
	uint8 protversion;
	data->Read(&protversion,1);

	//implicitly supported options by older clients
	if (protversion == EMULE_PROTOCOL) {
		//in the future do not use version to guess about new features

		if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22)
			m_byUDPVer = 1;

		if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21)
			m_bySourceExchangeVer = 1;

		if(m_byEmuleVersion == 0x24)
			m_byAcceptCommentVer = 1;

	} else {
		delete data;
		return;
	}
	m_bEmuleProtocol = true;

	uint32 tagcount;
	data->Read(&tagcount,4);
	for (int i = 0;i != tagcount; i++){
		CTag* temptag = new CTag(data);
		switch(temptag->tag->specialtag){
			case ET_COMPRESSION:
				m_byDataCompVer = temptag->tag->intvalue;
				break;
			case ET_UDPPORT:
				m_nUDPPort = temptag->tag->intvalue;
				break;
			case ET_UDPVER:
				m_byUDPVer = temptag->tag->intvalue;
				break;
			case ET_SOURCEEXCHANGE:
				m_bySourceExchangeVer = temptag->tag->intvalue;
				break;
			case ET_COMMENTS:
				m_byAcceptCommentVer = temptag->tag->intvalue;
				break;
			case ET_EXTENDEDREQUEST:
				m_byExtendedRequestsVer = temptag->tag->intvalue;
				break;
			case ET_COMPATABLECLIENT:
				m_byCompatableClient = temptag->tag->intvalue;
				break;
		}
		delete temptag;
	}
	if( m_byDataCompVer == 0 ){
		m_bySourceExchangeVer = 0;
		m_byExtendedRequestsVer = 0;
		m_byAcceptCommentVer = 0;
		m_nUDPPort = 0;
	}
	delete data;
}

void CUpDownClient::SendHelloAnswer(){
	CMemFile* data = new CMemFile();
	SendHelloTypePacket(data);
	Packet* packet = new Packet(data);
	delete data;
	packet->opcode = OP_HELLOANSWER;
	if (socket){
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
	}
}

void CUpDownClient::SendHelloTypePacket(CMemFile* data){
	data->Write(theApp.glob_prefs->GetUserHash(),16);
	uint32 clientid = theApp.serverconnect->GetClientID();
	data->Write(&clientid,4);
	uint16 nPort = theApp.glob_prefs->GetPort();
	data->Write(&nPort,2);
	uint32 tagcount = 2;
	data->Write(&tagcount,4);
	CTag* tag = new CTag(CT_NAME,theApp.glob_prefs->GetUserNick());
	tag->WriteTagToFile(data);
	delete tag;
	tag = new CTag(CT_VERSION,EDONKEYVERSION);
	tag->WriteTagToFile(data);
	delete tag;
//	tag = new CTag(CT_PORT,theApp.glob_prefs->GetPort());
//	tag->WriteTagToFile(data);
//	delete tag;
	uint32 dwIP;
	if (theApp.serverconnect->IsConnected()){
		dwIP = theApp.serverconnect->GetCurrentServer()->GetIP();
		nPort = theApp.serverconnect->GetCurrentServer()->GetPort();
	}
	else{
		nPort = 0;
		dwIP = 0;
	}
	data->Write(&dwIP,4);
	data->Write(&nPort,2);
}

void CUpDownClient::ProcessMuleCommentPacket(char* pachPacket, uint32 nSize){
	if (nSize>2){
		CSafeMemFile data((BYTE*)pachPacket,nSize);
		int length;
		data.Read(&m_iRate,sizeof(m_iRate));
		data.Read(&length,sizeof(length));
		reqfile->SetHasRating(true);
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_RATINGRECV),m_pszClientFilename,m_iRate);
		if (length>50) length=50;
		if (length>0){
			char* desc=new char[length+1];
			memset(desc,0,length+1);
			data.Read(desc,length);
			theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_DESCRIPTIONRECV), m_pszClientFilename, desc);
			m_strComment.Format("%s",desc);
			reqfile->SetHasComment(true);
			delete desc;
		}

	}
	if (reqfile->HasRating() || reqfile->HasComment()) theApp.emuledlg->transferwnd.downloadlistctrl.UpdateItem(reqfile);
}
void CUpDownClient::Disconnected(){
	ASSERT(theApp.clientlist->Debug_IsValidClient(this));
	if (GetUploadState() == US_UPLOADING)
		theApp.uploadqueue->RemoveFromUploadQueue(this);
	if (GetDownloadState() == DS_DOWNLOADING){
		SetDownloadState(DS_ONQUEUE);
        ClearPriorPartNumber();
	}
	if ((GetDownloadState() == DS_REQHASHSET) && (reqfile))
        reqfile->hashsetneeded= true;
	ASSERT(theApp.clientlist->Debug_IsValidClient(this));
	//check if this client is needed in any way, if not delete it
	bool bDelete = true;
	switch(m_byUploadState){
		case US_ONUPLOADQUEUE:
			bDelete = false;
	};
	switch(m_nDownloadState){
		case DS_ONQUEUE:
		case DS_TOOMANYCONNS:
		case DS_NONEEDEDPARTS:
		case DS_LOWTOLOWIP:
			bDelete = false;
	};

	switch(m_byUploadState){
		case US_CONNECTING:
		case US_WAITCALLBACK:
		case US_ERROR:
			bDelete = true;
	};
	switch(m_nDownloadState){
		case DS_CONNECTING:
		{
			m_cFailed++;
			if (m_cFailed <= 2){
				TryToConnect();
				return;
			}
		}
		case DS_WAITCALLBACK:
		case DS_ERROR:
			bDelete = true;
	};
	

	if (GetChatState()){
		bDelete = false;
		theApp.emuledlg->chatwnd.chatselector.ConnectingResult(this,false);
	}
	if (socket){
		ASSERT (theApp.listensocket->IsValidSocket(socket));
		socket->Safe_Delete();
	}
	socket = 0;
	if (m_bFileListRequested){
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_SHAREDFILES_FAILED),GetUserName());
		m_bFileListRequested = false;
	}
    if (m_Friend) {
		theApp.friendlist->RefreshFriend(m_Friend);

        // If friends with friendslots are deleted, the friendslot setting is
        // forgotten. Prevent that.
        if(GetFriendSlot()) {
            bDelete = false;
        }
    }
	if (bDelete){
		delete this;
	}

}

void CUpDownClient::TryToConnect(bool bIgnoreMaxCon){
	if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon && !(socket && socket->IsConnected())){
		Disconnected();
		return;
	}
	if ((theApp.serverconnect->GetClientID() < 16777216) && HasLowID()){
		if (GetDownloadState() == DS_CONNECTING)
			SetDownloadState(DS_LOWTOLOWIP);
		else if (GetDownloadState() == DS_REQHASHSET){
			SetDownloadState(DS_ONQUEUE);
			reqfile->hashsetneeded = true;
		}
		if (GetUploadState() == US_CONNECTING){
			Disconnected();
		}
	}

	if (!socket){
		socket = new CClientReqSocket(theApp.glob_prefs,this);
		if (!socket->Create()){
			socket->Safe_Delete();
			return;
		}
	}
	else if (!socket->IsConnected()){
		socket->Safe_Delete();
		socket = new CClientReqSocket(theApp.glob_prefs,this);
		if (!socket->Create()){
			socket->Safe_Delete();
			return;
		}
	}
	else{
		ConnectionEstablished();
		return;
	}
	// MOD Note: Do not change this part - Merkur
	if (HasLowID()){
		if (GetDownloadState() == DS_CONNECTING)
			SetDownloadState(DS_WAITCALLBACK);
		if (GetUploadState() == US_CONNECTING){
			Disconnected();
			return;
		}

		if (theApp.serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)){
			Packet* packet = new Packet(OP_CALLBACKREQUEST,4);
			memcpy(packet->pBuffer,&m_nUserID,4);
			theApp.uploadqueue->AddUpDataOverheadServer(packet->size);
			theApp.serverconnect->SendPacket(packet);
		}
		else{
			if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending) ){
				theApp.downloadqueue->RemoveSource(this);
				Disconnected();
				return;
			}
			else{
				if (GetDownloadState() == DS_WAITCALLBACK){
					m_bReaskPending = true;
					SetDownloadState(DS_ONQUEUE);
				}
			}
		}
	}
	// MOD Note - end
	else{
		socket->Connect(GetFullIP(),GetUserPort());
		SendHelloPacket();
	}
}

void CUpDownClient::ConnectionEstablished(){
	m_cFailed = 0;
	// ok we have a connection, lets see if we want anything from this client
	if (GetChatState() == MS_CONNECTING)
		theApp.emuledlg->chatwnd.chatselector.ConnectingResult(this,true);
	switch(GetDownloadState()){
		case DS_CONNECTING:
		case DS_WAITCALLBACK:
			m_bReaskPending = false;
			SetDownloadState(DS_CONNECTED);
			SendFileRequest();
	}
	if (m_bReaskPending){
		m_bReaskPending = false;
		if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING){
			SetDownloadState(DS_CONNECTED);
			SendFileRequest();
		}
	}
	switch(GetUploadState()){
		case US_CONNECTING:
		case US_WAITCALLBACK:
			if (theApp.uploadqueue->IsDownloading(this)){
				SetUploadState(US_UPLOADING);
				Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
				theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
				socket->SendPacket(packet,true);
			}
	}
	if (m_bFileListRequested){
		Packet* packet = new Packet(OP_ASKSHAREDFILES,0);
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true,true);
	}
}

void CUpDownClient::ReGetClientSoft(){
	if (!m_pszUsername) {m_clientSoft=SO_UNKNOWN;return;}
	if (m_achUserHash[5] == 13 && m_achUserHash[14] == 110) {m_clientSoft= SO_OLDEMULE;return;}
	if (m_achUserHash[5] == 14 && m_achUserHash[14] == 111){
		if( m_byCompatableClient == 1 ){
			m_clientSoft= SO_CDONKEY;
			return;
		}
		else{
			m_clientSoft= SO_EMULE;
			return;
		}
	}
	if (m_achUserHash[5] == 'M' && m_achUserHash[14] == 'L') {m_clientSoft= SO_MLDONKEY;return;}
	if( m_bIsHybrid )
		m_clientSoft=SO_EDONKEYHYBRID;
	else
		m_clientSoft=SO_EDONKEY;
}

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

void CUpDownClient::RequestSharedFileList(){
	theApp.emuledlg->AddDebugLogLine(true,GetResString(IDS_SHAREDFILES_REQUEST),GetUserName());
	m_bFileListRequested = true;
	TryToConnect(true);
}

void CUpDownClient::ProcessSharedFileList(char* pachPacket, uint32 nSize){
	if (m_bFileListRequested){
		m_bFileListRequested = false;
		theApp.searchlist->ProcessSearchanswer(pachPacket,nSize,this);
	}
}