// EM Neo Backup
//
// License
// -------
// This code is provided "as is" with no expressed or implied warranty.
// 
// You may use this code in a non commercial open source product with 
// or without acknowledgement. You may not sell this code or any 
// modification of this code.
//
//
// Copyright (c) 2004 
// http://neomule.sourceforge.net 
// davidxanatos@lycos.at
////////////////////////////////////////////////////////////////////////

// NEO: NB - [NeoBackup] -- Xanatos -->

#include "StdAfx.h"
#include "emule.h"
#include "EMBackup.h"
#include "emuleDlg.h"
#include "Ini2.h"
#include "Neo\functions.h"
#include "otherfunctions.h"
#include "preferences.h"
#include "opcodes.h"
#include "log.h"

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

/*     *** Return Codes: ***
*	Valid values 0,1,2,4,8,16,32,64,128,256,512,1024 
*
*	Backup:
*	0 - OK
*	1 - Unspecyfied Error
*	2 - File Copy/Move Error
*	
*	Restore:
*	0 - Nothing done
*	1 - Unspecyfied Error
*	2 - File Copy/Move Error
*	4 - auto restore disabled
*	8 - .bak File Not Found
*	16 - Some Files Restored
*	32 - Backup File not found
*	
*/

IMPLEMENT_DYNCREATE(CEMBackup, CObject)
CEMBackup::CEMBackup(void)
{
	m_iLastErrorState = NULL;

	LastBackupTime = ::GetTickCount();

	DoneBackup2 = false;

	BackupInProgres = false;
}

CEMBackup::~CEMBackup(void)
{
}

void CEMBackup::Init(){
	LoadPreferences();
	if (!prefs.Enable)
		return;
	if (prefs.FilesToAutoRestore & EMB_CFG){
		theApp.UpdateSplash(GetResString(IDS_X_SS_CHECK_BACKUP));
		Restore();
	}
}

void CEMBackup::RunBackup(){
	if (!prefs.Enable)
		return;
	if (prefs.AutoBackup){
		theApp.UpdateSplash(GetResString(IDS_X_SS_MAKE_BACKUP)); // NEO: SS - [SplashScreen] <-- Xanatos --
		Backup();
	}
}

void CEMBackup::AutoBackup(){
	if (!prefs.Enable)
		return;
	if (prefs.AutoBackup && prefs.RunTimeBackup){
		if ((LastBackupTime + prefs.RunTimeBackupTime) < ::GetTickCount() && !BackupInProgres){
			LastBackupTime = ::GetTickCount();
			BackupInProgres = true;
			DWORD tFiles = prefs.FilesToBackup;
			if (tFiles & EMB_TMP_PART) tFiles ^= EMB_TMP_PART;
			// - do NOT use Windows API 'CreateThread' to create a thread which uses MFC/CRT -> lot of mem leaks!
			if (!AfxBeginThread(run, (LPVOID)tFiles)){
				BackupInProgres = false;
				theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_AUTO_BACK_ERROR_FATAL));
			}
		}
	}
}

UINT AFX_CDECL CEMBackup::run(LPVOID lpParam)
{
	DWORD tFiles = (DWORD)lpParam;
	DbgSetThreadName("AutoBackup");
	InitThreadLocale();

	// NEO: STS - [SlugFillerThreadSafe] -- Xanatos -->
	CReadWriteLock lock(&theApp.m_threadlock);
	if (!lock.ReadLock(0))
		return 0;
	// NEO: STS END <-- Xanatos --

	try{ // In case we change the temp directory list while auto backup is runing
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_AUTO_BACK_START));
		if (!theApp.BackupEngine->Backup(tFiles,true)){
			theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_AUTO_BACK_DONE));
		}else{
			theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_AUTO_BACK_ERROR));
		}
	}
	catch(...){
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_AUTO_BACK_ERROR_FATAL));
	}

	theApp.BackupEngine->BackupInProgres = false;
	return 0;
}


