// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include "panic.h"
#include "shrepos.h"
#include "srvrepos_noc.h"
#include "srvres.h"
#include "cachemgr.h"
#include "sessnotf.h"
#include "srvPerf.h"
#include "srvreqs.h" 
#include "rstrepos.h"
#ifdef SYMBIAN_BAFL_SYSUTIL
#include <bafl/sysutil.h>
#endif
#include <e32def_private.h>


void CServerRepository::OpenL(TUid aUid, MObserver& aObserver, TBool aFailIfNotFound)
	{
	iNotifier = &aObserver;
	
	iRepository = TServerResources::iObserver->AccessL(aUid, aFailIfNotFound);
	//store uid
	iUid = aUid;	

	TServerResources::iObserver->AddObserverL(aUid, this);
	TServerResources::iObserver->AddSharedRepositoryInfoL(aUid);
	}

void CServerRepository::Close()
	{
	iRepository = NULL;

	TInt index = TServerResources::iObserver->FindOpenRepository(iUid);
	
	if (index>=0)
		{
		iRepository = TServerResources::iObserver->GetOpenRepository(index);
		// cancel to ensure any read/write locks are released and transaction settings cleaned up
		CancelTransaction();
		}
		
	TServerResources::iObserver->RemoveObserver(iUid, this, index);
	
	iNotifier = NULL;			
	}
	
/**
Notify about all changed keys stored in the specified reference to the
CRestoredRepository.

@param aRstRepos The reference to CRestoredRepository which holds the list 
of the changed keys.
*/	
void CServerRepository::RestoreNotify(const CRestoredRepository& aRstRepos)
	{
	const RArray<TUint32>& keys = aRstRepos.ChangedKeys();
	TInt count=keys.Count();
	for(TInt i = 0; i < count; i++)
		{
		 iRepository->Notify(keys[i]);
		}
	}
	
/**
Attempt to reset a single key to it's value in the file in the given location. Routine
attempts to find a .cre file first. If ( and only if ) a cre file doesn't exist the 
routine attempts to find a txt file.
Note that it would be possible to use LoadRepositoryLC here but for the txt file
that would take longer. This is because in LoadRepositoryLC the txt file is 
completely processed. The Reset specific txt file opening code below is quicker because 
it is just attempting to find the reset key.
*/
#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS	
void CServerRepository::ResetFromIniFileL(TUint32 aId, 
										  CIniFileIn::TIniFileOpenMode aIniFileOpenMode,
										  TBool& aKeyFound)
	{
	aKeyFound=EFalse;

	CSharedRepository* rep=NULL;
	// Attempt to reset key to the aLocation if exist
	//dont fail if repository not found
	TServerResources::iObserver->LoadRepositoryLC(iRepository->Uid(),EFalse,rep,aIniFileOpenMode);
	
	if (rep)
		{
		TServerSetting* s = rep->GetSettings().Find(aId);					
		if(s)
			{
			aKeyFound=ETrue;
			// Mark the setting as default again
			s->SetClean();
			iRepository->ResetAndPersistL(*s);
			s->SetAccessPolicy(GetFallbackAccessPolicy(aId));
			}
		}
	CleanupStack::PopAndDestroy(rep);
	}
