//this file is part of NeoMule
//Copyright (C)2006 David Xanatos ( Xanatos@Lycos.at / http://NeoMule.tk )
//
//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 <io.h>
#include "Preferences.h"
#include "PartFile.h"
#include "SafeFile.h"
#include "Packets.h"
#include "emule.h"
#include "Log.h"
#include "emuledlg.h"
#include "friend.h"
#include "friendlist.h"
#include "UpDownClient.h"
#include "ClientList.h"
#include "Transferwnd.h"
#include "ClientCredits.h"
#include "downloadqueue.h"
#include "Neo/NeoVersion.h"
#include "Neo/Defaults.h"
#include "Neo/NeoOpCodes.h"
#include "Neo/Functions.h"
#include "Neo/EMBackup.h" // NEO: NB - [NeoBackup]
//#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase]
#include "Neo/SourceList.h"
//#endif // NEO_CD // NEO: NCD END
#include "ClientFileStatus.h" // NEO: SCFS - [SmartClientFileStatus]
#ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection] -- Xanatos -->
#include "EMSocket.h"
#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

#ifdef NEO_SS // NEO: NSS - [NeoSourceStorage] -- Xanatos -->

#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
bool CPartFile::SortCompare(CUpDownClientPtrList* list, POSITION pos1, POSITION pos2){
	CUpDownClient* src1 = list->GetAt(pos1);
	CUpDownClient* src2 = list->GetAt(pos2);
	if(src2->Source() == NULL || src2->Source()->IsNullAvalibilityProbability())
		return false;
	if(src1->Source() == NULL || src1->Source()->IsNullAvalibilityProbability())
		return true;
	const int Probability1 = src1->Source()->GetAvalibilityProbability(PM_ENHANCED, PartPrefs.GetEnhancedFactor(),PartPrefs.GetMaxFailTolerance());
	const int Probability2 = src2->Source()->GetAvalibilityProbability(PM_ENHANCED, PartPrefs.GetEnhancedFactor(),PartPrefs.GetMaxFailTolerance());
	if(Probability1 == Probability2)
		return (src1->Source()->GetRemindingIPTime() < src2->Source()->GetRemindingIPTime());
	return (Probability1 < Probability2);
	
}

void CPartFile::SortSwap(CUpDownClientPtrList* list, POSITION pos1, POSITION pos2){
	CUpDownClient* src1 = list->GetAt(pos1);
	CUpDownClient* src2 = list->GetAt(pos2);
	list->SetAt(pos1, src2);
	list->SetAt(pos2, src1);
}

void CPartFile::HeapSortList(CUpDownClientPtrList* list, UINT first, UINT last){
	UINT r;
	POSITION pos1 = list->FindIndex(first);
	for ( r = first; !(r & 0x8000) && (r<<1) < last; ){
		UINT r2 = (r<<1)+1;
		POSITION pos2 = list->FindIndex(r2);
		if (r2 != last){
			POSITION pos3 = pos2;
			list->GetNext(pos3);
			if (!SortCompare(list, pos2, pos3)){
				pos2 = pos3;
				r2++;
			}
		}
		if (!SortCompare(list, pos1, pos2)) {
			SortSwap(list, pos1, pos2);
			r = r2;
			pos1 = pos2;
		}
		else
			break;
	}
}

void CPartFile::SortSourceList(CUpDownClientPtrList* list){
	UINT n = list->GetCount();
	if (!n)
		return;
	UINT i;
	for ( i = n/2; i--; )
		HeapSortList(list, i, n-1);
	for ( i = n; --i; ){
		SortSwap(list, list->FindIndex(0), list->FindIndex(i));
		HeapSortList(list, 0, i-1);
	}
}
#endif // NEO_SA // NEO: NSA END

bool CPartFile::SaveSources(CString sFileName, bool bFullData)
{
	if (IsStopped() || !PartPrefs.EnableSourceStorage()){
		return false;
	}

#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
	if(m_fullname.IsEmpty() && sFileName.IsEmpty()) // Virtual files does not need to save sources, but thay may export them
		return true;
#endif // VOODOO // NEO: VOODOO END

	CString strSrcFile;
	if(sFileName.IsEmpty()){
		sFileName.Format(m_fullname);

		strSrcFile.Format(sFileName);
		strSrcFile += PARTSRC_EXT;
	}else
		strSrcFile = sFileName;

	CString strTmpFile(strSrcFile);
	strTmpFile += PARTSRC_TMP_EXT;

	// save sources to part.src file
	CSafeBufferedFile file;
	CFileException fexp;
	if (!file.Open(strTmpFile, CFile::modeWrite|CFile::modeCreate|CFile::typeBinary|CFile::shareDenyWrite, &fexp)){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, GetFileName());
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	try{
		//version
		file.WriteUInt8(SRCFILE_VERSION);

		SaveSources(&file, bFullData);

		if (thePrefs.GetCommitFiles() >= 2 || (thePrefs.GetCommitFiles() >= 1 && !theApp.emuledlg->IsRunning())){
			file.Flush(); // flush file stream buffers to disk buffers
			if (_commit(_fileno(file.m_pStream)) != 0) // commit disk buffers to disk
				AfxThrowFileException(CFileException::hardIO, GetLastError(), file.GetFileName());
		}
		file.Close();
	}
	catch(CFileException* error){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, GetFileName());
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (error->GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		error->Delete();

		// remove the partially written or otherwise damaged temporary file
		file.Abort(); // need to close the file before removing it. call 'Abort' instead of 'Close', just to avoid an ASSERT.
		(void)_tremove(strTmpFile);
		return false;
	}

	// after successfully writing the temporary part.src file...
	if (_tremove(strSrcFile) != 0 && errno != ENOENT){
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Failed to remove \"%s\" - %s"), strSrcFile, strerror(errno));
	}

	if (_trename(strTmpFile, strSrcFile) != 0){
		int iErrno = errno;
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Failed to move temporary part.met.src file \"%s\" to \"%s\" - %s"), strTmpFile, strSrcFile, strerror(iErrno));

		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, GetFileName());
		strError += _T(" - ");
		strError += strerror(iErrno);
		ModLogError(_T("%s"), strError);
		return false;
	}

	// create a backup of the successfully written part.met file
	CString BAKName(strSrcFile);
	BAKName.Append(PARTSRC_BAK_EXT);
	if (!::CopyFile(strSrcFile, BAKName, FALSE)){
		if (thePrefs.GetVerbose())
			DebugLogError(_T("Failed to create backup of %s (%s) - %s"), strSrcFile, GetFileName(), GetErrorMessage(GetLastError()));
	}

	m_uLastSaveSource = ::GetTickCount();

	return true;
}