////////// BACKUP //////////////////////////////////////////////////////////////////////
int CEMBackup::Backup(DWORD FileTypes, bool AutoBackup){

	if (prefs.DoubleBackup && !DoneBackup2){
		DoneBackup2 = true;
		if(Backup2())
			if(/*AutoBackup || */AfxMessageBox(GetResString(IDS_X_BACK_BACKUP_BACKUP_ERROR),MB_YESNO,0) == IDNO)
				return 1;
	}

	DWORD tFiles;
	if (FileTypes)
		tFiles = FileTypes;
	else
		tFiles = prefs.FilesToBackup;

	int ret=0;
	if((tFiles & EMB_CFG_DAT) || (tFiles & EMB_CFG_MET) || (tFiles & EMB_CFG_INI))
		ret |= BackupDirectory(thePrefs.GetConfigDir(),StrLine(_T("%s\\"),prefs.BackupDir),tFiles,Config);
	if((tFiles & EMB_TMP_PART) || (tFiles & EMB_TMP_PART_MET) || (tFiles & EMB_TMP_PART_MET_NEO ) || (tFiles & EMB_TMP_PART_MET_SRC )){
		ret |= BackupDirectory(StrLine(_T("%s\\"),thePrefs.GetTempDir()),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),tFiles,Temp);
		for (POSITION pos = thePrefs.tempdir_list.GetHeadPosition();pos != 0;thePrefs.tempdir_list.GetNext(pos)) // NEO: MTD - [MultiTempDirectories]
			ret |= BackupDirectory(StrLine(_T("%s\\"),thePrefs.tempdir_list.GetAt(pos)),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),tFiles,Temp);
	}
	if(ret && !AutoBackup)
		AfxMessageBox(GetResString(IDS_X_BACK_BACKUP_ERROR),MB_OK,0);
	return ret;
}

int CEMBackup::Backup2(){
	if(!PathFileExists(prefs.BackupDir)) return 0;

	DWORD tFiles;
	tFiles = prefs.FilesToBackup;
	if (prefs.ExcludePartFiles && tFiles & EMB_TMP_PART)
		tFiles ^= EMB_TMP_PART;

	int ret=0;
	if((tFiles & EMB_CFG_DAT) || (tFiles & EMB_CFG_MET) || (tFiles & EMB_CFG_INI))
		//ret |= MoveBackupDirectory(StrLine(_T("%s\\"),prefs.BackupDir),StrLine(_T("%s\\"),prefs.BackupDir2));
		ret = BackupDirectory(StrLine(_T("%s\\"),prefs.BackupDir),StrLine(_T("%s\\"),prefs.BackupDir2),tFiles,Config);
	if((tFiles & EMB_TMP_PART ) || (tFiles & EMB_TMP_PART_MET) || (tFiles & EMB_TMP_PART_MET_NEO ) || (tFiles & EMB_TMP_PART_MET_SRC ))
		ret |= MoveBackupDirectory(StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),StrLine(_T("%s\\%s\\"),prefs.BackupDir2,EMB_TEMP_FILE_PATH));
		//ret = BackupDirectory(StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),StrLine(_T("%s\\%s\\"),prefs.BackupDir2,EMB_TEMP_FILE_PATH),tFiles,Temp);
		
	return ret;
}

int CEMBackup::BackupDirectory(CString SourcePath, CString BackupPath, DWORD Files, ETargetDir Target){
	int ret=0;

	if (Target == Config){
		if (Files & EMB_CFG_DAT)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_DAT);
		if (Files & EMB_CFG_MET)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_MET);
		if (Files & EMB_CFG_INI)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_INI);
	} else if (Target == Temp){
		if (Files & EMB_TMP_PART)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_PART);
		if (Files & EMB_TMP_PART_MET)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_PART_MET);
		if (Files & EMB_TMP_PART_MET_NEO)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_PART_MET_NEO);
		if (Files & EMB_TMP_PART_MET_SRC)
			ret |= BackupDirectory(SourcePath,BackupPath,EMB_FILE_PART_MET_SRC);
	}

	return ret;
}