#else
void CServerRepository::ResetFromIniFileL(TUint32 aId, 
										  TCentRepLocation aLocation,
										  TBool& aKeyFound)
	{
	aKeyFound=EFalse;

	// Attempt to reset key to value in cre file if it exists
	
	// Attempt to create a temporary repository from the cre file in aLocation
	CSharedRepository* rep = CSharedRepository::NewL(iRepository->Uid());
	CleanupStack::PushL(rep);
	TInt err = rep->CreateRepositoryFromCreFileL(aLocation);

	// Search for aId in the temporary repository
	if (err!=KErrNotFound)
		{		
		// Note that for all errors except KErrNotFound code leaves and doesn't
		// attempt to look for txt file. This is intentional. Code does not 
		// attempt to support coexisting cre and txt files.
		User::LeaveIfError(err);
		
		// Search for aId in the temporary repository
		TServerSetting* s = rep->GetSettings().Find(aId);					
		if(s)
			{
			aKeyFound=ETrue;
			// Mark the setting as default again
			s->SetClean();
			iRepository->ResetAndPersistL(*s);
			s->SetAccessPolicy(GetFallbackAccessPolicy(aId));
			}
			
		CleanupStack::PopAndDestroy(rep);
		return;
		}
	else
		{
		CleanupStack::PopAndDestroy(rep);
		}
		
	HBufC* fileName(NULL);	
	TServerResources::CreateRepositoryFileNameLC(fileName,iRepository->Uid(),aLocation,EIni);
	
	CIniFileIn* inputFile = 0;
	TInt r = CIniFileIn::NewLC(TServerResources::iFs,inputFile,*fileName);
	if(r==KErrNone)
		{
		//we don't want to read this stuff again... just skip over to get to settings!
		inputFile->SkipOwnerSectionL() ;
		inputFile->SkipTimeStampSectionL() ;
		inputFile->SkipDefaultMetaSectionL() ;
		inputFile->SkipPlatSecSectionL();
		
		// Find start of Main section
		inputFile->FindMainSectionL();
	
		TServerSetting s;
		TBool singleMetaFound=EFalse;
		TBool singleReadPolicyFound=EFalse;
		TBool singleWritePolicyFound=EFalse;
		TSecurityPolicy singleReadPolicy;
		TSecurityPolicy singleWritePolicy;

		// Note that calling CIniFile::ReadSettingL causes the single policy ( if it exists ) to be read from the
		// file being reset to, but doesn't update the single policy array, which is not required in the reset case. 
		while((r=inputFile->ReadSettingL(s,singleReadPolicy, singleWritePolicy, singleReadPolicyFound, singleWritePolicyFound, singleMetaFound)) == KErrNone)
			{	
			iRepository->SetMetaDataOnRead( s, singleMetaFound);			
			if(s.Key()==aId)
				{
				// Mark the setting as default again
				s.SetClean();
				iRepository->ResetAndPersistL(s);
				s.SetAccessPolicy(GetFallbackAccessPolicy(aId));
				aKeyFound = ETrue;
				break;
				}
			s.Reset();
			}

	
		}
	CleanupStack::PopAndDestroy(inputFile);	 // inputFile
	CleanupStack::PopAndDestroy(fileName);	 // filename
	}

#endif	

TInt CServerRepository::ResetL(TUint32 aId)
	{
	// not yet supported in transactions
	ASSERT(!IsInTransaction());

	// if setting has not changed, there nothing to do
	TServerSetting *targetSetting = GetSetting(aId) ;

	if (targetSetting)
		{
		if ((targetSetting->Meta() & KMetaDefaultValue))
			{
			return KErrNone;
			}
		}

	TInt error = KErrNone;
	TBool keyReset = EFalse;

	// Check for default value in any installed file first
#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
	ResetFromIniFileL(aId, CIniFileIn::EInstallOnly, keyReset);
#else
	ResetFromIniFileL(aId, EInstall, keyReset);
#endif	
	if (keyReset)
		return KErrNone;

	// Either we couldn't find a matching key or
	// there wasn't an installed file - try for a ROM
	// file
#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS	
	ResetFromIniFileL(aId, CIniFileIn::ERomOnly, keyReset);
#else
	ResetFromIniFileL(aId, ERom, keyReset);
#endif	
	if (keyReset)
		return KErrNone;
	
	// No default value found in install or ROM file
	// delete the key!
	error = iRepository->DeleteAndPersist(aId);

	return error ;
	}


void CServerRepository::CacheRomVersionL(const TDesC& aFilename,TDesC8& aVersion)
	{

	RFile file;
	TInt err = KErrNone; 
	_LIT(KTmpPersistedRomVersionFile, "_:\\private\\10202be9\\romversion\\romversion_info.tmp");	
	TBuf<KMaxFileName> tmpPersistedRomVersionFileName;
	
	tmpPersistedRomVersionFileName.Copy(KTmpPersistedRomVersionFile);
	tmpPersistedRomVersionFileName[0] = RFs::GetSystemDriveChar();
	
	//Create a new empty tmp file.
    err = file.Replace( TServerResources::iFs, tmpPersistedRomVersionFileName,
	                     EFileWrite | EFileStreamText );
	if (err != KErrNone)
	       {
	       file.Close();
	       User::Leave(err);
	       }

    err = file.Write(aVersion);
	if (err != KErrNone)
		{                                                                                                  
	       file.Close();
	       User::Leave(err);
	    }
	    
    file.Close();
    
	User::LeaveIfError(TServerResources::iFs.Replace(tmpPersistedRomVersionFileName,aFilename));

	}