#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
bool CPartFile::SaveSources(CFileDataIO* file, bool bFullData, uint32 uSizeLimit)
#else
bool CPartFile::SaveSources(CFileDataIO* file, bool bFullData)
#endif // VOODOO // NEO: VOODOO END
{
	uint32 uTagCount = 0;
	ULONG uTagCountFilePos = (ULONG)file->GetPosition();
	file->WriteUInt32(uTagCount);

	/*
	* Save Sources here
	*/
#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
	if(PartPrefs.EnableSourceAnalizer())
		SortSourceList(&srclist); // Sort sources
#endif // NEO_SA // NEO: NSA END
	for (POSITION pos = srclist.GetHeadPosition(); pos != NULL;){
		CUpDownClient* cur_src = srclist.GetNext(pos);
		if( !cur_src->IsSourceConfirmed() // It must be a Real client
			|| (cur_src->HasLowID() && !PartPrefs.StoreLowIDSources()) // Don't Store low ID Sources, obtional
			|| !cur_src->IsEd2kClient()) // This system Saves only ED2K clinets, http sources will be saved by an other procedure
			continue;
#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
		if(PartPrefs.DontStoreTemporarySources() && cur_src->Source())
			if(cur_src->Source()->GetIPType() == IP_Temporary
				&& cur_src->Source()->GetAnalisisQuality() > 2/*PartPrefs.GetMinAnalisisQuality()*/) // X-ToDo: Customize or so
				continue;
#endif // NEO_SA // NEO: NSA END
		cur_src->StoreToFile(file, bFullData); // Save general client informations
		cur_src->WriteToFile(file,this); // Save client informations about this partfile
		uTagCount++;
		if(uTagCount > (uint32)PartPrefs.GetSourceStorageLimit())
			break;
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
		else if(uSizeLimit && file->GetLength() > uSizeLimit) // failsave for voodoo, wen cant send pacet larger than 2 MB
			break;
#endif // VOODOO // NEO: VOODOO END
	}
	if(PartPrefs.StoreAlsoA4AFSources()){
#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
		if(PartPrefs.EnableSourceAnalizer())
			SortSourceList(&A4AFsrclist); // Sort sources
#endif // NEO_SA // NEO: NSA END
		for (POSITION pos = A4AFsrclist.GetHeadPosition(); pos != 0; ){
			CUpDownClient* cur_src = A4AFsrclist.GetNext(pos);
			if( !cur_src->IsSourceConfirmed() // It must be a Real client
				|| (cur_src->HasLowID() && !PartPrefs.StoreLowIDSources()) // Don't Store low ID Sources, obtional
				|| !cur_src->IsEd2kClient()) // This system Saves only ED2K clinets, http sources will be saved by an other procedure
				continue;
#ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
			if(PartPrefs.DontStoreTemporarySources() && cur_src->Source())
				if(cur_src->Source()->GetIPType() == IP_Temporary
					&& cur_src->Source()->GetAnalisisQuality() > 2/*PartPrefs.GetMinAnalisisQuality()*/) // X-ToDo: Customize or so
					continue;
#endif // NEO_SA // NEO: NSA END
			cur_src->StoreToFile(file, bFullData); // Save general client informations
			cur_src->WriteToFile(file,this); // Save client informations about this partfile
			uTagCount++;
			if(uTagCount > (uint32)PartPrefs.GetSourceStorageLimit())
				break;
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
			else if(uSizeLimit && file->GetLength() > uSizeLimit) // failsave for voodoo, wen cant send pacet larger than 2 MB
				break;
#endif // VOODOO // NEO: VOODOO END
		}
	}

	file->Seek(uTagCountFilePos, CFile::begin);
	file->WriteUInt32(uTagCount);
	file->Seek(0, CFile::end);

	return true;
}

bool CPartFile::LoadSources(CString sFileName)
{
	if (IsStopped() || !PartPrefs.EnableSourceStorage()){
		return false;
	}

#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
	if(m_fullname.IsEmpty() && sFileName.IsEmpty()) // Virtual files does not have saved sources, but thay may import them
		return true;
#endif // VOODOO // NEO: VOODOO END

	CString strSrcFile;
	if(sFileName.IsEmpty()){
		sFileName.Format(m_fullname);

		strSrcFile.Format(sFileName);
		strSrcFile += PARTSRC_EXT;
	}else
		strSrcFile = sFileName;

	uint8 version;
	
	// readfile tweaks form part.src file
	CSafeBufferedFile file;
	CFileException fexpMet;
	if (!file.Open(strSrcFile, CFile::modeRead|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyWrite, &fexpMet)){
		if (fexpMet.m_cause != CFileException::fileNotFound){
			CString strError;
			strError.Format(GetResString(IDS_X_ERR_OPENSRC), strSrcFile, _T(""));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexpMet.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			ModLogError(LOG_STATUSBAR, _T("%s"), strError);
			theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_UNRECOVERABLE); // NEO: NB - [NeoBackup]
			return false;
		}
		theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_RECOVERABLE); // NEO: NB - [NeoBackup]
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	try{
		version = file.ReadUInt8();
		
		if (version != SRCFILE_VERSION /*version > SRCFILE_VERSION || version < SRCFILE_VERSION_OLD*/){
			ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_BADSRCVERSION), strSrcFile, GetFileName());
			file.Close();
			theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_RECOVERABLE); // NEO: NB - [NeoBackup]
			return false;
		}
		
		LoadSources(&file);
		
		file.Close();
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile){
			ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_SRCMEOCORRUPT), strSrcFile, GetFileName());
			theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_RECOVERABLE); // NEO: NB - [NeoBackup]
		}else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer,ARRSIZE(buffer));
			ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_FILEERROR), strSrcFile, GetFileName(), buffer);
			theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_UNRECOVERABLE); // NEO: NB - [NeoBackup]
		}
		error->Delete();
		return false;
	}
	catch(...){
		ModLogError(LOG_STATUSBAR, GetResString(IDS_ERR_METCORRUPT), strSrcFile, GetFileName());
		theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_UNRECOVERABLE); // NEO: NB - [NeoBackup]
		ASSERT(0);
		return false;
	}

	if(PartPrefs.StoreSourcesFileStatus() == TRUE){
		UpdateSourceCount(); // NEO: FIX - [SourceCount]
		UpdatePartsInfo(true);
		UpdatePartsInfoEx(CFS_Incomplete); // NEO: ICS - [InteligentChunkSelection]
		UpdatePartsInfoEx(CFS_Hiden); // NEO: RPS - [RealPartStatus]
		UpdatePartsInfoEx(CFS_Blocked); // NEO: RPS - [RealPartStatus]
		UpdateAvailablePartsCount();
	}

	theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_CORRECT); // NEO: NB - [NeoBackup]
	return true;
}