int CEMBackup::BackupDirectory(CString SourcePath, CString BackupPath, CString Files){
	WIN32_FIND_DATA FileData; 
	HANDLE hSearch; 
	int ret = 0;

	if(!PathFileExists(BackupPath))
		CreateDirectory(BackupPath, NULL);

	hSearch = FindFirstFile(StrLine(_T("%s%s"),SourcePath,Files), &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
		return 0; // Propobly no files avalibly

	for(;;){ 
		if(!PathIsDirectory(StrLine(_T("%s%s"),SourcePath,FileData.cFileName))){
			//if(CheckFile(StrLine(_T("%s%s"),SourcePath,FileData.cFileName)))
			if (!CopyFile(StrLine(_T("%s%s"),SourcePath,FileData.cFileName), StrLine(_T("%s%s"),BackupPath,FileData.cFileName), FALSE))
				ret |= 2;
		}
		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() != ERROR_NO_MORE_FILES)
				ret |= 1;	
			break;
		}
	} 

	if (!FindClose(hSearch)) 
		ret |= 1;

	return ret;
}

int CEMBackup::MoveBackupDirectory(CString SourcePath, CString BackupPath, CString Files){
	WIN32_FIND_DATA FileData; 
	HANDLE hSearch; 
	int ret = 0;

	if(!PathFileExists(BackupPath))
		CreateDirectory(BackupPath, NULL);

	hSearch = FindFirstFile(StrLine(_T("%s%s"),SourcePath,Files), &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
		return 0; // Propobly no files avalibly

	for(;;){ 
		//if(CheckFile(StrLine(_T("%s%s"),SourcePath,FileData.cFileName)))
		if(!PathIsDirectory(StrLine(_T("%s%s"),SourcePath,FileData.cFileName))){
			if (!MoveFileEx(StrLine(_T("%s%s"),SourcePath,FileData.cFileName), StrLine(_T("%s%s"),BackupPath,FileData.cFileName),MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
				ret |= 2;
		}
		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() != ERROR_NO_MORE_FILES)
				ret |= 1;	
			break;
		}
	} 

	if (!FindClose(hSearch)) 
		ret |= 1;

	return ret;
}

////////// RESTORE //////////////////////////////////////////////////////////////////////
int CEMBackup::Restore(ETargetDir Target){
	if (!prefs.Enable)
		return 4;
	if(!PathFileExists(prefs.BackupDir)) return 1;

	int ret=0;

	if(Target == Config){
		if (prefs.FilesToBackup & EMB_CFG_DAT)
			ret |= RestoreConfigDirectory(configdir,StrLine(_T("%s\\"),prefs.BackupDir),EMB_FILE_DAT);
		if (prefs.FilesToBackup & EMB_CFG_MET)
			ret |= RestoreConfigDirectory(configdir,StrLine(_T("%s\\"),prefs.BackupDir),EMB_FILE_MET);
		if (prefs.FilesToBackup & EMB_CFG_INI)
			ret |= RestoreConfigDirectory(configdir,StrLine(_T("%s\\"),prefs.BackupDir),EMB_FILE_INI);

		if (ret & 16)
			AfxMessageBox(GetResString(IDS_X_BACK_RESTORE_CONFIG),MB_OK,0);
		if (ret & 2 || ret & 1)
			AfxMessageBox(GetResString(IDS_X_BACK_RESTORE_ERROR),MB_OK,0);
	} else if (Target == Temp){
		if (prefs.FilesToBackup & EMB_TMP_PART_MET)
			ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.GetTempDir()),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET);
		if (prefs.FilesToBackup & EMB_TMP_PART_MET_NEO)
			ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.GetTempDir()),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET_NEO);
		if (prefs.FilesToBackup & EMB_TMP_PART_MET_SRC)
			ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.GetTempDir()),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET_SRC);

		for (POSITION pos = thePrefs.tempdir_list.GetHeadPosition();pos != 0;thePrefs.tempdir_list.GetNext(pos)){ // NEO: MTD - [MultiTempDirectories]
			if (prefs.FilesToBackup & EMB_TMP_PART_MET)
				ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.tempdir_list.GetAt(pos)),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET);
			if (prefs.FilesToBackup & EMB_TMP_PART_MET_NEO)
				ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.tempdir_list.GetAt(pos)),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET_NEO);
			if (prefs.FilesToBackup & EMB_TMP_PART_MET_SRC)
				ret |= RestoreTempDirectory(StrLine(_T("%s\\"),thePrefs.tempdir_list.GetAt(pos)),StrLine(_T("%s\\%s\\"),prefs.BackupDir,EMB_TEMP_FILE_PATH),EMB_FILEEX_PART_MET_SRC);
		}

		if (ret & 2 || ret & 1)
			theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR));
	}


	return ret;
}