#ifdef SYMBIAN_BAFL_SYSUTIL
void CServerRepository::CheckROMReflashL()
	{
	TInt err=KErrNone;

	TBuf16<KSysUtilVersionTextLength> version;
	TBuf8<KSysUtilVersionTextLength*2> persistedCopyOfRomVersion;
	_LIT(KPersistedRomVersionFile, "_:\\private\\10202be9\\romversion\\romversion_info.txt");	
	TBuf<KMaxFileName> persistedRomVersionFileName;
	persistedRomVersionFileName.Copy(KPersistedRomVersionFile);
	persistedRomVersionFileName[0] = RFs::GetSystemDriveChar();
		
	TBuf8<KSysUtilVersionTextLength*2> eightBitVersion;

	
	if ((err = SysUtil::GetSWVersion(version)) == KErrNone )
		{
		eightBitVersion.Copy(version);//Converts to 8bit
		err = TServerResources::GetTextFromFile(persistedRomVersionFileName,persistedCopyOfRomVersion);		
        if(err == KErrNone)
        	{
        	if(eightBitVersion == persistedCopyOfRomVersion)//No rom update has occurred do nothing
        		{
        		return;
        		}
        	else //rom update detected process persists files.
        		{
        		//Call function with flag set to true causing Reflash merging activity.
        		ProcessPersistsRepositoriesL(ECenRepReflash);
        		}
        	}

		//create the persisted rom version file
		//if the persists files are successfully processed
		//if the persists file doesnt exist
		//if the persists file is corrupt
		//if the persists file is corrupt in such a way that its contents are too large.
		if (err == KErrNone || err == KErrNotFound || err == KErrPathNotFound || err == KErrCorrupt || err == KErrTooBig)
			{
			CServerRepository::CacheRomVersionL(persistedRomVersionFileName,eightBitVersion);
			}
		else
			{
			User::Leave(err);
			}
		}
	else
		{
		User::Leave(err);
		}
	}
#endif

void CServerRepository::RFSAllRepositoriesL()
	{
	ProcessPersistsRepositoriesL(ECenRepReset);	
	}
	
void CServerRepository::ProcessPersistsRepositoriesL(TPersistedRepActions aRomFlashOrReset)
	{
	// Read contents of persist directory to get a list of repositories
	TPtr dataDirectory = TServerResources::iDataDirectory->Des();
	RDir persistDir;
    CleanupClosePushL(persistDir);

	User::LeaveIfError(persistDir.Open(TServerResources::iFs, dataDirectory, KEntryAttNormal));

    TEntryArray dirEntries;
    TInt readError = KErrNone;
    
	while (readError != KErrEof)  
		{
	    readError = persistDir.Read(dirEntries);
    
	    if(readError != KErrNone && readError != KErrEof) 
	    	{
	    	User::Leave(readError);
	    	}
	    else
	    	{
	    	const TInt dirCount = dirEntries.Count();   
	    	for (TInt i=0; i<dirCount; i++)
	    		{
				// Attempt to extract a repository UID from directory entry
				TUid uid;
				if (!TServerResources::GetUid(const_cast<TEntry&>(dirEntries[i]), uid))
					{
					CSessionNotifier notifier;
	
					// Create shared repository
					CServerRepository *repository = new(ELeave) CServerRepository;
					CleanupStack::PushL(repository);
	
					repository->OpenL(uid, notifier);
			
					//Handle ROM re-flash
					TInt err = KErrNone;
					if(aRomFlashOrReset==ECenRepReflash)
						{
						TRAP(err, repository->HandleReflashofRepositoryL());
						}
					else if(aRomFlashOrReset==ECenRepReset)
						{
						// Restore settings
						TRAP(err,repository->RFSRepositoryL());	
						}
					if(err != KErrNone)
					  {
					  if(err == KErrNoMemory)
					    {
					    User::LeaveNoMemory();
					    }
				      else
					    {//Dont stop processing the rest of the persisted repositories becos one has a problem.
					     __CENTREP_TRACE1("CENTREP: CServerRepository::ProcessPersistsRepositoriesL - Error = %d", err);
					    }
				      }
	
					// delete repository.
					repository->Close();
					CleanupStack::PopAndDestroy(repository);
					}
	    		}
	    	}
		}
	
	CleanupStack::PopAndDestroy(&persistDir);
	}

