tzservices/tzserver/Server/Source/timezoneconfig.cpp
changeset 0 2e3d3ce01487
child 77 b01c07dfcf84
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tzservices/tzserver/Server/Source/timezoneconfig.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1674 @@
+// Copyright (c) 1997-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 <bacntf.h>             // CEnvironmentChangeNotifier.
+#include <centralrepository.h>  // CRepository.
+#include "tzconfigagent.h"
+#include "dataprovider.h"
+#include <tzupdate.h>   // auto-update notification constants.
+#include <vtzrules.h>
+#include "tzpersisted.h"
+#include "tzlocalizationdb.h"
+#include <bautils.h>
+#include "cbackuprestorenotification.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tzuserdefineddata.h>
+#endif
+
+_LIT8(KUnknownTZName, "Unknown/Zone");
+
+const TUint32 KUnknownTZId = 0x0ffffff0;
+const TInt KSecondsPerMinute = 60;
+
+_LIT(KTimeStamps, "c:\\private\\1020383e\\timestamps");
+_LIT(KTzDbFileNameFlash,"c:\\private\\1020383e\\TZDB.DBZ");
+_LIT(KUserDatabaseName, "c:\\private\\1020383e\\SQLite__tzuserdata.db");
+_LIT(KResourceDir, "c:\\resource\\timezonelocalization\\");
+
+// specifies the limits for rules caching.
+// (year - KRuleCacheLowerLimit) , (year + KRuleCacheUpperLimit)
+// the actual cache includes one more year at year - (KRuleCacheLowerLimit + 1)
+// required to provide the offset used at the start of the search 
+const TUint KRuleCacheLowerLimit = 2;
+const TUint KRuleCacheUpperLimit = 3;
+
+// Security policy for the Publish and Subscribe auto-update notification property.
+const TInt KServerUid = 0x1020383E;
+const TInt KNextDSTChangePropertyKey(0x10285B32);
+_LIT_SECURITY_POLICY_PASS(KReadPolicy);
+_LIT_SECURITY_POLICY_S0(KWritePolicy, KServerUid);
+
+
+CTzConfigAgent::~CTzConfigAgent()
+	{
+	// Flag that the server is shutting down so that we don't try and set 
+	// a new DST Change Timer when the current one is cancelled.
+	iShuttingDown = ETrue;
+	
+	delete iTzDataProvider;
+
+    // Cancel any exitsing timer.
+    if (iDstTimer)
+        {
+        iDstTimer->Cancel();
+        delete iDstTimer;
+        }
+        
+	delete iSystemTzCache;
+	delete iOtherTzCache;
+	delete iRepository;
+	delete iChangeNotifier;
+	delete iBackupNotifier;
+	iTzSwiObserver.RemoveObserver(this);
+	iChangeObservers.Close();
+	iFs.Close();
+	}
+
+/*
+*/
+CTzConfigAgent::CTzConfigAgent(MTZCfgAgentObserver& aServer, CTzUserDataDb& aTzUserDataDb,
+		CTzSwiObserver& aTzSwiObserver) 
+	: iTzServer(aServer),
+	iEnabled(RTz::ETZAutoDSTUpdateOn),
+	iTzSwiObserver(aTzSwiObserver), 
+	iShuttingDown(EFalse), 
+	iTzUserDataDb(aTzUserDataDb)
+	{
+	}
+/*
+*/
+void CTzConfigAgent::ConstructL()
+	{
+	User::LeaveIfError(iFs.Connect());
+
+	// Define a property using Publish and Subscribe.
+	// ** Note that the value of this property is unimportant - setting it
+	// (to any value) counts as a notification, so we do not set it here.
+    TInt err = RProperty::Define(
+        NTzUpdate::EUtcOffsetChangeNotification,
+        RProperty::EInt,
+	    KReadPolicy,
+	    KWritePolicy);
+	    
+	if (err != KErrAlreadyExists)
+	    {
+	    User::LeaveIfError(err);
+	    }
+	    
+    err = RProperty::Define(
+        NTzUpdate::ECurrentTimeZoneId,
+        RProperty::EByteArray,
+	    KReadPolicy,
+	    KWritePolicy);
+	    
+	if (err != KErrAlreadyExists)
+	    {
+	    User::LeaveIfError(err);
+	    }
+ 
+    err = RProperty::Define(
+        NTzUpdate::EHomeTimeZoneId,
+        RProperty::EByteArray,
+	    KReadPolicy,
+	    KWritePolicy);
+	    
+	if (err != KErrAlreadyExists)
+	    {
+	    User::LeaveIfError(err);
+	    }
+
+	err = RProperty::Define(
+        NTzUpdate::ETzRulesChange,
+        RProperty::EByteArray,
+	    KReadPolicy,
+	    KWritePolicy);
+	
+	if (err != KErrAlreadyExists)
+	    {
+	    User::LeaveIfError(err);
+	    }
+ 
+    err = RProperty::Define(
+        NTzUpdate::ETzNamesChange,
+        RProperty::EByteArray,
+	    KReadPolicy,
+	    KWritePolicy);
+	    
+	if (err != KErrAlreadyExists)
+	    {
+	    User::LeaveIfError(err);
+	    }
+
+	iTzDataProvider = CTzDataProvider::NewL(iFs, iTzSwiObserver, iTzUserDataDb,
+		*this);
+	
+	iDstTimer = CDstEventNotifier::NewL(*this);
+		
+    iRepository = CRepository::NewL(NTzUpdate::KPropertyCategory);
+
+	// Get the DST auto-update configuration value from the repository.
+    User::LeaveIfError(iRepository->Get(EConfigurationKey, iEnabled));
+
+	// Get the current time zone from the repository.
+	TInt timeZoneIdentity(0);
+    User::LeaveIfError(iRepository->Get(ETimeZoneKey, timeZoneIdentity));
+
+	// Extract the current time zone identifier.  This is stored in the bits
+	// not occupied by the old TLocale DST settings.
+	TUint localeZone = timeZoneIdentity & ~(EDstHome | EDstEuropean |
+		EDstNorthern | EDstSouthern);
+
+	// If the current time zone identifier is set (non-zero) then check that
+	// this zone exists. 
+    TBool timeZoneExists = EFalse;
+    if (localeZone > 0)
+    	{
+    	timeZoneExists = iTzDataProvider->IsIdInDbL(localeZone);
+    	}
+    
+    CTzId* timeZoneId = NULL;
+    if(timeZoneExists)
+    	{
+    	// Use the current time zone identifier obtained from the repository.
+    	timeZoneId = CTzId::NewL(localeZone);
+    	}
+    else 
+		{
+		// Either the current time zone is not set in the repository or it is
+		// and the time zone does not exist.  In either case we need to use the
+		// default time zone identifier.
+        timeZoneId = iTzDataProvider->GetDefaultTimeZoneIdL();
+        if (!timeZoneId)
+            {
+            // If we cannot obtain the default time zone identifier then use the
+            // "unknown" time zone identifier as a fallback solution.
+		    timeZoneId = CTzId::NewL(KUnknownTZId);
+            }  
+  		}
+
+    CleanupStack::PushL(timeZoneId);
+
+	// Setting the time zone updates the UTC offset and sets a new DST change
+	// timer if required.
+	SetTimeZoneL(*timeZoneId, static_cast<TAny*>(this), ETrue);
+
+	CleanupStack::PopAndDestroy(timeZoneId);
+	
+	// Create and start the environment change notifier.
+	iChangeNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityIdle, TCallBack(EnvironmentChangeCallBackL, this));
+	iChangeNotifier->Start();
+
+	TRAP_IGNORE(PublishNewDstChangeInfoL());
+
+	iTzSwiObserver.AddObserverL(this);
+
+	// Create backup notifier.  Note that file name argument is unimportant.
+	iBackupNotifier = CBackupRestoreNotification::NewL(KTzDbFileNameFlash(),*this);
+
+	// Publish any changes that may have happened to TZ databases or resources
+	// while the TZ Server was not running.
+	PublishTzDbChangeInfoL();
+	}
+
+void CTzConfigAgent::PublishTzDbChangeInfoL()
+	{
+	RFile file;
+	CleanupClosePushL(file);
+
+	TTime tzDbModified = Time::NullTTime();
+	TTime userDbModified = Time::NullTTime();
+	TTime resourceFileModified = Time::NullTTime();
+
+	TInt err = file.Open(iFs, KTimeStamps, EFileRead | EFileWrite);
+	if(err == KErrNone || err == KErrNotFound)
+		{
+		//Read time stamps
+		TInt err1 = iFs.Modified(KTzDbFileNameFlash, tzDbModified);
+		if(err1 != KErrNone && err1 != KErrNotFound)
+			{
+			User::Leave(err1);
+			}
+		err1 = iFs.Modified(KUserDatabaseName, userDbModified);
+		if(err1 != KErrNone && err1 != KErrNotFound)
+			{
+			User::Leave(err1);
+			}
+		resourceFileModified = GetResourceFileTimeStampsL();
+		}
+	else
+		{
+		User::Leave(err);
+		}
+	
+	TBool tzRuleChanged = EFalse;
+	TBool tzNameChanged = EFalse;
+	
+	TTime tzDbSaved = Time::NullTTime();
+	TTime userDbSaved  = Time::NullTTime();
+	TTime resourceFileSaved  = Time::NullTTime();
+
+	if (err == KErrNone)
+		{
+		ReadTimeStampsL(file, tzDbSaved, userDbSaved, resourceFileSaved);
+
+		if(tzDbModified != tzDbSaved)
+			{
+			tzRuleChanged = ETrue;		
+			}
+		if(userDbModified != userDbSaved)
+			{
+			tzRuleChanged = ETrue;
+			tzNameChanged = ETrue;
+			}
+		if(resourceFileModified != resourceFileSaved)
+			{
+			tzNameChanged = ETrue;		
+			}
+		}
+	else//err == KErrNotFound
+		{//Always publish the changes if the time stamps file is not there
+		tzRuleChanged = ETrue;
+		tzNameChanged = ETrue;
+		}
+	
+	if(tzRuleChanged || tzNameChanged)
+		{//Rewrite all three times
+		User::LeaveIfError(file.Replace(iFs, KTimeStamps, EFileRead | EFileWrite));
+		WriteTimeStampsL(file, tzDbModified, userDbModified, resourceFileModified);
+		}
+	CleanupStack::PopAndDestroy(&file); // file.Close()
+	
+	if (tzRuleChanged || tzNameChanged)
+		{
+		iTzDbHasChanged = ETrue;
+		if (tzRuleChanged)
+			{
+			//Publish the tz rules change
+			NTzUpdate::TTzRulesChange rulesChange;
+			rulesChange.iUTCTimeOfRulesChange.UniversalTime();
+			TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
+			RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules);
+			}
+	
+		if(tzNameChanged )
+			{
+			//Publish the names change for user defined DB or resource file change
+			NTzUpdate::TTzNamesChange namesChange;
+			namesChange.iUTCTimeOfNamesChange.UniversalTime();
+			TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
+			RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames);	
+			}
+		}
+	}
+
+void CTzConfigAgent::ReadTimeStampsL(RFile& aFile, TTime& aTzdbSaved, TTime& aUserDbSaved, TTime& aResourceFileSaved)
+	{
+	RFileReadStream readStream(aFile);
+	CleanupClosePushL(readStream);
+	
+	TUint32 low = readStream.ReadUint32L();
+	TUint32 high = readStream.ReadUint32L();
+	aTzdbSaved = TTime(MAKE_TINT64(high, low));
+
+	low = readStream.ReadUint32L();
+	high = readStream.ReadUint32L();
+	aUserDbSaved = TTime(MAKE_TINT64(high, low));
+
+	low = readStream.ReadUint32L();
+	high = readStream.ReadUint32L();
+	aResourceFileSaved = TTime(MAKE_TINT64(high, low));
+	CleanupStack::PopAndDestroy(&readStream);
+	}
+
+void CTzConfigAgent::WriteTimeStampsL(RFile& aFile, const TTime& aTzdbModified, const TTime& aUserDbModified, const TTime& aResourceFileModified)
+	{
+	RFileWriteStream writeStream(aFile);
+	CleanupClosePushL(writeStream);
+	writeStream << I64LOW(aTzdbModified.Int64());
+	writeStream << I64HIGH(aTzdbModified.Int64());
+	writeStream << I64LOW(aUserDbModified.Int64());
+	writeStream << I64HIGH(aUserDbModified.Int64());
+	writeStream << I64LOW(aResourceFileModified.Int64());
+	writeStream << I64HIGH(aResourceFileModified.Int64());
+	writeStream.CommitL();
+	CleanupStack::PopAndDestroy(&writeStream);
+	}
+
+/* Get the sum of time stamps of time zone resource files 
+ * It returns Time::NullTTime() if there is no resorece files in the "c:\\resource\\timezonelocalization\\" 
+ */
+TTime  CTzConfigAgent::GetResourceFileTimeStampsL()
+	{
+	CDir* files = NULL;
+	TInt err = iFs.GetDir(KResourceDir, KEntryAttNormal, ESortNone, files);
+	CleanupStack::PushL(files);
+	TInt64 sum = 0;
+	if(err != KErrNone && err != KErrNotFound && err != KErrPathNotFound)
+		{
+		User::Leave(err);
+		}
+	if(files)
+		{
+		TInt count = files->Count();
+		for(TInt ii = 0; ii < count; ++ii)
+			{
+			const TEntry& entry = (*files)[ii];
+			sum = sum + entry.iModified.Int64();
+			}
+		}
+	CleanupStack::PopAndDestroy(files);
+	if(sum==0)
+		{
+		return Time::NullTTime();
+		}
+	return TTime(sum);
+	}
+
+void CTzConfigAgent::PublishNewDstChangeInfoL()
+	{
+    TInt propertyDefineError = RProperty::Define(KUidSystemCategory,
+    												KNextDSTChangePropertyKey,
+    												RProperty::EByteArray,
+    												KReadPolicy,
+    												KWritePolicy,
+													sizeof(NTzUpdate::TDSTChangeInfo));
+
+	if (propertyDefineError != KErrAlreadyExists)
+		{
+	    // if there was an actual error defining the property then we should leave
+		User::LeaveIfError(propertyDefineError);
+		}
+	
+    // create the next DST change and set some default values
+    NTzUpdate::TDSTChangeInfo newDSTChangeInfo;
+    newDSTChangeInfo.iVersion = 2;
+	
+	if ( CalculateNextDstChangeL(newDSTChangeInfo.iNextDSTChangeUTC, newDSTChangeInfo.iPreviousDSTChangeUTC) 
+		&& (iEnabled == RTz::ETZAutoDSTUpdateOn) )
+		{
+		// There is a future DST change in this time zone and auto DST updates are on
+		CVTzActualisedRules& actualisedRules = GetTimeZoneRulesL(newDSTChangeInfo.iNextDSTChangeUTC, ETzUtcTimeReference);
+		newDSTChangeInfo.iNextUTCOffset = actualisedRules.GetOffsetFromRuleL(newDSTChangeInfo.iNextDSTChangeUTC, ETzUtcTimeReference);
+		newDSTChangeInfo.iPreviousUTCOffset = actualisedRules.GetOffsetFromRuleL(newDSTChangeInfo.iPreviousDSTChangeUTC-TTimeIntervalMinutes(1), ETzUtcTimeReference);
+		}
+	else
+		{
+		newDSTChangeInfo.iNextDSTChangeUTC = Time::NullTTime();
+		newDSTChangeInfo.iNextUTCOffset = 0;
+		newDSTChangeInfo.iPreviousDSTChangeUTC = Time::NullTTime();
+		newDSTChangeInfo.iPreviousUTCOffset = 0;
+		}
+	
+	// get the current value that is published
+	TPckgBuf<NTzUpdate::TDSTChangeInfo> currentNextDSTChangeBuf;
+	User::LeaveIfError(RProperty::Get(KUidSystemCategory, KNextDSTChangePropertyKey, currentNextDSTChangeBuf));
+	
+	// Publish if the next DST change is different from the previous version
+	if ((currentNextDSTChangeBuf().iNextUTCOffset != newDSTChangeInfo.iNextUTCOffset)
+		|| (currentNextDSTChangeBuf().iNextDSTChangeUTC != newDSTChangeInfo.iNextDSTChangeUTC)
+		|| (currentNextDSTChangeBuf().iPreviousUTCOffset != newDSTChangeInfo.iPreviousUTCOffset)
+		|| (currentNextDSTChangeBuf().iPreviousDSTChangeUTC != newDSTChangeInfo.iPreviousDSTChangeUTC)
+		|| (propertyDefineError != KErrAlreadyExists))
+		{
+		// package the data and set the property value 
+		TPckgBuf<NTzUpdate::TDSTChangeInfo> newDSTChangeInfoBuf(newDSTChangeInfo);
+	    User::LeaveIfError(RProperty::Set(KUidSystemCategory, KNextDSTChangePropertyKey, newDSTChangeInfoBuf));
+		}
+	}
+
+/*
+*/
+CTzConfigAgent* CTzConfigAgent::NewL(MTZCfgAgentObserver& aServer, CTzUserDataDb& aUserDataDb,
+		CTzSwiObserver& aTzSwiObserver)
+	{
+	CTzConfigAgent* self = new(ELeave) CTzConfigAgent(aServer, aUserDataDb, aTzSwiObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);		
+	return self;
+	}
+
+const CTzId& CTzConfigAgent::GetTimeZoneIdL() const
+	{
+	if (!iSystemTzCache)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	return iSystemTzCache->TimeZoneId();
+	}
+
+const CTzId& CTzConfigAgent::SetTimeZoneL(const CTzId& aZoneId, const TAny* aRequester, TBool aUpdateCentralRepository, TBool aForceCacheUpdate)
+	{
+	TInt oldTzId = 0;
+	TBool zoneChanged = EFalse;
+	TTime now;
+	now.UniversalTime();
+
+	if (!iSystemTzCache)
+		{
+		iSystemTzCache = CSystemTzRulesCache::NewL(aZoneId, *this, now);
+		}
+	else if (iSystemTzCache->TimeZoneId() == aZoneId && !aForceCacheUpdate)
+		{
+		return (iSystemTzCache->TimeZoneId());
+		}
+	else
+		{
+		oldTzId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
+		// replace the rule. create new before deleting old
+		CSystemTzRulesCache* newZone = CSystemTzRulesCache::NewL(aZoneId, *this, now);
+		CleanupStack::PushL(newZone);
+		
+		//For Invalid Timezone, rules doesnot exist 
+		CTzRules& newZoneRules =  newZone->GetEncodedTimeZoneRulesL();
+		if (newZoneRules.Count() == 0)
+		    {
+		    User::Leave(KErrNotFound);
+		    }
+
+		delete iSystemTzCache;
+		iSystemTzCache = newZone;
+
+		CleanupStack::Pop(newZone);
+		zoneChanged = ETrue;
+		}
+
+	TInt offset = iSystemTzCache->Rules().GetOffsetFromRuleL(now, ETzUtcTimeReference);
+		
+	// We need to publish an automatic time update event 
+	// Stop the auto time update observer and
+	// remove the published auto-update time.
+	// if the old and new timezone ids are the same but
+	// the new offset differs from what was originally there
+
+	if (iSystemTzCache->TimeZoneId().TimeZoneNumericID() != KUnknownTZId)
+		{
+		// Now set the new time zone and new UTC Offset.
+		TInt TimeZoneIdentity((TDaylightSavingZone)(iSystemTzCache->TimeZoneId().TimeZoneNumericID()));
+		
+ 		if(aUpdateCentralRepository)
+			{
+			// Set the currently used time zone from central repository
+			User::LeaveIfError(iRepository->Set(ETimeZoneKey, TimeZoneIdentity));	
+			}
+            
+        // Set the new UTC Offset.
+		const TTimeIntervalSeconds newUtcOffset = offset * KSecondsPerMinute;
+		User::SetUTCOffset(newUtcOffset);
+
+		// replace cached current time zone
+		if (zoneChanged)
+			{
+			iTzServer.NotifyTZStatusChange(RTz::ETZSystemTimeZoneChanged, aRequester);
+			}
+
+// Do not publish updates or set timers if compiled as part of
+// the unit test as this will conflict with the Time Zone Server.
+#ifndef SYMBIAN_TZ_UNIT_TEST
+
+        // Publish UTC Offset and set DST Change Timer if configured.
+        // Note that it would make sense to always publish the UTC Offset here (if it
+        // changes) as this is not a change due to the auto-update functionality, but 
+        // this would make the PREQ 234 changes only partly configurable.
+        if (iEnabled == RTz::ETZAutoDSTUpdateOn)
+            {
+            // Set a new DST Change Timer if required.
+            SetDstChangeTimerL();
+            }
+#endif  // SYMBIAN_TZ_UNIT_TEST
+
+		NTzUpdate::TTimeZoneChange change;
+		change.iNewTimeZoneId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
+		change.iOldTimeZoneId = oldTzId;
+		
+		TPckgBuf<NTzUpdate::TTimeZoneChange> changeBuf(change);
+		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ECurrentTimeZoneId, changeBuf);
+		}
+	
+	iTzDataProvider->ReleaseTzRules();
+	
+	TRAP_IGNORE(PublishNewDstChangeInfoL());
+	
+	return (iSystemTzCache->TimeZoneId());
+	}
+
+CTzRules& CTzConfigAgent::GetEncodedTimeZoneRulesL()
+	{
+	return iSystemTzCache->GetEncodedTimeZoneRulesL();
+	}
+
+TInt CTzConfigAgent::GetEncodedTimeZoneRulesSizeL(const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference aTimeRef)
+	{
+	TInt size = iSystemTzCache->GetEncodedTimeZoneRulesSizeL(aStartTime, aEndTime, aTimeRef);
+	iTzDataProvider->ReleaseTzRules();
+	return size;
+	}
+
+CTzRules& CTzConfigAgent::GetForeignEncodedTimeZoneRulesL()
+	{
+	if (iOtherTzCache == NULL)
+		{
+		User::Leave(KErrNotFound);
+		}
+		
+	return iOtherTzCache->GetEncodedTimeZoneRulesL();
+	}
+		
+TInt CTzConfigAgent::GetForeignEncodedTimeZoneRulesSizeL(const CTzId& aZoneId, const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference aTimeRef)
+	{
+	if (!iOtherTzCache)
+		{
+		iOtherTzCache = CTZRulesCache::NewL(aZoneId, *this, aStartTime);
+		}
+	else if (iOtherTzCache->TimeZoneId() != aZoneId)
+		{
+		// ids are different.
+		// replace the rule. create new before deleting old
+		CTZRulesCache* newZone = CTZRulesCache::NewL(aZoneId, *this, aStartTime);
+
+		delete iOtherTzCache;
+		iOtherTzCache = newZone;
+		}
+
+	TInt size = iOtherTzCache->GetEncodedTimeZoneRulesSizeL(aStartTime, aEndTime, aTimeRef);
+	iTzDataProvider->ReleaseTzRules();
+	return size; 
+	}
+										
+#if defined(_DEBUG)
+/**
+Required for OOM testing.  To obtain a balanced heap cell count check we need to
+reset any cached foreign time zone rules.
+*/
+void CTzConfigAgent::ResetForeignTimeZoneRulesCache(void)
+	{
+	delete iOtherTzCache;
+	iOtherTzCache = NULL;
+	}		
+#endif
+	
+CVTzActualisedRules& CTzConfigAgent::GetTimeZoneRulesL(const TTime& aTime,TTzTimeReference aTimerRef)
+	{
+	CVTzActualisedRules& rules = iSystemTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
+	iTzDataProvider->ReleaseTzRules();
+	return rules; 
+	}	
+	
+CVTzActualisedRules& CTzConfigAgent::GetForeignTimeZoneRulesL(const CTzId& aZoneId,
+															  const TTime& aTime,
+															  TTzTimeReference aTimerRef)
+	{
+	if (!iOtherTzCache)
+		{
+		iOtherTzCache = CTZRulesCache::NewL(aZoneId, *this, aTime);
+		}
+	else if (iOtherTzCache->TimeZoneId() != aZoneId)
+		{
+		// ids are different.
+		// replace the rule. create new before deleting old
+		CTZRulesCache* newZone = CTZRulesCache::NewL(aZoneId, *this, aTime);
+
+		delete iOtherTzCache;
+		iOtherTzCache = newZone;
+		}
+
+	CVTzActualisedRules& rules = iOtherTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
+	iTzDataProvider->ReleaseTzRules();
+	return rules; 
+	}	
+
+/*
+Retrieves the UTC offset for an array of numeric time zone ids.
+The offset is written back into aTimeZoneIdArray at the position that the numeric id 
+was read from, overwriting the id.
+@param aTimeZoneIdArray flat buffer consisting of a TInt for the number of ids,
+followed by the numeric time zone id (TInt) for which the current UTC offset is required.
+*/
+void CTzConfigAgent::GetOffsetsForTimeZoneIdsL(CBufFlat& aTimeZoneIdArray)
+	{
+	iTzDataProvider->GetOffsetsForTimeZoneIdsL(aTimeZoneIdArray);
+	iTzDataProvider->ReleaseTzRules();
+	}
+
+void CTzConfigAgent::ConvertL(const CTzId& aZone, TTime& aTime, TTzTimeReference aTimerRef)
+	{
+	CVTzActualisedRules& rules = GetForeignTimeZoneRulesL(aZone, aTime, aTimerRef);
+	CTzRules& tzRules = GetForeignEncodedTimeZoneRulesL();
+	iTzDataProvider->ReleaseTzRules();
+	
+	tzRules.ConvertTime(rules, aTime, aTimerRef);
+	}
+
+void CTzConfigAgent::ConvertL(TTime& aTime, TTzTimeReference aTimerRef)
+	{
+    CVTzActualisedRules& rules = iSystemTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
+	CTzRules& tzRules = GetEncodedTimeZoneRulesL();
+	iTzDataProvider->ReleaseTzRules();
+	tzRules.ConvertTime(rules, aTime, aTimerRef);
+	}
+
+TInt CTzConfigAgent::IsDaylightSavingOnL(const CTzId& aZone, TTime& aUTCTime)
+{
+	const CVTzActualisedRules& rules = GetForeignTimeZoneRulesL(aZone, aUTCTime, ETzUtcTimeReference);
+	iTzDataProvider->ReleaseTzRules();
+	return rules.IsDaylightSavingOn(aUTCTime);
+}
+
+// There is a change to the TZ database. A new one may have been installed
+// Reset the current time zone information to take advantage of any changes.
+void CTzConfigAgent::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange)
+	{
+	if (aChange == RTz::ETZLocalizationDataChanged)
+		{
+		TInt j = 0;
+  		TInt jEnd = iChangeObservers.Count();
+  		while (j < jEnd)
+  			{
+  			iChangeObservers[j]->NotifyTZDataStatusChangeL(aChange);
+  			++j;
+  			}
+
+		NTzUpdate::TTzNamesChange namesChange;
+		namesChange.iUTCTimeOfNamesChange.UniversalTime();
+		TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
+		User::LeaveIfError(RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames));
+		}
+	else 
+		{
+		delete iOtherTzCache;
+		iOtherTzCache = NULL;
+		SetTimeZoneL(iSystemTzCache->TimeZoneId(), static_cast<TAny*>(this), ETrue, ETrue);
+		iTzDataProvider->ReleaseTzRules();
+
+		// notify change
+		iTzServer.NotifyTZStatusChange(aChange, static_cast<TAny*>(this));
+		
+		//Publish the property
+		NTzUpdate::TTzRulesChange rulesChange;
+		rulesChange.iUTCTimeOfRulesChange.UniversalTime();
+		TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
+		User::LeaveIfError(RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules));
+		}
+	}
+
+/**
+Calculates the time/date (in UTC) of the next DST change event that will take
+place for the current time zone. Note that there may not be a DST change for
+the current time zone, in which case EFalse is returned and aNextDstEvent is
+not changed.
+
+@param aNextDstEvent returns the time of the next DST change event.
+@return ETrue if a change event was found, else EFalse.
+@internalComponent
+
+*/
+TBool CTzConfigAgent::CalculateNextDstChangeL(TTime& aNextDstEvent)
+	{
+	TTime dummy;
+	return CalculateNextDstChangeL(aNextDstEvent, dummy);
+	}
+
+/**
+Calculates the time/date (in UTC) of the next DST change event that will take
+place for the current time zone. Note that there may not be a DST change for
+the current time zone, in which case EFalse is returned and aNextDstEvent is
+not changed.
+
+@param aNextDstEvent returns the time of the next DST change event.
+@return ETrue if a change event was found, else EFalse.
+@internalComponent
+
+*/
+TBool CTzConfigAgent::CalculateNextDstChangeL(TTime& aNextDstEvent, TTime& aPreviousDstEvent)
+    {
+    // Get the current time/date.
+    TTime now;
+    now.UniversalTime();
+    
+    // Get the actualised rules for the current time zone
+    // - the next DST change will always exist within the range returned.
+    // (Note that the current time zone may not have any DST changes.)
+	CVTzActualisedRules& rules = GetTimeZoneRulesL(now,ETzUtcTimeReference);
+		
+    // Iterate through the actualised rules until we get the next rule change 
+    // after the current time/date. (Or we reach the end of the actualised rules 
+    // - in which case no DST change applies.)
+    const TInt KRuleCount = rules.Count();
+    
+    // Store the previous offset for converting the time of change to utc.
+    // Note: for times before any rules applied, the dst offset is always 0.
+    TInt offset;
+    
+    aPreviousDstEvent = Time::MinTTime();
+    for (TInt i = 0; i < KRuleCount; i++)
+        {
+        // Get the next time of change as a UTC time.
+        TTime utcTimeOfChange = rules[i].iTimeOfChange;
+     
+        __ASSERT_ALWAYS(rules[i].iTimeReference!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
+	
+        if (rules[i].iTimeReference == ETzWallTimeReference)
+            {
+        	// Get the previous offset as this was used to create the
+        	// local time version of utcTimeOfChange.
+    		if (i > 0)
+    			{
+    			// previous iNewOffset contains the STD offset plus
+    			// the previous DST offset
+    			offset = rules[i-1].iNewOffset;
+    			}
+    		else
+	    		{
+	    		// First offset will contain just the STD offset
+	    		offset = rules[i].iNewOffset;	
+	    		}
+            utcTimeOfChange -= static_cast<TTimeIntervalMinutes>(offset);
+            }
+        
+        if (utcTimeOfChange <= now)
+        	{
+        	aPreviousDstEvent = utcTimeOfChange;
+        	}
+        else
+            {
+            aNextDstEvent = utcTimeOfChange;
+            return ETrue;
+            }
+        }
+        
+    // No DST change has been found.
+    return EFalse;
+    }
+
+
+/**
+Calculates the current UTC offset using time zone rules for the current time
+zone. Note that this may be different from the value set in User::UTCOffset.
+
+@param aOffset returns the current UTC Offset in seconds
+@internalComponent
+
+*/
+void CTzConfigAgent::CalculateUtcOffsetL(TTimeIntervalSeconds& aOffset)
+    {
+    // Get the current time/date.
+    TTime now;
+    now.UniversalTime();
+    
+    // Get actualised rules for the current time zone.
+	CVTzActualisedRules& rules = GetTimeZoneRulesL(now,ETzUtcTimeReference);
+
+    // Get the current UTC Offset in minutes.
+    TInt offsetInMinutes = rules.GetOffsetFromRuleL(now, ETzUtcTimeReference);
+      
+    // Multiply up to get the offset in seconds.
+    aOffset = offsetInMinutes * KSecondsPerMinute;
+    }
+    
+    
+
+/**
+Gets the time/date (in UTC) of the next DST change event for the current time
+zone and sets a timer if it is a valid time.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::SetDstChangeTimerL()
+    {
+    // Cancel any existing DST Change Timer.
+    iDstTimer->Cancel();
+
+    // Get the time of the next DST change event (in UTC).
+    TTime nextTimer;
+    
+    if (CalculateNextDstChangeL(nextTimer))
+        {
+        // If the time is valid then set the timer.
+        iDstTimer->SetTimer(nextTimer);
+        }
+    }
+
+/**
+Handles cancellation or completion of a previous DST Change Timer. Updates the
+UTC Offset and sets a new DST Change Timer as necessary.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::HandleDstChangeTimerL()
+    {
+	// UTC offset must be updated only when Auto Update is ON
+	if (iEnabled == RTz::ETZAutoDSTUpdateOn)
+		{
+		UpdateUtcOffsetL();
+		}
+
+	// Notification must be generated when Auto Update is ON or NOTIFY
+	// (unless the server is shutting down)
+	if (iEnabled != RTz::ETZAutoDSTUpdateOff && !iShuttingDown)
+ 	    {
+		// reset dst timer
+		SetDstChangeTimerL();
+
+		// Publish update notification.
+		// Note that the value published is the same as
+		// the AutoUpdate Configuration
+		TInt err = RProperty::Set(
+   				NTzUpdate::KPropertyCategory, 
+   				NTzUpdate::EUtcOffsetChangeNotification, iEnabled);
+			User::LeaveIfError(err);
+	    }
+	
+	TRAP_IGNORE(PublishNewDstChangeInfoL());
+    }
+
+    
+/**
+Calculates what the UTC Offset should be - if this differs from the current
+offset then the new offset is set using User::SetUTCOffset() and subscribed
+clients are notified of the change through the Publish and Subscribe API.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::UpdateUtcOffsetL()
+    {
+    
+    // Calculate the current UTC Offset in seconds.
+    TTimeIntervalSeconds currentOffset;
+    CalculateUtcOffsetL(currentOffset);
+    
+    if (currentOffset != User::UTCOffset())
+		{
+    	// Set the new UTC Offset.
+		iChangeNotifier->Cancel();
+    	User::SetUTCOffset(currentOffset);
+		// enable observer again
+		iChangeNotifier->Start();
+    	// Notify session observer.
+		iTzServer.NotifyTZStatusChange(RTz::ETZAutomaticTimeUpdate, static_cast<TAny*>(this));
+		}
+    }
+        
+/**
+Sets the configuration of the UTC Offset auto-update functionality.
+
+@param aUpdateEnabled If set to RTz::ETZAutoDSTUpdateOn then the UTC Offset is automatically
+updated for changes to Daylight Savings Time. If set to RTz::ETZAutoDSTUpdateOff then auto-update
+is disabled. The RTz::ETZAutoDSTNotificationOnly - Means that the client app needs to confirm that the 
+time should be updated whenever a DST event occurs.
+
+
+@internalComponent
+
+*/
+void CTzConfigAgent::SetAutoUpdateBehaviorL(TInt aUpdateEnabled)
+    {
+    // Check if the configuration has changed.
+    if (aUpdateEnabled != iEnabled)
+        {
+        // Persist the new configuration.
+        iEnabled = aUpdateEnabled;
+       	iRepository->Set(EConfigurationKey, iEnabled);
+
+        // Handle configuration change.
+        if (aUpdateEnabled != RTz::ETZAutoDSTUpdateOff)
+            {
+			// Update the UTC Offset (if required) and set a new DST Change Timer.       
+
+            SetDstChangeTimerL();
+			// Don't update Kernel for Notify - only for ON
+			if (aUpdateEnabled == RTz::ETZAutoDSTUpdateOn)
+				{
+				UpdateUtcOffsetL();   
+				}
+            }
+        else
+            {
+            // Cancel any existing DST Change Timer.
+            iDstTimer->Cancel();
+            }
+        }
+    
+    TRAP_IGNORE(PublishNewDstChangeInfoL());
+    }
+
+ /**
+Change current local time.
+
+@param aHomeTime The time to set in wall-clock time.
+
+@return An error code. KErrNone is expected unless there is an error in
+converting the given local time to UTC.
+
+@internalComponent
+
+*/
+TInt CTzConfigAgent::SetHomeTimeL(const TTime& aHomeTime)     
+	{
+	TTime utcTime(aHomeTime);
+
+	ConvertL(utcTime, ETzWallTimeReference);
+
+	//Cancel environment change notification in case double updating UTC offset.
+	iChangeNotifier->Cancel();   
+
+	//Cancel DST timer.
+	iDstTimer->Cancel();
+
+	TTimeIntervalSeconds utcOffset(0);
+	aHomeTime.SecondsFrom(utcTime,utcOffset);
+
+	//Update kernel time and utc offset.
+	TInt result = User::SetUTCTimeAndOffset(utcTime, utcOffset);
+
+	// Get the time of the next DST change event (in UTC).
+	TTime nextTimer;
+
+	if (iEnabled != RTz::ETZAutoDSTUpdateOff)
+		{
+		if (CalculateNextDstChangeL(nextTimer))
+			{
+			// Restart the dst timer.
+			iDstTimer->SetTimer(nextTimer);
+			}
+		}
+
+	//Restart observe environment change notification.
+	iChangeNotifier->Start();
+	
+	TRAP_IGNORE(PublishNewDstChangeInfoL());
+
+	return result;
+	}
+
+TInt CTzConfigAgent::SetUnknownTimeZoneTimeL(const TTime& aUTCTime, const TInt aUTCOffset, TBool aPersistInCenRep)     
+	{
+	//
+	// Cancel DST timer. (It will not be restarted, as we won't have DST rules for this unknown zone)
+	//
+	iDstTimer->Cancel();
+
+	//Update kernel time and utc offset.
+	const TTimeIntervalSeconds newUtcOffset = aUTCOffset * KSecondsPerMinute;
+
+	//
+	// Cancel environment change notification in case double updating UTC offset.
+	//
+	iChangeNotifier->Cancel();   
+
+	TInt result = User::SetUTCTimeAndOffset(aUTCTime, newUtcOffset);
+	//
+	// Restart environment change notification.
+	//
+	iChangeNotifier->Start();
+
+	User::LeaveIfError(result);
+
+	TInt oldTzId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
+
+	// replace the rule, create an new unknown before deleting old
+	CTzId* timeZoneId = CTzId::NewL(KUnknownTZId);
+	CleanupStack::PushL(timeZoneId);
+
+	// CSystemTzRulesCache::NewL will create a default rule based on the offset in the Kernel
+	CSystemTzRulesCache* newZone = CSystemTzRulesCache::NewL(*timeZoneId, *this, aUTCTime);
+	CleanupStack::PushL(newZone);
+
+	delete iSystemTzCache;
+	iSystemTzCache = newZone;
+
+	if (aPersistInCenRep)
+		{
+		// Set the unknown time zone in central repository
+		// 0 is used to represent the Unknow time zone value although in the code KUnknownTZId is used
+		User::LeaveIfError(iRepository->Set(ETimeZoneKey, (TInt)KUnknownTZId));
+		}
+	else
+		{
+		// Set the unknown time zone in central repository
+		// 0 is used to represent the Unknow time zone value although in the code KUnknownTZId is used
+		User::LeaveIfError(iRepository->Set(ETimeZoneKey, 0));
+		}
+
+	CleanupStack::Pop(newZone);
+	CleanupStack::PopAndDestroy(timeZoneId);
+
+	iTzServer.NotifyTZStatusChange(RTz::ETZSystemTimeZoneChanged, static_cast<TAny*>(this));
+
+
+	NTzUpdate::TTimeZoneChange change;
+	change.iNewTimeZoneId = 0;
+	change.iOldTimeZoneId = oldTzId;
+
+	TPckgBuf<NTzUpdate::TTimeZoneChange> changeBuf(change);
+	RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ECurrentTimeZoneId, changeBuf);
+
+	iTzDataProvider->ReleaseTzRules();
+
+	return KErrNone;
+	}
+
+/**
+Gets the daylight saving update
+*/
+TInt CTzConfigAgent::AutoUpdateSetting()
+    {
+	return iEnabled;
+    }
+
+
+/**
+Observer method called as a result of a change in system time. Updates the UTC
+Offset and sets a new DST Change Timer as necessary.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::HandleSystemTimeChangeL()
+    {
+    HandleDstChangeTimerL();
+    }
+
+/**
+Observer method called as a result of a DST Change Timer completing. Updates
+the UTC Offset and sets a new DST Change Timer as necessary.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::HandleDstTimerCompleteL()
+    {
+    HandleDstChangeTimerL();
+    }
+
+/**
+Observer method called as a result of a DST Change Timer being cancelled. (The
+underlying RTimer is cancelled - for example, because of a change to the UTC
+offset.) This is not called when Cancel() or DoCancel() are called.) Updates
+the UTC Offset and sets a new DST Change Timer as necessary.
+
+@internalComponent
+
+*/
+void CTzConfigAgent::HandleDstTimerCancellationL()
+    {
+	HandleDstChangeTimerL();
+    }
+    
+/**
+Observer method called due to an error with the DST Change Timer that tries to
+recover from the error. We only expect this to get called with a value of
+KErrUnderflow (if the system time is changed to a time past the current timer)
+or a value of KErrOverflow as returned by RTimer.
+
+@param aError The error returned from the timer.
+@internalComponent
+
+*/
+void CTzConfigAgent::DstTimerErrorOccurredL(TInt aError)
+    {
+    // Remove the compiler warning about aError not being used. (It's useful in debugging.)
+    aError = aError;
+    
+    // Try and recover by updating the UTC Offset and setting a new 
+    // DST Change Timer as necessary.
+    HandleDstChangeTimerL();
+    }
+
+/**
+Environment observer callback - called when the kernel causes a system change.
+This can be used to pick up any changes when there is no DST Change Timer and
+may also provide a faster response to system time or locale changes.
+
+@param aSelf A pointer to this class.
+@return Always returns ETrue.
+@internalComponent
+
+*/
+TBool CTzConfigAgent::EnvironmentChangeCallBackL(TAny* aSelf)
+	{
+	CTzConfigAgent* self = static_cast<CTzConfigAgent*>(aSelf);
+
+	const TInt KChanges = self->iChangeNotifier->Change();
+	
+	if (KChanges == KErrCancel)
+	    {
+	    return ETrue;   // Observer is being cancelled.
+	    }
+
+    if (KChanges & (EChangesLocale | EChangesSystemTime))
+		{
+        // Update the UTC Offset and set a new DST Change Timer as necessary.
+        self->UpdateUtcOffsetL();
+        self->SetDstChangeTimerL();
+		}
+	    
+	return ETrue;
+	}
+	
+/** Reponding to the change in user defined time zone
+ 
+The CTzConfigAgent class maintains a cache of TZ rules (including actualised rules for 
+the last used rule) for the system (also known as current) TZ in the iSystemTzCache member
+and for a “foreign” TZ in the iOtherTzCache member.  Either of these members could be a cache
+of the TZ rules from a user-defined TZ.  If the associated user-defined TZ data is updated
+or deleted or a restore of user-defined TZ data has taken place then this cache needs to be
+updated appropriately.
+*/
+void CTzConfigAgent::NotifyUserTzRulesChange(TTzUserDataChange aChange)
+	{
+	TRAP_IGNORE(NotifyUserTzRulesChangeL(aChange));
+	}
+void CTzConfigAgent::NotifyUserTzRulesChangeL(TTzUserDataChange aChange)
+	{
+	//Only interested when a user TZ rule is updated or deleted
+	if (aChange.iOperation == ETzUserDataUpdated ||	aChange.iOperation == ETzUserDataDeleted)
+		{	
+		//Chached time zone (iOtherTzCache) should be cleaned off.
+		delete iOtherTzCache;
+		iOtherTzCache = NULL;
+		
+		TUint id = aChange.iTzId;
+		if(iSystemTzCache && id == iSystemTzCache->TimeZoneId().TimeZoneNumericID())	
+			{
+			CTzId* tzid = NULL;
+			if (aChange.iOperation == ETzUserDataUpdated)
+				{
+				//Cached symstem time zone (iSystemTzCache) should be updated.
+				tzid = CTzId::NewL(id);
+				}
+			else if (aChange.iOperation == ETzUserDataDeleted)
+				{//Cached symstem time zone (iSystemTzCache) should be reverted to the default time zone.
+				tzid = iTzDataProvider->GetDefaultTimeZoneIdL();
+				if(!tzid)
+					{
+					tzid = CTzId::NewL(KUnknownTZId);
+					}
+				}
+			CleanupStack::PushL(tzid);
+			SetTimeZoneL(*tzid, static_cast<TAny*>(this), ETrue, ETrue);	
+			CleanupStack::PopAndDestroy(tzid);	
+			}
+		}
+	}
+ 
+void CTzConfigAgent::NotifyUserTzNamesChange(TTzUserDataChange /*aChange*/)
+    {// There is no action needed when the names of a user defined time zone has been changed.
+    }
+  
+void CTzConfigAgent::AddObserverL(MTzDataObserver* aChangeObs)
+	{
+	User::LeaveIfError(iChangeObservers.Append(aChangeObs));
+	}
+
+void CTzConfigAgent::RemoveObserver(MTzDataObserver* aChangeObs)
+	{
+	TInt j = 0;
+	TInt jEnd = iChangeObservers.Count();
+	while (j < jEnd)
+		{
+		if (iChangeObservers[j] == aChangeObs)
+			{
+			iChangeObservers.Remove(j);
+			break;
+			}
+		++j;
+		}
+	}
+
+
+void CTzConfigAgent::BackupBeginningL()
+	{
+	iTzLocalizationDb->BackupBeginningL();
+	iTzDataProvider->BackupBeginningL();
+	}
+
+void CTzConfigAgent::BackupCompletedL()
+	{
+	iTzDataProvider->BackupCompletedL();
+	iTzLocalizationDb->BackupCompletedL();
+	}
+void CTzConfigAgent::RestoreBeginningL()
+	{
+	iTzLocalizationDb->RestoreBeginningL();
+	iTzDataProvider->RestoreBeginningL();
+	}
+
+void CTzConfigAgent::RestoreCompletedL(TInt aRestoreResult)
+	{
+	if(aRestoreResult == KErrNone)
+		{
+		//Both read only DB and user defined DB will refresh the data
+		iTzDataProvider->RestoreCompletedL();
+		
+		//Update cached tz rules
+		delete iOtherTzCache;
+ 		iOtherTzCache = NULL;
+
+		if(iSystemTzCache)
+			{
+			// Find out whether the cached system time zone rule still exists in
+			// the rules database.  If not, set the current time zone using the
+			// default time zone identifier.
+			TBool timeZoneExists = iTzDataProvider->IsIdInDbL(iSystemTzCache->TimeZoneId().TimeZoneNumericID());
+			if(timeZoneExists)
+				{
+				SetTimeZoneL(iSystemTzCache->TimeZoneId(), static_cast<TAny*>(this), EFalse, ETrue);
+				}
+			else
+				{
+				CTzId* tzid = iTzDataProvider->GetDefaultTimeZoneIdL();
+				CleanupStack::PushL(tzid);
+				SetTimeZoneL(*tzid, static_cast<TAny*>(this), EFalse, ETrue);
+				CleanupStack::PopAndDestroy(tzid);
+				}
+			}
+		
+		// Notify change to the clients.
+		iTzServer.NotifyTZStatusChange(RTz::ETZDatabaseChanged, static_cast<TAny*>(this));
+
+		// Notify the localization DB.
+		iTzLocalizationDb->RestoreCompletedL();
+		
+		//Publish tz rules change 
+		NTzUpdate::TTzRulesChange rulesChange;
+		rulesChange.iUTCTimeOfRulesChange.UniversalTime();
+		TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
+		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules);
+		
+		//Publish the names change for user defined DB
+		NTzUpdate::TTzNamesChange namesChange;
+		namesChange.iUTCTimeOfNamesChange.UniversalTime();
+		TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
+		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames);	
+		}
+	}
+//------------------------------------------------------------------------------------
+CTZRulesCache::~CTZRulesCache()
+	{
+	delete iTimeZoneId;		// time zone Id
+	delete iActualisedRules;// caches the last used rule for zone
+	delete iEncodedRules;
+	}
+
+// template method used for final construction of a time zone rules cache
+// this is the base implementation -- see ConstructL()
+void CTZRulesCache::SetDefaultZoneIdL()
+	{
+	// does nothing
+	User::Leave(KErrNotFound);
+	}
+
+const CTzRules& CTZRulesCache::doGetEncodedTimeZoneRulesL(TInt aStartYear, TInt aEndYear)
+	{
+	CTzDataProvider& tzDataProvider = iTimeZoneConfigAgent.TzDataProvider();
+	
+	CTzRules* newRules = CTzRules::NewL(aStartYear, aEndYear);
+	CleanupStack::PushL(newRules);
+	
+	tzDataProvider.GetTzRulesL(*newRules, *iTimeZoneId);
+
+
+	CleanupStack::Pop(newRules);
+	
+	// replace current cached rules
+	delete iEncodedRules;
+	iEncodedRules = newRules;
+	
+	return *iEncodedRules;
+	}
+	
+void CTZRulesCache::doGetActualisedTimeZoneRulesL(const TTime& aTime)
+	{
+	TDateTime dateTime(aTime.DateTime() );
+
+	// At least we need the rule for the year preceeding the converted time
+	// in order to convert the time to use it to find the correct rule. (Sounds roundabout!)
+	// hence the extra one added to the cache limit
+
+	// avoid over/under flow
+	TUint startYear = dateTime.Year();
+	TUint endYear = startYear;
+	if (startYear >= (KRuleCacheLowerLimit+1))
+		{
+		startYear -= (KRuleCacheLowerLimit+1);
+		}
+	if (endYear < (KMaxTUint - KRuleCacheUpperLimit))
+		{
+		endYear += KRuleCacheUpperLimit;
+		}
+
+	CVTzActualisedRules* newRules = CVTzActualisedRules::NewL(startYear, endYear);
+	CleanupStack::PushL(newRules);
+
+    iEncodedRules->GetActualisedRulesL(*newRules);
+
+	if (newRules->Count() == 0) // there will always be at least one rule
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CleanupStack::Pop(newRules);
+
+	// replace current cached rules
+	delete iActualisedRules;
+	iActualisedRules = newRules;
+	}
+	
+void CTZRulesCache::ConstructL(const CTzId& aTimeZoneId, const TTime& aTime)
+	{
+	if (aTimeZoneId.TimeZoneNumericID() != KUnknownTZId)
+		{
+		iTimeZoneId	= aTimeZoneId.CloneL();
+
+		TRAPD(err,doGetEncodedTimeZoneRulesL(KMinYear, KMaxYear));
+		if (err == KErrNotFound)
+			{
+			SetDefaultZoneIdL();	
+			}
+		else
+			{
+			User::LeaveIfError(err);
+	
+			// avoid over/under flow
+			TDateTime dateTime(aTime.DateTime() );
+			TUint startYear = dateTime.Year();
+			TUint endYear = startYear;
+			
+			if (startYear >= (KRuleCacheLowerLimit+1))
+				{
+				startYear -= (KRuleCacheLowerLimit+1);
+				}
+			if (endYear < (KMaxTUint - KRuleCacheUpperLimit))
+				{
+				endYear += KRuleCacheUpperLimit;
+				}
+		
+			iActualisedRules = CVTzActualisedRules::NewL(startYear, endYear);
+			iEncodedRules->GetActualisedRulesL(*iActualisedRules);
+			}
+		}
+	else
+		{
+		// Call Template Method to Set defaultZoneId
+		SetDefaultZoneIdL();
+		}
+	}
+
+
+CTZRulesCache* CTZRulesCache::NewL(const CTzId& aTimeZoneId,
+								CTzConfigAgent& aTimeZoneConfigAgent,
+								const TTime& aTime)
+	{
+	CTZRulesCache* self = new (ELeave) CTZRulesCache(aTimeZoneConfigAgent);
+	CleanupStack::PushL(self);
+
+	self->ConstructL(aTimeZoneId, aTime);
+
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CTzRules& CTZRulesCache::GetEncodedTimeZoneRulesL()
+	{
+	// return the rules held in cache
+	if (iEncodedRules == NULL)
+		{
+		User::Leave(KErrNotFound);
+		}
+	return *iEncodedRules;
+	}
+
+TInt CTZRulesCache::GetEncodedTimeZoneRulesSizeL(const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference /*aTimeRef */)
+	{
+	// fetch a new set of rules from the data provider if the range of the rules in iEncodedRules does not
+	// contain both aStartTime and aEndTime
+	if (
+		(iTimeZoneId->TimeZoneNumericID() != KUnknownTZId)
+		&&
+		( (iEncodedRules == NULL) || !(iEncodedRules->RulesApply(aStartTime)) || !(iEncodedRules->RulesApply(aEndTime) ) )
+	    )
+		{
+        TInt startYear = aStartTime.DateTime().Year();
+        TInt endYear = aEndTime.DateTime().Year();
+		doGetEncodedTimeZoneRulesL(startYear, endYear);
+		}
+
+	if (iEncodedRules)
+		{
+		return iEncodedRules->Count() * sizeof (TTzRule) + sizeof (CTzRules);
+		}
+	else
+		{
+		return 0;
+		}
+	}
+
+CVTzActualisedRules& CTZRulesCache::GetTimeZoneRulesL(const TTime& aTime,TTzTimeReference aTimerRef)
+	{
+    if ((iTimeZoneId->TimeZoneNumericID() != KUnknownTZId) 
+		&& (!(RuleApplies(*iActualisedRules, aTime, aTimerRef))))
+		{
+		doGetActualisedTimeZoneRulesL(aTime);
+		}
+	return *iActualisedRules;
+	}
+
+/** 
+Tests if the period covered by the cached rules applies to the supplied time.
+*/
+TBool CTZRulesCache::RuleApplies(CVTzActualisedRules& actRules, 
+    const TTime& aTime, TTzTimeReference aTimerRef) const 
+	{
+	TInt startYear = actRules.StartYear();
+	TInt endYear = actRules.EndYear();
+	
+	TDateTime dateTime(aTime.DateTime());
+	
+	__ASSERT_ALWAYS(aTimerRef!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
+	
+	// aTime may be in UTC or wall time. If aTime is provided
+	// in wall time the range which is checked will be reduced by one year
+	// on either side, to avoid false inclusions. eg. If the time zone was
+	// Japan and the date passed in here was Jan 1st at 6:00 local time,
+	// that would be a different year in UTC time. This will result
+	// in more fetches to the database in some cases, but the alternative
+	// is to iterate through all the rules every time this method is called
+	// to find the matching rule, which is not very efficent in itself.
+
+	if (aTimerRef == ETzWallTimeReference)
+		{
+		// This reduces the range that is checked. For example, if the
+		// actualised rules are from 2000 to 2006, this will
+		// check Jan 2001 to Jan 2006
+		startYear++;
+		}
+	else
+		{
+		// This checks the whole range. For example, if the
+		// actualised rules are from 2000 to 2006, this will
+		// check Jan 2000 to Jan 2007
+		endYear++; 
+		}
+		
+	const TTime KStart(TDateTime(startYear, EJanuary, 0, 0, 0, 0, 0));
+	const TTime KEnd(TDateTime(endYear, EJanuary, 0, 0, 0, 0, 0));
+	return ((aTime >= KStart) && (aTime < KEnd));
+	}
+
+//------------------------------------------------------------------------------------
+//
+CSystemTzRulesCache::~CSystemTzRulesCache()
+	{
+	// does nothing
+	}
+
+
+void CSystemTzRulesCache::SetDefaultZoneIdL()
+	{
+	// default to old TLocale DST Rule
+	delete iTimeZoneId;
+	iTimeZoneId = NULL;
+	iTimeZoneId = CTzId::NewL(KUnknownTZName);
+	iTimeZoneId->SetId(KUnknownTZId);
+
+	// The UTC Offset combines both the standard and the dst offset
+	TInt stdOffset = User::UTCOffset().Int() / KSecondsPerMinute;
+		
+	// create a default std only encoded rule
+	delete iEncodedRules;
+	iEncodedRules = NULL;
+	iEncodedRules = CTzRules::NewL(KMinYear,KMaxYear);
+	TTimeWithReference timeRef;
+	TTimeWithReference timeRef2(TTimeWithReference::Max());
+	TTzRule encodedRule(timeRef, timeRef2,stdOffset,stdOffset,EJanuary,ETzFixedDate,0,0,ETzWallTimeReference,0);
+	iEncodedRules->AddRuleL(encodedRule);
+	
+	delete iActualisedRules;
+	iActualisedRules = NULL;
+	iActualisedRules = CVTzActualisedRules::NewL(KMinYear, KMaxYear);
+    iEncodedRules->GetActualisedRulesL(*iActualisedRules);
+	}
+
+
+CSystemTzRulesCache* CSystemTzRulesCache::NewL(const CTzId& aTimeZoneId,
+								CTzConfigAgent& aTimeZoneConfigAgent,
+								const TTime& aTime)
+	{
+	CSystemTzRulesCache* self = new (ELeave) CSystemTzRulesCache(aTimeZoneConfigAgent);
+	CleanupStack::PushL(self);
+
+	self->ConstructL(aTimeZoneId, aTime);
+
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+
+//------------------------------------------------------------------------------------
+// CDstEventNotifier
+//
+
+/**
+Creates a new instance of CDstEventNotifier on the heap.
+
+@param aObserver the observer of the timer.
+@return CDstEventNotifier* the instance created.
+@internalComponent
+
+*/
+CDstEventNotifier* CDstEventNotifier::NewL(MDstEventObserver& aObserver)
+    {
+	CDstEventNotifier* self = new (ELeave) CDstEventNotifier(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();     // Construct CTimer.
+	CActiveScheduler::Add(self);
+	CleanupStack::Pop(self);
+	return self;
+    }
+    
+/**
+Sets a new DST Change Timer at the given time.
+
+@param aUtcTime the UTC time of the DST event.
+@internalComponent
+
+*/
+void CDstEventNotifier::SetTimer(const TTime& aUtcTime)
+    {
+    // Cancel any existing timer
+    Cancel();
+	// Start the new timer.
+	AtUTC(aUtcTime);
+    }
+    
+/**
+Constructor.
+
+@param aObserver the observer of the timer.
+@internalComponent
+
+*/
+CDstEventNotifier::CDstEventNotifier(MDstEventObserver& aObserver)
+ :  CTimer(EPriorityStandard),
+    iObserver(aObserver)
+    {
+    }
+
+/**
+Called when the timer completes. The observer is notified.
+
+@internalComponent
+
+*/
+void CDstEventNotifier::RunL()
+    {
+    // Notify the observer.
+    // Notifications based on the behaviour of RTimer
+
+    switch (iStatus.Int())
+        {
+        case KErrNone:
+            // The timer completed normally at the requested time.
+            iObserver.HandleDstTimerCompleteL();
+            break;
+        case KErrAbort:
+            // The timer was aborted because the system time changed.
+			// This is taken care of by the environment change notifier
+			// but is still handled to avoid falling into the default case 
+			// and setting the alarm twice for each locale/time change.
+            break;
+        case KErrCancel:
+            // The timer was cancelled.
+            iObserver.HandleDstTimerCancellationL();
+            break;
+        default:
+            // KErrUnderflow, KErrOverflow may be expected if an out-of-range timer is set.
+            iObserver.DstTimerErrorOccurredL(iStatus.Int());
+            break;
+        }
+    }
+    
+/**
+Called if RunL leaves.
+
+@internalComponent
+
+*/
+TInt CDstEventNotifier::RunError(TInt aError)
+    {
+    // Just return the error.
+    return aError;
+    }
+
+/**
+Cancels any existing timer.
+
+@internalComponent
+
+*/
+void CDstEventNotifier::DoCancel()
+    {
+    // Cancel the timer.   
+    CTimer::DoCancel();
+    
+    // Do not notify the observer here as it will create an infinite loop!
+    // Cancellation of the RTimer is notified in RunL() with a status of KErrCancel.
+    // That is what MDstEventObserver::HandleDstTimerCancellationL() is for.
+    }