void CEMBackup::RestoreTemp(){
	if (!prefs.Enable)
		return;
	if (prefs.FilesToAutoRestore & EMB_TMP)
		Restore(Temp);
}

int CEMBackup::RestoreConfigDirectory(CString TargetPath, CString BackupPath, CString Files){
	WIN32_FIND_DATA FileData; 
	HANDLE hSearch; 
	int ret = 0;

	hSearch = FindFirstFile(StrLine(_T("%s%s"),BackupPath,Files), &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
		return 0; // Propobly no files avalibly
		//error = TRUE;

	for(;;){ 
		if(!PathIsDirectory(StrLine(_T("%s%s"),BackupPath,FileData.cFileName))){
			if (TestFile(StrLine(_T("%s%s"),TargetPath,FileData.cFileName),StrLine(_T("%s%s"),BackupPath,FileData.cFileName))){
				ret |= 16;
				if(!CopyFile(StrLine(_T("%s%s"),BackupPath,FileData.cFileName),StrLine(_T("%s%s"),TargetPath,FileData.cFileName), FALSE))
					ret |= 2;
			}
		}
		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() != ERROR_NO_MORE_FILES)
				ret |= 1;
			break;
		}
	} 

	if (!FindClose(hSearch)) 
		ret |= 1;

	return ret;
}

int CEMBackup::RestoreTempDirectory(CString TargetPath, CString BackupPath, CString Files){
	WIN32_FIND_DATA FileData; 
	HANDLE hSearch; 
	int ret = 0;
	CString strTarget;
	CString strBackup;

	hSearch = FindFirstFile(StrLine(_T("%s%s"),TargetPath,EMB_FILE_PART), &FileData); 
	if (hSearch == INVALID_HANDLE_VALUE) 
		return 0; // Propobly no files avalibly
		//error = TRUE;

	for(;;){ 
		strTarget = StrLine(_T("%s%s%s"),TargetPath,FileData.cFileName,Files);
		strBackup = StrLine(_T("%s%s%s"),BackupPath,FileData.cFileName,Files);
		if(!PathIsDirectory(strTarget)){
			if (TestFile(strTarget,strBackup)){
				ret |= 16;
				theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_TEMP), StrLine(_T("%s%s"),FileData.cFileName,Files));
				if(!CopyFile(strBackup, strTarget, FALSE))
					ret |= 2;
				if (Files == EMB_FILEEX_PART_MET){
					ret |= BackupPartMetBack(strTarget);
					if (ret & 8)
						theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_MET_BAK_NOT_FOUND), FileData.cFileName);
				}
			}
		}

		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() != ERROR_NO_MORE_FILES)
				ret |= 1;
			break;
		}
	} 

	if (!FindClose(hSearch)) 
		ret |= 1;

	return ret;
}