TInt CServerRepository::RFSRepositoryL()
	{
	// for each key in combined ROM/Install restore
	TUid uid = iRepository->Uid();

	CSharedRepository* defaultRepository = 0;
	TInt err=KErrNone;
	
	//Determine if ROM and Install files exist
  	TBool romExists=TServerResources::RomFileExistsL(uid);
  	TBool installExists=TServerResources::InstallFileExistsL(uid);
  		
	if(romExists)
		{
		// Create a rep using the ROM file
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, defaultRepository, CIniFileIn::ERomOnly);
		
		if(installExists)
			{			
			CSharedRepository *installRep = 0;
			// Create install rep for merging
			TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, installRep, CIniFileIn::EInstallOnly);
		
			// If install and ROM exist create a merged rep to Reset against
			defaultRepository->MergeL(*installRep, ESWIUpgradeMerge);
		
			//pop and destroy install repository as this has now been 
			//merged with repository
			CleanupStack::PopAndDestroy(installRep);
			}		
		}
		
	else if(installExists)
		{		
		// Reset against install repository if only the install file exists
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, defaultRepository, CIniFileIn::EInstallOnly);		
		}
	else
		{	
		// Reset against empty repository if neither ROM or install file are found
		defaultRepository = CSharedRepository::NewL(uid);
		CleanupStack::PushL(defaultRepository);
		}

	for(TInt i = 0; i < iRepository->GetSettings().Count(); i++)
		{
		// setting in persists
		TServerSetting* persistedSetting = &iRepository->GetSettings()[i];

		// If the clean is set on setting in the persist, nothing to do			
		if (persistedSetting->Meta() & KMetaDefaultValue)
			{
			continue;
			}

		TUint32 key = persistedSetting->Key();		
		// setting in ROM/install
		TServerSetting* defaultSetting = defaultRepository->GetSettings().Find(key);

		if (defaultSetting)
			{
			if ((defaultSetting->Meta() & KMetaRfsValue))
				{
				iRepository->ResetNoPersistL(*defaultSetting);
				}
			//remove from Reset repository
			defaultRepository->GetSettings().Remove(key);
			}
		else
			{
			// if setting has no default value (i.e. doesn't exist in any default file but RFS meta is 
			// set (using pre-set default range meta),  delete the setting 
			if ((persistedSetting->Meta() & KMetaRfsValue))			
				{
				iRepository->DeleteNoPersist(key);				
				}
			}
		}
	// search for remaining items in default file, because previous loop has already removed all items 
	// from the persists file
	for(TInt i = 0; i < defaultRepository->GetSettings().Count(); i++)
		{
		TServerSetting* defaultSetting = &defaultRepository->GetSettings()[i];

		if ((defaultSetting->Meta() & KMetaRfsValue) != KMetaRfsValue)
			{
			continue;
			}
		iRepository->ResetNoPersistL(*defaultSetting);
		}

	// Persist settings
	iRepository->CommitChangesL();

	CleanupStack::PopAndDestroy(defaultRepository);

	return err;
	}

	
TInt CServerRepository::HandleReflashofRepositoryL()
	{
	// for each key in persists repository
	TUid uid = iRepository->Uid();

	CSharedRepository* defaultRepository = 0;
	
	//Determine if ROM and Install files exist
  	TBool romExists=TServerResources::RomFileExistsL(uid);
	TBool installExists=TServerResources::InstallFileExistsL(uid);
 
	if(romExists)
		{
		// Create a rep using the ROM file
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, defaultRepository, CIniFileIn::ERomOnly);

		if(installExists)//Then create a merged repository of rom and install settings
			{		
			CSharedRepository *installRep = 0;
			// Create install rep for merging
			TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, installRep, CIniFileIn::EInstallOnly);
		
			// If install and ROM exist create a merged rep to Reset against
			defaultRepository->MergeL(*installRep, ESWIUpgradeMerge);
		
			//pop and destroy install repository as this has now been 
			//merged with the rom repository
			CleanupStack::PopAndDestroy(installRep);
			}		
		}		
	else if(installExists)//There was no ROM repository just an install repository
		{			
		// Reset against install repository if only the install file exists
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, defaultRepository, CIniFileIn::EInstallOnly);		
		}
	else //If rom file and install files have been removed for this repository
		{//then remove the persists file.
			TServerResources::DeleteCentrepFileL(uid, EPersists, ECre);
			TServerResources::DeleteCentrepFileL(uid, EPersists, EIni);
			return KErrNone;
		}

	// Merge rom and/or install with persists repository
	iRepository->MergeL(*defaultRepository, ERomFlash);

	// Persist settings
	iRepository->CommitChangesL();

	CleanupStack::PopAndDestroy(defaultRepository);

	return KErrNone;
	}