#ifdef VOODOO // NEO: VOODOOx - [VoodooSourceExchange]
bool CPartFile::LoadSources(CFileDataIO* file, bool bFromVoodoo)
#else
bool CPartFile::LoadSources(CFileDataIO* file)
#endif // VOODOO // NEO: VOODOOx END
{
	uint32 ownIP = theApp.GetPublicIP();
	uint16 ownPort = thePrefs.GetPort();

#ifdef VOODOO // NEO: VOODOOx - [VoodooSourceExchange]
	const bool bRestore = (bFromVoodoo || PartPrefs.IsTotalSourceRestore());
#else
	const bool bRestore = PartPrefs.IsTotalSourceRestore();
#endif // VOODOO // NEO: VOODOOx END
	CUpDownClient* toadd = NULL;
	try{
		UINT RecordsNumber = file->ReadUInt32();
		for (UINT i = 0; i < RecordsNumber; i++) {
			/*
			* Load All Sources here
			*/
			toadd = new CUpDownClient();
			if(!toadd->CreateFromFile(file)){
				delete toadd;
				return false;
			}

			if (!theApp.clientlist->AttachToAlreadyKnown(&toadd,0,ATTACH_LOAD)){
				// here we know that the client instance 'source' is a new created client instance (see callers) 
				// which is therefor not already in the clientlist, we can avoid the check for duplicate client list entries 
				// when adding this client
				theApp.clientlist->AddClient(toadd);
			}

			// to prevent haveing clinets with reqfile = NULL but files in other request lists
			// we will add the source immidetly to the proper reqfile, even if we are currently in an other PartFile
			CPartFile* tempreqfile = toadd->LoadFromFile(file,this);

			// filter own ip the source packet may comm from a voodoo node
			if(toadd->GetConnectIP() == ownIP && toadd->GetUserPort() == ownPort){
				delete toadd;
				continue;
			}

			// when the right owner is gone, take the source over
			if(tempreqfile == NULL || tempreqfile->IsStopped())
				tempreqfile = this;

			if(tempreqfile != this && !PartPrefs.StoreAlsoA4AFSources()){
				// At this point we know that this is an a4af source, as also the reast, if A4AF Storage is disabled, abort here.
				toadd->ClearWhenNeeded();
				break;
			}

			// The source may be already added ba an other a4af list, or was found for an other file, bevoure this file was resumed
			// Add client as source if the clinet isn't already a source already for some file
			if(toadd->GetRequestFile() == NULL){
				ASSERT(tempreqfile->srclist.Find(toadd) == NULL);
#ifdef VOODOO // NEO: VOODOOx - [VoodooSourceExchange]
				toadd->SetSourceFrom(bFromVoodoo ? SF_VOODOO : SF_STORAGE);
#else
				toadd->SetSourceFrom(SF_STORAGE);
#endif // VOODOO // NEO: VOODOOx END
				toadd->SetRequestFile(tempreqfile);
				if(!toadd->IsActive() && !(bRestore && toadd->IsLinkedLastSeen())) // When the soure was seen les than an hour load as activ
					toadd->SetDownloadState(DS_LOADED);
				tempreqfile->srclist.AddTail(toadd);
				theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(tempreqfile,toadd,false);
			}

			// if an other file already have this source, add it to our A4AF List
			if(toadd->GetRequestFile() != this){
				if (toadd->AddRequestForAnotherFile(this))
					theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(this,toadd,true);
			}
		}
	}catch(CFileException* error){
		if(toadd)
			delete toadd;
		throw error;
	}
	return true;
}

bool CDownloadQueue::ExportSources(CTypedPtrList<CPtrList, CPartFile*>& ExportList, CString strSrcFile)
{
	if(ExportList.GetCount() == 0)
		return false;

	if(ExportList.GetCount() == 1) // export one file to songle source format
		return ExportList.GetHead()->SaveSources(strSrcFile,true);


	// save sources to part.src file
	CSafeBufferedFile file;
	CFileException fexp;
	if (!file.Open(strSrcFile, CFile::modeWrite|CFile::modeCreate|CFile::typeBinary|CFile::shareDenyWrite, &fexp)){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, _T(""));
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	try{
		//version
		file.WriteUInt8(MULTI_SRCFILE_VERSION);

		uint32 uTagCount = 0;
		ULONG uTagCountFilePos = (ULONG)file.GetPosition();
		file.WriteUInt32(uTagCount);
	
		CPartFile* cur_file;
		while(!ExportList.IsEmpty())
		{
			cur_file = ExportList.RemoveHead();
			file.WriteHash16(cur_file->GetFileHash());

			cur_file->SaveSources(&file,true);

			uTagCount++;
		}

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

		if (thePrefs.GetCommitFiles() >= 2 || (thePrefs.GetCommitFiles() >= 1 && !theApp.emuledlg->IsRunning())){
			file.Flush(); // flush file stream buffers to disk buffers
			if (_commit(_fileno(file.m_pStream)) != 0) // commit disk buffers to disk
				AfxThrowFileException(CFileException::hardIO, GetLastError(), file.GetFileName());
		}
		file.Close();
	}
	catch(CFileException* error){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, _T(""));
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (error->GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		error->Delete();

		// remove the partially written or otherwise damaged temporary file
		file.Abort(); // need to close the file before removing it. call 'Abort' instead of 'Close', just to avoid an ASSERT.
		(void)_tremove(strSrcFile);
		return false;
	}

	return true;
}