////////// RESTORE 2 //////////////////////////////////////////////////////////////////////
bool CEMBackup::RestoreFile(EConfigFiles File){
	if (!prefs.Enable)
		return false;
	if (!(prefs.FilesToAutoRestore & EMB_CFG_MAIN))
		return false;

	int ret = 0;
	static int Trys = 0;
	static EConfigFiles LastFile = NullMet;
	if (LastFile != File){
		Trys = 0;
		LastFile = File;
	}

	if (m_iLastErrorState != EMB_ERROR_STATE_RECOVERABLE || Trys > 1)
		return false;

	CString ConfigDir;
	ConfigDir.Format(_T("%s%s"),appdir,EMB_CONFIG_FILE_PATH);

	switch(File){
	case KnownMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_KNOWNMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_KNOWNMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_KNOWNMET, Trys);
		break;
	case CancelledMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_CANCELLEDMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_CANCELLEDMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_CANCELLEDMET, Trys);
		break;
	case TrafficMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_TRAFFICMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_TRAFFICMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_TRAFFICMET, Trys);
		break;
	case KnownPrefsMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_KNOWNPREFSMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_KNOWNPREFSMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_KNOWNPREFSMET, Trys);
		break;
	case CommentsMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_COMMENTSMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_COMMENTSMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_COMMENTSMET, Trys);
		break;
	case ServerMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_SERVERMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_SERVERMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_SERVERMET, Trys);
		break;
	case FriendsMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_FRIENDSMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_FRIENDSMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_FRIENDSMET, Trys);
		break;
	case ClientsMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_CLIENTSMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_CLIENTSMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_CLIENTSMET, Trys);
		break;
	case SourcesMet:
		ret |= BackupBadMet(StrLine(_T("%s\\%s"),ConfigDir,EMB_FILE_SOURCESMET));
		ret |= RestoreSingelFile(ConfigDir,EMB_FILE_SOURCESMET, &Trys, Config);
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_CONFIG_MET), EMB_FILE_SOURCESMET, Trys);
		break;
	default:
		ASSERT(0);
		return false;
	}

	if (ret & 32)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR_NO_BACKUP));
	else if (ret)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR));

	if (ret)
		return false;
	return true;
}

bool CEMBackup::RestorePartMet(CString Path, CString FileName, ETempFiles File){
	if (!prefs.Enable)
		return false;

	switch(File){
	case PartMet:
		if (!(prefs.FilesToAutoRestore & EMB_TMP_PART_MET))
			return false;
		break;
	case PartMetNeo:
		if (!(prefs.FilesToAutoRestore & EMB_TMP_PART_MET_NEO))
			return false;
		FileName += EMB_FILEEX_PART_NEO;
		break;
	case PartMetSrc:
		if (!(prefs.FilesToAutoRestore & EMB_TMP_PART_MET_SRC))
			return false;
		FileName += EMB_FILEEX_PART_SRC;
		break;
	default:
		ASSERT(0);
		return false;
	}

	if (m_iLastErrorState != EMB_ERROR_STATE_RECOVERABLE)
		return false;

	int ret = 0;
	static int Trys = 0;
	static CString LastFileName = _T("");
	if (StrCmp(FileName,LastFileName)){
		Trys = 0;
		LastFileName = FileName;
	}

	if (Trys > 1)
		return false;
	ret |= BackupBadMet(StrLine(_T("%s\\%s"),Path,FileName));
	ret |= BackupPartMetBack(StrLine(_T("%s\\%s"),Path,FileName));
	ret |= RestoreSingelFile(Path,FileName,&Trys,Temp);
	theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_CORTUPT_MET), FileName, Trys);

	if (ret & 32)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR_NO_BACKUP));
	else if (ret)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR));

	if(ret)
		return false;
	return true;
}

