tzservices/tzserver/Server/Source/timezoneconfig.cpp
changeset 0 2e3d3ce01487
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <bacntf.h>             // CEnvironmentChangeNotifier.
       
    17 #include <centralrepository.h>  // CRepository.
       
    18 #include "tzconfigagent.h"
       
    19 #include "dataprovider.h"
       
    20 #include <tzupdate.h>   // auto-update notification constants.
       
    21 #include <vtzrules.h>
       
    22 #include "tzpersisted.h"
       
    23 #include "tzlocalizationdb.h"
       
    24 #include <bautils.h>
       
    25 #include "cbackuprestorenotification.h"
       
    26 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    27 #include <tzuserdefineddata.h>
       
    28 #endif
       
    29 
       
    30 _LIT8(KUnknownTZName, "Unknown/Zone");
       
    31 
       
    32 const TUint32 KUnknownTZId = 0x0ffffff0;
       
    33 const TInt KSecondsPerMinute = 60;
       
    34 
       
    35 _LIT(KTimeStamps, "c:\\private\\1020383e\\timestamps");
       
    36 _LIT(KTzDbFileNameFlash,"c:\\private\\1020383e\\TZDB.DBZ");
       
    37 _LIT(KUserDatabaseName, "c:\\private\\1020383e\\SQLite__tzuserdata.db");
       
    38 _LIT(KResourceDir, "c:\\resource\\timezonelocalization\\");
       
    39 
       
    40 // specifies the limits for rules caching.
       
    41 // (year - KRuleCacheLowerLimit) , (year + KRuleCacheUpperLimit)
       
    42 // the actual cache includes one more year at year - (KRuleCacheLowerLimit + 1)
       
    43 // required to provide the offset used at the start of the search 
       
    44 const TUint KRuleCacheLowerLimit = 2;
       
    45 const TUint KRuleCacheUpperLimit = 3;
       
    46 
       
    47 // Security policy for the Publish and Subscribe auto-update notification property.
       
    48 const TInt KServerUid = 0x1020383E;
       
    49 const TInt KNextDSTChangePropertyKey(0x10285B32);
       
    50 _LIT_SECURITY_POLICY_PASS(KReadPolicy);
       
    51 _LIT_SECURITY_POLICY_S0(KWritePolicy, KServerUid);
       
    52 
       
    53 
       
    54 CTzConfigAgent::~CTzConfigAgent()
       
    55 	{
       
    56 	// Flag that the server is shutting down so that we don't try and set 
       
    57 	// a new DST Change Timer when the current one is cancelled.
       
    58 	iShuttingDown = ETrue;
       
    59 	
       
    60 	delete iTzDataProvider;
       
    61 
       
    62     // Cancel any exitsing timer.
       
    63     if (iDstTimer)
       
    64         {
       
    65         iDstTimer->Cancel();
       
    66         delete iDstTimer;
       
    67         }
       
    68         
       
    69 	delete iSystemTzCache;
       
    70 	delete iOtherTzCache;
       
    71 	delete iRepository;
       
    72 	delete iChangeNotifier;
       
    73 	delete iBackupNotifier;
       
    74 	iTzSwiObserver.RemoveObserver(this);
       
    75 	iChangeObservers.Close();
       
    76 	iFs.Close();
       
    77 	}
       
    78 
       
    79 /*
       
    80 */
       
    81 CTzConfigAgent::CTzConfigAgent(MTZCfgAgentObserver& aServer, CTzUserDataDb& aTzUserDataDb,
       
    82 		CTzSwiObserver& aTzSwiObserver) 
       
    83 	: iTzServer(aServer),
       
    84 	iEnabled(RTz::ETZAutoDSTUpdateOn),
       
    85 	iTzSwiObserver(aTzSwiObserver), 
       
    86 	iShuttingDown(EFalse), 
       
    87 	iTzUserDataDb(aTzUserDataDb)
       
    88 	{
       
    89 	}
       
    90 /*
       
    91 */
       
    92 void CTzConfigAgent::ConstructL()
       
    93 	{
       
    94 	User::LeaveIfError(iFs.Connect());
       
    95 
       
    96 	// Define a property using Publish and Subscribe.
       
    97 	// ** Note that the value of this property is unimportant - setting it
       
    98 	// (to any value) counts as a notification, so we do not set it here.
       
    99     TInt err = RProperty::Define(
       
   100         NTzUpdate::EUtcOffsetChangeNotification,
       
   101         RProperty::EInt,
       
   102 	    KReadPolicy,
       
   103 	    KWritePolicy);
       
   104 	    
       
   105 	if (err != KErrAlreadyExists)
       
   106 	    {
       
   107 	    User::LeaveIfError(err);
       
   108 	    }
       
   109 	    
       
   110     err = RProperty::Define(
       
   111         NTzUpdate::ECurrentTimeZoneId,
       
   112         RProperty::EByteArray,
       
   113 	    KReadPolicy,
       
   114 	    KWritePolicy);
       
   115 	    
       
   116 	if (err != KErrAlreadyExists)
       
   117 	    {
       
   118 	    User::LeaveIfError(err);
       
   119 	    }
       
   120  
       
   121     err = RProperty::Define(
       
   122         NTzUpdate::EHomeTimeZoneId,
       
   123         RProperty::EByteArray,
       
   124 	    KReadPolicy,
       
   125 	    KWritePolicy);
       
   126 	    
       
   127 	if (err != KErrAlreadyExists)
       
   128 	    {
       
   129 	    User::LeaveIfError(err);
       
   130 	    }
       
   131 
       
   132 	err = RProperty::Define(
       
   133         NTzUpdate::ETzRulesChange,
       
   134         RProperty::EByteArray,
       
   135 	    KReadPolicy,
       
   136 	    KWritePolicy);
       
   137 	
       
   138 	if (err != KErrAlreadyExists)
       
   139 	    {
       
   140 	    User::LeaveIfError(err);
       
   141 	    }
       
   142  
       
   143     err = RProperty::Define(
       
   144         NTzUpdate::ETzNamesChange,
       
   145         RProperty::EByteArray,
       
   146 	    KReadPolicy,
       
   147 	    KWritePolicy);
       
   148 	    
       
   149 	if (err != KErrAlreadyExists)
       
   150 	    {
       
   151 	    User::LeaveIfError(err);
       
   152 	    }
       
   153 
       
   154 	iTzDataProvider = CTzDataProvider::NewL(iFs, iTzSwiObserver, iTzUserDataDb,
       
   155 		*this);
       
   156 	
       
   157 	iDstTimer = CDstEventNotifier::NewL(*this);
       
   158 		
       
   159     iRepository = CRepository::NewL(NTzUpdate::KPropertyCategory);
       
   160 
       
   161 	// Get the DST auto-update configuration value from the repository.
       
   162     User::LeaveIfError(iRepository->Get(EConfigurationKey, iEnabled));
       
   163 
       
   164 	// Get the current time zone from the repository.
       
   165 	TInt timeZoneIdentity(0);
       
   166     User::LeaveIfError(iRepository->Get(ETimeZoneKey, timeZoneIdentity));
       
   167 
       
   168 	// Extract the current time zone identifier.  This is stored in the bits
       
   169 	// not occupied by the old TLocale DST settings.
       
   170 	TUint localeZone = timeZoneIdentity & ~(EDstHome | EDstEuropean |
       
   171 		EDstNorthern | EDstSouthern);
       
   172 
       
   173 	// If the current time zone identifier is set (non-zero) then check that
       
   174 	// this zone exists. 
       
   175     TBool timeZoneExists = EFalse;
       
   176     if (localeZone > 0)
       
   177     	{
       
   178     	timeZoneExists = iTzDataProvider->IsIdInDbL(localeZone);
       
   179     	}
       
   180     
       
   181     CTzId* timeZoneId = NULL;
       
   182     if(timeZoneExists)
       
   183     	{
       
   184     	// Use the current time zone identifier obtained from the repository.
       
   185     	timeZoneId = CTzId::NewL(localeZone);
       
   186     	}
       
   187     else 
       
   188 		{
       
   189 		// Either the current time zone is not set in the repository or it is
       
   190 		// and the time zone does not exist.  In either case we need to use the
       
   191 		// default time zone identifier.
       
   192         timeZoneId = iTzDataProvider->GetDefaultTimeZoneIdL();
       
   193         if (!timeZoneId)
       
   194             {
       
   195             // If we cannot obtain the default time zone identifier then use the
       
   196             // "unknown" time zone identifier as a fallback solution.
       
   197 		    timeZoneId = CTzId::NewL(KUnknownTZId);
       
   198             }  
       
   199   		}
       
   200 
       
   201     CleanupStack::PushL(timeZoneId);
       
   202 
       
   203 	// Setting the time zone updates the UTC offset and sets a new DST change
       
   204 	// timer if required.
       
   205 	SetTimeZoneL(*timeZoneId, static_cast<TAny*>(this), ETrue);
       
   206 
       
   207 	CleanupStack::PopAndDestroy(timeZoneId);
       
   208 	
       
   209 	// Create and start the environment change notifier.
       
   210 	iChangeNotifier = CEnvironmentChangeNotifier::NewL(CActive::EPriorityIdle, TCallBack(EnvironmentChangeCallBackL, this));
       
   211 	iChangeNotifier->Start();
       
   212 
       
   213 	TRAP_IGNORE(PublishNewDstChangeInfoL());
       
   214 
       
   215 	iTzSwiObserver.AddObserverL(this);
       
   216 
       
   217 	// Create backup notifier.  Note that file name argument is unimportant.
       
   218 	iBackupNotifier = CBackupRestoreNotification::NewL(KTzDbFileNameFlash(),*this);
       
   219 
       
   220 	// Publish any changes that may have happened to TZ databases or resources
       
   221 	// while the TZ Server was not running.
       
   222 	PublishTzDbChangeInfoL();
       
   223 	}
       
   224 
       
   225 void CTzConfigAgent::PublishTzDbChangeInfoL()
       
   226 	{
       
   227 	RFile file;
       
   228 	CleanupClosePushL(file);
       
   229 
       
   230 	TTime tzDbModified = Time::NullTTime();
       
   231 	TTime userDbModified = Time::NullTTime();
       
   232 	TTime resourceFileModified = Time::NullTTime();
       
   233 
       
   234 	TInt err = file.Open(iFs, KTimeStamps, EFileRead | EFileWrite);
       
   235 	if(err == KErrNone || err == KErrNotFound)
       
   236 		{
       
   237 		//Read time stamps
       
   238 		TInt err1 = iFs.Modified(KTzDbFileNameFlash, tzDbModified);
       
   239 		if(err1 != KErrNone && err1 != KErrNotFound)
       
   240 			{
       
   241 			User::Leave(err1);
       
   242 			}
       
   243 		err1 = iFs.Modified(KUserDatabaseName, userDbModified);
       
   244 		if(err1 != KErrNone && err1 != KErrNotFound)
       
   245 			{
       
   246 			User::Leave(err1);
       
   247 			}
       
   248 		resourceFileModified = GetResourceFileTimeStampsL();
       
   249 		}
       
   250 	else
       
   251 		{
       
   252 		User::Leave(err);
       
   253 		}
       
   254 	
       
   255 	TBool tzRuleChanged = EFalse;
       
   256 	TBool tzNameChanged = EFalse;
       
   257 	
       
   258 	TTime tzDbSaved = Time::NullTTime();
       
   259 	TTime userDbSaved  = Time::NullTTime();
       
   260 	TTime resourceFileSaved  = Time::NullTTime();
       
   261 
       
   262 	if (err == KErrNone)
       
   263 		{
       
   264 		ReadTimeStampsL(file, tzDbSaved, userDbSaved, resourceFileSaved);
       
   265 
       
   266 		if(tzDbModified != tzDbSaved)
       
   267 			{
       
   268 			tzRuleChanged = ETrue;		
       
   269 			}
       
   270 		if(userDbModified != userDbSaved)
       
   271 			{
       
   272 			tzRuleChanged = ETrue;
       
   273 			tzNameChanged = ETrue;
       
   274 			}
       
   275 		if(resourceFileModified != resourceFileSaved)
       
   276 			{
       
   277 			tzNameChanged = ETrue;		
       
   278 			}
       
   279 		}
       
   280 	else//err == KErrNotFound
       
   281 		{//Always publish the changes if the time stamps file is not there
       
   282 		tzRuleChanged = ETrue;
       
   283 		tzNameChanged = ETrue;
       
   284 		}
       
   285 	
       
   286 	if(tzRuleChanged || tzNameChanged)
       
   287 		{//Rewrite all three times
       
   288 		User::LeaveIfError(file.Replace(iFs, KTimeStamps, EFileRead | EFileWrite));
       
   289 		WriteTimeStampsL(file, tzDbModified, userDbModified, resourceFileModified);
       
   290 		}
       
   291 	CleanupStack::PopAndDestroy(&file); // file.Close()
       
   292 	
       
   293 	if (tzRuleChanged || tzNameChanged)
       
   294 		{
       
   295 		iTzDbHasChanged = ETrue;
       
   296 		if (tzRuleChanged)
       
   297 			{
       
   298 			//Publish the tz rules change
       
   299 			NTzUpdate::TTzRulesChange rulesChange;
       
   300 			rulesChange.iUTCTimeOfRulesChange.UniversalTime();
       
   301 			TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
       
   302 			RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules);
       
   303 			}
       
   304 	
       
   305 		if(tzNameChanged )
       
   306 			{
       
   307 			//Publish the names change for user defined DB or resource file change
       
   308 			NTzUpdate::TTzNamesChange namesChange;
       
   309 			namesChange.iUTCTimeOfNamesChange.UniversalTime();
       
   310 			TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
       
   311 			RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames);	
       
   312 			}
       
   313 		}
       
   314 	}
       
   315 
       
   316 void CTzConfigAgent::ReadTimeStampsL(RFile& aFile, TTime& aTzdbSaved, TTime& aUserDbSaved, TTime& aResourceFileSaved)
       
   317 	{
       
   318 	RFileReadStream readStream(aFile);
       
   319 	CleanupClosePushL(readStream);
       
   320 	
       
   321 	TUint32 low = readStream.ReadUint32L();
       
   322 	TUint32 high = readStream.ReadUint32L();
       
   323 	aTzdbSaved = TTime(MAKE_TINT64(high, low));
       
   324 
       
   325 	low = readStream.ReadUint32L();
       
   326 	high = readStream.ReadUint32L();
       
   327 	aUserDbSaved = TTime(MAKE_TINT64(high, low));
       
   328 
       
   329 	low = readStream.ReadUint32L();
       
   330 	high = readStream.ReadUint32L();
       
   331 	aResourceFileSaved = TTime(MAKE_TINT64(high, low));
       
   332 	CleanupStack::PopAndDestroy(&readStream);
       
   333 	}
       
   334 
       
   335 void CTzConfigAgent::WriteTimeStampsL(RFile& aFile, const TTime& aTzdbModified, const TTime& aUserDbModified, const TTime& aResourceFileModified)
       
   336 	{
       
   337 	RFileWriteStream writeStream(aFile);
       
   338 	CleanupClosePushL(writeStream);
       
   339 	writeStream << I64LOW(aTzdbModified.Int64());
       
   340 	writeStream << I64HIGH(aTzdbModified.Int64());
       
   341 	writeStream << I64LOW(aUserDbModified.Int64());
       
   342 	writeStream << I64HIGH(aUserDbModified.Int64());
       
   343 	writeStream << I64LOW(aResourceFileModified.Int64());
       
   344 	writeStream << I64HIGH(aResourceFileModified.Int64());
       
   345 	writeStream.CommitL();
       
   346 	CleanupStack::PopAndDestroy(&writeStream);
       
   347 	}
       
   348 
       
   349 /* Get the sum of time stamps of time zone resource files 
       
   350  * It returns Time::NullTTime() if there is no resorece files in the "c:\\resource\\timezonelocalization\\" 
       
   351  */
       
   352 TTime  CTzConfigAgent::GetResourceFileTimeStampsL()
       
   353 	{
       
   354 	CDir* files = NULL;
       
   355 	TInt err = iFs.GetDir(KResourceDir, KEntryAttNormal, ESortNone, files);
       
   356 	CleanupStack::PushL(files);
       
   357 	TInt64 sum = 0;
       
   358 	if(err != KErrNone && err != KErrNotFound && err != KErrPathNotFound)
       
   359 		{
       
   360 		User::Leave(err);
       
   361 		}
       
   362 	if(files)
       
   363 		{
       
   364 		TInt count = files->Count();
       
   365 		for(TInt ii = 0; ii < count; ++ii)
       
   366 			{
       
   367 			const TEntry& entry = (*files)[ii];
       
   368 			sum = sum + entry.iModified.Int64();
       
   369 			}
       
   370 		}
       
   371 	CleanupStack::PopAndDestroy(files);
       
   372 	if(sum==0)
       
   373 		{
       
   374 		return Time::NullTTime();
       
   375 		}
       
   376 	return TTime(sum);
       
   377 	}
       
   378 
       
   379 void CTzConfigAgent::PublishNewDstChangeInfoL()
       
   380 	{
       
   381     TInt propertyDefineError = RProperty::Define(KUidSystemCategory,
       
   382     												KNextDSTChangePropertyKey,
       
   383     												RProperty::EByteArray,
       
   384     												KReadPolicy,
       
   385     												KWritePolicy,
       
   386 													sizeof(NTzUpdate::TDSTChangeInfo));
       
   387 
       
   388 	if (propertyDefineError != KErrAlreadyExists)
       
   389 		{
       
   390 	    // if there was an actual error defining the property then we should leave
       
   391 		User::LeaveIfError(propertyDefineError);
       
   392 		}
       
   393 	
       
   394     // create the next DST change and set some default values
       
   395     NTzUpdate::TDSTChangeInfo newDSTChangeInfo;
       
   396     newDSTChangeInfo.iVersion = 2;
       
   397 	
       
   398 	if ( CalculateNextDstChangeL(newDSTChangeInfo.iNextDSTChangeUTC, newDSTChangeInfo.iPreviousDSTChangeUTC) 
       
   399 		&& (iEnabled == RTz::ETZAutoDSTUpdateOn) )
       
   400 		{
       
   401 		// There is a future DST change in this time zone and auto DST updates are on
       
   402 		CVTzActualisedRules& actualisedRules = GetTimeZoneRulesL(newDSTChangeInfo.iNextDSTChangeUTC, ETzUtcTimeReference);
       
   403 		newDSTChangeInfo.iNextUTCOffset = actualisedRules.GetOffsetFromRuleL(newDSTChangeInfo.iNextDSTChangeUTC, ETzUtcTimeReference);
       
   404 		newDSTChangeInfo.iPreviousUTCOffset = actualisedRules.GetOffsetFromRuleL(newDSTChangeInfo.iPreviousDSTChangeUTC-TTimeIntervalMinutes(1), ETzUtcTimeReference);
       
   405 		}
       
   406 	else
       
   407 		{
       
   408 		newDSTChangeInfo.iNextDSTChangeUTC = Time::NullTTime();
       
   409 		newDSTChangeInfo.iNextUTCOffset = 0;
       
   410 		newDSTChangeInfo.iPreviousDSTChangeUTC = Time::NullTTime();
       
   411 		newDSTChangeInfo.iPreviousUTCOffset = 0;
       
   412 		}
       
   413 	
       
   414 	// get the current value that is published
       
   415 	TPckgBuf<NTzUpdate::TDSTChangeInfo> currentNextDSTChangeBuf;
       
   416 	User::LeaveIfError(RProperty::Get(KUidSystemCategory, KNextDSTChangePropertyKey, currentNextDSTChangeBuf));
       
   417 	
       
   418 	// Publish if the next DST change is different from the previous version
       
   419 	if ((currentNextDSTChangeBuf().iNextUTCOffset != newDSTChangeInfo.iNextUTCOffset)
       
   420 		|| (currentNextDSTChangeBuf().iNextDSTChangeUTC != newDSTChangeInfo.iNextDSTChangeUTC)
       
   421 		|| (currentNextDSTChangeBuf().iPreviousUTCOffset != newDSTChangeInfo.iPreviousUTCOffset)
       
   422 		|| (currentNextDSTChangeBuf().iPreviousDSTChangeUTC != newDSTChangeInfo.iPreviousDSTChangeUTC)
       
   423 		|| (propertyDefineError != KErrAlreadyExists))
       
   424 		{
       
   425 		// package the data and set the property value 
       
   426 		TPckgBuf<NTzUpdate::TDSTChangeInfo> newDSTChangeInfoBuf(newDSTChangeInfo);
       
   427 	    User::LeaveIfError(RProperty::Set(KUidSystemCategory, KNextDSTChangePropertyKey, newDSTChangeInfoBuf));
       
   428 		}
       
   429 	}
       
   430 
       
   431 /*
       
   432 */
       
   433 CTzConfigAgent* CTzConfigAgent::NewL(MTZCfgAgentObserver& aServer, CTzUserDataDb& aUserDataDb,
       
   434 		CTzSwiObserver& aTzSwiObserver)
       
   435 	{
       
   436 	CTzConfigAgent* self = new(ELeave) CTzConfigAgent(aServer, aUserDataDb, aTzSwiObserver);
       
   437 	CleanupStack::PushL(self);
       
   438 	self->ConstructL();
       
   439 	CleanupStack::Pop(self);		
       
   440 	return self;
       
   441 	}
       
   442 
       
   443 const CTzId& CTzConfigAgent::GetTimeZoneIdL() const
       
   444 	{
       
   445 	if (!iSystemTzCache)
       
   446 		{
       
   447 		User::Leave(KErrNotFound);
       
   448 		}
       
   449 
       
   450 	return iSystemTzCache->TimeZoneId();
       
   451 	}
       
   452 
       
   453 const CTzId& CTzConfigAgent::SetTimeZoneL(const CTzId& aZoneId, const TAny* aRequester, TBool aUpdateCentralRepository, TBool aForceCacheUpdate)
       
   454 	{
       
   455 	TInt oldTzId = 0;
       
   456 	TBool zoneChanged = EFalse;
       
   457 	TTime now;
       
   458 	now.UniversalTime();
       
   459 
       
   460 	if (!iSystemTzCache)
       
   461 		{
       
   462 		iSystemTzCache = CSystemTzRulesCache::NewL(aZoneId, *this, now);
       
   463 		}
       
   464 	else if (iSystemTzCache->TimeZoneId() == aZoneId && !aForceCacheUpdate)
       
   465 		{
       
   466 		return (iSystemTzCache->TimeZoneId());
       
   467 		}
       
   468 	else
       
   469 		{
       
   470 		oldTzId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
       
   471 		// replace the rule. create new before deleting old
       
   472 		CSystemTzRulesCache* newZone = CSystemTzRulesCache::NewL(aZoneId, *this, now);
       
   473 		CleanupStack::PushL(newZone);
       
   474 		
       
   475 		//For Invalid Timezone, rules doesnot exist 
       
   476 		CTzRules& newZoneRules =  newZone->GetEncodedTimeZoneRulesL();
       
   477 		if (newZoneRules.Count() == 0)
       
   478 		    {
       
   479 		    User::Leave(KErrNotFound);
       
   480 		    }
       
   481 
       
   482 		delete iSystemTzCache;
       
   483 		iSystemTzCache = newZone;
       
   484 
       
   485 		CleanupStack::Pop(newZone);
       
   486 		zoneChanged = ETrue;
       
   487 		}
       
   488 
       
   489 	TInt offset = iSystemTzCache->Rules().GetOffsetFromRuleL(now, ETzUtcTimeReference);
       
   490 		
       
   491 	// We need to publish an automatic time update event 
       
   492 	// Stop the auto time update observer and
       
   493 	// remove the published auto-update time.
       
   494 	// if the old and new timezone ids are the same but
       
   495 	// the new offset differs from what was originally there
       
   496 
       
   497 	if (iSystemTzCache->TimeZoneId().TimeZoneNumericID() != KUnknownTZId)
       
   498 		{
       
   499 		// Now set the new time zone and new UTC Offset.
       
   500 		TInt TimeZoneIdentity((TDaylightSavingZone)(iSystemTzCache->TimeZoneId().TimeZoneNumericID()));
       
   501 		
       
   502  		if(aUpdateCentralRepository)
       
   503 			{
       
   504 			// Set the currently used time zone from central repository
       
   505 			User::LeaveIfError(iRepository->Set(ETimeZoneKey, TimeZoneIdentity));	
       
   506 			}
       
   507             
       
   508         // Set the new UTC Offset.
       
   509 		const TTimeIntervalSeconds newUtcOffset = offset * KSecondsPerMinute;
       
   510 		User::SetUTCOffset(newUtcOffset);
       
   511 
       
   512 		// replace cached current time zone
       
   513 		if (zoneChanged)
       
   514 			{
       
   515 			iTzServer.NotifyTZStatusChange(RTz::ETZSystemTimeZoneChanged, aRequester);
       
   516 			}
       
   517 
       
   518 // Do not publish updates or set timers if compiled as part of
       
   519 // the unit test as this will conflict with the Time Zone Server.
       
   520 #ifndef SYMBIAN_TZ_UNIT_TEST
       
   521 
       
   522         // Publish UTC Offset and set DST Change Timer if configured.
       
   523         // Note that it would make sense to always publish the UTC Offset here (if it
       
   524         // changes) as this is not a change due to the auto-update functionality, but 
       
   525         // this would make the PREQ 234 changes only partly configurable.
       
   526         if (iEnabled == RTz::ETZAutoDSTUpdateOn)
       
   527             {
       
   528             // Set a new DST Change Timer if required.
       
   529             SetDstChangeTimerL();
       
   530             }
       
   531 #endif  // SYMBIAN_TZ_UNIT_TEST
       
   532 
       
   533 		NTzUpdate::TTimeZoneChange change;
       
   534 		change.iNewTimeZoneId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
       
   535 		change.iOldTimeZoneId = oldTzId;
       
   536 		
       
   537 		TPckgBuf<NTzUpdate::TTimeZoneChange> changeBuf(change);
       
   538 		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ECurrentTimeZoneId, changeBuf);
       
   539 		}
       
   540 	
       
   541 	iTzDataProvider->ReleaseTzRules();
       
   542 	
       
   543 	TRAP_IGNORE(PublishNewDstChangeInfoL());
       
   544 	
       
   545 	return (iSystemTzCache->TimeZoneId());
       
   546 	}
       
   547 
       
   548 CTzRules& CTzConfigAgent::GetEncodedTimeZoneRulesL()
       
   549 	{
       
   550 	return iSystemTzCache->GetEncodedTimeZoneRulesL();
       
   551 	}
       
   552 
       
   553 TInt CTzConfigAgent::GetEncodedTimeZoneRulesSizeL(const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference aTimeRef)
       
   554 	{
       
   555 	TInt size = iSystemTzCache->GetEncodedTimeZoneRulesSizeL(aStartTime, aEndTime, aTimeRef);
       
   556 	iTzDataProvider->ReleaseTzRules();
       
   557 	return size;
       
   558 	}
       
   559 
       
   560 CTzRules& CTzConfigAgent::GetForeignEncodedTimeZoneRulesL()
       
   561 	{
       
   562 	if (iOtherTzCache == NULL)
       
   563 		{
       
   564 		User::Leave(KErrNotFound);
       
   565 		}
       
   566 		
       
   567 	return iOtherTzCache->GetEncodedTimeZoneRulesL();
       
   568 	}
       
   569 		
       
   570 TInt CTzConfigAgent::GetForeignEncodedTimeZoneRulesSizeL(const CTzId& aZoneId, const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference aTimeRef)
       
   571 	{
       
   572 	if (!iOtherTzCache)
       
   573 		{
       
   574 		iOtherTzCache = CTZRulesCache::NewL(aZoneId, *this, aStartTime);
       
   575 		}
       
   576 	else if (iOtherTzCache->TimeZoneId() != aZoneId)
       
   577 		{
       
   578 		// ids are different.
       
   579 		// replace the rule. create new before deleting old
       
   580 		CTZRulesCache* newZone = CTZRulesCache::NewL(aZoneId, *this, aStartTime);
       
   581 
       
   582 		delete iOtherTzCache;
       
   583 		iOtherTzCache = newZone;
       
   584 		}
       
   585 
       
   586 	TInt size = iOtherTzCache->GetEncodedTimeZoneRulesSizeL(aStartTime, aEndTime, aTimeRef);
       
   587 	iTzDataProvider->ReleaseTzRules();
       
   588 	return size; 
       
   589 	}
       
   590 										
       
   591 #if defined(_DEBUG)
       
   592 /**
       
   593 Required for OOM testing.  To obtain a balanced heap cell count check we need to
       
   594 reset any cached foreign time zone rules.
       
   595 */
       
   596 void CTzConfigAgent::ResetForeignTimeZoneRulesCache(void)
       
   597 	{
       
   598 	delete iOtherTzCache;
       
   599 	iOtherTzCache = NULL;
       
   600 	}		
       
   601 #endif
       
   602 	
       
   603 CVTzActualisedRules& CTzConfigAgent::GetTimeZoneRulesL(const TTime& aTime,TTzTimeReference aTimerRef)
       
   604 	{
       
   605 	CVTzActualisedRules& rules = iSystemTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
       
   606 	iTzDataProvider->ReleaseTzRules();
       
   607 	return rules; 
       
   608 	}	
       
   609 	
       
   610 CVTzActualisedRules& CTzConfigAgent::GetForeignTimeZoneRulesL(const CTzId& aZoneId,
       
   611 															  const TTime& aTime,
       
   612 															  TTzTimeReference aTimerRef)
       
   613 	{
       
   614 	if (!iOtherTzCache)
       
   615 		{
       
   616 		iOtherTzCache = CTZRulesCache::NewL(aZoneId, *this, aTime);
       
   617 		}
       
   618 	else if (iOtherTzCache->TimeZoneId() != aZoneId)
       
   619 		{
       
   620 		// ids are different.
       
   621 		// replace the rule. create new before deleting old
       
   622 		CTZRulesCache* newZone = CTZRulesCache::NewL(aZoneId, *this, aTime);
       
   623 
       
   624 		delete iOtherTzCache;
       
   625 		iOtherTzCache = newZone;
       
   626 		}
       
   627 
       
   628 	CVTzActualisedRules& rules = iOtherTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
       
   629 	iTzDataProvider->ReleaseTzRules();
       
   630 	return rules; 
       
   631 	}	
       
   632 
       
   633 /*
       
   634 Retrieves the UTC offset for an array of numeric time zone ids.
       
   635 The offset is written back into aTimeZoneIdArray at the position that the numeric id 
       
   636 was read from, overwriting the id.
       
   637 @param aTimeZoneIdArray flat buffer consisting of a TInt for the number of ids,
       
   638 followed by the numeric time zone id (TInt) for which the current UTC offset is required.
       
   639 */
       
   640 void CTzConfigAgent::GetOffsetsForTimeZoneIdsL(CBufFlat& aTimeZoneIdArray)
       
   641 	{
       
   642 	iTzDataProvider->GetOffsetsForTimeZoneIdsL(aTimeZoneIdArray);
       
   643 	iTzDataProvider->ReleaseTzRules();
       
   644 	}
       
   645 
       
   646 void CTzConfigAgent::ConvertL(const CTzId& aZone, TTime& aTime, TTzTimeReference aTimerRef)
       
   647 	{
       
   648 	CVTzActualisedRules& rules = GetForeignTimeZoneRulesL(aZone, aTime, aTimerRef);
       
   649 	CTzRules& tzRules = GetForeignEncodedTimeZoneRulesL();
       
   650 	iTzDataProvider->ReleaseTzRules();
       
   651 	
       
   652 	tzRules.ConvertTime(rules, aTime, aTimerRef);
       
   653 	}
       
   654 
       
   655 void CTzConfigAgent::ConvertL(TTime& aTime, TTzTimeReference aTimerRef)
       
   656 	{
       
   657     CVTzActualisedRules& rules = iSystemTzCache->GetTimeZoneRulesL(aTime,aTimerRef);
       
   658 	CTzRules& tzRules = GetEncodedTimeZoneRulesL();
       
   659 	iTzDataProvider->ReleaseTzRules();
       
   660 	tzRules.ConvertTime(rules, aTime, aTimerRef);
       
   661 	}
       
   662 
       
   663 TInt CTzConfigAgent::IsDaylightSavingOnL(const CTzId& aZone, TTime& aUTCTime)
       
   664 {
       
   665 	const CVTzActualisedRules& rules = GetForeignTimeZoneRulesL(aZone, aUTCTime, ETzUtcTimeReference);
       
   666 	iTzDataProvider->ReleaseTzRules();
       
   667 	return rules.IsDaylightSavingOn(aUTCTime);
       
   668 }
       
   669 
       
   670 // There is a change to the TZ database. A new one may have been installed
       
   671 // Reset the current time zone information to take advantage of any changes.
       
   672 void CTzConfigAgent::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange)
       
   673 	{
       
   674 	if (aChange == RTz::ETZLocalizationDataChanged)
       
   675 		{
       
   676 		TInt j = 0;
       
   677   		TInt jEnd = iChangeObservers.Count();
       
   678   		while (j < jEnd)
       
   679   			{
       
   680   			iChangeObservers[j]->NotifyTZDataStatusChangeL(aChange);
       
   681   			++j;
       
   682   			}
       
   683 
       
   684 		NTzUpdate::TTzNamesChange namesChange;
       
   685 		namesChange.iUTCTimeOfNamesChange.UniversalTime();
       
   686 		TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
       
   687 		User::LeaveIfError(RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames));
       
   688 		}
       
   689 	else 
       
   690 		{
       
   691 		delete iOtherTzCache;
       
   692 		iOtherTzCache = NULL;
       
   693 		SetTimeZoneL(iSystemTzCache->TimeZoneId(), static_cast<TAny*>(this), ETrue, ETrue);
       
   694 		iTzDataProvider->ReleaseTzRules();
       
   695 
       
   696 		// notify change
       
   697 		iTzServer.NotifyTZStatusChange(aChange, static_cast<TAny*>(this));
       
   698 		
       
   699 		//Publish the property
       
   700 		NTzUpdate::TTzRulesChange rulesChange;
       
   701 		rulesChange.iUTCTimeOfRulesChange.UniversalTime();
       
   702 		TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
       
   703 		User::LeaveIfError(RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules));
       
   704 		}
       
   705 	}
       
   706 
       
   707 /**
       
   708 Calculates the time/date (in UTC) of the next DST change event that will take
       
   709 place for the current time zone. Note that there may not be a DST change for
       
   710 the current time zone, in which case EFalse is returned and aNextDstEvent is
       
   711 not changed.
       
   712 
       
   713 @param aNextDstEvent returns the time of the next DST change event.
       
   714 @return ETrue if a change event was found, else EFalse.
       
   715 @internalComponent
       
   716 
       
   717 */
       
   718 TBool CTzConfigAgent::CalculateNextDstChangeL(TTime& aNextDstEvent)
       
   719 	{
       
   720 	TTime dummy;
       
   721 	return CalculateNextDstChangeL(aNextDstEvent, dummy);
       
   722 	}
       
   723 
       
   724 /**
       
   725 Calculates the time/date (in UTC) of the next DST change event that will take
       
   726 place for the current time zone. Note that there may not be a DST change for
       
   727 the current time zone, in which case EFalse is returned and aNextDstEvent is
       
   728 not changed.
       
   729 
       
   730 @param aNextDstEvent returns the time of the next DST change event.
       
   731 @return ETrue if a change event was found, else EFalse.
       
   732 @internalComponent
       
   733 
       
   734 */
       
   735 TBool CTzConfigAgent::CalculateNextDstChangeL(TTime& aNextDstEvent, TTime& aPreviousDstEvent)
       
   736     {
       
   737     // Get the current time/date.
       
   738     TTime now;
       
   739     now.UniversalTime();
       
   740     
       
   741     // Get the actualised rules for the current time zone
       
   742     // - the next DST change will always exist within the range returned.
       
   743     // (Note that the current time zone may not have any DST changes.)
       
   744 	CVTzActualisedRules& rules = GetTimeZoneRulesL(now,ETzUtcTimeReference);
       
   745 		
       
   746     // Iterate through the actualised rules until we get the next rule change 
       
   747     // after the current time/date. (Or we reach the end of the actualised rules 
       
   748     // - in which case no DST change applies.)
       
   749     const TInt KRuleCount = rules.Count();
       
   750     
       
   751     // Store the previous offset for converting the time of change to utc.
       
   752     // Note: for times before any rules applied, the dst offset is always 0.
       
   753     TInt offset;
       
   754     
       
   755     aPreviousDstEvent = Time::MinTTime();
       
   756     for (TInt i = 0; i < KRuleCount; i++)
       
   757         {
       
   758         // Get the next time of change as a UTC time.
       
   759         TTime utcTimeOfChange = rules[i].iTimeOfChange;
       
   760      
       
   761         __ASSERT_ALWAYS(rules[i].iTimeReference!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
       
   762 	
       
   763         if (rules[i].iTimeReference == ETzWallTimeReference)
       
   764             {
       
   765         	// Get the previous offset as this was used to create the
       
   766         	// local time version of utcTimeOfChange.
       
   767     		if (i > 0)
       
   768     			{
       
   769     			// previous iNewOffset contains the STD offset plus
       
   770     			// the previous DST offset
       
   771     			offset = rules[i-1].iNewOffset;
       
   772     			}
       
   773     		else
       
   774 	    		{
       
   775 	    		// First offset will contain just the STD offset
       
   776 	    		offset = rules[i].iNewOffset;	
       
   777 	    		}
       
   778             utcTimeOfChange -= static_cast<TTimeIntervalMinutes>(offset);
       
   779             }
       
   780         
       
   781         if (utcTimeOfChange <= now)
       
   782         	{
       
   783         	aPreviousDstEvent = utcTimeOfChange;
       
   784         	}
       
   785         else
       
   786             {
       
   787             aNextDstEvent = utcTimeOfChange;
       
   788             return ETrue;
       
   789             }
       
   790         }
       
   791         
       
   792     // No DST change has been found.
       
   793     return EFalse;
       
   794     }
       
   795 
       
   796 
       
   797 /**
       
   798 Calculates the current UTC offset using time zone rules for the current time
       
   799 zone. Note that this may be different from the value set in User::UTCOffset.
       
   800 
       
   801 @param aOffset returns the current UTC Offset in seconds
       
   802 @internalComponent
       
   803 
       
   804 */
       
   805 void CTzConfigAgent::CalculateUtcOffsetL(TTimeIntervalSeconds& aOffset)
       
   806     {
       
   807     // Get the current time/date.
       
   808     TTime now;
       
   809     now.UniversalTime();
       
   810     
       
   811     // Get actualised rules for the current time zone.
       
   812 	CVTzActualisedRules& rules = GetTimeZoneRulesL(now,ETzUtcTimeReference);
       
   813 
       
   814     // Get the current UTC Offset in minutes.
       
   815     TInt offsetInMinutes = rules.GetOffsetFromRuleL(now, ETzUtcTimeReference);
       
   816       
       
   817     // Multiply up to get the offset in seconds.
       
   818     aOffset = offsetInMinutes * KSecondsPerMinute;
       
   819     }
       
   820     
       
   821     
       
   822 
       
   823 /**
       
   824 Gets the time/date (in UTC) of the next DST change event for the current time
       
   825 zone and sets a timer if it is a valid time.
       
   826 
       
   827 @internalComponent
       
   828 
       
   829 */
       
   830 void CTzConfigAgent::SetDstChangeTimerL()
       
   831     {
       
   832     // Cancel any existing DST Change Timer.
       
   833     iDstTimer->Cancel();
       
   834 
       
   835     // Get the time of the next DST change event (in UTC).
       
   836     TTime nextTimer;
       
   837     
       
   838     if (CalculateNextDstChangeL(nextTimer))
       
   839         {
       
   840         // If the time is valid then set the timer.
       
   841         iDstTimer->SetTimer(nextTimer);
       
   842         }
       
   843     }
       
   844 
       
   845 /**
       
   846 Handles cancellation or completion of a previous DST Change Timer. Updates the
       
   847 UTC Offset and sets a new DST Change Timer as necessary.
       
   848 
       
   849 @internalComponent
       
   850 
       
   851 */
       
   852 void CTzConfigAgent::HandleDstChangeTimerL()
       
   853     {
       
   854 	// UTC offset must be updated only when Auto Update is ON
       
   855 	if (iEnabled == RTz::ETZAutoDSTUpdateOn)
       
   856 		{
       
   857 		UpdateUtcOffsetL();
       
   858 		}
       
   859 
       
   860 	// Notification must be generated when Auto Update is ON or NOTIFY
       
   861 	// (unless the server is shutting down)
       
   862 	if (iEnabled != RTz::ETZAutoDSTUpdateOff && !iShuttingDown)
       
   863  	    {
       
   864 		// reset dst timer
       
   865 		SetDstChangeTimerL();
       
   866 
       
   867 		// Publish update notification.
       
   868 		// Note that the value published is the same as
       
   869 		// the AutoUpdate Configuration
       
   870 		TInt err = RProperty::Set(
       
   871    				NTzUpdate::KPropertyCategory, 
       
   872    				NTzUpdate::EUtcOffsetChangeNotification, iEnabled);
       
   873 			User::LeaveIfError(err);
       
   874 	    }
       
   875 	
       
   876 	TRAP_IGNORE(PublishNewDstChangeInfoL());
       
   877     }
       
   878 
       
   879     
       
   880 /**
       
   881 Calculates what the UTC Offset should be - if this differs from the current
       
   882 offset then the new offset is set using User::SetUTCOffset() and subscribed
       
   883 clients are notified of the change through the Publish and Subscribe API.
       
   884 
       
   885 @internalComponent
       
   886 
       
   887 */
       
   888 void CTzConfigAgent::UpdateUtcOffsetL()
       
   889     {
       
   890     
       
   891     // Calculate the current UTC Offset in seconds.
       
   892     TTimeIntervalSeconds currentOffset;
       
   893     CalculateUtcOffsetL(currentOffset);
       
   894     
       
   895     if (currentOffset != User::UTCOffset())
       
   896 		{
       
   897     	// Set the new UTC Offset.
       
   898 		iChangeNotifier->Cancel();
       
   899     	User::SetUTCOffset(currentOffset);
       
   900 		// enable observer again
       
   901 		iChangeNotifier->Start();
       
   902     	// Notify session observer.
       
   903 		iTzServer.NotifyTZStatusChange(RTz::ETZAutomaticTimeUpdate, static_cast<TAny*>(this));
       
   904 		}
       
   905     }
       
   906         
       
   907 /**
       
   908 Sets the configuration of the UTC Offset auto-update functionality.
       
   909 
       
   910 @param aUpdateEnabled If set to RTz::ETZAutoDSTUpdateOn then the UTC Offset is automatically
       
   911 updated for changes to Daylight Savings Time. If set to RTz::ETZAutoDSTUpdateOff then auto-update
       
   912 is disabled. The RTz::ETZAutoDSTNotificationOnly - Means that the client app needs to confirm that the 
       
   913 time should be updated whenever a DST event occurs.
       
   914 
       
   915 
       
   916 @internalComponent
       
   917 
       
   918 */
       
   919 void CTzConfigAgent::SetAutoUpdateBehaviorL(TInt aUpdateEnabled)
       
   920     {
       
   921     // Check if the configuration has changed.
       
   922     if (aUpdateEnabled != iEnabled)
       
   923         {
       
   924         // Persist the new configuration.
       
   925         iEnabled = aUpdateEnabled;
       
   926        	iRepository->Set(EConfigurationKey, iEnabled);
       
   927 
       
   928         // Handle configuration change.
       
   929         if (aUpdateEnabled != RTz::ETZAutoDSTUpdateOff)
       
   930             {
       
   931 			// Update the UTC Offset (if required) and set a new DST Change Timer.       
       
   932 
       
   933             SetDstChangeTimerL();
       
   934 			// Don't update Kernel for Notify - only for ON
       
   935 			if (aUpdateEnabled == RTz::ETZAutoDSTUpdateOn)
       
   936 				{
       
   937 				UpdateUtcOffsetL();   
       
   938 				}
       
   939             }
       
   940         else
       
   941             {
       
   942             // Cancel any existing DST Change Timer.
       
   943             iDstTimer->Cancel();
       
   944             }
       
   945         }
       
   946     
       
   947     TRAP_IGNORE(PublishNewDstChangeInfoL());
       
   948     }
       
   949 
       
   950  /**
       
   951 Change current local time.
       
   952 
       
   953 @param aHomeTime The time to set in wall-clock time.
       
   954 
       
   955 @return An error code. KErrNone is expected unless there is an error in
       
   956 converting the given local time to UTC.
       
   957 
       
   958 @internalComponent
       
   959 
       
   960 */
       
   961 TInt CTzConfigAgent::SetHomeTimeL(const TTime& aHomeTime)     
       
   962 	{
       
   963 	TTime utcTime(aHomeTime);
       
   964 
       
   965 	ConvertL(utcTime, ETzWallTimeReference);
       
   966 
       
   967 	//Cancel environment change notification in case double updating UTC offset.
       
   968 	iChangeNotifier->Cancel();   
       
   969 
       
   970 	//Cancel DST timer.
       
   971 	iDstTimer->Cancel();
       
   972 
       
   973 	TTimeIntervalSeconds utcOffset(0);
       
   974 	aHomeTime.SecondsFrom(utcTime,utcOffset);
       
   975 
       
   976 	//Update kernel time and utc offset.
       
   977 	TInt result = User::SetUTCTimeAndOffset(utcTime, utcOffset);
       
   978 
       
   979 	// Get the time of the next DST change event (in UTC).
       
   980 	TTime nextTimer;
       
   981 
       
   982 	if (iEnabled != RTz::ETZAutoDSTUpdateOff)
       
   983 		{
       
   984 		if (CalculateNextDstChangeL(nextTimer))
       
   985 			{
       
   986 			// Restart the dst timer.
       
   987 			iDstTimer->SetTimer(nextTimer);
       
   988 			}
       
   989 		}
       
   990 
       
   991 	//Restart observe environment change notification.
       
   992 	iChangeNotifier->Start();
       
   993 	
       
   994 	TRAP_IGNORE(PublishNewDstChangeInfoL());
       
   995 
       
   996 	return result;
       
   997 	}
       
   998 
       
   999 TInt CTzConfigAgent::SetUnknownTimeZoneTimeL(const TTime& aUTCTime, const TInt aUTCOffset, TBool aPersistInCenRep)     
       
  1000 	{
       
  1001 	//
       
  1002 	// Cancel DST timer. (It will not be restarted, as we won't have DST rules for this unknown zone)
       
  1003 	//
       
  1004 	iDstTimer->Cancel();
       
  1005 
       
  1006 	//Update kernel time and utc offset.
       
  1007 	const TTimeIntervalSeconds newUtcOffset = aUTCOffset * KSecondsPerMinute;
       
  1008 
       
  1009 	//
       
  1010 	// Cancel environment change notification in case double updating UTC offset.
       
  1011 	//
       
  1012 	iChangeNotifier->Cancel();   
       
  1013 
       
  1014 	TInt result = User::SetUTCTimeAndOffset(aUTCTime, newUtcOffset);
       
  1015 	//
       
  1016 	// Restart environment change notification.
       
  1017 	//
       
  1018 	iChangeNotifier->Start();
       
  1019 
       
  1020 	User::LeaveIfError(result);
       
  1021 
       
  1022 	TInt oldTzId = iSystemTzCache->TimeZoneId().TimeZoneNumericID();
       
  1023 
       
  1024 	// replace the rule, create an new unknown before deleting old
       
  1025 	CTzId* timeZoneId = CTzId::NewL(KUnknownTZId);
       
  1026 	CleanupStack::PushL(timeZoneId);
       
  1027 
       
  1028 	// CSystemTzRulesCache::NewL will create a default rule based on the offset in the Kernel
       
  1029 	CSystemTzRulesCache* newZone = CSystemTzRulesCache::NewL(*timeZoneId, *this, aUTCTime);
       
  1030 	CleanupStack::PushL(newZone);
       
  1031 
       
  1032 	delete iSystemTzCache;
       
  1033 	iSystemTzCache = newZone;
       
  1034 
       
  1035 	if (aPersistInCenRep)
       
  1036 		{
       
  1037 		// Set the unknown time zone in central repository
       
  1038 		// 0 is used to represent the Unknow time zone value although in the code KUnknownTZId is used
       
  1039 		User::LeaveIfError(iRepository->Set(ETimeZoneKey, (TInt)KUnknownTZId));
       
  1040 		}
       
  1041 	else
       
  1042 		{
       
  1043 		// Set the unknown time zone in central repository
       
  1044 		// 0 is used to represent the Unknow time zone value although in the code KUnknownTZId is used
       
  1045 		User::LeaveIfError(iRepository->Set(ETimeZoneKey, 0));
       
  1046 		}
       
  1047 
       
  1048 	CleanupStack::Pop(newZone);
       
  1049 	CleanupStack::PopAndDestroy(timeZoneId);
       
  1050 
       
  1051 	iTzServer.NotifyTZStatusChange(RTz::ETZSystemTimeZoneChanged, static_cast<TAny*>(this));
       
  1052 
       
  1053 
       
  1054 	NTzUpdate::TTimeZoneChange change;
       
  1055 	change.iNewTimeZoneId = 0;
       
  1056 	change.iOldTimeZoneId = oldTzId;
       
  1057 
       
  1058 	TPckgBuf<NTzUpdate::TTimeZoneChange> changeBuf(change);
       
  1059 	RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ECurrentTimeZoneId, changeBuf);
       
  1060 
       
  1061 	iTzDataProvider->ReleaseTzRules();
       
  1062 
       
  1063 	return KErrNone;
       
  1064 	}
       
  1065 
       
  1066 /**
       
  1067 Gets the daylight saving update
       
  1068 */
       
  1069 TInt CTzConfigAgent::AutoUpdateSetting()
       
  1070     {
       
  1071 	return iEnabled;
       
  1072     }
       
  1073 
       
  1074 
       
  1075 /**
       
  1076 Observer method called as a result of a change in system time. Updates the UTC
       
  1077 Offset and sets a new DST Change Timer as necessary.
       
  1078 
       
  1079 @internalComponent
       
  1080 
       
  1081 */
       
  1082 void CTzConfigAgent::HandleSystemTimeChangeL()
       
  1083     {
       
  1084     HandleDstChangeTimerL();
       
  1085     }
       
  1086 
       
  1087 /**
       
  1088 Observer method called as a result of a DST Change Timer completing. Updates
       
  1089 the UTC Offset and sets a new DST Change Timer as necessary.
       
  1090 
       
  1091 @internalComponent
       
  1092 
       
  1093 */
       
  1094 void CTzConfigAgent::HandleDstTimerCompleteL()
       
  1095     {
       
  1096     HandleDstChangeTimerL();
       
  1097     }
       
  1098 
       
  1099 /**
       
  1100 Observer method called as a result of a DST Change Timer being cancelled. (The
       
  1101 underlying RTimer is cancelled - for example, because of a change to the UTC
       
  1102 offset.) This is not called when Cancel() or DoCancel() are called.) Updates
       
  1103 the UTC Offset and sets a new DST Change Timer as necessary.
       
  1104 
       
  1105 @internalComponent
       
  1106 
       
  1107 */
       
  1108 void CTzConfigAgent::HandleDstTimerCancellationL()
       
  1109     {
       
  1110 	HandleDstChangeTimerL();
       
  1111     }
       
  1112     
       
  1113 /**
       
  1114 Observer method called due to an error with the DST Change Timer that tries to
       
  1115 recover from the error. We only expect this to get called with a value of
       
  1116 KErrUnderflow (if the system time is changed to a time past the current timer)
       
  1117 or a value of KErrOverflow as returned by RTimer.
       
  1118 
       
  1119 @param aError The error returned from the timer.
       
  1120 @internalComponent
       
  1121 
       
  1122 */
       
  1123 void CTzConfigAgent::DstTimerErrorOccurredL(TInt aError)
       
  1124     {
       
  1125     // Remove the compiler warning about aError not being used. (It's useful in debugging.)
       
  1126     aError = aError;
       
  1127     
       
  1128     // Try and recover by updating the UTC Offset and setting a new 
       
  1129     // DST Change Timer as necessary.
       
  1130     HandleDstChangeTimerL();
       
  1131     }
       
  1132 
       
  1133 /**
       
  1134 Environment observer callback - called when the kernel causes a system change.
       
  1135 This can be used to pick up any changes when there is no DST Change Timer and
       
  1136 may also provide a faster response to system time or locale changes.
       
  1137 
       
  1138 @param aSelf A pointer to this class.
       
  1139 @return Always returns ETrue.
       
  1140 @internalComponent
       
  1141 
       
  1142 */
       
  1143 TBool CTzConfigAgent::EnvironmentChangeCallBackL(TAny* aSelf)
       
  1144 	{
       
  1145 	CTzConfigAgent* self = static_cast<CTzConfigAgent*>(aSelf);
       
  1146 
       
  1147 	const TInt KChanges = self->iChangeNotifier->Change();
       
  1148 	
       
  1149 	if (KChanges == KErrCancel)
       
  1150 	    {
       
  1151 	    return ETrue;   // Observer is being cancelled.
       
  1152 	    }
       
  1153 
       
  1154     if (KChanges & (EChangesLocale | EChangesSystemTime))
       
  1155 		{
       
  1156         // Update the UTC Offset and set a new DST Change Timer as necessary.
       
  1157         self->UpdateUtcOffsetL();
       
  1158         self->SetDstChangeTimerL();
       
  1159 		}
       
  1160 	    
       
  1161 	return ETrue;
       
  1162 	}
       
  1163 	
       
  1164 /** Reponding to the change in user defined time zone
       
  1165  
       
  1166 The CTzConfigAgent class maintains a cache of TZ rules (including actualised rules for 
       
  1167 the last used rule) for the system (also known as current) TZ in the iSystemTzCache member
       
  1168 and for a “foreign” TZ in the iOtherTzCache member.  Either of these members could be a cache
       
  1169 of the TZ rules from a user-defined TZ.  If the associated user-defined TZ data is updated
       
  1170 or deleted or a restore of user-defined TZ data has taken place then this cache needs to be
       
  1171 updated appropriately.
       
  1172 */
       
  1173 void CTzConfigAgent::NotifyUserTzRulesChange(TTzUserDataChange aChange)
       
  1174 	{
       
  1175 	TRAP_IGNORE(NotifyUserTzRulesChangeL(aChange));
       
  1176 	}
       
  1177 void CTzConfigAgent::NotifyUserTzRulesChangeL(TTzUserDataChange aChange)
       
  1178 	{
       
  1179 	//Only interested when a user TZ rule is updated or deleted
       
  1180 	if (aChange.iOperation == ETzUserDataUpdated ||	aChange.iOperation == ETzUserDataDeleted)
       
  1181 		{	
       
  1182 		//Chached time zone (iOtherTzCache) should be cleaned off.
       
  1183 		delete iOtherTzCache;
       
  1184 		iOtherTzCache = NULL;
       
  1185 		
       
  1186 		TUint id = aChange.iTzId;
       
  1187 		if(iSystemTzCache && id == iSystemTzCache->TimeZoneId().TimeZoneNumericID())	
       
  1188 			{
       
  1189 			CTzId* tzid = NULL;
       
  1190 			if (aChange.iOperation == ETzUserDataUpdated)
       
  1191 				{
       
  1192 				//Cached symstem time zone (iSystemTzCache) should be updated.
       
  1193 				tzid = CTzId::NewL(id);
       
  1194 				}
       
  1195 			else if (aChange.iOperation == ETzUserDataDeleted)
       
  1196 				{//Cached symstem time zone (iSystemTzCache) should be reverted to the default time zone.
       
  1197 				tzid = iTzDataProvider->GetDefaultTimeZoneIdL();
       
  1198 				if(!tzid)
       
  1199 					{
       
  1200 					tzid = CTzId::NewL(KUnknownTZId);
       
  1201 					}
       
  1202 				}
       
  1203 			CleanupStack::PushL(tzid);
       
  1204 			SetTimeZoneL(*tzid, static_cast<TAny*>(this), ETrue, ETrue);	
       
  1205 			CleanupStack::PopAndDestroy(tzid);	
       
  1206 			}
       
  1207 		}
       
  1208 	}
       
  1209  
       
  1210 void CTzConfigAgent::NotifyUserTzNamesChange(TTzUserDataChange /*aChange*/)
       
  1211     {// There is no action needed when the names of a user defined time zone has been changed.
       
  1212     }
       
  1213   
       
  1214 void CTzConfigAgent::AddObserverL(MTzDataObserver* aChangeObs)
       
  1215 	{
       
  1216 	User::LeaveIfError(iChangeObservers.Append(aChangeObs));
       
  1217 	}
       
  1218 
       
  1219 void CTzConfigAgent::RemoveObserver(MTzDataObserver* aChangeObs)
       
  1220 	{
       
  1221 	TInt j = 0;
       
  1222 	TInt jEnd = iChangeObservers.Count();
       
  1223 	while (j < jEnd)
       
  1224 		{
       
  1225 		if (iChangeObservers[j] == aChangeObs)
       
  1226 			{
       
  1227 			iChangeObservers.Remove(j);
       
  1228 			break;
       
  1229 			}
       
  1230 		++j;
       
  1231 		}
       
  1232 	}
       
  1233 
       
  1234 
       
  1235 void CTzConfigAgent::BackupBeginningL()
       
  1236 	{
       
  1237 	iTzLocalizationDb->BackupBeginningL();
       
  1238 	iTzDataProvider->BackupBeginningL();
       
  1239 	}
       
  1240 
       
  1241 void CTzConfigAgent::BackupCompletedL()
       
  1242 	{
       
  1243 	iTzDataProvider->BackupCompletedL();
       
  1244 	iTzLocalizationDb->BackupCompletedL();
       
  1245 	}
       
  1246 void CTzConfigAgent::RestoreBeginningL()
       
  1247 	{
       
  1248 	iTzLocalizationDb->RestoreBeginningL();
       
  1249 	iTzDataProvider->RestoreBeginningL();
       
  1250 	}
       
  1251 
       
  1252 void CTzConfigAgent::RestoreCompletedL(TInt aRestoreResult)
       
  1253 	{
       
  1254 	if(aRestoreResult == KErrNone)
       
  1255 		{
       
  1256 		//Both read only DB and user defined DB will refresh the data
       
  1257 		iTzDataProvider->RestoreCompletedL();
       
  1258 		
       
  1259 		//Update cached tz rules
       
  1260 		delete iOtherTzCache;
       
  1261  		iOtherTzCache = NULL;
       
  1262 
       
  1263 		if(iSystemTzCache)
       
  1264 			{
       
  1265 			// Find out whether the cached system time zone rule still exists in
       
  1266 			// the rules database.  If not, set the current time zone using the
       
  1267 			// default time zone identifier.
       
  1268 			TBool timeZoneExists = iTzDataProvider->IsIdInDbL(iSystemTzCache->TimeZoneId().TimeZoneNumericID());
       
  1269 			if(timeZoneExists)
       
  1270 				{
       
  1271 				SetTimeZoneL(iSystemTzCache->TimeZoneId(), static_cast<TAny*>(this), EFalse, ETrue);
       
  1272 				}
       
  1273 			else
       
  1274 				{
       
  1275 				CTzId* tzid = iTzDataProvider->GetDefaultTimeZoneIdL();
       
  1276 				CleanupStack::PushL(tzid);
       
  1277 				SetTimeZoneL(*tzid, static_cast<TAny*>(this), EFalse, ETrue);
       
  1278 				CleanupStack::PopAndDestroy(tzid);
       
  1279 				}
       
  1280 			}
       
  1281 		
       
  1282 		// Notify change to the clients.
       
  1283 		iTzServer.NotifyTZStatusChange(RTz::ETZDatabaseChanged, static_cast<TAny*>(this));
       
  1284 
       
  1285 		// Notify the localization DB.
       
  1286 		iTzLocalizationDb->RestoreCompletedL();
       
  1287 		
       
  1288 		//Publish tz rules change 
       
  1289 		NTzUpdate::TTzRulesChange rulesChange;
       
  1290 		rulesChange.iUTCTimeOfRulesChange.UniversalTime();
       
  1291 		TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
       
  1292 		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules);
       
  1293 		
       
  1294 		//Publish the names change for user defined DB
       
  1295 		NTzUpdate::TTzNamesChange namesChange;
       
  1296 		namesChange.iUTCTimeOfNamesChange.UniversalTime();
       
  1297 		TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
       
  1298 		RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames);	
       
  1299 		}
       
  1300 	}
       
  1301 //------------------------------------------------------------------------------------
       
  1302 CTZRulesCache::~CTZRulesCache()
       
  1303 	{
       
  1304 	delete iTimeZoneId;		// time zone Id
       
  1305 	delete iActualisedRules;// caches the last used rule for zone
       
  1306 	delete iEncodedRules;
       
  1307 	}
       
  1308 
       
  1309 // template method used for final construction of a time zone rules cache
       
  1310 // this is the base implementation -- see ConstructL()
       
  1311 void CTZRulesCache::SetDefaultZoneIdL()
       
  1312 	{
       
  1313 	// does nothing
       
  1314 	User::Leave(KErrNotFound);
       
  1315 	}
       
  1316 
       
  1317 const CTzRules& CTZRulesCache::doGetEncodedTimeZoneRulesL(TInt aStartYear, TInt aEndYear)
       
  1318 	{
       
  1319 	CTzDataProvider& tzDataProvider = iTimeZoneConfigAgent.TzDataProvider();
       
  1320 	
       
  1321 	CTzRules* newRules = CTzRules::NewL(aStartYear, aEndYear);
       
  1322 	CleanupStack::PushL(newRules);
       
  1323 	
       
  1324 	tzDataProvider.GetTzRulesL(*newRules, *iTimeZoneId);
       
  1325 
       
  1326 
       
  1327 	CleanupStack::Pop(newRules);
       
  1328 	
       
  1329 	// replace current cached rules
       
  1330 	delete iEncodedRules;
       
  1331 	iEncodedRules = newRules;
       
  1332 	
       
  1333 	return *iEncodedRules;
       
  1334 	}
       
  1335 	
       
  1336 void CTZRulesCache::doGetActualisedTimeZoneRulesL(const TTime& aTime)
       
  1337 	{
       
  1338 	TDateTime dateTime(aTime.DateTime() );
       
  1339 
       
  1340 	// At least we need the rule for the year preceeding the converted time
       
  1341 	// in order to convert the time to use it to find the correct rule. (Sounds roundabout!)
       
  1342 	// hence the extra one added to the cache limit
       
  1343 
       
  1344 	// avoid over/under flow
       
  1345 	TUint startYear = dateTime.Year();
       
  1346 	TUint endYear = startYear;
       
  1347 	if (startYear >= (KRuleCacheLowerLimit+1))
       
  1348 		{
       
  1349 		startYear -= (KRuleCacheLowerLimit+1);
       
  1350 		}
       
  1351 	if (endYear < (KMaxTUint - KRuleCacheUpperLimit))
       
  1352 		{
       
  1353 		endYear += KRuleCacheUpperLimit;
       
  1354 		}
       
  1355 
       
  1356 	CVTzActualisedRules* newRules = CVTzActualisedRules::NewL(startYear, endYear);
       
  1357 	CleanupStack::PushL(newRules);
       
  1358 
       
  1359     iEncodedRules->GetActualisedRulesL(*newRules);
       
  1360 
       
  1361 	if (newRules->Count() == 0) // there will always be at least one rule
       
  1362 		{
       
  1363 		User::Leave(KErrNotFound);
       
  1364 		}
       
  1365 
       
  1366 	CleanupStack::Pop(newRules);
       
  1367 
       
  1368 	// replace current cached rules
       
  1369 	delete iActualisedRules;
       
  1370 	iActualisedRules = newRules;
       
  1371 	}
       
  1372 	
       
  1373 void CTZRulesCache::ConstructL(const CTzId& aTimeZoneId, const TTime& aTime)
       
  1374 	{
       
  1375 	if (aTimeZoneId.TimeZoneNumericID() != KUnknownTZId)
       
  1376 		{
       
  1377 		iTimeZoneId	= aTimeZoneId.CloneL();
       
  1378 
       
  1379 		TRAPD(err,doGetEncodedTimeZoneRulesL(KMinYear, KMaxYear));
       
  1380 		if (err == KErrNotFound)
       
  1381 			{
       
  1382 			SetDefaultZoneIdL();	
       
  1383 			}
       
  1384 		else
       
  1385 			{
       
  1386 			User::LeaveIfError(err);
       
  1387 	
       
  1388 			// avoid over/under flow
       
  1389 			TDateTime dateTime(aTime.DateTime() );
       
  1390 			TUint startYear = dateTime.Year();
       
  1391 			TUint endYear = startYear;
       
  1392 			
       
  1393 			if (startYear >= (KRuleCacheLowerLimit+1))
       
  1394 				{
       
  1395 				startYear -= (KRuleCacheLowerLimit+1);
       
  1396 				}
       
  1397 			if (endYear < (KMaxTUint - KRuleCacheUpperLimit))
       
  1398 				{
       
  1399 				endYear += KRuleCacheUpperLimit;
       
  1400 				}
       
  1401 		
       
  1402 			iActualisedRules = CVTzActualisedRules::NewL(startYear, endYear);
       
  1403 			iEncodedRules->GetActualisedRulesL(*iActualisedRules);
       
  1404 			}
       
  1405 		}
       
  1406 	else
       
  1407 		{
       
  1408 		// Call Template Method to Set defaultZoneId
       
  1409 		SetDefaultZoneIdL();
       
  1410 		}
       
  1411 	}
       
  1412 
       
  1413 
       
  1414 CTZRulesCache* CTZRulesCache::NewL(const CTzId& aTimeZoneId,
       
  1415 								CTzConfigAgent& aTimeZoneConfigAgent,
       
  1416 								const TTime& aTime)
       
  1417 	{
       
  1418 	CTZRulesCache* self = new (ELeave) CTZRulesCache(aTimeZoneConfigAgent);
       
  1419 	CleanupStack::PushL(self);
       
  1420 
       
  1421 	self->ConstructL(aTimeZoneId, aTime);
       
  1422 
       
  1423 	CleanupStack::Pop(self);
       
  1424 	return self;
       
  1425 	}
       
  1426 
       
  1427 CTzRules& CTZRulesCache::GetEncodedTimeZoneRulesL()
       
  1428 	{
       
  1429 	// return the rules held in cache
       
  1430 	if (iEncodedRules == NULL)
       
  1431 		{
       
  1432 		User::Leave(KErrNotFound);
       
  1433 		}
       
  1434 	return *iEncodedRules;
       
  1435 	}
       
  1436 
       
  1437 TInt CTZRulesCache::GetEncodedTimeZoneRulesSizeL(const TTime& aStartTime, const TTime& aEndTime, TTzTimeReference /*aTimeRef */)
       
  1438 	{
       
  1439 	// fetch a new set of rules from the data provider if the range of the rules in iEncodedRules does not
       
  1440 	// contain both aStartTime and aEndTime
       
  1441 	if (
       
  1442 		(iTimeZoneId->TimeZoneNumericID() != KUnknownTZId)
       
  1443 		&&
       
  1444 		( (iEncodedRules == NULL) || !(iEncodedRules->RulesApply(aStartTime)) || !(iEncodedRules->RulesApply(aEndTime) ) )
       
  1445 	    )
       
  1446 		{
       
  1447         TInt startYear = aStartTime.DateTime().Year();
       
  1448         TInt endYear = aEndTime.DateTime().Year();
       
  1449 		doGetEncodedTimeZoneRulesL(startYear, endYear);
       
  1450 		}
       
  1451 
       
  1452 	if (iEncodedRules)
       
  1453 		{
       
  1454 		return iEncodedRules->Count() * sizeof (TTzRule) + sizeof (CTzRules);
       
  1455 		}
       
  1456 	else
       
  1457 		{
       
  1458 		return 0;
       
  1459 		}
       
  1460 	}
       
  1461 
       
  1462 CVTzActualisedRules& CTZRulesCache::GetTimeZoneRulesL(const TTime& aTime,TTzTimeReference aTimerRef)
       
  1463 	{
       
  1464     if ((iTimeZoneId->TimeZoneNumericID() != KUnknownTZId) 
       
  1465 		&& (!(RuleApplies(*iActualisedRules, aTime, aTimerRef))))
       
  1466 		{
       
  1467 		doGetActualisedTimeZoneRulesL(aTime);
       
  1468 		}
       
  1469 	return *iActualisedRules;
       
  1470 	}
       
  1471 
       
  1472 /** 
       
  1473 Tests if the period covered by the cached rules applies to the supplied time.
       
  1474 */
       
  1475 TBool CTZRulesCache::RuleApplies(CVTzActualisedRules& actRules, 
       
  1476     const TTime& aTime, TTzTimeReference aTimerRef) const 
       
  1477 	{
       
  1478 	TInt startYear = actRules.StartYear();
       
  1479 	TInt endYear = actRules.EndYear();
       
  1480 	
       
  1481 	TDateTime dateTime(aTime.DateTime());
       
  1482 	
       
  1483 	__ASSERT_ALWAYS(aTimerRef!=ETzStdTimeReference, RTz::Panic(RTz::EPanicUnsupportedTimeReference));
       
  1484 	
       
  1485 	// aTime may be in UTC or wall time. If aTime is provided
       
  1486 	// in wall time the range which is checked will be reduced by one year
       
  1487 	// on either side, to avoid false inclusions. eg. If the time zone was
       
  1488 	// Japan and the date passed in here was Jan 1st at 6:00 local time,
       
  1489 	// that would be a different year in UTC time. This will result
       
  1490 	// in more fetches to the database in some cases, but the alternative
       
  1491 	// is to iterate through all the rules every time this method is called
       
  1492 	// to find the matching rule, which is not very efficent in itself.
       
  1493 
       
  1494 	if (aTimerRef == ETzWallTimeReference)
       
  1495 		{
       
  1496 		// This reduces the range that is checked. For example, if the
       
  1497 		// actualised rules are from 2000 to 2006, this will
       
  1498 		// check Jan 2001 to Jan 2006
       
  1499 		startYear++;
       
  1500 		}
       
  1501 	else
       
  1502 		{
       
  1503 		// This checks the whole range. For example, if the
       
  1504 		// actualised rules are from 2000 to 2006, this will
       
  1505 		// check Jan 2000 to Jan 2007
       
  1506 		endYear++; 
       
  1507 		}
       
  1508 		
       
  1509 	const TTime KStart(TDateTime(startYear, EJanuary, 0, 0, 0, 0, 0));
       
  1510 	const TTime KEnd(TDateTime(endYear, EJanuary, 0, 0, 0, 0, 0));
       
  1511 	return ((aTime >= KStart) && (aTime < KEnd));
       
  1512 	}
       
  1513 
       
  1514 //------------------------------------------------------------------------------------
       
  1515 //
       
  1516 CSystemTzRulesCache::~CSystemTzRulesCache()
       
  1517 	{
       
  1518 	// does nothing
       
  1519 	}
       
  1520 
       
  1521 
       
  1522 void CSystemTzRulesCache::SetDefaultZoneIdL()
       
  1523 	{
       
  1524 	// default to old TLocale DST Rule
       
  1525 	delete iTimeZoneId;
       
  1526 	iTimeZoneId = NULL;
       
  1527 	iTimeZoneId = CTzId::NewL(KUnknownTZName);
       
  1528 	iTimeZoneId->SetId(KUnknownTZId);
       
  1529 
       
  1530 	// The UTC Offset combines both the standard and the dst offset
       
  1531 	TInt stdOffset = User::UTCOffset().Int() / KSecondsPerMinute;
       
  1532 		
       
  1533 	// create a default std only encoded rule
       
  1534 	delete iEncodedRules;
       
  1535 	iEncodedRules = NULL;
       
  1536 	iEncodedRules = CTzRules::NewL(KMinYear,KMaxYear);
       
  1537 	TTimeWithReference timeRef;
       
  1538 	TTimeWithReference timeRef2(TTimeWithReference::Max());
       
  1539 	TTzRule encodedRule(timeRef, timeRef2,stdOffset,stdOffset,EJanuary,ETzFixedDate,0,0,ETzWallTimeReference,0);
       
  1540 	iEncodedRules->AddRuleL(encodedRule);
       
  1541 	
       
  1542 	delete iActualisedRules;
       
  1543 	iActualisedRules = NULL;
       
  1544 	iActualisedRules = CVTzActualisedRules::NewL(KMinYear, KMaxYear);
       
  1545     iEncodedRules->GetActualisedRulesL(*iActualisedRules);
       
  1546 	}
       
  1547 
       
  1548 
       
  1549 CSystemTzRulesCache* CSystemTzRulesCache::NewL(const CTzId& aTimeZoneId,
       
  1550 								CTzConfigAgent& aTimeZoneConfigAgent,
       
  1551 								const TTime& aTime)
       
  1552 	{
       
  1553 	CSystemTzRulesCache* self = new (ELeave) CSystemTzRulesCache(aTimeZoneConfigAgent);
       
  1554 	CleanupStack::PushL(self);
       
  1555 
       
  1556 	self->ConstructL(aTimeZoneId, aTime);
       
  1557 
       
  1558 	CleanupStack::Pop(self);
       
  1559 	return self;
       
  1560 	}
       
  1561 
       
  1562 
       
  1563 
       
  1564 //------------------------------------------------------------------------------------
       
  1565 // CDstEventNotifier
       
  1566 //
       
  1567 
       
  1568 /**
       
  1569 Creates a new instance of CDstEventNotifier on the heap.
       
  1570 
       
  1571 @param aObserver the observer of the timer.
       
  1572 @return CDstEventNotifier* the instance created.
       
  1573 @internalComponent
       
  1574 
       
  1575 */
       
  1576 CDstEventNotifier* CDstEventNotifier::NewL(MDstEventObserver& aObserver)
       
  1577     {
       
  1578 	CDstEventNotifier* self = new (ELeave) CDstEventNotifier(aObserver);
       
  1579 	CleanupStack::PushL(self);
       
  1580 	self->ConstructL();     // Construct CTimer.
       
  1581 	CActiveScheduler::Add(self);
       
  1582 	CleanupStack::Pop(self);
       
  1583 	return self;
       
  1584     }
       
  1585     
       
  1586 /**
       
  1587 Sets a new DST Change Timer at the given time.
       
  1588 
       
  1589 @param aUtcTime the UTC time of the DST event.
       
  1590 @internalComponent
       
  1591 
       
  1592 */
       
  1593 void CDstEventNotifier::SetTimer(const TTime& aUtcTime)
       
  1594     {
       
  1595     // Cancel any existing timer
       
  1596     Cancel();
       
  1597 	// Start the new timer.
       
  1598 	AtUTC(aUtcTime);
       
  1599     }
       
  1600     
       
  1601 /**
       
  1602 Constructor.
       
  1603 
       
  1604 @param aObserver the observer of the timer.
       
  1605 @internalComponent
       
  1606 
       
  1607 */
       
  1608 CDstEventNotifier::CDstEventNotifier(MDstEventObserver& aObserver)
       
  1609  :  CTimer(EPriorityStandard),
       
  1610     iObserver(aObserver)
       
  1611     {
       
  1612     }
       
  1613 
       
  1614 /**
       
  1615 Called when the timer completes. The observer is notified.
       
  1616 
       
  1617 @internalComponent
       
  1618 
       
  1619 */
       
  1620 void CDstEventNotifier::RunL()
       
  1621     {
       
  1622     // Notify the observer.
       
  1623     // Notifications based on the behaviour of RTimer
       
  1624 
       
  1625     switch (iStatus.Int())
       
  1626         {
       
  1627         case KErrNone:
       
  1628             // The timer completed normally at the requested time.
       
  1629             iObserver.HandleDstTimerCompleteL();
       
  1630             break;
       
  1631         case KErrAbort:
       
  1632             // The timer was aborted because the system time changed.
       
  1633 			// This is taken care of by the environment change notifier
       
  1634 			// but is still handled to avoid falling into the default case 
       
  1635 			// and setting the alarm twice for each locale/time change.
       
  1636             break;
       
  1637         case KErrCancel:
       
  1638             // The timer was cancelled.
       
  1639             iObserver.HandleDstTimerCancellationL();
       
  1640             break;
       
  1641         default:
       
  1642             // KErrUnderflow, KErrOverflow may be expected if an out-of-range timer is set.
       
  1643             iObserver.DstTimerErrorOccurredL(iStatus.Int());
       
  1644             break;
       
  1645         }
       
  1646     }
       
  1647     
       
  1648 /**
       
  1649 Called if RunL leaves.
       
  1650 
       
  1651 @internalComponent
       
  1652 
       
  1653 */
       
  1654 TInt CDstEventNotifier::RunError(TInt aError)
       
  1655     {
       
  1656     // Just return the error.
       
  1657     return aError;
       
  1658     }
       
  1659 
       
  1660 /**
       
  1661 Cancels any existing timer.
       
  1662 
       
  1663 @internalComponent
       
  1664 
       
  1665 */
       
  1666 void CDstEventNotifier::DoCancel()
       
  1667     {
       
  1668     // Cancel the timer.   
       
  1669     CTimer::DoCancel();
       
  1670     
       
  1671     // Do not notify the observer here as it will create an infinite loop!
       
  1672     // Cancellation of the RTimer is notified in RunL() with a status of KErrCancel.
       
  1673     // That is what MDstEventObserver::HandleDstTimerCancellationL() is for.
       
  1674     }