TInt CServerRepository::ResetAllL()
	{
	// not yet supported in transactions
	ASSERT(!IsInTransaction());
	// fail all sessions' transactions first
	iRepository->FailAllTransactions(/*aExcludeTransactor*/NULL);

	TUid uid = iRepository->Uid();

	// Reset
 	 	
	// Create a rep using the ROM file
	CSharedRepository* rep = 0;
  	TBool romExists=TServerResources::RomFileExistsL(uid);
	if(romExists)
		{
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, rep, CIniFileIn::ERomOnly);
		}
		
	// Create install rep for merging
	CSharedRepository *installRep = 0;
	TBool installExists=TServerResources::InstallFileExistsL(uid);
	if(installExists)
		{			
		TServerResources::iObserver->LoadRepositoryLC(uid, ETrue, installRep, CIniFileIn::EInstallOnly);
		}
		
	TInt err=KErrNone;
	if(	romExists && installExists)
		{
		// If install and ROM exist create a merged rep to Reset against
		rep->MergeL(*installRep, ESWIUpgradeMerge);
		err=iRepository->ResetAllNoPersistL(*rep);
		CleanupStack::PopAndDestroy(installRep);
		CleanupStack::PopAndDestroy(rep);
		}
	else if(romExists)
		{
		// Reset against ROM
		err=iRepository->ResetAllNoPersistL(*rep);
		CleanupStack::PopAndDestroy(rep);
		}
	else if(installExists)
		{
		// Reset against install
		err=iRepository->ResetAllNoPersistL(*installRep);
		CleanupStack::PopAndDestroy(installRep);
		}
	else
		{
		// Reset against empty repository
		rep = CSharedRepository::NewL(uid);
		CleanupStack::PushL(rep);
		err=iRepository->ResetAllNoPersistL(*rep);
		CleanupStack::PopAndDestroy(rep);
		}
	
	return err;
	}

// Handle install directory file update. 
void CServerRepository::HandleSWIUpdateL(TUid aUid, TTime aModified, CSessionNotifier &aNotifier)
	{		
	// A file create or update has just occurred in the SWI directory. 
	// Need to check if this is a new install. 
	
	if(TServerResources::PersistsFileExistsL(aUid) ||
	   TServerResources::RomFileExistsL(aUid))
		{	
		// Create a rep using the ROM or persists file
		OpenL(aUid, aNotifier);
		if(iRepository->IsTransactionActive())			
			{
			// Fail transactions on any currently open session
			iRepository->FailAllTransactions(NULL);
			}
			
		// Create install rep for merging
 		CSharedRepository *installRep = 0;
 		TServerResources::iObserver->LoadRepositoryLC(aUid, ETrue, installRep, CIniFileIn::EInstallOnly);
	
		// Perform merge
		iRepository->HandleUpdateMergeL(aModified, *installRep);
						
		CleanupStack::PopAndDestroy(installRep);
		Close();
		}
	else	// No ROM or persists
		{
		// Create install rep for persisting
		OpenL(aUid, aNotifier);
	
		iRepository->CommitChangesL();
		Close();
		}
	}


