tzservices/tzserver/Server/Source/tzlocalizationdb.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
child 82 4610cd70c542
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tzservices/tzserver/Server/Source/tzlocalizationdb.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1357 @@
+// Copyright (c) 2008-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 "tzlocalizationdb.h"
+#include "timezoneserver.h"
+#include "mtimezonedataaccess.h"
+
+#include <centralrepository.h>				// For CRepository.
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tzusernames.h>//new file added for CTzUserNames which is publishedPartner
+#endif
+#include <tzlocalizedcityrecord.h>
+#include <tzlocalizedtimezonerecord.h>
+
+// Database location and access policy
+_LIT(KTzLocalizationDbName,"c:TzLocalization.db");
+_LIT(KTzLocalizationDbSecurityPolicy,"secure[10206A8B]");
+
+//Table and Column names for Cached Time Zone Table
+//These text strings are never visible and do not need localizing
+_LIT(KCZTableName, 			"FrequentlyUsedZones");
+_LIT(KCZTableTzIdCol, 		"TzId");
+_LIT(KCZTableStdCol, 		"StandardName");
+_LIT(KCZTableDSTCol, 		"DSTName");
+_LIT(KCZTableShortStdCol,	"ShortStandardName");
+_LIT(KCZTableShortDSTCol, 	"ShortDSTName");
+_LIT(KCZTableCityCol, 		"City");
+_LIT(KCZTableCityGroupCol, 	"GroupId");
+_LIT(KCZTableResourceIdCol,	"ResourceId");
+_LIT(KCZTableCityIndexCol,	"CityIndex");
+
+//Table and Column names for User Added Cities Table
+//These text strings are never visible and do not need localizing
+_LIT(KUCTableName, 			"UserCities");
+_LIT(KUCTableTzId, 			"TzId");
+_LIT(KUCTableCity, 			"City");
+_LIT(KUCTableGroup, 		"GroupId");
+_LIT(KUCTableResourceId,	"ResourceId");
+
+enum TTzZoneColumn
+	{
+	// Enum will used as a DB column index, so it must start at 1
+	ETzZoneId = 1,
+	ETzZoneStdName,
+	ETzZoneDSTName,
+	ETzZoneShortStdName,
+	ETzZoneShortDSTName,
+	ETzZoneCity,
+	ETzZoneGroupId,
+	ETzZoneResourceId,
+	ETzZoneCityIndex
+	};
+
+_LIT(KTzMutexName, 	"TZ_GlobalMutex");
+
+void CTzLocalizationDb::CleanupTimeZonePointerArray(TAny* aArray)
+	{
+	RPointerArray<CTzLocalizedTimeZoneRecord>* array = static_cast<RPointerArray<CTzLocalizedTimeZoneRecord>* >(aArray);
+	if (array)
+		{
+		array->ResetAndDestroy();
+		array->Close();
+		}
+	}
+
+void CTzLocalizationDb::CleanupCityPointerArray(TAny* aArray)
+	{
+	RPointerArray<CTzLocalizedCityRecord>* array = static_cast<RPointerArray<CTzLocalizedCityRecord>* >(aArray);
+	if (array)
+		{
+		array->ResetAndDestroy();
+		array->Close();
+		}
+	}
+
+CTzLocalizationDb* CTzLocalizationDb::NewL(CTzServer& aServer)
+	{
+	CTzLocalizationDb* self = new(ELeave) CTzLocalizationDb(aServer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CTzLocalizationDb::~CTzLocalizationDb()
+	{
+	iServer.UserTimeZoneDb().RemoveObserver(this);
+	CloseDb();
+	iDbsSession.Close();
+	}
+
+CTzLocalizationDb::CTzLocalizationDb(CTzServer& aServer)
+	: iServer(aServer)
+	{
+	}
+
+void CTzLocalizationDb::ConstructL()
+	{
+	User::LeaveIfError(iDbsSession.Connect());
+	OpenDbL();
+	iServer.UserTimeZoneDb().AddObserverL(this);
+	}
+
+void CTzLocalizationDb::OpenDbL()
+	{
+	if (iZoneMutex.OpenGlobal(KTzMutexName) != KErrNone)
+		{
+		User::LeaveIfError(iZoneMutex.CreateGlobal(KTzMutexName)) ;
+		}
+	//Attempt to open the database
+	TInt error = iLocalizedTimeZoneDb.Open(iDbsSession,KTzLocalizationDbName,KTzLocalizationDbSecurityPolicy);
+	if (error == KErrNotFound)
+		{
+		// Database file doesn't exist.  Attempt to create a new one.
+		CreateBlankDatabaseL();
+		}
+	else if ((error == KErrNone) && IsInvalidL())
+		{
+		RecreateBlankDatabaseL();
+		}
+	else if (error == KErrNone && iServer.TimeZoneManager().TzDbHasChanged())
+		{	
+		// We have to refresh the data in the frequently used zones table
+		// and the city table because it may contain the time zone id that
+		// is not existing in the Tz database. Or the the details of a tz rule
+		// has been changed.
+		RestoreDbL();
+		}
+	else if (error != KErrNone)
+		{
+		User::Leave(error);
+		}
+	}
+
+void CTzLocalizationDb::CloseDb()
+    {
+	iLocalizedTimeZoneDb.Close();
+	if (iZoneMutex.IsHeld())    // it is a leave, so release mutex
+		{
+		iZoneMutex.Signal();
+		}       
+	iZoneMutex.Close();
+	}
+
+void CTzLocalizationDb::CreateBlankDatabaseL()
+	{
+	User::LeaveIfError(iLocalizedTimeZoneDb.Create(iDbsSession,KTzLocalizationDbName,KTzLocalizationDbSecurityPolicy));
+	CreateBlankFrequentlyUsedZoneTableL();
+	CreateBlankUserCityTableL();
+	}
+
+/**
+Creates the Cached Zone Table.
+@return KErrNone if succesful, or one of the DBMS Leave codes
+@internalTechnology
+*/
+void CTzLocalizationDb::CreateBlankFrequentlyUsedZoneTableL()
+	{
+	// Create the columns for the cached zones table
+	RArray<TDbCol> cachedTableCols;
+	CleanupClosePushL(cachedTableCols);
+	cachedTableCols.AppendL(TDbCol(KCZTableTzIdCol,			EDbColUint16));
+	cachedTableCols.AppendL(TDbCol(KCZTableStdCol, 			EDbColText));
+	cachedTableCols.AppendL(TDbCol(KCZTableDSTCol, 			EDbColText));
+	cachedTableCols.AppendL(TDbCol(KCZTableShortStdCol, 	EDbColText));
+	cachedTableCols.AppendL(TDbCol(KCZTableShortDSTCol, 	EDbColText));
+	cachedTableCols.AppendL(TDbCol(KCZTableCityCol, 		EDbColText));
+	cachedTableCols.AppendL(TDbCol(KCZTableCityGroupCol, 	EDbColUint8));
+	cachedTableCols.AppendL(TDbCol(KCZTableResourceIdCol, 	EDbColUint32));
+    cachedTableCols.AppendL(TDbCol(KCZTableCityIndexCol,	EDbColInt32));
+
+	// Create the columnset - add the columns
+	// Columns MUST be added in the same order they appear in TTzZoneColumn
+	CDbColSet* frequentlyUsedZoneColSet = CDbColSet::NewLC();
+	TInt numCols = cachedTableCols.Count();
+	for(TInt i = 0; i < numCols; ++i)
+		{
+		frequentlyUsedZoneColSet->AddL(cachedTableCols[i]);
+		}
+
+	// Create the Cached Time Zone table
+	User::LeaveIfError(iLocalizedTimeZoneDb.CreateTable(KCZTableName,*frequentlyUsedZoneColSet));
+
+	//Open the newly created table
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+	zoneView.Reset();
+	//Populate with initial (blank) data.
+
+	_LIT(KEmptyString," ");
+
+	for (TInt x = 0; x < CTzLocalizedTimeZone::ECachedTimeZones; ++x)
+		{
+		iZoneMutex.Wait();
+		CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+		// Insert empty row
+		zoneView.InsertL();
+		// Fill the table with blank data
+		zoneView.SetColL(ETzZoneId,			0);
+		zoneView.SetColL(ETzZoneStdName,		KEmptyString);
+		zoneView.SetColL(ETzZoneDSTName,		KEmptyString);
+		zoneView.SetColL(ETzZoneShortStdName,	KEmptyString);
+		zoneView.SetColL(ETzZoneShortDSTName,	KEmptyString);
+		zoneView.SetColL(ETzZoneCity,			KEmptyString);
+		zoneView.SetColL(ETzZoneGroupId,		0);
+		zoneView.SetColL(ETzZoneResourceId,	0);
+		zoneView.SetColL(ETzZoneCityIndex,		0);
+		zoneView.PutL(); // Complete insertion
+		CleanupStack::Pop() ;
+		iZoneMutex.Signal() ;
+		}
+	
+	CleanupStack::PopAndDestroy(&zoneView);
+	CleanupStack::PopAndDestroy(frequentlyUsedZoneColSet);
+	CleanupStack::PopAndDestroy(&cachedTableCols); //cachedTableCols
+	}
+
+/**
+Creates the user added city database table.
+@return KErrNone if succesful, or one of the DBMS Leave codes
+@internalTechnology
+*/
+void CTzLocalizationDb::CreateBlankUserCityTableL()
+	{
+	//Create the columns for the user aded cities table
+	RArray<TDbCol> cityTableCols;
+	CleanupClosePushL(cityTableCols);
+	cityTableCols.AppendL(TDbCol(KUCTableTzId,			EDbColUint16));
+	cityTableCols.AppendL(TDbCol(KUCTableCity,			EDbColText));
+	cityTableCols.AppendL(TDbCol(KUCTableGroup,			EDbColUint8));
+	cityTableCols.AppendL(TDbCol(KUCTableResourceId,	EDbColUint32));
+
+	// Create the columnset - add the columns
+	// Columns MUST be added in the same order they appear in TTzCityColumn
+	CDbColSet* userCityColSet = CDbColSet::NewLC();
+	TInt numCols = cityTableCols.Count();
+	for(TInt i = 0; i < numCols; ++i)
+		{
+		userCityColSet->AddL(cityTableCols[i]);
+		}
+
+	// Create the User City table
+	User::LeaveIfError(iLocalizedTimeZoneDb.CreateTable(KUCTableName,*userCityColSet));
+	
+	CleanupStack::PopAndDestroy(userCityColSet);
+	CleanupStack::PopAndDestroy(&cityTableCols);
+	}
+
+//Check if the database is corrupt or invalid.
+TBool CTzLocalizationDb::IsInvalidL()
+	{
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+	TBool isInvalid = EFalse;
+	if (!zoneView.FirstL())
+		{
+		isInvalid = ETrue;
+		}
+	if (!isInvalid)
+		{
+		for (TInt i = 1; i < CTzLocalizedTimeZone::ECachedTimeZones; i++)
+			{
+		    if (!zoneView.NextL())
+			    {
+			    isInvalid = ETrue;
+			    break;
+		        }
+		    }
+		}
+	CleanupStack::PopAndDestroy(&zoneView);
+	return isInvalid;
+	}
+
+void CTzLocalizationDb::RecreateBlankDatabaseL()
+	{
+	iLocalizedTimeZoneDb.Close();
+	const TUid KTzLocalizationDbSecurityPolicyUid = {0x10206A8B};
+    User::LeaveIfError(iDbsSession.DeleteDatabase(KTzLocalizationDbName(),KTzLocalizationDbSecurityPolicyUid));
+    CreateBlankDatabaseL();
+	}
+
+TBool CTzLocalizationDb::NeedsUpdatingL()
+	{
+	// Check the version of the database
+    // There are 9 columns as of Oct 2006
+	TBool result = ETrue;
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+    if (zoneView.ColCount() == ETzZoneCityIndex)
+        {
+        result = EFalse;
+        }
+    CleanupStack::PopAndDestroy(&zoneView);
+    return result;
+	}
+
+void CTzLocalizationDb::NotifyUserTzRulesChange(TTzUserDataChange /*aChange*/)
+	{
+	// Do nothing as we don't use any rules information
+	}
+
+void CTzLocalizationDb::NotifyUserTzNamesChange(TTzUserDataChange aChange)
+	{
+	if (iLocked)
+		{
+		return;
+		}
+	
+	if (aChange.iOperation == ETzUserDataCreated)
+		{
+		// Creation of new zones has no impact on existing zones
+		return;
+		}
+	
+	// Iterate through the tables and refresh contents if needed
+	TRAPD(err, NotifyUserTzNamesChangeL(aChange));
+	if (err != KErrNone)
+		{
+		// If there has been an error we can't guarantee the contents of the
+		// database. Safest option is to lock it. The only way to unlock it
+		// is to reboot the server.
+		iLocked = ETrue;
+		}
+	}
+
+void CTzLocalizationDb::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange)
+	{
+	if (iLocked)
+		{
+		return;
+		}
+	
+	if(aChange == RTz::ETZLocalizationDataChanged)
+		{
+		CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
+		
+		RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
+		CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
+		
+		RPointerArray<CTzLocalizedCityRecord> cachedCities;
+		CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&cachedCities));
+			
+		for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
+			{
+			CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
+			CTzLocalizedTimeZoneRecord* timeZoneRecord = ReadFrequentlyUsedZoneL(freqUsedZone);
+			CleanupStack::PushL(timeZoneRecord);
+			CTzLocalizedCityRecord* cityRecord = ReadCachedTimeZoneCityL(freqUsedZone);
+			CleanupStack::PushL(cityRecord);
+		
+			// If a change occurred, check if the timezone exists in the resource file and refresh it
+			// If not, delete it
+			if(!ExistsInSystemDbL(timeZoneRecord->Id(), *systemDataDb) && !CTzId::IsUserTzId(timeZoneRecord->Id()))
+				{	
+				CleanupStack::PopAndDestroy(cityRecord);
+				cityRecord = NULL;
+				CleanupStack::PopAndDestroy(timeZoneRecord);
+				timeZoneRecord = NULL;
+				if(freqUsedZone != CTzLocalizedTimeZone::ECurrentZone)
+					{
+					// Put the default cached zone and its default city in the array instead
+					timeZoneRecord = systemDataDb->ReadFrequentlyUsedZoneL(freqUsedZone);
+					}
+				else
+					{
+					// get the current zone from the time zone server
+					TInt id = GetTimeZoneIdFromTzServerL(*systemDataDb);
+					timeZoneRecord = systemDataDb->ReadTimeZoneL(id);
+					}
+				CleanupStack::PushL(timeZoneRecord);
+				cityRecord = systemDataDb->ReadDefaultCityL(timeZoneRecord->Id());
+				CleanupStack::PushL(cityRecord);
+				
+				cachedCities.AppendL(cityRecord);
+				// ownership is transferred into the array
+				CleanupStack::Pop(cityRecord);
+				frequentlyUsedZones.AppendL(timeZoneRecord);
+				// ownership is transferred into the array
+				CleanupStack::Pop(timeZoneRecord);
+				}	
+			else
+				{
+				TUint tzid = timeZoneRecord->Id();
+				CleanupStack::PopAndDestroy(cityRecord);
+				cityRecord = NULL;
+				CleanupStack::PopAndDestroy(timeZoneRecord);
+				timeZoneRecord = NULL;
+				UpdateTimeZoneAndCityRecordForSystemDataL(frequentlyUsedZones, cachedCities, tzid, *systemDataDb);	
+				}
+			}
+		WriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
+	
+		// Get the cities with the deleted time zone id
+		RDbView cityView;
+		CleanupClosePushL(cityView);
+		_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
+		// Iterate through all the cities and delete them when
+		// the corresponding tz id doesn't exist anymore
+		PrepareCityViewL(cityView, KSQLQueryLit);
+		// Loop through the rowset and delete the cities
+		for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
+			{
+			cityView.GetL();
+			if (!ExistsInSystemDbL(cityView.ColUint16(ETzCityId), *systemDataDb))
+				{
+				cityView.DeleteL();
+				}
+			}
+		CleanupStack::PopAndDestroy(&cityView);
+		CleanupStack::PopAndDestroy(&cachedCities); 
+		CleanupStack::PopAndDestroy(&frequentlyUsedZones); 
+		CleanupStack::PopAndDestroy(systemDataDb);
+		}
+	}
+
+void CTzLocalizationDb::UpdateTimeZoneAndCityRecordForSystemDataL(RPointerArray<CTzLocalizedTimeZoneRecord>& aFrequentlyUsedZones, 
+		RPointerArray<CTzLocalizedCityRecord>& aCachedCities, TInt aTzId, CTzSystemDataDb& aSystemDataDb)
+	{
+	CTzLocalizedTimeZoneRecord* timeZone = aSystemDataDb.ReadTimeZoneL(aTzId);
+	CleanupStack::PushL(timeZone);
+
+	CTzLocalizedCityRecord* city = aSystemDataDb.ReadDefaultCityL(aTzId);
+	CleanupStack::PushL(city);
+	
+	aCachedCities.AppendL(city);
+	// ownership is transferred into the array
+	CleanupStack::Pop(city);
+	aFrequentlyUsedZones.AppendL(timeZone);
+	// ownership is transferred into the array
+	CleanupStack::Pop(timeZone);
+	}
+
+TBool CTzLocalizationDb::ExistsInSystemDbL(TUint aTzId, CTzSystemDataDb& aSystemDataDb)
+	{
+	CTzLocalizedTimeZoneRecord* timeZoneRecord = NULL;
+	TRAPD(err, timeZoneRecord = aSystemDataDb.ReadTimeZoneL(aTzId));
+	delete timeZoneRecord;
+	if(err == KErrNone)
+		{
+		return ETrue;
+		}
+	return EFalse;	
+	}
+
+/**
+Reads all the user defined cities stored in the
+database. If the database is empty the
+returned array will contain no elements.
+@param aCities Array of cities to add the user defined to.
+@internalTechnology
+*/
+void CTzLocalizationDb::ReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
+	DoReadCitiesL(aCities,KSQLQueryLit());
+	}
+
+void CTzLocalizationDb::ReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities, TInt aTimeZoneId)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	// Assign basic SQL query literal
+	_LIT(KSQLQueryLit,"SELECT * FROM UserCities WHERE TzId = ");
+	// Assign a buffer with enough room to hold the query including the time zone id
+	HBufC* sqlStr = HBufC::NewLC(KSQLQueryLit().Length() + EMaxTimeZoneIdStringLength);
+	// Set the buffer to the start of the query
+	*sqlStr = KSQLQueryLit;
+	// Append the time zone ID
+	sqlStr->Des().AppendNum(aTimeZoneId);
+
+	DoReadCitiesL(aCities,*sqlStr);
+	CleanupStack::PopAndDestroy(sqlStr);
+	}
+
+void CTzLocalizationDb::ReadCitiesInGroupL(RPointerArray<CTzLocalizedCityRecord>& aCities, TUint8 aGroupId)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	// Assign basic SQL query literal
+	_LIT(KSQLQueryLit,"SELECT * FROM UserCities WHERE GroupId = ");
+	HBufC* sqlStr = HBufC::NewLC(KSQLQueryLit().Length() + EMaxGroupIdStringLength);
+	// Set the buffer to the start of the query
+	*sqlStr = KSQLQueryLit;
+	// Append the time zone ID
+	sqlStr->Des().AppendNum(aGroupId);
+
+	DoReadCitiesL(aCities,*sqlStr);
+	CleanupStack::PopAndDestroy(sqlStr);
+	}
+
+/**
+Retrieves a cached zone from the database.
+The calling function takes ownership of the returned zone
+@param aFrequentlyUsedZone - The cached zone to return
+@return a cached zone from the database
+@internalTechnology
+*/
+CTzLocalizedTimeZoneRecord* CTzLocalizationDb::ReadFrequentlyUsedZoneL(TInt aFrequentlyUsedZone)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	return DoReadFrequentlyUsedZoneL(aFrequentlyUsedZone);
+	}
+
+CTzLocalizedTimeZoneRecord* CTzLocalizationDb::DoReadFrequentlyUsedZoneL(TInt aFrequentlyUsedZone)
+	{
+	// You cannot pass ECachedTimeZones in as the argument, because it is only
+	// used to keep count of how many cached zones there are.
+	__ASSERT_ALWAYS(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
+	
+	//Prepare a view of the zone table
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+	
+	//Ensure the cursor is at the first row in the table.
+	zoneView.FirstL();
+	
+	//Skip through the rows until we reach the row for the required zone
+	for (TInt x = 0; x < aFrequentlyUsedZone; ++x)
+		{
+		zoneView.NextL();
+		}
+	
+	//Get the row
+	zoneView.GetL();
+	
+	//Create the new localized time zone from the row data
+	CTzLocalizedTimeZoneRecord* localizedTimeZone = CTzLocalizedTimeZoneRecord::NewL(zoneView.ColUint16(ETzZoneId),
+		zoneView.ColDes(ETzZoneStdName), zoneView.ColDes(ETzZoneDSTName), zoneView.ColDes(ETzZoneShortStdName),
+		zoneView.ColDes(ETzZoneShortDSTName), zoneView.ColUint32(ETzZoneResourceId));
+	
+	CleanupStack::PopAndDestroy(&zoneView);
+	return localizedTimeZone;
+	}
+
+/**
+Retrieves the city used to select this time zone if set.  If the time zone was not originally
+set using a city then the default city for the time zone will be returned instead.
+@param aFrequentlyUsedZone - The cached zone to find the city for
+@return	 selected city for the cached zone
+@internalTechnology
+*/
+CTzLocalizedCityRecord* CTzLocalizationDb::ReadCachedTimeZoneCityL(TInt aFrequentlyUsedZone)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	
+	// You cannot pass ECachedTimeZones in as the argument, because it is only
+	// used to keep count of how many cached zones there are.
+	__ASSERT_ALWAYS(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
+
+	//Prepare a view of the zone table
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+
+	//Ensure the cursor is at the first row in the table.
+	zoneView.FirstL();
+
+	//Skip through the rows until we reach the row for the required zone
+	for (TInt x = 0; x < aFrequentlyUsedZone; ++x)
+		{
+		zoneView.NextL();
+		}
+
+	//Get the row
+	zoneView.GetL();
+
+	//Create the new localized time zone from the row data
+	TInt index = 0;
+	// An extra column was added but we still have to cope with the old format as we
+	// need to read the database contents when upgrading to the new format
+	if (zoneView.ColCount() == ETzZoneCityIndex)
+        {
+        index = zoneView.ColInt32(ETzZoneCityIndex);
+        }
+	CTzLocalizedCityRecord* city = CTzLocalizedCityRecord::NewL(zoneView.ColDes(ETzZoneCity),
+		zoneView.ColUint8(ETzZoneGroupId), index, zoneView.ColUint16(ETzZoneId),
+		zoneView.ColUint32(ETzZoneResourceId));
+    
+	CleanupStack::PopAndDestroy(&zoneView);
+	return city;
+	}
+
+void CTzLocalizationDb::WriteCityL(const TDesC& aCityName, TUint16 aCityTzId, TUint8 aCityGroupId, TUint aCityTzResourceId)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	
+	// Build a SQL query to check if the city name already exists in the database
+	// with a matching timezoneID
+	RDbView cityView;
+	CleanupClosePushL(cityView);
+	HBufC* sqlStr = GetCityQueryLC(aCityName, aCityTzId);
+	PrepareCityViewL(cityView, *sqlStr);
+	CleanupStack::PopAndDestroy(sqlStr);
+	sqlStr = NULL;
+
+	TInt cityCount = cityView.CountL();
+
+	if (cityCount == 0)
+		{
+		//City was not found.  Add the new city to the database
+		//Retrieve the CdbColSet from the view
+		CDbColSet* cityColSet = cityView.ColSetL();
+		CleanupStack::PushL(cityColSet);
+
+		//Set the rowset cursor to the beginning of the rowset,
+		//insert an empty row to write the city to
+		cityView.Reset();
+		cityView.InsertL();
+
+		//Set the city information for the new row
+		cityView.SetColL(ETzCityId,aCityTzId);
+		cityView.SetColL(ETzCityCity,aCityName);
+		cityView.SetColL(ETzCityGroup,aCityGroupId);
+		cityView.SetColL(ETzCityResourceId,aCityTzResourceId);
+
+		CleanupStack::PopAndDestroy(cityColSet);
+		cityView.PutL(); // Complete insertion
+		}
+	else
+		{
+		//City already exists.
+		User::Leave(KErrAlreadyExists);
+		}
+	CleanupStack::PopAndDestroy(&cityView);
+	iZoneMutex.Wait();
+	iLocalizedTimeZoneDb.Compact();
+	iZoneMutex.Signal();
+	}
+
+void CTzLocalizationDb::DeleteCityL(const TDesC& aCityName, TUint16 aCityTzId)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	
+	//Build a SQL query to check if the city name and time zone ID exist in the database
+	RDbView cityView;
+	CleanupClosePushL(cityView);
+	HBufC* sqlStr = GetCityQueryLC(aCityName, aCityTzId);
+	PrepareCityViewL(cityView, *sqlStr);
+	CleanupStack::PopAndDestroy(sqlStr);
+	sqlStr = NULL;
+	
+	TInt cityCount = cityView.CountL();
+
+	if (cityCount > 0)
+		{
+		//A city with this name exists in the database.  Delete it.
+		if (cityView.FirstL())
+			{
+			cityView.DeleteL();
+			//Reset the cursor, as it now points to an invalid row
+			cityView.Reset();
+			}
+		}
+	else
+		{
+		//City was not found
+		User::Leave(KErrNotFound);
+		}
+	CleanupStack::PopAndDestroy(&cityView);
+	iZoneMutex.Wait();
+	iLocalizedTimeZoneDb.Compact();
+	iZoneMutex.Signal();
+	}
+
+/**
+Stores the localized time zone in the database for easy retrieval.
+The database keeps track of the two most recently used zones, these are updated every time
+a new zone is set.  The zone to be replaced becomes recently used zone 1, and recently used zone 1 becomes
+recently used zone 2.  The old recently used zone 2 is discarded.
+@param Any city in the time zone to store
+@param aFrequentlyUsedZone - specifies which time zone to overwrite in the database
+@internalTechnology
+*/
+void CTzLocalizationDb::WriteFrequentlyUsedZoneL(const CTzLocalizedTimeZoneRecord& aTimeZone, 
+		const CTzLocalizedCityRecord& aCity, TInt aFrequentlyUsedZone)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	
+	// Only the Current, Home and Zone of Interest can be changed explicitly
+	// using this function.  Recent Zones are automatically updated.
+	__ASSERT_ALWAYS(aFrequentlyUsedZone < CTzLocalizedTimeZone::ERecentZone1, User::Leave(KErrArgument));
+	
+	iZoneMutex.Wait();
+	
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+	//Ensure the cursor is at the first row in the table.
+	zoneView.FirstL();
+	TInt x;
+	//Skip through the rows until we reach the row for the zone to update
+	for (x = 0; x < aFrequentlyUsedZone; ++x)
+		{
+		zoneView.NextL();
+		}
+
+	//Get the row
+	zoneView.GetL();
+	
+	//Bookmark the row
+	TDbBookmark rowToUpdate(zoneView.Bookmark());
+
+	//Insert a copy of the row - this is now the last row in the table, and will become
+	//recently used zone 1 after the original recently used zones are deleted
+
+	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+	zoneView.InsertCopyL();
+	zoneView.PutL();
+	CleanupStack::Pop();
+	
+	//Position the cursor back at the row to update
+	zoneView.GotoL(rowToUpdate);
+
+	//Update the row with the new data
+	DoWriteFrequentlyUsedZoneL(zoneView, aTimeZone, aCity);
+
+	//Reset the cursor back to the first row in the table.
+	zoneView.FirstL();
+
+	//Skip through the rows until we reach the row for recent zone 1
+	for (x = 0; x < CTzLocalizedTimeZone::ERecentZone1; ++x)
+		{
+		zoneView.NextL();
+		}
+
+	//Get the row
+	zoneView.GetL();
+
+	//Bookmark the row
+	TDbBookmark recentZone1(zoneView.Bookmark());
+
+	//Insert a copy of the row - this is now the last row in the table, and will become
+	//recently used zone 2 after the original recently used zones are deleted
+	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+	zoneView.InsertCopyL();
+	zoneView.PutL();
+	CleanupStack::Pop();
+
+	//Reset the cursor to the orignal recent zone 1 position
+	zoneView.GotoL(recentZone1);
+
+	//Delete the original recent zone 1 and recent zone 2.
+	//The new recent zone 1 and recent zone 2 are moved back into the correct
+	//position by the removal of the preceding rows
+	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+	zoneView.DeleteL();
+	CleanupStack::Pop();
+
+	zoneView.NextL();
+
+	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+	zoneView.DeleteL();
+	CleanupStack::Pop();
+	
+	//Cursor is now invalid (pointing to an empty row)
+	//and shuold be reset to a known state before reusing
+	//Cleanup
+	CleanupStack::PopAndDestroy(&zoneView);
+	iLocalizedTimeZoneDb.Compact();
+	iZoneMutex.Signal();
+	}
+
+/**
+Sets all the cached zones and their associated cities to be those that are
+supplied.
+@param aTimeZones Array of time zones to be written.
+@param aCities Array of cities to be written.
+@internalTechnology
+*/
+void CTzLocalizationDb::WriteAllFrequentlyUsedZonesL(const RPointerArray<CTzLocalizedTimeZoneRecord>& aTimeZones, 
+		const RPointerArray<CTzLocalizedCityRecord>& aCities)
+	{
+	if (iLocked)
+		{
+		User::Leave(KErrLocked);
+		}
+	DoWriteAllFrequentlyUsedZonesL(aTimeZones, aCities);
+	}
+
+void CTzLocalizationDb::DoWriteAllFrequentlyUsedZonesL(const RPointerArray<CTzLocalizedTimeZoneRecord>& aTimeZones, 
+		const RPointerArray<CTzLocalizedCityRecord>& aCities)
+	{
+	// Ensure that the numbers of items in the arrays are the expected amount
+	__ASSERT_ALWAYS(aTimeZones.Count() == CTzLocalizedTimeZone::ECachedTimeZones &&
+					aCities.Count() == CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
+	
+	iZoneMutex.Wait();	
+		
+	RDbView zoneView;
+	CleanupClosePushL(zoneView);
+	PrepareZoneViewL(zoneView);
+	//Ensure the cursor is at the first row in the table.
+	zoneView.FirstL();
+
+	//Skip through the rows until we reach the row for the zone to update
+	for (TInt i = 0; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
+		{
+		DoWriteFrequentlyUsedZoneL(zoneView, *aTimeZones[i], *aCities[i]);
+		zoneView.NextL();
+		}
+
+	CleanupStack::PopAndDestroy(&zoneView);
+	
+	iLocalizedTimeZoneDb.Compact();
+	iZoneMutex.Signal();
+	}
+
+/**
+Opens the a view on the city table and returns a reference to it.
+The view should be released after use with a call to CloseCityView()
+@param aSql A sql string to prepare the view with
+@return reference to opened iCityTable
+@internalTechnology
+*/
+void CTzLocalizationDb::PrepareCityViewL(RDbView& aCityView, const TDesC& aSqlQuery)
+	{
+	User::LeaveIfError(aCityView.Prepare(iLocalizedTimeZoneDb, TDbQuery(aSqlQuery),	aCityView.EUpdatable));
+	User::LeaveIfError(aCityView.EvaluateAll());
+	}
+
+/**
+Opens a view to the zone table
+@internalTechnology
+*/
+void CTzLocalizationDb::PrepareZoneViewL(RDbView& aZoneView)
+	{
+	_LIT(KReadZoneView,"SELECT * FROM FrequentlyUsedZones");
+	User::LeaveIfError(aZoneView.Prepare(iLocalizedTimeZoneDb, TDbQuery(KReadZoneView),	aZoneView.EUpdatable));
+	User::LeaveIfError(aZoneView.EvaluateAll());
+	}
+
+/**
+Returns the SQL string that will pick the specified city out of the user-added
+cities database. Leaves the returned HBufC pointer on the Cleanup Stack.
+The query is of the form:
+	"SELECT * FROM UserCities WHERE City = 'London' AND TZID = 2592"
+@param aCity The city to make the query for.
+@return The SQL Query that will select the aCity form the DB
+@internalTechnology
+*/
+HBufC* CTzLocalizationDb::GetCityQueryLC(const TDesC& aCityName, TInt aCityTimeZoneId)
+	{
+	// Assign the start and middle of the basic SQL query literal 
+	_LIT(KSQLQueryLitStart,"SELECT * FROM UserCities WHERE City = '");
+	_LIT(KSQLQueryLitMiddle,"' AND TZID = ");
+	
+	/* Assign a buffer with enough room to hold the query including the city 
+	   name and the time zone id */
+	TInt maxBufferLength = KSQLQueryLitStart().Length() + KSQLQueryLitMiddle().Length() 
+							+ aCityName.Length() + EMaxTimeZoneIdStringLength;
+	HBufC* sqlStr = HBufC::NewLC(maxBufferLength);
+	
+	// Append the beginning of the query
+	sqlStr->Des().Append(KSQLQueryLitStart);
+	// Append the city name into the query
+	sqlStr->Des().Append(aCityName);
+	// Append the middle of the query
+	sqlStr->Des().Append(KSQLQueryLitMiddle);
+	// Append the time zone ID into the query
+	sqlStr->Des().AppendNum(aCityTimeZoneId);
+	
+	return sqlStr;
+	}
+
+HBufC* CTzLocalizationDb::GetCityQueryLC(TInt aCityTimeZoneId)
+	{
+	// Assign the start and middle of the basic SQL query literal 
+	_LIT(KSQLQueryLitStart,"SELECT * FROM UserCities WHERE TZID = ");
+	
+	/* Assign a buffer with enough room to hold the query including the city 
+	   name and the time zone id */
+	TInt maxBufferLength = KSQLQueryLitStart().Length() + EMaxTimeZoneIdStringLength;
+	HBufC* sqlStr = HBufC::NewLC(maxBufferLength);
+	
+	// Append the beginning of the query
+	sqlStr->Des().Append(KSQLQueryLitStart);
+	// Append the time zone ID into the query
+	sqlStr->Des().AppendNum(aCityTimeZoneId);
+	
+	return sqlStr;
+	}
+
+/**
+Reads the user defined cities in the database
+matched by the SQL query into the supplied array. If the
+database is empty the returned array will contain no elements.
+@param aCities array of cities to add the user defined to.
+@param aSqlString - SQL search string determining the cities to retrieve
+@internalTechnology
+*/
+void CTzLocalizationDb::DoReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities, const TDesC& aSqlString)
+	{
+	RDbView cityView;
+	CleanupClosePushL(cityView);
+	PrepareCityViewL(cityView, aSqlString);
+	
+	//Loop through the rowset
+	for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
+		{
+		// Fetch a cached copy of current row
+		cityView.GetL();
+
+		//Create the new city from the row data
+		CTzLocalizedCityRecord* newCity = CTzLocalizedCityRecord::NewLC(cityView.ColDes(ETzCityCity), 
+			cityView.ColUint8(ETzCityGroup), aCities.Count(), cityView.ColUint16(ETzCityId),
+			cityView.ColUint32(ETzCityResourceId));
+     
+		//Append the new city to the city array - aCities takes ownership of newCity
+		aCities.AppendL(newCity);
+		CleanupStack::Pop(newCity);
+		}
+	CleanupStack::PopAndDestroy(&cityView);
+	}
+
+/**
+Does the actual writing of a zone and city into the database. iZoneView must
+have already been prepared and moved to the correct offset into the row set
+before this function is called. e.g. at least the following should have been
+done:
+	PrepareZoneViewL();
+	iZoneView.FirstL();
+Otherwise the cursor position may be invalid and a DBMS panic will occur.
+@param aTimeZone The time zone to write.
+@param aCity The city to write.
+@param aFrequentlyUsedZone The enum of the cached zone to write to.
+@internalTechnology
+*/
+void CTzLocalizationDb::DoWriteFrequentlyUsedZoneL(RDbView& aZoneView, const CTzLocalizedTimeZoneRecord& aTimeZone,
+		const CTzLocalizedCityRecord& aCity)
+	{
+	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
+	aZoneView.UpdateL();  
+	aZoneView.SetColL(ETzZoneId, (TInt)aTimeZone.Id());
+	aZoneView.SetColL(ETzZoneStdName, aTimeZone.StandardName());
+	aZoneView.SetColL(ETzZoneDSTName, aTimeZone.DaylightName());
+	aZoneView.SetColL(ETzZoneShortStdName, aTimeZone.ShortStandardName());
+	aZoneView.SetColL(ETzZoneShortDSTName, aTimeZone.ShortDaylightName());
+	aZoneView.SetColL(ETzZoneCity, aCity.Name());
+	aZoneView.SetColL(ETzZoneGroupId, aCity.GroupId());
+	aZoneView.SetColL(ETzZoneResourceId, aTimeZone.ResourceId());
+    if (aZoneView.ColCount() == ETzZoneCityIndex)
+        {
+        aZoneView.SetColL(ETzZoneCityIndex, aCity.Index());
+        }
+    aZoneView.PutL();
+	CleanupStack::Pop();
+	}
+
+TInt CTzLocalizationDb::GetTimeZoneIdFromTzServerL(CTzSystemDataDb& aSystemDataDb)
+	{
+	// Get current time zone using the current CTzId from the time zone server
+	TUint timeZoneIdInt = iServer.TimeZoneManager().GetTimeZoneIdL().TimeZoneNumericID();
+	
+	// Is the time zone ID the unknown/invalid ID?
+	// This is temporary measure that is required until PREQ 234' TzServer
+	// changes are introduced
+	const TUint32 KUnknownTZId = 0x0ffffff0;
+	if((TUint32)timeZoneIdInt == KUnknownTZId)
+		{
+		// Return the ID of the DEFAULT home zone instead
+		CTzLocalizedTimeZoneRecord* homeZone = aSystemDataDb.ReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone);
+		CleanupStack::PushL(homeZone);
+		timeZoneIdInt = homeZone->Id();
+		CleanupStack::PopAndDestroy(homeZone);
+		}
+		
+	return timeZoneIdInt;
+	}
+
+void CTzLocalizationDb::NotifyUserTzNamesChangeL(TTzUserDataChange aChange)
+	{
+	// If an existing user-defined time zone is updated it means we may have
+	// to refresh the data in the frequently used zones table but the city table
+	// only contains the time zone id so there is nothing to update in there.
+	
+	// If an existing user-defined time zone is deleted it means we may have
+	// to refresh the data in the frequently used zones table and the city table
+	// because it may contain the time zone id that has been deleted.
+	CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
+	TBool frequentlyUsedZonesNeedUpdating = EFalse;
+	RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
+	CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
+	RPointerArray<CTzLocalizedCityRecord> cachedCities;
+	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cachedCities));
+	for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
+		{
+		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
+		CTzLocalizedTimeZoneRecord* timeZoneRecord = ReadFrequentlyUsedZoneL(freqUsedZone);
+		CleanupStack::PushL(timeZoneRecord);
+		CTzLocalizedCityRecord* cityRecord = ReadCachedTimeZoneCityL(freqUsedZone);
+		CleanupStack::PushL(cityRecord);
+		
+	 if (timeZoneRecord->Id() == aChange.iTzId || cityRecord->TzId() == aChange.iTzId)
+		{
+		if (aChange.iOperation == ETzUserDataUpdated)
+			{
+			CleanupStack::PopAndDestroy(cityRecord);
+			cityRecord = NULL;
+			CleanupStack::PopAndDestroy(timeZoneRecord);
+			timeZoneRecord = NULL;
+			UpdateTimeZoneAndCityRecordL(frequentlyUsedZones, cachedCities, aChange.iTzId);
+			}
+		else if (aChange.iOperation == ETzUserDataDeleted)
+			{
+			CleanupStack::PopAndDestroy(cityRecord);
+			cityRecord = NULL;
+			CleanupStack::PopAndDestroy(timeZoneRecord);
+			timeZoneRecord = NULL;
+			
+			if(freqUsedZone != CTzLocalizedTimeZone::ECurrentZone)
+				{
+				// Put the default cached zone and its default city in the array instead
+				timeZoneRecord = systemDataDb->ReadFrequentlyUsedZoneL(freqUsedZone);
+				}
+			else
+				{
+				// get the current zone from the time zone server
+				TInt id = GetTimeZoneIdFromTzServerL(*systemDataDb);
+				timeZoneRecord = systemDataDb->ReadTimeZoneL(id);
+				}
+			CleanupStack::PushL(timeZoneRecord);
+			cityRecord = systemDataDb->ReadDefaultCityL(timeZoneRecord->Id());
+			CleanupStack::PushL(cityRecord);
+			
+			cachedCities.AppendL(cityRecord);
+			// ownership is transferred into the array
+			CleanupStack::Pop(cityRecord);
+			frequentlyUsedZones.AppendL(timeZoneRecord);
+			// ownership is transferred into the array
+			CleanupStack::Pop(timeZoneRecord);
+			}
+		frequentlyUsedZonesNeedUpdating = ETrue;
+		}
+	else
+		{
+		cachedCities.AppendL(cityRecord);
+		// ownership is transferred into the array
+		CleanupStack::Pop(cityRecord);
+		frequentlyUsedZones.AppendL(timeZoneRecord);
+		// ownership is transferred into the array
+		CleanupStack::Pop(timeZoneRecord);
+		}
+	}
+			
+	if (frequentlyUsedZonesNeedUpdating)
+		{
+		WriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
+		}
+		
+	if (aChange.iOperation == ETzUserDataDeleted)
+		{
+		DeleteCitiesL(aChange);
+		iZoneMutex.Wait();
+		iLocalizedTimeZoneDb.Compact();
+		iZoneMutex.Signal();
+		}
+	CleanupStack::PopAndDestroy(&cachedCities); 
+	CleanupStack::PopAndDestroy(&frequentlyUsedZones);
+	CleanupStack::PopAndDestroy(systemDataDb);
+	}
+
+void CTzLocalizationDb::UpdateTimeZoneAndCityRecordL(RPointerArray<CTzLocalizedTimeZoneRecord>& aFrequentlyUsedZones, RPointerArray<CTzLocalizedCityRecord>& aCachedCities, TInt aTzId)
+	{
+	CTzUserNames* names = iServer.UserTimeZoneDb().ReadTzNamesL(aTzId);
+	CleanupStack::PushL(names);
+
+	CTzLocalizedTimeZoneRecord* timeZoneRecord = CTzLocalizedTimeZoneRecord::NewL(aTzId, names->StandardName(),
+		names->DaylightSaveName(), names->ShortStandardName(), names->ShortDaylightSaveName(), 0);
+	CleanupStack::PushL(timeZoneRecord);
+	
+	CTzLocalizedCityRecord* cityRecord = CTzLocalizedCityRecord::NewL(names->CityName(), 0, 0, aTzId, 0);
+	CleanupStack::PushL(cityRecord);
+
+	aCachedCities.AppendL(cityRecord);
+	// ownership is transferred into the array
+	CleanupStack::Pop(cityRecord);
+	aFrequentlyUsedZones.AppendL(timeZoneRecord);
+	// ownership is transferred into the array
+	CleanupStack::Pop(timeZoneRecord);
+	CleanupStack::PopAndDestroy(names);
+	}
+
+void CTzLocalizationDb::DeleteCitiesL(TTzUserDataChange aChange)
+	{
+	// Get the cities with the deleted time zone id
+	RDbView cityView;
+	CleanupClosePushL(cityView);
+	if(aChange.iOperation == ETzUserDataDeleted)
+		{
+		HBufC* sqlStr = GetCityQueryLC(aChange.iTzId);
+		PrepareCityViewL(cityView, *sqlStr);
+		CleanupStack::PopAndDestroy(sqlStr);
+		sqlStr = NULL;
+		}
+	else if(aChange.iOperation == ETzUserDataRestored)
+		{
+		_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
+		// Iterate through all the cities and delete them when
+		// the corresponding tz id doesn't exist anymore
+		PrepareCityViewL(cityView, KSQLQueryLit);
+		}
+	// Loop through the rowset and delete the cities
+	for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
+		{
+		if(aChange.iOperation == ETzUserDataDeleted)
+			{
+			cityView.DeleteL();		
+			}
+		else if(aChange.iOperation == ETzUserDataRestored)
+			{
+			cityView.GetL();
+			if (!iServer.TimeZoneManager().TzDataProvider().IsIdInDbL(cityView.ColUint16(ETzCityId)))
+				{
+				cityView.DeleteL();
+				}
+			}	
+		}
+	CleanupStack::PopAndDestroy(&cityView);
+	}
+
+/**
+Releases the mutex if leave occurs between wait and signal.
+@internalTechnology
+*/
+void CTzLocalizationDb::ReleaseMutex(TAny* iTarget)
+	{
+	RMutex* mutex = static_cast<RMutex*>(iTarget);	
+	mutex->Signal();	
+	}
+
+// Backup and restore operations
+void CTzLocalizationDb::BackupBeginningL()
+	{
+	CloseDb();
+	iLocked = ETrue;
+	}
+
+void CTzLocalizationDb::BackupCompletedL()
+	{
+	OpenDbL();
+	iLocked = EFalse;
+	}
+
+void CTzLocalizationDb::RestoreBeginningL()
+	{
+	CloseDb();
+	iLocked = ETrue;
+	}
+
+void CTzLocalizationDb::RestoreDbL()
+	{
+	// When the Tz server is connected or a restore completes, we have to
+	// refresh the data in the frequently used zones table and the city table
+	// because it may contain the time zone id that has been deleted.  Or if the
+	// time zone id is still there but the details of the rule has been changed.
+
+	CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
+
+	TBool frequentlyUsedZonesNeedUpdating = EFalse;
+
+	RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
+	CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
+
+	RPointerArray<CTzLocalizedCityRecord> cachedCities;
+	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cachedCities));
+
+	for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
+		{//Loop through each record in frequently used table
+		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
+		CTzLocalizedTimeZoneRecord* timeZoneRecord = DoReadFrequentlyUsedZoneL(freqUsedZone);
+		TUint tzid = timeZoneRecord->Id();
+		delete timeZoneRecord;
+		TBool tzIdExistInDb = iServer.TimeZoneManager().TzDataProvider().IsIdInDbL(tzid);
+		
+		if(!tzIdExistInDb)
+			{
+			if(freqUsedZone == CTzLocalizedTimeZone::ECurrentZone)
+				{
+				tzid = GetTimeZoneIdFromTzServerL(*systemDataDb);
+				}
+			else
+				{
+				tzid = GetFrequentlyUsedDefaultZoneIdL(freqUsedZone, *systemDataDb);
+				}
+			}
+		
+		if (CTzId::IsUserTzId(tzid))
+			{
+			UpdateTimeZoneAndCityRecordL(frequentlyUsedZones, cachedCities, tzid);	
+			}
+		else
+			{
+			UpdateTimeZoneAndCityRecordForSystemDataL(frequentlyUsedZones, cachedCities, tzid, *systemDataDb);
+			}
+
+		frequentlyUsedZonesNeedUpdating = ETrue;
+		}
+			
+	if (frequentlyUsedZonesNeedUpdating)
+		{
+		//Update the frequently used zone table
+		DoWriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
+		}
+	
+	TTzUserDataChange change;
+	change.iOperation = ETzUserDataRestored;
+	change.iTzId = KInvalidTzId;
+	//Delete the city infomation if the associated time zone no longer exist.
+	DeleteCitiesL(change);
+	
+	CleanupStack::PopAndDestroy(&cachedCities); 
+	CleanupStack::PopAndDestroy(&frequentlyUsedZones);
+	CleanupStack::PopAndDestroy(systemDataDb);
+	}
+
+/**
+Get the localized default time zone Id for the given frequently used time zone.
+The default time zone for each of the possible frequently used time zones may be
+specified in the TZ Server repository or in the TZ Localization resource file.
+Check the possible sources in this order.
+
+@param aFreqUsedZone The frequently used time zone for which the localized
+default time zone is required.
+@param aSystemDataDb For TZ Localization database access.
+
+@return The localized default time zone Id for the given frequently used time zone.
+*/
+TInt CTzLocalizationDb::GetFrequentlyUsedDefaultZoneIdL(
+	CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone,
+	CTzSystemDataDb& aSystemDataDb)
+	{
+	// Assume that we will not find the key in the repository or that we do find
+	// the key but it has no value.  If either of these scenarios is true then
+	// we will use the time zone identifier recorded in the resource file for
+	// the default time zone.
+	
+	TUint32 defaultTimeZoneKey = GetFrequentlyUsedDefaultZoneCenRepKeyL(aFreqUsedZone);
+	CRepository* tzRepository = CRepository::NewL(NTzUpdate::KPropertyCategory);
+	CleanupStack::PushL(tzRepository);
+	TInt defaultTimeZoneId = 0;
+	TInt err = tzRepository->Get(defaultTimeZoneKey, defaultTimeZoneId);
+	CleanupStack::PopAndDestroy(tzRepository);
+	
+	if(err != KErrNotFound)
+		{
+		User::LeaveIfError(err);
+		}
+	
+	if(defaultTimeZoneId == 0)
+		{
+		defaultTimeZoneId = aSystemDataDb.ReadFrequentlyUsedZoneIdL(aFreqUsedZone);
+		}
+	
+	return defaultTimeZoneId;
+	}
+
+/**
+Get the TZ Server's CenRep repository key for the given frequently used zone.
+
+@param aFreqUsedZone The frequently used time zone for which the TZ Server's
+CenRep repository key is required.
+
+@return The TZ Server's CenRep repository key for the given frequently used
+zone.
+*/
+TUint32 CTzLocalizationDb::GetFrequentlyUsedDefaultZoneCenRepKeyL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone)
+	{
+	// These key values are copied from those defined in tzconfigagent.h.  We
+	// want to keep the key values private - this is one way to do it.
+	const TUint32 KDefaultHomeTimeZoneKey = 0x3UL;
+	const TUint32 KDefaultInterestTimeZoneKey = 0x4UL;
+	const TUint32 KDefaultRecent1TimeZoneKey = 0x5UL;
+	const TUint32 KDefaultRecent2TimeZoneKey = 0x6UL;
+
+	TUint32 key = 0;
+
+	switch(aFreqUsedZone)
+	    {
+	    case CTzLocalizedTimeZone::EHomeZone:
+	    	{
+	    	key = KDefaultHomeTimeZoneKey;
+	        }
+	    break;
+
+	    case CTzLocalizedTimeZone::EInterestZone:
+	    	{
+	    	key = KDefaultInterestTimeZoneKey;
+	        }
+	    break;
+
+	    case CTzLocalizedTimeZone::ERecentZone1:
+	    	{
+	    	key = KDefaultRecent1TimeZoneKey;
+	        }
+	    break;
+
+	    case CTzLocalizedTimeZone::ERecentZone2:
+	    	{
+	    	key = KDefaultRecent2TimeZoneKey;
+	        }
+	    break;
+	    
+	    default:
+	    	{
+	    	User::Leave(KErrArgument);
+	    	}
+	    }
+
+	return key;
+    }
+
+void CTzLocalizationDb::RestoreCompletedL()
+	{
+	OpenDbL();
+	iLocked = EFalse;
+	RestoreDbL();
+	}
+