bool CEMBackup::RestorePart(CString Path, CString FileName){
	if (!prefs.Enable)
		return false;
	if (!(prefs.FilesToAutoRestore & EMB_TMP_PART))
		return false;

	int ret = 0;

	static CString LastFileName = _T("");
	if (StrCmp(FileName,LastFileName)){
		LastFileName = FileName;
		return false;
	}

	//static int Trys = 0;
	//static CString LastFileName = _T("");
	/*if (StrCmp(FileName,LastFileName)){
		Trys = 0;
		ret = 0;
		LastFileName = FileName;
	}*/

	/*if (Trys > 1)
		return false;*/
	theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_MISSING_PART), FileName);
	ret |= RestoreFile(Path,FileName,prefs.BackupDir,Temp);
	//ret |= RestoreSingelFile(Path,FileName,&Trys,Temp);

	if (ret & 32)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR_NO_BACKUP));
	else if (ret)
		theApp.QueueModLogLineEx(LOG_STATUSBAR, GetResString(IDS_X_BACK_RESTORE_ERROR));

	if(ret)
		return false;
	return true;
}

int	CEMBackup::RestoreSingelFile(CString Path, CString FileName, int* Trys, ETargetDir Target){
	int ret = 0;

	switch (*Trys){
	case 0:
		*Trys = 1;
		ret = RestoreFile(Path,FileName,prefs.BackupDir,Target);
		if (ret != 32)
			break;
	case 1:
		*Trys = 2;
		if (prefs.DoubleBackup)
			ret = RestoreFile(Path,FileName,prefs.BackupDir2,Target);
		break;
	default:
		return 1;
	}

	return ret;
}

int	CEMBackup::RestoreFile(CString Path, CString FileName, CString BackupPath, ETargetDir Target){
	CString BackupDir;
	if (Target == Config)
		BackupDir = BackupPath;
	else if (Target == Temp)
		BackupDir.Format(_T("%s\\%s"),BackupPath,EMB_TEMP_FILE_PATH);
	else return 1;

	if (!CheckFile(StrLine(_T("%s\\%s"),BackupDir,FileName)))
		return 32;
	if (!CopyFile(StrLine(_T("%s\\%s"),BackupDir,FileName), StrLine(_T("%s\\%s"),Path,FileName),FALSE))
		return 2;

	return 0;
}

void CEMBackup::DeleteFiles(CString Path, CString FileName){
	CString slsfilepath;

	slsfilepath.Format(_T("%s\\%s%s"), Path, FileName,EMB_FILEEX_BAD);
	if (::DeleteFile(slsfilepath)) if (errno != ENOENT)
		theApp.QueueModLogLineEx(LOG_STATUSBAR,GetResString(IDS_X_BACK_DEL_ERROR), slsfilepath);

	slsfilepath.Format(_T("%s\\%s%s%s"), Path, FileName,EMB_FILEEX_BAK,EMB_FILEEX_BAK_OLD);
	if (::DeleteFile(slsfilepath)) if (errno != ENOENT)
		theApp.QueueModLogLineEx(LOG_STATUSBAR,GetResString(IDS_X_BACK_DEL_ERROR), slsfilepath);
}