// Handle install directory file delete 
void CServerRepository::HandleSWIDeleteL(TUid aUid, CSessionNotifier &aNotifier)
	{			
	// A file delete has just occurred in the SWI directory. If there is no ROM file
	// this is a complete uninstall, so delete persists file.Otherwise, do downgrade
	// merge.
	
	if(TServerResources::RomFileExistsL(aUid))		// ROM file, this is a downgrade uninstall
		{
		if(!TServerResources::PersistsFileExistsL(aUid))
			{
			// If we are downgrading the ROM, there should be a persists file because the
			// original upgrade should have created one.
			// However if there isn't a persists file, there's nothing to do, so just return
			return;
			}
			
		// Create a rep using the persists file
		OpenL(aUid, aNotifier);
		if(iRepository->IsTransactionActive())			
			{
			// Fail transactions on any currently open session
			iRepository->FailAllTransactions(NULL);
			}
		
		// Create ROM rep for merging
	 	CSharedRepository *romRep = 0;
		TServerResources::iObserver->LoadRepositoryLC(aUid, ETrue, romRep, CIniFileIn::ERomOnly);

		// Perform merge
		iRepository->HandleDeleteMergeL(*romRep);
		
		CleanupStack::PopAndDestroy(romRep);
		Close();
		}
	else											// No ROM file, this is a complete uninstall
		{		
		if(TServerResources::PersistsFileExistsL(aUid))
			{
		 	TServerResources::DeleteCentrepFileL(aUid, EPersists, ECre);
		 	
			// Check if the repository was open
			TInt i = TServerResources::iObserver->FindOpenRepository(aUid);

			// If repository is open, fail all transactions 
			if(i>KErrNotFound)			   					  
				{
				OpenL(aUid, aNotifier);
				if(iRepository->IsTransactionActive())			
					{
					// Fail transactions on any currently open session
					iRepository->FailAllTransactions(NULL);
					}
				iRepository->ResetContent();
				Close();				
				}
			}
		}
	}

void CServerRepository::StoreRepositoryContentsL(CStreamStore& aStore, TStreamId & aSettingStreamId, TStreamId & aDeletedSettingsStreamId) const
	{
	StoreRepositorySettingValuesL(aStore, aSettingStreamId); // Stores current repository setting values
	
	RStoreWriteStream outStream;
	aDeletedSettingsStreamId = outStream.CreateLC(aStore); // Creates the write for settings stream
	iRepository->WriteDeletedSettingsStream(outStream) ;
	outStream.CommitL(); // Commits the stream
	CleanupStack::PopAndDestroy(&outStream); // Performs cleanup on the write stream object
	}

void CServerRepository::StoreRepositorySettingValuesL(CStreamStore& aStore, TStreamId & aSettingStreamId) const
	{
	RStoreWriteStream outStream;
	aSettingStreamId = outStream.CreateLC(aStore); // Creates the write stream
	iRepository->WriteBackupStream(outStream); // Only care about repository contents.
	outStream.CommitL(); // Commits the stream
	CleanupStack::PopAndDestroy(&outStream); // Performs cleanup on the write stream object
	}
	
void CServerRepository::RestoreRepositoryContentsL(CStreamStore& aStore, TStreamId aSettingStreamId, TStreamId aDeletedSettingsStreamId, CRestoredRepository& aRstRepos)
	{
	RestoreRepositorySettingValuesL(aStore, aSettingStreamId, aRstRepos);
	
	RStoreReadStream inStream;
	// If the backup contains a list of deleted settings read them in and apply them.
	if (aDeletedSettingsStreamId != KNullStreamId)
		{
		inStream.OpenLC(aStore, aDeletedSettingsStreamId); // Creates read stream for deleted settings (if available)

		TCardinality numDeletedSettings ;
		inStream >> numDeletedSettings ;
		
		for (TInt i = 0; i < numDeletedSettings; i++)
			{
			TUint32 settingToDelete ;
			inStream >> settingToDelete ;
			TInt err = iRepository->DeleteNoPersist(settingToDelete) ; 
			// Add the deleted key to the restored repository if it has existed before being deleted.
			// If it has not existed before being deleted, we do not add it to the list because nothing 
			// has changed.
			if(err == KErrNone)
				{
				aRstRepos.AddKeyL(settingToDelete);
				}
			}
		CleanupStack::PopAndDestroy(&inStream);            // Perform cleanup on the read stream object		
		}
	return;
	}

void CServerRepository::RestoreRepositorySettingValuesL(CStreamStore& aStore, TStreamId aSettingStreamId, CRestoredRepository& aRstRepos)
	{
	RStoreReadStream inStream;
	inStream.OpenLC(aStore, aSettingStreamId); // Creates the write stream
	iRepository->InternalizeL(inStream, aRstRepos); // Only care about repository contents.
	CleanupStack::PopAndDestroy(&inStream);    // Perform cleanup on the read stream object
	}

static void CancelTransactionCleanupOperation(TAny* aRepository)
	{
	static_cast<CServerRepository*>(aRepository)->CancelTransaction();
	}

// So CancelTransaction is called in case of Leave. Must pop with CleanupStack::Pop() or similar
void CServerRepository::CleanupCancelTransactionPushL()
	{
	CleanupStack::PushL(TCleanupItem(CancelTransactionCleanupOperation, this));
	}