bool CDownloadQueue::ImportSources(CTypedPtrList<CPtrList, CPartFile*>& ImportList, CString strSrcFile)
{
	if(ImportList.GetCount() == 0)
		return false;

	uint8 version;
	
	// readfile tweaks form part.src file
	CSafeBufferedFile file;
	CFileException fexpMet;
	if (!file.Open(strSrcFile, CFile::modeRead|CFile::osSequentialScan|CFile::typeBinary|CFile::shareDenyWrite, &fexpMet)){
		if (fexpMet.m_cause != CFileException::fileNotFound){
			CString strError;
			strError.Format(GetResString(IDS_X_ERR_OPENSRC), strSrcFile, _T(""));
			TCHAR szError[MAX_CFEXP_ERRORMSG];
			if (fexpMet.GetErrorMessage(szError, ARRSIZE(szError))){
				strError += _T(" - ");
				strError += szError;
			}
			ModLogError(LOG_STATUSBAR, _T("%s"), strError);
			return false;
		}
		return false;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	try{
		version = file.ReadUInt8();

		if (version != MULTI_SRCFILE_VERSION){
			if (version != SRCFILE_VERSION /*version > SRCFILE_VERSION || version < SRCFILE_VERSION_OLD*/){
				ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_BADSRCVERSION), strSrcFile, _T(""));
				file.Close();
				return false;
			}
			return ImportList.GetHead()->LoadSources(&file);
		}

		bool bListes = ImportList.GetCount() > 1;

		uchar ucHash[16];
		CPartFile* cur_file;

		UINT RecordsNumber = file.ReadUInt32();
		for (UINT i = 0; i < RecordsNumber; i++){
			file.ReadHash16(ucHash);

			cur_file = theApp.downloadqueue->GetFileByID(ucHash);
			if(cur_file == NULL || (bListes && !ImportList.Find(cur_file))){
				ClearSourceEntry(&file);
				ModLog(GetResString(IDS_X_ERR_SRC_FILE_UNKNOWN),strSrcFile,md4str(ucHash));
				continue;
			}

			cur_file->LoadSources(&file);

			if(cur_file->PartPrefs.StoreSourcesFileStatus() == TRUE){
				cur_file->UpdateSourceCount(); // NEO: FIX - [SourceCount]
				cur_file->UpdatePartsInfo(true);
				cur_file->UpdatePartsInfoEx(CFS_Incomplete); // NEO: ICS - [InteligentChunkSelection]
				cur_file->UpdatePartsInfoEx(CFS_Hiden); // NEO: RPS - [RealPartStatus]
				cur_file->UpdatePartsInfoEx(CFS_Blocked); // NEO: RPS - [RealPartStatus]
				cur_file->UpdateAvailablePartsCount();
			}
		}

		file.Close();
	}
	catch(CFileException* error){
		if (error->m_cause == CFileException::endOfFile){
			ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_SRCMEOCORRUPT), strSrcFile, _T(""));
		}else{
			TCHAR buffer[MAX_CFEXP_ERRORMSG];
			error->GetErrorMessage(buffer,ARRSIZE(buffer));
			ModLogError(LOG_STATUSBAR, GetResString(IDS_X_ERR_FILEERROR), strSrcFile, _T(""), buffer);
		}
		error->Delete();
		return false;
	}
	catch(...){
		ModLogError(LOG_STATUSBAR, GetResString(IDS_ERR_METCORRUPT), strSrcFile, _T(""));
		ASSERT(0);
		return false;
	}

	return true;
}

bool CDownloadQueue::ClearSourceEntry(CFileDataIO* file)
{
	UINT RecordsNumber = file->ReadUInt32();
	for (UINT i = 0; i < RecordsNumber; i++) {

		UINT tagcount = file->ReadUInt32();
		for (UINT j = 0; j < tagcount; j++){
			CTag* newtag = new CTag(file, false);
			delete newtag;
		}

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase]
		uint8 SourceVersion = file->ReadUInt8();
		if(SourceVersion){
			if (SourceVersion != SOURCEFILE_VERSION /*version > SOURCEFILE_VERSION || version < SOURCEFILE_VERSION_OLD*/){
				ModLogError(GetResString(IDS_X_ERR_SOURCESMET_UNKNOWN_VERSION));
				return false;
			}
			CKnownSource* newsource = new CKnownSource(file);
			delete newsource;
		}
#endif // NEO_CD // NEO: NCD END

		tagcount = file->ReadUInt32();
		for (UINT j = 0; j < tagcount; j++){
			CTag* newtag = new CTag(file, false);
			delete newtag;
		}
	}

	return true;
}