////////// FUNCTIONS //////////////////////////////////////////////////////////////////////
bool CEMBackup::TestFile(CString OriginalFile, CString BackupFile){
	HANDLE hFile;
	bool ret=0;

	if(!PathFileExists(OriginalFile)){
		ret=TRUE;
	}else{ 
		hFile = CreateFile(OriginalFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
		if (GetFileSize(hFile,NULL) == 0)
			ret=TRUE;
		CloseHandle(hFile);
	}

	hFile = CreateFile(BackupFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,NULL,NULL);
	if (GetFileSize(hFile,NULL) == 0)
		ret=FALSE;
	CloseHandle(hFile);

	return ret;
}

bool CEMBackup::CheckFile(CString File){
	HANDLE hFile;
	bool ret=FALSE;

	if(PathFileExists(File)){
		hFile = CreateFile(File,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
		if (GetFileSize(hFile,NULL) != 0)
			ret=TRUE;
		CloseHandle(hFile);
	}
	return ret;
}

int	CEMBackup::BackupPartMetBack(CString FilePath){
	if(!PathFileExists(StrLine(_T("%s%s"),FilePath,EMB_FILEEX_BAK))) return 8;
	if(!CopyFile(StrLine(_T("%s%s"),FilePath,EMB_FILEEX_BAK), StrLine(_T("%s%s%s"),FilePath,EMB_FILEEX_BAK,EMB_FILEEX_BAK_OLD),FALSE))
		return 2;
	return 0;
}

int	CEMBackup::BackupBadMet(CString FilePath){
	if(!PathFileExists(FilePath)) return 1;
	if(!CopyFile(FilePath, StrLine(_T("%s%s"),FilePath,EMB_FILEEX_BAD),FALSE))
		return 2;
	return 0;
}
////////// SETTINGS //////////////////////////////////////////////////////////////////////
void CEMBackup::LoadPreferences(){
	TCHAR buffer[490];
	::GetModuleFileName(0, buffer, 490);
	LPTSTR pszFileName = _tcsrchr(buffer, '\\') + 1;
	*pszFileName = '\0';

	appdir = buffer;
	configdir = appdir + CONFIGFOLDER;

	::CreateDirectory(configdir, 0);

	CString strFileName;
	strFileName.Format(BACKUPINI, configdir);
	CIni ini(strFileName, _T("EMBackup"));

	prefs.Enable = ini.GetBool(_T("EnableNeoBackup"),0);

	prefs.AutoBackup = ini.GetBool(_T("AutoBackup"),1);

	prefs.RunTimeBackup = ini.GetBool(_T("RunTimeBackup"),0);
	prefs.RunTimeBackupTime = ini.GetInt(_T("RunTimeBackupTime"),DEF_BACKUP_TIME);

	_stprintf(prefs.BackupDir,_T("%s"),ini.GetString(_T("BackupDir"),StrLine(_T("%sBackup"),appdir)));
	MakeFoldername(prefs.BackupDir);

	prefs.DoubleBackup = ini.GetBool(_T("DoubleBackup"),0);
	prefs.ExcludePartFiles = ini.GetBool(_T("ExcludePartFiles"),1);
	
	_stprintf(prefs.BackupDir2,_T("%s"),ini.GetString(_T("BackupDir2"),StrLine(_T("%s\\Recent"),prefs.BackupDir)));
	MakeFoldername(prefs.BackupDir2);


	prefs.FilesToAutoRestore = NULL;

	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreConfig"),0,_T("FileRestore"))	? EMB_CFG : NULL;
	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreMainConfig"),1,_T("FileRestore"))? EMB_CFG_MAIN : NULL;
	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreTemp"),0,_T("FileRestore"))		? EMB_TMP : NULL;

	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreMet"),1,_T("FileRestore"))		? EMB_TMP_PART_MET : NULL;
	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreMetNeo"),1,_T("FileRestore"))	? EMB_TMP_PART_MET_NEO : NULL;
	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestoreMetSrc"),0,_T("FileRestore"))	? EMB_TMP_PART_MET_SRC : NULL;
	prefs.FilesToAutoRestore |= ini.GetBool(_T("AutoRestorePart"),0,_T("FileRestore"))		? EMB_TMP_PART : NULL;


	prefs.FilesToBackup = NULL;

	prefs.FilesToBackup |= ini.GetBool(_T("dat"),1,_T("FileTypes")) ? EMB_CFG_DAT : NULL;
	prefs.FilesToBackup |= ini.GetBool(_T("met"),1,_T("FileTypes")) ? EMB_CFG_MET : NULL;
	prefs.FilesToBackup |= ini.GetBool(_T("ini"),0,_T("FileTypes")) ? EMB_CFG_INI : NULL;

	prefs.FilesToBackup |= ini.GetBool(_T("part"),0,_T("FileTypes")) ? EMB_TMP_PART : NULL;
	prefs.FilesToBackup |= ini.GetBool(_T("part.met"),1,_T("FileTypes")) ? EMB_TMP_PART_MET : NULL;
	prefs.FilesToBackup |= ini.GetBool(_T("part.met.neo"),1,_T("FileTypes")) ? EMB_TMP_PART_MET_NEO : NULL;
	prefs.FilesToBackup |= ini.GetBool(_T("part.met.src"),0,_T("FileTypes")) ? EMB_TMP_PART_MET_SRC : NULL;

	if(prefs.Enable){
		if(prefs.AutoBackup)
			::CreateDirectory(prefs.BackupDir,0);
		if(prefs.DoubleBackup)
			::CreateDirectory(prefs.BackupDir2,0);
	}
}

void CEMBackup::SavePreferences(){
	CString strFileName;
	strFileName.Format(BACKUPINI, thePrefs.GetConfigDir());
	CIni ini(strFileName, _T("EMBackup"));

	ini.WriteBool(_T("EnableNeoBackup"),prefs.Enable);

	ini.WriteBool(_T("AutoBackup"),prefs.AutoBackup);

	ini.WriteBool(_T("RunTimeBackup"),prefs.RunTimeBackup);
	ini.WriteInt(_T("RunTimeBackupTime"),prefs.RunTimeBackupTime);

	ini.WriteString(_T("BackupDir"),prefs.BackupDir);

	ini.WriteBool(_T("DoubleBackup"),prefs.DoubleBackup);
	ini.WriteBool(_T("ExcludePartFiles"),prefs.ExcludePartFiles);
	ini.WriteString(_T("BackupDir2"),prefs.BackupDir2);


	ini.WriteBool(_T("AutoRestoreConfig"),(prefs.FilesToAutoRestore & EMB_CFG) ? 1 : 0,_T("FileRestore"));
	ini.WriteBool(_T("AutoRestoreMainConfig"),(prefs.FilesToAutoRestore & EMB_CFG_MAIN) ? 1 : 0,_T("FileRestore"));
	ini.WriteBool(_T("AutoRestoreTemp"),(prefs.FilesToAutoRestore & EMB_TMP) ? 1 : 0,_T("FileRestore"));

	ini.WriteBool(_T("AutoRestoreMet"),(prefs.FilesToAutoRestore & EMB_TMP_PART_MET) ? 1 : 0,_T("FileRestore"));
	ini.WriteBool(_T("AutoRestoreMetNeo"),(prefs.FilesToAutoRestore & EMB_TMP_PART_MET_NEO) ? 1 : 0,_T("FileRestore"));
	ini.WriteBool(_T("AutoRestoreMetSrc"),(prefs.FilesToAutoRestore & EMB_TMP_PART_MET_SRC) ? 1 : 0,_T("FileRestore"));
	ini.WriteBool(_T("AutoRestorePart"),(prefs.FilesToAutoRestore & EMB_TMP_PART) ? 1 : 0,_T("FileRestore"));


	ini.WriteBool(_T("dat"),(prefs.FilesToBackup & EMB_CFG_DAT) ? 1 : 0,_T("FileTypes"));
	ini.WriteBool(_T("met"),(prefs.FilesToBackup & EMB_CFG_MET) ? 1 : 0,_T("FileTypes"));
	ini.WriteBool(_T("ini"),(prefs.FilesToBackup & EMB_CFG_INI) ? 1 : 0,_T("FileTypes"));

	ini.WriteBool(_T("part"),(prefs.FilesToBackup & EMB_TMP_PART) ? 1 : 0,_T("FileTypes"));
	ini.WriteBool(_T("part.met"),(prefs.FilesToBackup & EMB_TMP_PART_MET) ? 1 : 0,_T("FileTypes"));
	ini.WriteBool(_T("part.met.neo"),(prefs.FilesToBackup & EMB_TMP_PART_MET_NEO) ? 1 : 0,_T("FileTypes"));
	ini.WriteBool(_T("part.met.src"),(prefs.FilesToBackup & EMB_TMP_PART_MET_SRC) ? 1 : 0,_T("FileTypes"));
}

// NEO: NB END <-- Xanatos --