/**
@internalTechnology
Check the range of security policies against RMessage
@return
	KErrNone if read access policies of all settings in array pass,
	KErrPermissionDenied if any single policy fails.
*/
TInt CServerRepository::CheckPermissions(RSettingPointerArray& aSettings, const TClientRequest& aMessage, const char* aDiagnostic, TBool aReadPolicy,TUint32& aErrId)
	{
	TInt error = KErrNone;
	TInt numSettings = aSettings.Count();
	for (TInt i = 0; i < numSettings; i++)
		{
		ASSERT(aSettings[i]);
		const TServerSetting& setting = *aSettings[i];
		if (aReadPolicy)
			{
			if (!aMessage.CheckPolicy(GetReadAccessPolicy(setting),aDiagnostic))
				{
				aErrId=setting.Key();	
				error = KErrPermissionDenied;
				break;
				}
			}
		else
			{
			if (!aMessage.CheckPolicy(GetWriteAccessPolicy(setting),aDiagnostic))
				{
				aErrId=setting.Key();			
				error = KErrPermissionDenied;
				break;
				}			
			}
		}
	return error;
	}

TInt CServerRepository::TransactionDeleteRangeL(const TClientRequest& aMessage, TUint32& aErrorKey)
	{
	// all write operations now done in a transaction
	ASSERT(IsInActiveReadWriteTransaction());
	TInt error = KErrNone;
	aErrorKey = KUnspecifiedKey;
		
	TUint32 partialKey = aMessage.Int0();
	TUint32 keyMask = aMessage.Int1();
	
	RSettingPointerArray settingsToDelete;
	CleanupClosePushL(settingsToDelete);	
	error = FindSettings(partialKey, keyMask, settingsToDelete);
	if (error==KErrNoMemory)
		User::LeaveNoMemory();
	
	//perform write security check first
	error=CheckPermissions(settingsToDelete,aMessage,__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerRepository::DeleteRangeL - Attempt made to delete a setting"),EFalse,aErrorKey);
	
	if (error==KErrNone)
		{
		TRAP(error,DeleteSettingsRangeL(settingsToDelete,partialKey,aErrorKey));
		if (error==KErrNoMemory)
			User::LeaveNoMemory();
		}
	CleanupStack::PopAndDestroy(&settingsToDelete);

	if ((error != KErrNone) && (error != KErrNotFound))
		{
		FailTransaction(error, aErrorKey);
		}
	return error;
	}

TInt CServerRepository::TransactionMoveL(const TClientRequest& aMessage, TUint32& aErrorKey)	
	{
	// all write operations now done in a transaction
	ASSERT(IsInActiveReadWriteTransaction());	
	//read the source and target partial key
	TKeyFilter sourceKeyIdentifier;
	TPckg<TKeyFilter> pSource(sourceKeyIdentifier);
	aMessage.Read(0, pSource);

	TKeyFilter targetKeyIdentifier;
	TPckg<TKeyFilter> pTarget(targetKeyIdentifier);
	aMessage.Read(1, pTarget);

	TUint32 sourceToTarget = (sourceKeyIdentifier.iPartialId & sourceKeyIdentifier.iIdMask) ^ (targetKeyIdentifier.iPartialId & targetKeyIdentifier.iIdMask);
	if (sourceToTarget==0)
		{
		return KErrNone;
		}
	
	//Need to get the list of source settings to perform some security policy check
	RSettingPointerArray sourceSettings;
	CleanupClosePushL(sourceSettings);
	TInt error=FindSettings(sourceKeyIdentifier.iPartialId & sourceKeyIdentifier.iIdMask, sourceKeyIdentifier.iIdMask, sourceSettings);
	
	//dont fail transaction if source settings is empty
	if ((error == KErrNone) && (sourceSettings.Count() == 0))
		{
		error = KErrNotFound;
		aErrorKey = sourceKeyIdentifier.iPartialId;
		CleanupStack::PopAndDestroy(&sourceSettings);
		TPckg<TUint32> p(aErrorKey);
		aMessage.WriteL(2, p);		
		return error;

		}
	if (error!=KErrNone)
		{
		aErrorKey = sourceKeyIdentifier.iPartialId;
		CleanupStack::PopAndDestroy(&sourceSettings);
		return error;				
		}	
		
	//Now validate against the security policy before doing the settings move
	error=CheckMovePermissions(sourceSettings,aMessage,sourceToTarget,aErrorKey);
	if (error!=KErrNone)
		{
		CleanupStack::PopAndDestroy(&sourceSettings);
		return error;		
		}	
	
	error =MoveL(sourceKeyIdentifier.iPartialId,targetKeyIdentifier.iPartialId,sourceKeyIdentifier.iIdMask,aErrorKey, sourceSettings);
	CleanupStack::PopAndDestroy(&sourceSettings);
	return error;	
	}

void CServerRepository::LoadIniRepL(CIniFileIn::TIniFileOpenMode aMode)
	{
	if (iIniRep == NULL)
		{
	 	CSharedRepository *rep = NULL;
		TServerResources::iObserver->LoadRepositoryLC(iUid, ETrue, rep, aMode);
		CleanupStack::Pop();
		iIniRep = rep;
		}
	}

TBool CServerRepository::GetMetaFromIni(TUint32 aKey, TUint32& aMeta)
	{
	// Note: cannot use iRepository even if 
	// iRepository->iSettings.IsDefault() is true.
	// The flag is not updated on TransactionCommit.
	if (iIniRep == NULL)
		{
		TInt err;
		TRAP(err, LoadIniRepL(CIniFileIn::EInstallOnly));
		if (err != KErrNone)
			{
			TRAP(err,LoadIniRepL(CIniFileIn::ERomOnly));
			}
		if (err != KErrNone)
			{
			return EFalse;
			}
		}

	ASSERT(iIniRep);
	TServerSetting* s = iIniRep->GetSettings().Find(aKey);					
	if (s)
		{
		aMeta = s->Meta();
		return ETrue;
		}

	return EFalse;
	}

void CServerRepository::RestoreInstallRepositoryL(TUid aUid, CStreamStore& aStore, TStreamId& aSettingStreamId, CRestoredRepository& aRstRepos)
	{
	iRepository = CSharedRepository::NewL(aUid);
	CleanupStack::PushL(iRepository);
	iUid = aUid;
	RestoreRepositorySettingValuesL(aStore, aSettingStreamId, aRstRepos);
	CommitChangesL(EInstall);
	CleanupStack::PopAndDestroy(iRepository);
	iRepository = NULL;
	}

void CServerRepository::BackupInstallRepositoryL(TUid aUid, CStreamStore& aStore, TStreamId& aSettingStreamId)
	{
	TServerResources::iObserver->LoadRepositoryLC(aUid, EFalse, iRepository, CIniFileIn::EInstallOnly);
	iUid = aUid;
	StoreRepositorySettingValuesL(aStore, aSettingStreamId);	
	CleanupStack::PopAndDestroy(iRepository);
	iRepository = NULL;
	}

TInt CServerRepository::CheckAccessPolicyBeforeMoving(const TClientRequest& aMessage, const TServerSetting& aSourceSetting, 
				TUint32 aSourceKey, const TServerSetting& aTargetSetting, TUint32 aTargetKey, TUint32& aErrorKey)
	{
	TInt error = KErrNone;
	
	if (&aTargetSetting && !aTargetSetting.IsDeleted())
		{
		error=KErrAlreadyExists;
		aErrorKey=aTargetKey;
		}

	if (!aMessage.CheckPolicy(GetReadAccessPolicy(aSourceSetting),
		__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerRepository::MoveL - Attempt made to read a setting")))
		{
		error = KErrPermissionDenied;
		aErrorKey = aSourceKey;
		}
	else if (!aMessage.CheckPolicy(GetWriteAccessPolicy(aSourceSetting),
		__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerRepository::MoveL - Attempt made to delete a setting")))
		{
		error = KErrPermissionDenied;
		aErrorKey = aSourceKey;
		}
	else if (error == KErrAlreadyExists)
		{
		// set error to KErrPermissionDenied in preference to KErrAlreadyExists
		if (!aMessage.CheckPolicy(GetWriteAccessPolicy(aTargetSetting),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerRepository::MoveL - Attempt made to create a setting")))
			{
			error = KErrPermissionDenied;
			aErrorKey = aTargetKey;
			}
		}
	else if (!aMessage.CheckPolicy(GetFallbackWriteAccessPolicy(aTargetKey),
			__PLATSEC_DIAGNOSTIC_STRING("CenRep: CServerRepository::MoveL - Attempt made to create a setting")))
		{
		error = KErrPermissionDenied;
		aErrorKey = aTargetKey;
		}
	return error;
	}