void CUpDownClient::StoreToFile(CFileDataIO* file, bool bFullData)
{
	UINT uTagCount = 0;
	ULONG uTagCountFilePos = (ULONG)file->GetPosition();
	file->WriteUInt32(uTagCount);

	// Primary Group:
	// Main Information needed for connection and basic informations

	if (m_dwUserIP){
		CTag tag(SFT_IP, m_dwUserIP);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}else if(m_nConnectIP){
		CTag tag(SFT_IP2, m_nConnectIP);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_dwServerIP){
		CTag tag(SFT_SERVER_IP, m_dwServerIP);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nUserIDHybrid){
		CTag tag(SFT_HYBRID_ID, m_nUserIDHybrid);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nUserPort){
		CTag tag(SFT_PORT, m_nUserPort);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nServerPort){
		CTag tag(SFT_SERVER_PORT, m_nServerPort);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (!m_strUsername.IsEmpty()){ // NEO: FIX - [StabilityFix]
		CTag tag(SFT_USER_NAME, m_strUsername);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (HasValidHash()){
		CTag tag(SFT_USER_HASH, m_achUserHash);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nUDPPort){
		CTag tag(SFT_UDP_PORT, m_nUDPPort);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nKadPort){
		CTag tag(SFT_KAD_PORT, m_nKadPort);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (HasValidBuddyID()){
		CTag tag(SFT_BUDDY_ID, m_achBuddyID);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nBuddyIP){
		CTag tag(SFT_BUDDY_IP, m_nBuddyIP);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nBuddyPort){
		CTag tag(SFT_BUDDY_PORT, m_nBuddyPort);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
	if (m_uNatTraversalVersion){
		uint32 uSupport =	((m_uNatCharacteristic		& 0x03)	<< 9) | 
							((m_uNatPortRelaiable		& 0x01)	<< 8) |
							//((						& 0x0f)	<< 4) |
							((m_uNatTraversalVersion	& 0x0f)	<< 0);
		CTag tag(SFT_NATTRAVERSAL, uSupport);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
 #endif // NATTUNNELING // NEO: NATT END

	 // NEO: TCR - [TCPConnectionRetry]
	if (m_uFaildCount){
		CTag tag(SFT_FAILD_CONTRYS, m_uFaildCount);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: TCR END

	if (m_uLastSeen){
		CTag tag(SFT_LAST_SEEN, m_uLastSeen);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_clientSoft != SO_UNKNOWN){
		CTag tag(SFT_CLIENT_SOFTWARE, m_clientSoft);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (!m_strClientSoftware.IsEmpty()){
		CTag tag(SFT_SOFTWARE_VERSION, m_strClientSoftware);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	
	if (m_nClientVersion){
		CTag tag(SFT_CLIENT_VERSION, m_nClientVersion);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (!m_strModVersion.IsEmpty()){
		CTag tag(SFT_CLIENT_MODIFICATION, m_strModVersion);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	// Secundary Group:
	// Protocol extensions informations, not nessesery, becouse all datas will be updaten during Hello Procedure
	// But this info are displayed so we store it

	if (m_bySourceExchangeVer){
		CTag tag(SFT_SOURCE_EXCHANGE, m_bySourceExchangeVer);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_byAcceptCommentVer){
		CTag tag(SFT_FILE_COMMENTS, m_byAcceptCommentVer);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	// NEO: XCFS - [ExtendedClientFileStatus]
	uint32 uFileStatus =	
					//	((0								& 0xff)	<< 24) |
					//	((0								& 0xff)	<< 16) |
						(((m_BlockedPartStatusVer != 0) & 0x01)	<< 15) |
						(((m_HidenPartStatusVer != 0)   & 0x01)	<< 14) |
						((m_HidenPartStatusVer			& 0x07)	<< 11) |
						((m_IncompletePartVer			& 0x07)	<< 8 ) |
					//	((0								& 0x0f)	<< 4 ) |
						((m_SubChunksVer				& 0x0f)	<< 0 ); 
	if (uFileStatus){
		CTag tag(SFT_FILE_STATUS, uFileStatus);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: XCFS END

 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
	if (m_SecureCommunicationVer){
		uint32 uVersions =	
							//((0x00						& 0xff)	<< 24) | // unused
							//((0x00						& 0xff)	<< 16) | // reserved
							//((0x00						& 0x01)	<< 15) | // reserved
							((m_uSupportSecureCallback		& 0x01)	<< 14) |
							((m_uUseUDPSecurity				& 0x01)	<< 13) |
  #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
							((m_uUseNATEncrpytion			& 0x01)	<< 12) |
  #endif //NATTUNNELING // NEO: NATT END
							((m_uPKEncrpytion				& 0x01)	<< 11) |
							((m_uPreferUnEnCryptedPayload	& 0x01)	<< 10) |
							((m_uRequierEncryption			& 0x03)	<< 8 ) |
							//((							& 0x0f)	<< 4 ) |
							((m_SecureCommunicationVer		& 0x0f)	<< 0);
		CTag tag(SFT_ISPBYPASS, uVersions);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_nRemoteSecurePort || m_nLocalSecurePort) {
		UINT nSecurePort = (m_nLocalSecurePort << 16)
						 | (m_nRemoteSecurePort);
		CTag(SFT_AUX_PORT, nSecurePort).WriteNewEd2kTag(file);
		uTagCount++;
	}

	if (m_abyRemoteDHPrime) {
		CSafeMemFile data(100);
		data.Write(m_abyRemoteDHPrime,SOCKET_KEY_SIZE);
		data.WriteUInt8(m_abyRemoteDHBase);
		CTag(SFT_DH_DATA, (int)data.GetLength(),data.GetBuffer()).WriteNewEd2kTag(file);
		uTagCount++;
	}
 #endif // ISPBYPASS // NEO: SCC END

	// NEO: NXI - [NeoExtraInfo]
	if (m_ExtraInfoVer){
		CTag tag(SFT_EXTRA_INFO, m_ExtraInfoVer);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: NXI END

	// NEO: EDT - [EstimatedDownloadTime]
	if (m_DownloadTimeVer){
		CTag tag(SFT_EDT_SUPPORT, m_DownloadTimeVer);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: EDT END

	// NEO: L2H - [LowID2HighIDAutoCallback]
	if (m_L2HAC_support){
		CTag tag(SFT_L2HAC_SUPPORT, m_L2HAC_support);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: L2H END

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

	// NEO: NMP - [NeoModProt]
	if (m_NeoModProtVersion){
		uint32 uNeoFeatures =	
					//	((0 & 0xff)							<<  24 ) | // unused
					//	((0 & 0xff)							<<  16 ) | // Reserved
						((m_NeoXSVersion & 0x0f)			<<  12 ) | // Neo XS
					//	((0 & 0x03)							<< 10  | // Reserved
						((m_LowIDUDPPingSupport & 0x01)		<< 9 ) | 
					//	((m_UnsolicitedPartStatus & 0x01)	<< 8 ) | 
					//	((0 & 0x0f)							<< 4 ) | // Reserved
						(m_NeoModProtVersion				<<  0);   // support for Neo Mod Prot / Neo Mod Multi Packet
		CTag tag(SFT_NEOFEATURES, uNeoFeatures);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}
	// NEO: NMP END

	if (m_fNoViewSharedFiles){
		CTag tag(SFT_NOSHARE_VIEW, m_fNoViewSharedFiles);
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}


	// Handle unknown tags
	for (int j = 0; j < taglist1.GetCount(); j++){
		if (taglist1[j]->IsStr() || taglist1[j]->IsInt()){
			taglist1[j]->WriteNewEd2kTag(file);
			uTagCount++;
		}
	}

	file->Seek(uTagCountFilePos, CFile::begin);
	file->WriteUInt32(uTagCount);
	file->Seek(0, CFile::end);

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase]
	if(source && (thePrefs.SaveSourceDataInClient() || bFullData)){ // when we export a source this datas must be always exported to
		file->WriteUInt8(SOURCEFILE_VERSION);
		source->WriteToFile(file,true);
	}else
		file->WriteUInt8(0);
#endif // NEO_CD // NEO: NCD END

}

bool CUpDownClient::CreateFromFile(CFileDataIO* file)
{
	UINT tagcount = file->ReadUInt32();
	for (UINT j = 0; j < tagcount; j++){
		CTag* newtag = new CTag(file, false);
		switch (newtag->GetNameID()){
	// Primary Group:
	// Main Information needed for connection and basic informations
			case SFT_IP:{
                ASSERT( newtag->IsInt() );
				SetIP( newtag->GetInt() ); // m_nConnectIP = m_dwUserIP
                delete newtag;
                break;
            }

			case SFT_IP2:{
                ASSERT( newtag->IsInt() );
				m_nConnectIP = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_SERVER_IP:{
                ASSERT( newtag->IsInt() );
 #ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
				if(time(NULL) - GetLastSeen() < (thePrefs.GetTempralIPBorderLineS()))
 #endif //NEO_SA // NEO: NSA END
					m_dwServerIP = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_HYBRID_ID:{
                ASSERT( newtag->IsInt() );
                m_nUserIDHybrid = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_PORT:{
                ASSERT( newtag->IsInt() );
				m_nUserPort = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_SERVER_PORT:{
                ASSERT( newtag->IsInt() );
 #ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
				if(time(NULL) - GetLastSeen() < (thePrefs.GetTempralIPBorderLineS()))
 #endif //NEO_SA // NEO: NSA END
					m_nServerPort = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_USER_NAME:{
                ASSERT( newtag->IsStr() );
				SetUserName(newtag->GetStr());
                delete newtag;
                break;
            }

			case SFT_USER_HASH:{
                ASSERT( newtag->IsHash() );
				SetUserHash(newtag->GetHash());
                delete newtag;
                break;
            }

			case SFT_UDP_PORT:{
                ASSERT( newtag->IsInt() );
                m_nUDPPort = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_KAD_PORT:{
                ASSERT( newtag->IsInt() );
                m_nKadPort = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_BUDDY_ID:{
                ASSERT( newtag->IsHash() );
				SetBuddyID(newtag->GetHash());
                delete newtag;
                break;
            }

			case SFT_BUDDY_IP:{
                ASSERT( newtag->IsInt() );
 #ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
				if(time(NULL) - GetLastSeen() < (thePrefs.GetTempralIPBorderLineS() / 2))
 #endif //NEO_SA // NEO: NSA END
					m_nBuddyIP = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_BUDDY_PORT:{
                ASSERT( newtag->IsInt() );
 #ifdef NEO_SA // NEO: NSA - [NeoSourceAnaliser]
				if(time(NULL) - GetLastSeen() < (thePrefs.GetTempralIPBorderLineS() / 2))
 #endif //NEO_SA // NEO: NSA END
					m_nBuddyPort = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }

 #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
			case SFT_NATTRAVERSAL:{
                ASSERT( newtag->IsInt() );
				//						= (uint8)(newtag->IsInt() >> 24) & 0xff;
				//						= (uint8)(newtag->IsInt() >> 16) & 0xff;
				//						= (uint8)(newtag->IsInt() >> 11) & 0x1f;
				m_uNatCharacteristic	= (uint8)(newtag->IsInt() >> 9 ) & 0x03;
				m_uNatPortRelaiable		= (uint8)(newtag->IsInt() >> 8 ) & 0x01;
				//						= (uint8)(newtag->IsInt() >> 4 ) & 0x0f;
				m_uNatTraversalVersion  = (uint8)(newtag->IsInt() >> 0 ) & 0x0f;

                delete newtag;
                break;
            }
 #endif // NATTUNNELING // NEO: NATT END

			// NEO: TCR - [TCPConnectionRetry]
			case SFT_FAILD_CONTRYS:{
                ASSERT( newtag->IsInt() );
                m_uFaildCount = (uint16)newtag->GetInt();
                delete newtag;
                break;
            }
			// NEO: TCR END

			case SFT_LAST_SEEN:{
                ASSERT( newtag->IsInt() );
                m_uLastSeen = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_CLIENT_SOFTWARE:{
                ASSERT( newtag->IsInt() );
                m_clientSoft = (EClientSoftware)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_SOFTWARE_VERSION:{
                ASSERT( newtag->IsStr() );
                m_strClientSoftware = newtag->GetStr();
                delete newtag;
                break;
            }

			case SFT_CLIENT_VERSION:{
                ASSERT( newtag->IsInt() );
                m_nClientVersion = newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_CLIENT_MODIFICATION:{
                ASSERT( newtag->IsStr() );
                m_strModVersion = newtag->GetStr();
				// NEO: MID - [NeoID]
				if(StrStrI(m_strModVersion,MOD_ID))
					m_iIsNeoMod = SO_NEO;
				else
					m_iIsNeoMod = SO_NULL;
				// NEO: MID END
                delete newtag;
                break;
            }

		// Secundary Group:
		// Protocol extensions informations, not nessesery, becouse all datas will be updaten during Hello Procedure
		// But this info are displayed so we store it

			case SFT_SOURCE_EXCHANGE:{
                ASSERT( newtag->IsInt() );
                m_bySourceExchangeVer = (uint8)newtag->GetInt();
                delete newtag;
                break;
            }

			case SFT_FILE_COMMENTS:{
                ASSERT( newtag->IsInt() );
                m_byAcceptCommentVer = (uint8)newtag->GetInt();
                delete newtag;
                break;
            }


			// NEO: XCFS - [ExtendedClientFileStatus]
			case SFT_FILE_STATUS:{
				ASSERT( newtag->IsInt() );
				//							= (uint8)(newtag->GetInt() >> 24) & 0xff;
				//							= (uint8)(newtag->GetInt() >> 16) & 0xff;
				uint8 BlockedPartStatus		= (uint8)(newtag->GetInt() >> 15) & 0x01;
				uint8 HidenPartStatus		= (uint8)(newtag->GetInt() >> 14) & 0x01;
				uint8 RealPartStatusVer		= (uint8)(newtag->GetInt() >> 11) & 0x07;
				m_IncompletePartVer			= (uint8)(newtag->GetInt() >> 8 ) & 0x07;
				//							= (uint8)(newtag->GetInt() >> 4 ) & 0x0f;
				m_SubChunksVer				= (uint8)(newtag->GetInt() >> 0 ) & 0x0f;

				ASSERT(!BlockedPartStatus && !HidenPartStatus || RealPartStatusVer);
				if(BlockedPartStatus)
					m_BlockedPartStatusVer = RealPartStatusVer;
				if(HidenPartStatus)
					m_HidenPartStatusVer = RealPartStatusVer;

                delete newtag;
                break;
			}
			// NEO: XCFS END


 #ifdef ISPBYPASS // NEO: SCC - [SecureClinetConnection]
			case SFT_ISPBYPASS:{
                ASSERT( newtag->IsInt() );
				//							= (uint8)(newtag->GetInt() >> 24) & 0xff;
				//							= (uint8)(newtag->GetInt() >> 16) & 0xff;
				//							= (uint8)(newtag->GetInt() >> 15) & 0x01;
				m_uSupportSecureCallback	= (uint8)(newtag->GetInt() >> 14) & 0x01;
				m_uUseUDPSecurity			= (uint8)(newtag->GetInt() >> 13) & 0x01;
  #ifdef NATTUNNELING // NEO: NATT - [NatTraversal]
				m_uUseNATEncrpytion			= (uint8)(newtag->GetInt() >> 12) & 0x01;
  #endif //NATTUNNELING // NEO: NATT END
				m_uPKEncrpytion				= (uint8)(newtag->GetInt() >> 11) & 0x01;
				m_uPreferUnEnCryptedPayload = (uint8)(newtag->GetInt() >> 10) & 0x01;
				m_uRequierEncryption		= (uint8)(newtag->GetInt() >> 8 ) & 0x02;
				//							= (uint8)(newtag->GetInt() >> 4 ) & 0x0f;
				m_SecureCommunicationVer	= (uint8)(newtag->GetInt() >> 0 ) & 0x0f;

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

                delete newtag;
                break;
            }

			case SFT_AUX_PORT:{
                ASSERT( newtag->IsInt() );
                m_nLocalSecurePort = (uint16)(newtag->GetInt() >> 16);
				m_nRemoteSecurePort = (uint16)(newtag->GetInt());
                delete newtag;
                break;
            }

			case SFT_DH_DATA:{
                ASSERT( newtag->IsBlob() );
				CSafeMemFile data(newtag->GetBlob(),newtag->GetBlobSize());
				m_abyRemoteDHPrime = new byte[SOCKET_KEY_SIZE];
				data.Read(m_abyRemoteDHPrime,SOCKET_KEY_SIZE);
				m_abyRemoteDHBase = data.ReadUInt8();
                delete newtag;
                break;
            }
 #endif // ISPBYPASS // NEO: SCC END

			// NEO: NXI - [NeoExtraInfo]
			case SFT_EXTRA_INFO:{
                ASSERT( newtag->IsInt() );
                m_ExtraInfoVer = (uint8)newtag->GetInt();
                delete newtag;
                break;
            }
			// NEO: NXI END

			// NEO: EDT - [EstimatedDownloadTime]
			case SFT_EDT_SUPPORT:{
                ASSERT( newtag->IsInt() );
                m_DownloadTimeVer = (uint8)newtag->GetInt();
                delete newtag;
                break;
            }
			// NEO: EDT END

			// NEO: L2H - [LowID2HighIDAutoCallback]
			case SFT_L2HAC_SUPPORT:{
                ASSERT( newtag->IsInt() );
				m_L2HAC_support = I2B(newtag->GetInt());
                delete newtag;
                break;
            }
			// NEO: L2H END

			// NEO: NMP - [NeoModProt]
			case SFT_NEOFEATURES:{
                ASSERT( newtag->IsInt() );
				//							= (uint8)(newtag->GetInt() >> 24) & 0xff;
				//							= (uint8)(newtag->GetInt() >> 16) & 0xff;
				m_NeoXSVersion				= (uint8)(newtag->GetInt() >> 12) & 0x0f;
				//							= (uint8)(newtag->GetInt() >> 9 ) & 0x07;
				//							= (uint8)(newtag->GetInt() >> 10) & 0x03;
				m_LowIDUDPPingSupport		= (uint8)(newtag->GetInt() >> 9 ) & 0x01;
				//m_UnsolicitedPartStatus	= (uint8)(newtag->GetInt() >> 8 ) & 0x01;
				//							= (uint8)(newtag->GetInt() >> 4 ) & 0x0f;
				m_NeoModProtVersion			= (uint8)(newtag->GetInt() >> 0 ) & 0x0f;
                delete newtag;
                break;
            }
			// NEO: NMP END

			case SFT_NOSHARE_VIEW:{
                ASSERT( newtag->IsInt() );
				m_fNoViewSharedFiles = I2B(newtag->GetInt());
                delete newtag;
                break;
            }

			// Handle unknown tags
			default:{
				taglist1.Add(newtag);
			}
		}
	}

#ifdef NEO_CD // NEO: NCD - [NeoClientDatabase]
	uint8 SourceVersion = file->ReadUInt8();
	CKnownSource* newsource = NULL;
	if(SourceVersion){
		if (SourceVersion != SOURCEFILE_VERSION /*version > SOURCEFILE_VERSION || version < SOURCEFILE_VERSION_OLD*/){
			ModLogError(GetResString(IDS_X_ERR_SOURCESMET_UNKNOWN_VERSION));
			theApp.BackupEngine->SetLastErrorState(EMB_ERROR_STATE_RECOVERABLE); // NEO: NB - [NeoBackup]
			return false;
		}
		newsource = new CKnownSource(file);
	}

	if(thePrefs.EnableSourceList()){
		if(newsource)
			LinkSource(theApp.sourcelist->MergeSource(newsource));
		else if(!source && HasValidHash())
			LinkSource(theApp.sourcelist->GetSource(m_achUserHash));
	}else if(newsource)
		delete newsource;
#endif // NEO_CD // NEO: NCD END

	if(HasValidHash())
		credits = theApp.clientcredits->GetCredit(m_achUserHash);

	if(m_dwUserIP && m_nUserPort && HasValidHash()){
		m_Friend = theApp.friendlist->SearchFriend(m_achUserHash, m_dwUserIP, m_nUserPort);
		if(m_Friend)
			m_Friend->SetLinkedClient(this);// Link the friend to that client
	}

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

	return true;
}

void CUpDownClient::WriteToFile(CFileDataIO* file, CPartFile* owner)
{
	UINT uTagCount = 0;
	ULONG uTagCountFilePos = (ULONG)file->GetPosition();
	file->WriteUInt32(uTagCount);

	// Note: We need this informations to load a source properly
	if(reqfile){
		CTag tag(SFT_SOURCE_REQFILE, reqfile->GetFileHash());
		tag.WriteNewEd2kTag(file);
		uTagCount++;
	}

	// NEO: SCFS - [SmartClientFileStatus]
	if(owner->PartPrefs.StoreSourcesFileStatus()){
		CClientFileStatus* status = GetFileStatus(owner); 
		if(status){
			CTag tag(SFT_FILE_NAME,status->GetFileName());
			tag.WriteNewEd2kTag(file);
			uTagCount++;

			for(uint16 i = 0; i<CFS_COUNT; i++){
				if(status->WriteFileStatusTag((EPartStatus)i,file))
					uTagCount++;
			}
		}
	}
	// NEO: SCFS END

	// Handle unknown tags
	for (int j = 0; j < taglist2.GetCount(); j++){
		if (taglist2[j]->IsStr() || taglist2[j]->IsInt()){
			taglist2[j]->WriteNewEd2kTag(file);
			uTagCount++;
		}
	}

	file->Seek(uTagCountFilePos, CFile::begin);
	file->WriteUInt32(uTagCount);
	file->Seek(0, CFile::end);
}

CPartFile* CUpDownClient::LoadFromFile(CFileDataIO* file, CPartFile* owner)
{
	CClientFileStatus* status = NULL; // NEO: SCFS - [SmartClientFileStatus]
	CPartFile* tempreqfile = NULL;
	UINT tagcount = file->ReadUInt32();
	for (UINT j = 0; j < tagcount; j++){
		CTag* newtag = new CTag(file, false);
		switch (newtag->GetNameID()){
			
			case SFT_SOURCE_REQFILE:{
                ASSERT( newtag->IsHash() );
				tempreqfile = theApp.downloadqueue->GetFileByID(newtag->GetHash());
                delete newtag;
                break;
            }

			// NEO: SCFS - [SmartClientFileStatus]
			case SFT_FILE_NAME:{
				ASSERT( newtag->IsStr() );
				if(newtag->IsStr()){
					if(!status)
						status = GetFileStatus(owner, true);
					status->SetFileName(newtag->GetStr());
				}
                delete newtag;
                break;
            }

			case SFT_PART_STATUS:
			case SFT_INC_PART_STATUS:
			case SFT_HIDEN_PART_STATUS:
			case SFT_BLOCKED_PART_STATUS:
			case SFT_SEEN_PART_STATUS:{
				ASSERT( newtag->IsBlob() || newtag->IsInt() ); // Int is old
				if(newtag->IsBlob() && status) // if we write status we write the filname *ALWAYS* first
					status->ReadFileStatusTag(newtag);
				delete newtag;
				break;
			}
			// NEO: SCFS END

			// delete old tags
			case SFT_SOURCE_OWNER:{
                delete newtag;
                break;
            }

		    // Handle unknown tags
			default:{
				taglist2.Add(newtag);
			}
		}
	}

	return tempreqfile;
}

void CUpDownClient::ClearTags()
{
	for (int i = 0; i < taglist1.GetSize(); i++)
		delete taglist1[i];
	taglist1.RemoveAll();

	for (int i = 0; i < taglist2.GetSize(); i++)
		delete taglist2[i];
	taglist2.RemoveAll();
}

void CPartFile::ExportSources(CString strSrcFile,CTypedPtrList<CPtrList, CUpDownClient*> &selectedList)
{
	// save sources to part.src file
	CSafeBufferedFile file;
	CFileException fexp;
	if (!file.Open(strSrcFile, CFile::modeWrite|CFile::modeCreate|CFile::typeBinary|CFile::shareDenyWrite, &fexp)){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, GetFileName());
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (fexp.GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		return;
	}
	setvbuf(file.m_pStream, NULL, _IOFBF, 16384);

	try{
		//version
		file.WriteUInt8(SRCFILE_VERSION);

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

		while (!selectedList.IsEmpty()){
			selectedList.GetHead()->StoreToFile(&file, true); // Save general client informations
			if(selectedList.GetHead()->GetRequestFile() == this)
				selectedList.GetHead()->WriteToFile(&file,this); // Save client informations about reqfile partfile
			else
				file.WriteUInt32(0); // If an partfile loads this source, this says no tags with part file informations

			uTagCount++;

			selectedList.RemoveHead();
		}

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

		if (thePrefs.GetCommitFiles() >= 2 || (thePrefs.GetCommitFiles() >= 1 && !theApp.emuledlg->IsRunning())){
			file.Flush(); // flush file stream buffers to disk buffers
			if (_commit(_fileno(file.m_pStream)) != 0) // commit disk buffers to disk
				AfxThrowFileException(CFileException::hardIO, GetLastError(), file.GetFileName());
		}
		file.Close();
	}
	catch(CFileException* error){
		CString strError;
		strError.Format(GetResString(IDS_X_ERR_SAVESRC), strSrcFile, GetFileName() );
		TCHAR szError[MAX_CFEXP_ERRORMSG];
		if (error->GetErrorMessage(szError, ARRSIZE(szError))){
			strError += _T(" - ");
			strError += szError;
		}
		ModLogError(LOG_STATUSBAR, _T("%s"), strError);
		error->Delete();

		// remove the partially written or otherwise damaged temporary file
		file.Abort(); // need to close the file before removing it. call 'Abort' instead of 'Close', just to avoid an ASSERT.
		(void)_tremove(strSrcFile);
		return;
	}

	return;
}
#endif // NEO_SS // NEO: NSS END <-- Xanatos --
