tzservices/tzserver/Server/Source/tzlocalizationdb.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
child 82 4610cd70c542
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // Copyright (c) 2008-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 "tzlocalizationdb.h"
       
    17 #include "timezoneserver.h"
       
    18 #include "mtimezonedataaccess.h"
       
    19 
       
    20 #include <centralrepository.h>				// For CRepository.
       
    21 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    22 #include <tzusernames.h>//new file added for CTzUserNames which is publishedPartner
       
    23 #endif
       
    24 #include <tzlocalizedcityrecord.h>
       
    25 #include <tzlocalizedtimezonerecord.h>
       
    26 
       
    27 // Database location and access policy
       
    28 _LIT(KTzLocalizationDbName,"c:TzLocalization.db");
       
    29 _LIT(KTzLocalizationDbSecurityPolicy,"secure[10206A8B]");
       
    30 
       
    31 //Table and Column names for Cached Time Zone Table
       
    32 //These text strings are never visible and do not need localizing
       
    33 _LIT(KCZTableName, 			"FrequentlyUsedZones");
       
    34 _LIT(KCZTableTzIdCol, 		"TzId");
       
    35 _LIT(KCZTableStdCol, 		"StandardName");
       
    36 _LIT(KCZTableDSTCol, 		"DSTName");
       
    37 _LIT(KCZTableShortStdCol,	"ShortStandardName");
       
    38 _LIT(KCZTableShortDSTCol, 	"ShortDSTName");
       
    39 _LIT(KCZTableCityCol, 		"City");
       
    40 _LIT(KCZTableCityGroupCol, 	"GroupId");
       
    41 _LIT(KCZTableResourceIdCol,	"ResourceId");
       
    42 _LIT(KCZTableCityIndexCol,	"CityIndex");
       
    43 
       
    44 //Table and Column names for User Added Cities Table
       
    45 //These text strings are never visible and do not need localizing
       
    46 _LIT(KUCTableName, 			"UserCities");
       
    47 _LIT(KUCTableTzId, 			"TzId");
       
    48 _LIT(KUCTableCity, 			"City");
       
    49 _LIT(KUCTableGroup, 		"GroupId");
       
    50 _LIT(KUCTableResourceId,	"ResourceId");
       
    51 
       
    52 enum TTzZoneColumn
       
    53 	{
       
    54 	// Enum will used as a DB column index, so it must start at 1
       
    55 	ETzZoneId = 1,
       
    56 	ETzZoneStdName,
       
    57 	ETzZoneDSTName,
       
    58 	ETzZoneShortStdName,
       
    59 	ETzZoneShortDSTName,
       
    60 	ETzZoneCity,
       
    61 	ETzZoneGroupId,
       
    62 	ETzZoneResourceId,
       
    63 	ETzZoneCityIndex
       
    64 	};
       
    65 
       
    66 _LIT(KTzMutexName, 	"TZ_GlobalMutex");
       
    67 
       
    68 void CTzLocalizationDb::CleanupTimeZonePointerArray(TAny* aArray)
       
    69 	{
       
    70 	RPointerArray<CTzLocalizedTimeZoneRecord>* array = static_cast<RPointerArray<CTzLocalizedTimeZoneRecord>* >(aArray);
       
    71 	if (array)
       
    72 		{
       
    73 		array->ResetAndDestroy();
       
    74 		array->Close();
       
    75 		}
       
    76 	}
       
    77 
       
    78 void CTzLocalizationDb::CleanupCityPointerArray(TAny* aArray)
       
    79 	{
       
    80 	RPointerArray<CTzLocalizedCityRecord>* array = static_cast<RPointerArray<CTzLocalizedCityRecord>* >(aArray);
       
    81 	if (array)
       
    82 		{
       
    83 		array->ResetAndDestroy();
       
    84 		array->Close();
       
    85 		}
       
    86 	}
       
    87 
       
    88 CTzLocalizationDb* CTzLocalizationDb::NewL(CTzServer& aServer)
       
    89 	{
       
    90 	CTzLocalizationDb* self = new(ELeave) CTzLocalizationDb(aServer);
       
    91 	CleanupStack::PushL(self);
       
    92 	self->ConstructL();
       
    93 	CleanupStack::Pop(self);
       
    94 	return self;
       
    95 	}
       
    96 
       
    97 CTzLocalizationDb::~CTzLocalizationDb()
       
    98 	{
       
    99 	iServer.UserTimeZoneDb().RemoveObserver(this);
       
   100 	CloseDb();
       
   101 	iDbsSession.Close();
       
   102 	}
       
   103 
       
   104 CTzLocalizationDb::CTzLocalizationDb(CTzServer& aServer)
       
   105 	: iServer(aServer)
       
   106 	{
       
   107 	}
       
   108 
       
   109 void CTzLocalizationDb::ConstructL()
       
   110 	{
       
   111 	User::LeaveIfError(iDbsSession.Connect());
       
   112 	OpenDbL();
       
   113 	iServer.UserTimeZoneDb().AddObserverL(this);
       
   114 	}
       
   115 
       
   116 void CTzLocalizationDb::OpenDbL()
       
   117 	{
       
   118 	if (iZoneMutex.OpenGlobal(KTzMutexName) != KErrNone)
       
   119 		{
       
   120 		User::LeaveIfError(iZoneMutex.CreateGlobal(KTzMutexName)) ;
       
   121 		}
       
   122 	//Attempt to open the database
       
   123 	TInt error = iLocalizedTimeZoneDb.Open(iDbsSession,KTzLocalizationDbName,KTzLocalizationDbSecurityPolicy);
       
   124 	if (error == KErrNotFound)
       
   125 		{
       
   126 		// Database file doesn't exist.  Attempt to create a new one.
       
   127 		CreateBlankDatabaseL();
       
   128 		}
       
   129 	else if ((error == KErrNone) && IsInvalidL())
       
   130 		{
       
   131 		RecreateBlankDatabaseL();
       
   132 		}
       
   133 	else if (error == KErrNone && iServer.TimeZoneManager().TzDbHasChanged())
       
   134 		{	
       
   135 		// We have to refresh the data in the frequently used zones table
       
   136 		// and the city table because it may contain the time zone id that
       
   137 		// is not existing in the Tz database. Or the the details of a tz rule
       
   138 		// has been changed.
       
   139 		RestoreDbL();
       
   140 		}
       
   141 	else if (error != KErrNone)
       
   142 		{
       
   143 		User::Leave(error);
       
   144 		}
       
   145 	}
       
   146 
       
   147 void CTzLocalizationDb::CloseDb()
       
   148     {
       
   149 	iLocalizedTimeZoneDb.Close();
       
   150 	if (iZoneMutex.IsHeld())    // it is a leave, so release mutex
       
   151 		{
       
   152 		iZoneMutex.Signal();
       
   153 		}       
       
   154 	iZoneMutex.Close();
       
   155 	}
       
   156 
       
   157 void CTzLocalizationDb::CreateBlankDatabaseL()
       
   158 	{
       
   159 	User::LeaveIfError(iLocalizedTimeZoneDb.Create(iDbsSession,KTzLocalizationDbName,KTzLocalizationDbSecurityPolicy));
       
   160 	CreateBlankFrequentlyUsedZoneTableL();
       
   161 	CreateBlankUserCityTableL();
       
   162 	}
       
   163 
       
   164 /**
       
   165 Creates the Cached Zone Table.
       
   166 @return KErrNone if succesful, or one of the DBMS Leave codes
       
   167 @internalTechnology
       
   168 */
       
   169 void CTzLocalizationDb::CreateBlankFrequentlyUsedZoneTableL()
       
   170 	{
       
   171 	// Create the columns for the cached zones table
       
   172 	RArray<TDbCol> cachedTableCols;
       
   173 	CleanupClosePushL(cachedTableCols);
       
   174 	cachedTableCols.AppendL(TDbCol(KCZTableTzIdCol,			EDbColUint16));
       
   175 	cachedTableCols.AppendL(TDbCol(KCZTableStdCol, 			EDbColText));
       
   176 	cachedTableCols.AppendL(TDbCol(KCZTableDSTCol, 			EDbColText));
       
   177 	cachedTableCols.AppendL(TDbCol(KCZTableShortStdCol, 	EDbColText));
       
   178 	cachedTableCols.AppendL(TDbCol(KCZTableShortDSTCol, 	EDbColText));
       
   179 	cachedTableCols.AppendL(TDbCol(KCZTableCityCol, 		EDbColText));
       
   180 	cachedTableCols.AppendL(TDbCol(KCZTableCityGroupCol, 	EDbColUint8));
       
   181 	cachedTableCols.AppendL(TDbCol(KCZTableResourceIdCol, 	EDbColUint32));
       
   182     cachedTableCols.AppendL(TDbCol(KCZTableCityIndexCol,	EDbColInt32));
       
   183 
       
   184 	// Create the columnset - add the columns
       
   185 	// Columns MUST be added in the same order they appear in TTzZoneColumn
       
   186 	CDbColSet* frequentlyUsedZoneColSet = CDbColSet::NewLC();
       
   187 	TInt numCols = cachedTableCols.Count();
       
   188 	for(TInt i = 0; i < numCols; ++i)
       
   189 		{
       
   190 		frequentlyUsedZoneColSet->AddL(cachedTableCols[i]);
       
   191 		}
       
   192 
       
   193 	// Create the Cached Time Zone table
       
   194 	User::LeaveIfError(iLocalizedTimeZoneDb.CreateTable(KCZTableName,*frequentlyUsedZoneColSet));
       
   195 
       
   196 	//Open the newly created table
       
   197 	RDbView zoneView;
       
   198 	CleanupClosePushL(zoneView);
       
   199 	PrepareZoneViewL(zoneView);
       
   200 	zoneView.Reset();
       
   201 	//Populate with initial (blank) data.
       
   202 
       
   203 	_LIT(KEmptyString," ");
       
   204 
       
   205 	for (TInt x = 0; x < CTzLocalizedTimeZone::ECachedTimeZones; ++x)
       
   206 		{
       
   207 		iZoneMutex.Wait();
       
   208 		CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   209 		// Insert empty row
       
   210 		zoneView.InsertL();
       
   211 		// Fill the table with blank data
       
   212 		zoneView.SetColL(ETzZoneId,			0);
       
   213 		zoneView.SetColL(ETzZoneStdName,		KEmptyString);
       
   214 		zoneView.SetColL(ETzZoneDSTName,		KEmptyString);
       
   215 		zoneView.SetColL(ETzZoneShortStdName,	KEmptyString);
       
   216 		zoneView.SetColL(ETzZoneShortDSTName,	KEmptyString);
       
   217 		zoneView.SetColL(ETzZoneCity,			KEmptyString);
       
   218 		zoneView.SetColL(ETzZoneGroupId,		0);
       
   219 		zoneView.SetColL(ETzZoneResourceId,	0);
       
   220 		zoneView.SetColL(ETzZoneCityIndex,		0);
       
   221 		zoneView.PutL(); // Complete insertion
       
   222 		CleanupStack::Pop() ;
       
   223 		iZoneMutex.Signal() ;
       
   224 		}
       
   225 	
       
   226 	CleanupStack::PopAndDestroy(&zoneView);
       
   227 	CleanupStack::PopAndDestroy(frequentlyUsedZoneColSet);
       
   228 	CleanupStack::PopAndDestroy(&cachedTableCols); //cachedTableCols
       
   229 	}
       
   230 
       
   231 /**
       
   232 Creates the user added city database table.
       
   233 @return KErrNone if succesful, or one of the DBMS Leave codes
       
   234 @internalTechnology
       
   235 */
       
   236 void CTzLocalizationDb::CreateBlankUserCityTableL()
       
   237 	{
       
   238 	//Create the columns for the user aded cities table
       
   239 	RArray<TDbCol> cityTableCols;
       
   240 	CleanupClosePushL(cityTableCols);
       
   241 	cityTableCols.AppendL(TDbCol(KUCTableTzId,			EDbColUint16));
       
   242 	cityTableCols.AppendL(TDbCol(KUCTableCity,			EDbColText));
       
   243 	cityTableCols.AppendL(TDbCol(KUCTableGroup,			EDbColUint8));
       
   244 	cityTableCols.AppendL(TDbCol(KUCTableResourceId,	EDbColUint32));
       
   245 
       
   246 	// Create the columnset - add the columns
       
   247 	// Columns MUST be added in the same order they appear in TTzCityColumn
       
   248 	CDbColSet* userCityColSet = CDbColSet::NewLC();
       
   249 	TInt numCols = cityTableCols.Count();
       
   250 	for(TInt i = 0; i < numCols; ++i)
       
   251 		{
       
   252 		userCityColSet->AddL(cityTableCols[i]);
       
   253 		}
       
   254 
       
   255 	// Create the User City table
       
   256 	User::LeaveIfError(iLocalizedTimeZoneDb.CreateTable(KUCTableName,*userCityColSet));
       
   257 	
       
   258 	CleanupStack::PopAndDestroy(userCityColSet);
       
   259 	CleanupStack::PopAndDestroy(&cityTableCols);
       
   260 	}
       
   261 
       
   262 //Check if the database is corrupt or invalid.
       
   263 TBool CTzLocalizationDb::IsInvalidL()
       
   264 	{
       
   265 	RDbView zoneView;
       
   266 	CleanupClosePushL(zoneView);
       
   267 	PrepareZoneViewL(zoneView);
       
   268 	TBool isInvalid = EFalse;
       
   269 	if (!zoneView.FirstL())
       
   270 		{
       
   271 		isInvalid = ETrue;
       
   272 		}
       
   273 	if (!isInvalid)
       
   274 		{
       
   275 		for (TInt i = 1; i < CTzLocalizedTimeZone::ECachedTimeZones; i++)
       
   276 			{
       
   277 		    if (!zoneView.NextL())
       
   278 			    {
       
   279 			    isInvalid = ETrue;
       
   280 			    break;
       
   281 		        }
       
   282 		    }
       
   283 		}
       
   284 	CleanupStack::PopAndDestroy(&zoneView);
       
   285 	return isInvalid;
       
   286 	}
       
   287 
       
   288 void CTzLocalizationDb::RecreateBlankDatabaseL()
       
   289 	{
       
   290 	iLocalizedTimeZoneDb.Close();
       
   291 	const TUid KTzLocalizationDbSecurityPolicyUid = {0x10206A8B};
       
   292     User::LeaveIfError(iDbsSession.DeleteDatabase(KTzLocalizationDbName(),KTzLocalizationDbSecurityPolicyUid));
       
   293     CreateBlankDatabaseL();
       
   294 	}
       
   295 
       
   296 TBool CTzLocalizationDb::NeedsUpdatingL()
       
   297 	{
       
   298 	// Check the version of the database
       
   299     // There are 9 columns as of Oct 2006
       
   300 	TBool result = ETrue;
       
   301 	RDbView zoneView;
       
   302 	CleanupClosePushL(zoneView);
       
   303 	PrepareZoneViewL(zoneView);
       
   304     if (zoneView.ColCount() == ETzZoneCityIndex)
       
   305         {
       
   306         result = EFalse;
       
   307         }
       
   308     CleanupStack::PopAndDestroy(&zoneView);
       
   309     return result;
       
   310 	}
       
   311 
       
   312 void CTzLocalizationDb::NotifyUserTzRulesChange(TTzUserDataChange /*aChange*/)
       
   313 	{
       
   314 	// Do nothing as we don't use any rules information
       
   315 	}
       
   316 
       
   317 void CTzLocalizationDb::NotifyUserTzNamesChange(TTzUserDataChange aChange)
       
   318 	{
       
   319 	if (iLocked)
       
   320 		{
       
   321 		return;
       
   322 		}
       
   323 	
       
   324 	if (aChange.iOperation == ETzUserDataCreated)
       
   325 		{
       
   326 		// Creation of new zones has no impact on existing zones
       
   327 		return;
       
   328 		}
       
   329 	
       
   330 	// Iterate through the tables and refresh contents if needed
       
   331 	TRAPD(err, NotifyUserTzNamesChangeL(aChange));
       
   332 	if (err != KErrNone)
       
   333 		{
       
   334 		// If there has been an error we can't guarantee the contents of the
       
   335 		// database. Safest option is to lock it. The only way to unlock it
       
   336 		// is to reboot the server.
       
   337 		iLocked = ETrue;
       
   338 		}
       
   339 	}
       
   340 
       
   341 void CTzLocalizationDb::NotifyTZDataStatusChangeL(RTz::TTzChanges aChange)
       
   342 	{
       
   343 	if (iLocked)
       
   344 		{
       
   345 		return;
       
   346 		}
       
   347 	
       
   348 	if(aChange == RTz::ETZLocalizationDataChanged)
       
   349 		{
       
   350 		CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
       
   351 		
       
   352 		RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
       
   353 		CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
       
   354 		
       
   355 		RPointerArray<CTzLocalizedCityRecord> cachedCities;
       
   356 		CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&cachedCities));
       
   357 			
       
   358 		for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
   359 			{
       
   360 			CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
       
   361 			CTzLocalizedTimeZoneRecord* timeZoneRecord = ReadFrequentlyUsedZoneL(freqUsedZone);
       
   362 			CleanupStack::PushL(timeZoneRecord);
       
   363 			CTzLocalizedCityRecord* cityRecord = ReadCachedTimeZoneCityL(freqUsedZone);
       
   364 			CleanupStack::PushL(cityRecord);
       
   365 		
       
   366 			// If a change occurred, check if the timezone exists in the resource file and refresh it
       
   367 			// If not, delete it
       
   368 			if(!ExistsInSystemDbL(timeZoneRecord->Id(), *systemDataDb) && !CTzId::IsUserTzId(timeZoneRecord->Id()))
       
   369 				{	
       
   370 				CleanupStack::PopAndDestroy(cityRecord);
       
   371 				cityRecord = NULL;
       
   372 				CleanupStack::PopAndDestroy(timeZoneRecord);
       
   373 				timeZoneRecord = NULL;
       
   374 				if(freqUsedZone != CTzLocalizedTimeZone::ECurrentZone)
       
   375 					{
       
   376 					// Put the default cached zone and its default city in the array instead
       
   377 					timeZoneRecord = systemDataDb->ReadFrequentlyUsedZoneL(freqUsedZone);
       
   378 					}
       
   379 				else
       
   380 					{
       
   381 					// get the current zone from the time zone server
       
   382 					TInt id = GetTimeZoneIdFromTzServerL(*systemDataDb);
       
   383 					timeZoneRecord = systemDataDb->ReadTimeZoneL(id);
       
   384 					}
       
   385 				CleanupStack::PushL(timeZoneRecord);
       
   386 				cityRecord = systemDataDb->ReadDefaultCityL(timeZoneRecord->Id());
       
   387 				CleanupStack::PushL(cityRecord);
       
   388 				
       
   389 				cachedCities.AppendL(cityRecord);
       
   390 				// ownership is transferred into the array
       
   391 				CleanupStack::Pop(cityRecord);
       
   392 				frequentlyUsedZones.AppendL(timeZoneRecord);
       
   393 				// ownership is transferred into the array
       
   394 				CleanupStack::Pop(timeZoneRecord);
       
   395 				}	
       
   396 			else
       
   397 				{
       
   398 				TUint tzid = timeZoneRecord->Id();
       
   399 				CleanupStack::PopAndDestroy(cityRecord);
       
   400 				cityRecord = NULL;
       
   401 				CleanupStack::PopAndDestroy(timeZoneRecord);
       
   402 				timeZoneRecord = NULL;
       
   403 				UpdateTimeZoneAndCityRecordForSystemDataL(frequentlyUsedZones, cachedCities, tzid, *systemDataDb);	
       
   404 				}
       
   405 			}
       
   406 		WriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
       
   407 	
       
   408 		// Get the cities with the deleted time zone id
       
   409 		RDbView cityView;
       
   410 		CleanupClosePushL(cityView);
       
   411 		_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
       
   412 		// Iterate through all the cities and delete them when
       
   413 		// the corresponding tz id doesn't exist anymore
       
   414 		PrepareCityViewL(cityView, KSQLQueryLit);
       
   415 		// Loop through the rowset and delete the cities
       
   416 		for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
       
   417 			{
       
   418 			cityView.GetL();
       
   419 			if (!ExistsInSystemDbL(cityView.ColUint16(ETzCityId), *systemDataDb))
       
   420 				{
       
   421 				cityView.DeleteL();
       
   422 				}
       
   423 			}
       
   424 		CleanupStack::PopAndDestroy(&cityView);
       
   425 		CleanupStack::PopAndDestroy(&cachedCities); 
       
   426 		CleanupStack::PopAndDestroy(&frequentlyUsedZones); 
       
   427 		CleanupStack::PopAndDestroy(systemDataDb);
       
   428 		}
       
   429 	}
       
   430 
       
   431 void CTzLocalizationDb::UpdateTimeZoneAndCityRecordForSystemDataL(RPointerArray<CTzLocalizedTimeZoneRecord>& aFrequentlyUsedZones, 
       
   432 		RPointerArray<CTzLocalizedCityRecord>& aCachedCities, TInt aTzId, CTzSystemDataDb& aSystemDataDb)
       
   433 	{
       
   434 	CTzLocalizedTimeZoneRecord* timeZone = aSystemDataDb.ReadTimeZoneL(aTzId);
       
   435 	CleanupStack::PushL(timeZone);
       
   436 
       
   437 	CTzLocalizedCityRecord* city = aSystemDataDb.ReadDefaultCityL(aTzId);
       
   438 	CleanupStack::PushL(city);
       
   439 	
       
   440 	aCachedCities.AppendL(city);
       
   441 	// ownership is transferred into the array
       
   442 	CleanupStack::Pop(city);
       
   443 	aFrequentlyUsedZones.AppendL(timeZone);
       
   444 	// ownership is transferred into the array
       
   445 	CleanupStack::Pop(timeZone);
       
   446 	}
       
   447 
       
   448 TBool CTzLocalizationDb::ExistsInSystemDbL(TUint aTzId, CTzSystemDataDb& aSystemDataDb)
       
   449 	{
       
   450 	CTzLocalizedTimeZoneRecord* timeZoneRecord = NULL;
       
   451 	TRAPD(err, timeZoneRecord = aSystemDataDb.ReadTimeZoneL(aTzId));
       
   452 	delete timeZoneRecord;
       
   453 	if(err == KErrNone)
       
   454 		{
       
   455 		return ETrue;
       
   456 		}
       
   457 	return EFalse;	
       
   458 	}
       
   459 
       
   460 /**
       
   461 Reads all the user defined cities stored in the
       
   462 database. If the database is empty the
       
   463 returned array will contain no elements.
       
   464 @param aCities Array of cities to add the user defined to.
       
   465 @internalTechnology
       
   466 */
       
   467 void CTzLocalizationDb::ReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities)
       
   468 	{
       
   469 	if (iLocked)
       
   470 		{
       
   471 		User::Leave(KErrLocked);
       
   472 		}
       
   473 	_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
       
   474 	DoReadCitiesL(aCities,KSQLQueryLit());
       
   475 	}
       
   476 
       
   477 void CTzLocalizationDb::ReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities, TInt aTimeZoneId)
       
   478 	{
       
   479 	if (iLocked)
       
   480 		{
       
   481 		User::Leave(KErrLocked);
       
   482 		}
       
   483 	// Assign basic SQL query literal
       
   484 	_LIT(KSQLQueryLit,"SELECT * FROM UserCities WHERE TzId = ");
       
   485 	// Assign a buffer with enough room to hold the query including the time zone id
       
   486 	HBufC* sqlStr = HBufC::NewLC(KSQLQueryLit().Length() + EMaxTimeZoneIdStringLength);
       
   487 	// Set the buffer to the start of the query
       
   488 	*sqlStr = KSQLQueryLit;
       
   489 	// Append the time zone ID
       
   490 	sqlStr->Des().AppendNum(aTimeZoneId);
       
   491 
       
   492 	DoReadCitiesL(aCities,*sqlStr);
       
   493 	CleanupStack::PopAndDestroy(sqlStr);
       
   494 	}
       
   495 
       
   496 void CTzLocalizationDb::ReadCitiesInGroupL(RPointerArray<CTzLocalizedCityRecord>& aCities, TUint8 aGroupId)
       
   497 	{
       
   498 	if (iLocked)
       
   499 		{
       
   500 		User::Leave(KErrLocked);
       
   501 		}
       
   502 	// Assign basic SQL query literal
       
   503 	_LIT(KSQLQueryLit,"SELECT * FROM UserCities WHERE GroupId = ");
       
   504 	HBufC* sqlStr = HBufC::NewLC(KSQLQueryLit().Length() + EMaxGroupIdStringLength);
       
   505 	// Set the buffer to the start of the query
       
   506 	*sqlStr = KSQLQueryLit;
       
   507 	// Append the time zone ID
       
   508 	sqlStr->Des().AppendNum(aGroupId);
       
   509 
       
   510 	DoReadCitiesL(aCities,*sqlStr);
       
   511 	CleanupStack::PopAndDestroy(sqlStr);
       
   512 	}
       
   513 
       
   514 /**
       
   515 Retrieves a cached zone from the database.
       
   516 The calling function takes ownership of the returned zone
       
   517 @param aFrequentlyUsedZone - The cached zone to return
       
   518 @return a cached zone from the database
       
   519 @internalTechnology
       
   520 */
       
   521 CTzLocalizedTimeZoneRecord* CTzLocalizationDb::ReadFrequentlyUsedZoneL(TInt aFrequentlyUsedZone)
       
   522 	{
       
   523 	if (iLocked)
       
   524 		{
       
   525 		User::Leave(KErrLocked);
       
   526 		}
       
   527 	return DoReadFrequentlyUsedZoneL(aFrequentlyUsedZone);
       
   528 	}
       
   529 
       
   530 CTzLocalizedTimeZoneRecord* CTzLocalizationDb::DoReadFrequentlyUsedZoneL(TInt aFrequentlyUsedZone)
       
   531 	{
       
   532 	// You cannot pass ECachedTimeZones in as the argument, because it is only
       
   533 	// used to keep count of how many cached zones there are.
       
   534 	__ASSERT_ALWAYS(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
       
   535 	
       
   536 	//Prepare a view of the zone table
       
   537 	RDbView zoneView;
       
   538 	CleanupClosePushL(zoneView);
       
   539 	PrepareZoneViewL(zoneView);
       
   540 	
       
   541 	//Ensure the cursor is at the first row in the table.
       
   542 	zoneView.FirstL();
       
   543 	
       
   544 	//Skip through the rows until we reach the row for the required zone
       
   545 	for (TInt x = 0; x < aFrequentlyUsedZone; ++x)
       
   546 		{
       
   547 		zoneView.NextL();
       
   548 		}
       
   549 	
       
   550 	//Get the row
       
   551 	zoneView.GetL();
       
   552 	
       
   553 	//Create the new localized time zone from the row data
       
   554 	CTzLocalizedTimeZoneRecord* localizedTimeZone = CTzLocalizedTimeZoneRecord::NewL(zoneView.ColUint16(ETzZoneId),
       
   555 		zoneView.ColDes(ETzZoneStdName), zoneView.ColDes(ETzZoneDSTName), zoneView.ColDes(ETzZoneShortStdName),
       
   556 		zoneView.ColDes(ETzZoneShortDSTName), zoneView.ColUint32(ETzZoneResourceId));
       
   557 	
       
   558 	CleanupStack::PopAndDestroy(&zoneView);
       
   559 	return localizedTimeZone;
       
   560 	}
       
   561 
       
   562 /**
       
   563 Retrieves the city used to select this time zone if set.  If the time zone was not originally
       
   564 set using a city then the default city for the time zone will be returned instead.
       
   565 @param aFrequentlyUsedZone - The cached zone to find the city for
       
   566 @return	 selected city for the cached zone
       
   567 @internalTechnology
       
   568 */
       
   569 CTzLocalizedCityRecord* CTzLocalizationDb::ReadCachedTimeZoneCityL(TInt aFrequentlyUsedZone)
       
   570 	{
       
   571 	if (iLocked)
       
   572 		{
       
   573 		User::Leave(KErrLocked);
       
   574 		}
       
   575 	
       
   576 	// You cannot pass ECachedTimeZones in as the argument, because it is only
       
   577 	// used to keep count of how many cached zones there are.
       
   578 	__ASSERT_ALWAYS(aFrequentlyUsedZone != CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
       
   579 
       
   580 	//Prepare a view of the zone table
       
   581 	RDbView zoneView;
       
   582 	CleanupClosePushL(zoneView);
       
   583 	PrepareZoneViewL(zoneView);
       
   584 
       
   585 	//Ensure the cursor is at the first row in the table.
       
   586 	zoneView.FirstL();
       
   587 
       
   588 	//Skip through the rows until we reach the row for the required zone
       
   589 	for (TInt x = 0; x < aFrequentlyUsedZone; ++x)
       
   590 		{
       
   591 		zoneView.NextL();
       
   592 		}
       
   593 
       
   594 	//Get the row
       
   595 	zoneView.GetL();
       
   596 
       
   597 	//Create the new localized time zone from the row data
       
   598 	TInt index = 0;
       
   599 	// An extra column was added but we still have to cope with the old format as we
       
   600 	// need to read the database contents when upgrading to the new format
       
   601 	if (zoneView.ColCount() == ETzZoneCityIndex)
       
   602         {
       
   603         index = zoneView.ColInt32(ETzZoneCityIndex);
       
   604         }
       
   605 	CTzLocalizedCityRecord* city = CTzLocalizedCityRecord::NewL(zoneView.ColDes(ETzZoneCity),
       
   606 		zoneView.ColUint8(ETzZoneGroupId), index, zoneView.ColUint16(ETzZoneId),
       
   607 		zoneView.ColUint32(ETzZoneResourceId));
       
   608     
       
   609 	CleanupStack::PopAndDestroy(&zoneView);
       
   610 	return city;
       
   611 	}
       
   612 
       
   613 void CTzLocalizationDb::WriteCityL(const TDesC& aCityName, TUint16 aCityTzId, TUint8 aCityGroupId, TUint aCityTzResourceId)
       
   614 	{
       
   615 	if (iLocked)
       
   616 		{
       
   617 		User::Leave(KErrLocked);
       
   618 		}
       
   619 	
       
   620 	// Build a SQL query to check if the city name already exists in the database
       
   621 	// with a matching timezoneID
       
   622 	RDbView cityView;
       
   623 	CleanupClosePushL(cityView);
       
   624 	HBufC* sqlStr = GetCityQueryLC(aCityName, aCityTzId);
       
   625 	PrepareCityViewL(cityView, *sqlStr);
       
   626 	CleanupStack::PopAndDestroy(sqlStr);
       
   627 	sqlStr = NULL;
       
   628 
       
   629 	TInt cityCount = cityView.CountL();
       
   630 
       
   631 	if (cityCount == 0)
       
   632 		{
       
   633 		//City was not found.  Add the new city to the database
       
   634 		//Retrieve the CdbColSet from the view
       
   635 		CDbColSet* cityColSet = cityView.ColSetL();
       
   636 		CleanupStack::PushL(cityColSet);
       
   637 
       
   638 		//Set the rowset cursor to the beginning of the rowset,
       
   639 		//insert an empty row to write the city to
       
   640 		cityView.Reset();
       
   641 		cityView.InsertL();
       
   642 
       
   643 		//Set the city information for the new row
       
   644 		cityView.SetColL(ETzCityId,aCityTzId);
       
   645 		cityView.SetColL(ETzCityCity,aCityName);
       
   646 		cityView.SetColL(ETzCityGroup,aCityGroupId);
       
   647 		cityView.SetColL(ETzCityResourceId,aCityTzResourceId);
       
   648 
       
   649 		CleanupStack::PopAndDestroy(cityColSet);
       
   650 		cityView.PutL(); // Complete insertion
       
   651 		}
       
   652 	else
       
   653 		{
       
   654 		//City already exists.
       
   655 		User::Leave(KErrAlreadyExists);
       
   656 		}
       
   657 	CleanupStack::PopAndDestroy(&cityView);
       
   658 	iZoneMutex.Wait();
       
   659 	iLocalizedTimeZoneDb.Compact();
       
   660 	iZoneMutex.Signal();
       
   661 	}
       
   662 
       
   663 void CTzLocalizationDb::DeleteCityL(const TDesC& aCityName, TUint16 aCityTzId)
       
   664 	{
       
   665 	if (iLocked)
       
   666 		{
       
   667 		User::Leave(KErrLocked);
       
   668 		}
       
   669 	
       
   670 	//Build a SQL query to check if the city name and time zone ID exist in the database
       
   671 	RDbView cityView;
       
   672 	CleanupClosePushL(cityView);
       
   673 	HBufC* sqlStr = GetCityQueryLC(aCityName, aCityTzId);
       
   674 	PrepareCityViewL(cityView, *sqlStr);
       
   675 	CleanupStack::PopAndDestroy(sqlStr);
       
   676 	sqlStr = NULL;
       
   677 	
       
   678 	TInt cityCount = cityView.CountL();
       
   679 
       
   680 	if (cityCount > 0)
       
   681 		{
       
   682 		//A city with this name exists in the database.  Delete it.
       
   683 		if (cityView.FirstL())
       
   684 			{
       
   685 			cityView.DeleteL();
       
   686 			//Reset the cursor, as it now points to an invalid row
       
   687 			cityView.Reset();
       
   688 			}
       
   689 		}
       
   690 	else
       
   691 		{
       
   692 		//City was not found
       
   693 		User::Leave(KErrNotFound);
       
   694 		}
       
   695 	CleanupStack::PopAndDestroy(&cityView);
       
   696 	iZoneMutex.Wait();
       
   697 	iLocalizedTimeZoneDb.Compact();
       
   698 	iZoneMutex.Signal();
       
   699 	}
       
   700 
       
   701 /**
       
   702 Stores the localized time zone in the database for easy retrieval.
       
   703 The database keeps track of the two most recently used zones, these are updated every time
       
   704 a new zone is set.  The zone to be replaced becomes recently used zone 1, and recently used zone 1 becomes
       
   705 recently used zone 2.  The old recently used zone 2 is discarded.
       
   706 @param Any city in the time zone to store
       
   707 @param aFrequentlyUsedZone - specifies which time zone to overwrite in the database
       
   708 @internalTechnology
       
   709 */
       
   710 void CTzLocalizationDb::WriteFrequentlyUsedZoneL(const CTzLocalizedTimeZoneRecord& aTimeZone, 
       
   711 		const CTzLocalizedCityRecord& aCity, TInt aFrequentlyUsedZone)
       
   712 	{
       
   713 	if (iLocked)
       
   714 		{
       
   715 		User::Leave(KErrLocked);
       
   716 		}
       
   717 	
       
   718 	// Only the Current, Home and Zone of Interest can be changed explicitly
       
   719 	// using this function.  Recent Zones are automatically updated.
       
   720 	__ASSERT_ALWAYS(aFrequentlyUsedZone < CTzLocalizedTimeZone::ERecentZone1, User::Leave(KErrArgument));
       
   721 	
       
   722 	iZoneMutex.Wait();
       
   723 	
       
   724 	RDbView zoneView;
       
   725 	CleanupClosePushL(zoneView);
       
   726 	PrepareZoneViewL(zoneView);
       
   727 	//Ensure the cursor is at the first row in the table.
       
   728 	zoneView.FirstL();
       
   729 	TInt x;
       
   730 	//Skip through the rows until we reach the row for the zone to update
       
   731 	for (x = 0; x < aFrequentlyUsedZone; ++x)
       
   732 		{
       
   733 		zoneView.NextL();
       
   734 		}
       
   735 
       
   736 	//Get the row
       
   737 	zoneView.GetL();
       
   738 	
       
   739 	//Bookmark the row
       
   740 	TDbBookmark rowToUpdate(zoneView.Bookmark());
       
   741 
       
   742 	//Insert a copy of the row - this is now the last row in the table, and will become
       
   743 	//recently used zone 1 after the original recently used zones are deleted
       
   744 
       
   745 	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   746 	zoneView.InsertCopyL();
       
   747 	zoneView.PutL();
       
   748 	CleanupStack::Pop();
       
   749 	
       
   750 	//Position the cursor back at the row to update
       
   751 	zoneView.GotoL(rowToUpdate);
       
   752 
       
   753 	//Update the row with the new data
       
   754 	DoWriteFrequentlyUsedZoneL(zoneView, aTimeZone, aCity);
       
   755 
       
   756 	//Reset the cursor back to the first row in the table.
       
   757 	zoneView.FirstL();
       
   758 
       
   759 	//Skip through the rows until we reach the row for recent zone 1
       
   760 	for (x = 0; x < CTzLocalizedTimeZone::ERecentZone1; ++x)
       
   761 		{
       
   762 		zoneView.NextL();
       
   763 		}
       
   764 
       
   765 	//Get the row
       
   766 	zoneView.GetL();
       
   767 
       
   768 	//Bookmark the row
       
   769 	TDbBookmark recentZone1(zoneView.Bookmark());
       
   770 
       
   771 	//Insert a copy of the row - this is now the last row in the table, and will become
       
   772 	//recently used zone 2 after the original recently used zones are deleted
       
   773 	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   774 	zoneView.InsertCopyL();
       
   775 	zoneView.PutL();
       
   776 	CleanupStack::Pop();
       
   777 
       
   778 	//Reset the cursor to the orignal recent zone 1 position
       
   779 	zoneView.GotoL(recentZone1);
       
   780 
       
   781 	//Delete the original recent zone 1 and recent zone 2.
       
   782 	//The new recent zone 1 and recent zone 2 are moved back into the correct
       
   783 	//position by the removal of the preceding rows
       
   784 	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   785 	zoneView.DeleteL();
       
   786 	CleanupStack::Pop();
       
   787 
       
   788 	zoneView.NextL();
       
   789 
       
   790 	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   791 	zoneView.DeleteL();
       
   792 	CleanupStack::Pop();
       
   793 	
       
   794 	//Cursor is now invalid (pointing to an empty row)
       
   795 	//and shuold be reset to a known state before reusing
       
   796 	//Cleanup
       
   797 	CleanupStack::PopAndDestroy(&zoneView);
       
   798 	iLocalizedTimeZoneDb.Compact();
       
   799 	iZoneMutex.Signal();
       
   800 	}
       
   801 
       
   802 /**
       
   803 Sets all the cached zones and their associated cities to be those that are
       
   804 supplied.
       
   805 @param aTimeZones Array of time zones to be written.
       
   806 @param aCities Array of cities to be written.
       
   807 @internalTechnology
       
   808 */
       
   809 void CTzLocalizationDb::WriteAllFrequentlyUsedZonesL(const RPointerArray<CTzLocalizedTimeZoneRecord>& aTimeZones, 
       
   810 		const RPointerArray<CTzLocalizedCityRecord>& aCities)
       
   811 	{
       
   812 	if (iLocked)
       
   813 		{
       
   814 		User::Leave(KErrLocked);
       
   815 		}
       
   816 	DoWriteAllFrequentlyUsedZonesL(aTimeZones, aCities);
       
   817 	}
       
   818 
       
   819 void CTzLocalizationDb::DoWriteAllFrequentlyUsedZonesL(const RPointerArray<CTzLocalizedTimeZoneRecord>& aTimeZones, 
       
   820 		const RPointerArray<CTzLocalizedCityRecord>& aCities)
       
   821 	{
       
   822 	// Ensure that the numbers of items in the arrays are the expected amount
       
   823 	__ASSERT_ALWAYS(aTimeZones.Count() == CTzLocalizedTimeZone::ECachedTimeZones &&
       
   824 					aCities.Count() == CTzLocalizedTimeZone::ECachedTimeZones, User::Leave(KErrArgument));
       
   825 	
       
   826 	iZoneMutex.Wait();	
       
   827 		
       
   828 	RDbView zoneView;
       
   829 	CleanupClosePushL(zoneView);
       
   830 	PrepareZoneViewL(zoneView);
       
   831 	//Ensure the cursor is at the first row in the table.
       
   832 	zoneView.FirstL();
       
   833 
       
   834 	//Skip through the rows until we reach the row for the zone to update
       
   835 	for (TInt i = 0; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
   836 		{
       
   837 		DoWriteFrequentlyUsedZoneL(zoneView, *aTimeZones[i], *aCities[i]);
       
   838 		zoneView.NextL();
       
   839 		}
       
   840 
       
   841 	CleanupStack::PopAndDestroy(&zoneView);
       
   842 	
       
   843 	iLocalizedTimeZoneDb.Compact();
       
   844 	iZoneMutex.Signal();
       
   845 	}
       
   846 
       
   847 /**
       
   848 Opens the a view on the city table and returns a reference to it.
       
   849 The view should be released after use with a call to CloseCityView()
       
   850 @param aSql A sql string to prepare the view with
       
   851 @return reference to opened iCityTable
       
   852 @internalTechnology
       
   853 */
       
   854 void CTzLocalizationDb::PrepareCityViewL(RDbView& aCityView, const TDesC& aSqlQuery)
       
   855 	{
       
   856 	User::LeaveIfError(aCityView.Prepare(iLocalizedTimeZoneDb, TDbQuery(aSqlQuery),	aCityView.EUpdatable));
       
   857 	User::LeaveIfError(aCityView.EvaluateAll());
       
   858 	}
       
   859 
       
   860 /**
       
   861 Opens a view to the zone table
       
   862 @internalTechnology
       
   863 */
       
   864 void CTzLocalizationDb::PrepareZoneViewL(RDbView& aZoneView)
       
   865 	{
       
   866 	_LIT(KReadZoneView,"SELECT * FROM FrequentlyUsedZones");
       
   867 	User::LeaveIfError(aZoneView.Prepare(iLocalizedTimeZoneDb, TDbQuery(KReadZoneView),	aZoneView.EUpdatable));
       
   868 	User::LeaveIfError(aZoneView.EvaluateAll());
       
   869 	}
       
   870 
       
   871 /**
       
   872 Returns the SQL string that will pick the specified city out of the user-added
       
   873 cities database. Leaves the returned HBufC pointer on the Cleanup Stack.
       
   874 The query is of the form:
       
   875 	"SELECT * FROM UserCities WHERE City = 'London' AND TZID = 2592"
       
   876 @param aCity The city to make the query for.
       
   877 @return The SQL Query that will select the aCity form the DB
       
   878 @internalTechnology
       
   879 */
       
   880 HBufC* CTzLocalizationDb::GetCityQueryLC(const TDesC& aCityName, TInt aCityTimeZoneId)
       
   881 	{
       
   882 	// Assign the start and middle of the basic SQL query literal 
       
   883 	_LIT(KSQLQueryLitStart,"SELECT * FROM UserCities WHERE City = '");
       
   884 	_LIT(KSQLQueryLitMiddle,"' AND TZID = ");
       
   885 	
       
   886 	/* Assign a buffer with enough room to hold the query including the city 
       
   887 	   name and the time zone id */
       
   888 	TInt maxBufferLength = KSQLQueryLitStart().Length() + KSQLQueryLitMiddle().Length() 
       
   889 							+ aCityName.Length() + EMaxTimeZoneIdStringLength;
       
   890 	HBufC* sqlStr = HBufC::NewLC(maxBufferLength);
       
   891 	
       
   892 	// Append the beginning of the query
       
   893 	sqlStr->Des().Append(KSQLQueryLitStart);
       
   894 	// Append the city name into the query
       
   895 	sqlStr->Des().Append(aCityName);
       
   896 	// Append the middle of the query
       
   897 	sqlStr->Des().Append(KSQLQueryLitMiddle);
       
   898 	// Append the time zone ID into the query
       
   899 	sqlStr->Des().AppendNum(aCityTimeZoneId);
       
   900 	
       
   901 	return sqlStr;
       
   902 	}
       
   903 
       
   904 HBufC* CTzLocalizationDb::GetCityQueryLC(TInt aCityTimeZoneId)
       
   905 	{
       
   906 	// Assign the start and middle of the basic SQL query literal 
       
   907 	_LIT(KSQLQueryLitStart,"SELECT * FROM UserCities WHERE TZID = ");
       
   908 	
       
   909 	/* Assign a buffer with enough room to hold the query including the city 
       
   910 	   name and the time zone id */
       
   911 	TInt maxBufferLength = KSQLQueryLitStart().Length() + EMaxTimeZoneIdStringLength;
       
   912 	HBufC* sqlStr = HBufC::NewLC(maxBufferLength);
       
   913 	
       
   914 	// Append the beginning of the query
       
   915 	sqlStr->Des().Append(KSQLQueryLitStart);
       
   916 	// Append the time zone ID into the query
       
   917 	sqlStr->Des().AppendNum(aCityTimeZoneId);
       
   918 	
       
   919 	return sqlStr;
       
   920 	}
       
   921 
       
   922 /**
       
   923 Reads the user defined cities in the database
       
   924 matched by the SQL query into the supplied array. If the
       
   925 database is empty the returned array will contain no elements.
       
   926 @param aCities array of cities to add the user defined to.
       
   927 @param aSqlString - SQL search string determining the cities to retrieve
       
   928 @internalTechnology
       
   929 */
       
   930 void CTzLocalizationDb::DoReadCitiesL(RPointerArray<CTzLocalizedCityRecord>& aCities, const TDesC& aSqlString)
       
   931 	{
       
   932 	RDbView cityView;
       
   933 	CleanupClosePushL(cityView);
       
   934 	PrepareCityViewL(cityView, aSqlString);
       
   935 	
       
   936 	//Loop through the rowset
       
   937 	for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
       
   938 		{
       
   939 		// Fetch a cached copy of current row
       
   940 		cityView.GetL();
       
   941 
       
   942 		//Create the new city from the row data
       
   943 		CTzLocalizedCityRecord* newCity = CTzLocalizedCityRecord::NewLC(cityView.ColDes(ETzCityCity), 
       
   944 			cityView.ColUint8(ETzCityGroup), aCities.Count(), cityView.ColUint16(ETzCityId),
       
   945 			cityView.ColUint32(ETzCityResourceId));
       
   946      
       
   947 		//Append the new city to the city array - aCities takes ownership of newCity
       
   948 		aCities.AppendL(newCity);
       
   949 		CleanupStack::Pop(newCity);
       
   950 		}
       
   951 	CleanupStack::PopAndDestroy(&cityView);
       
   952 	}
       
   953 
       
   954 /**
       
   955 Does the actual writing of a zone and city into the database. iZoneView must
       
   956 have already been prepared and moved to the correct offset into the row set
       
   957 before this function is called. e.g. at least the following should have been
       
   958 done:
       
   959 	PrepareZoneViewL();
       
   960 	iZoneView.FirstL();
       
   961 Otherwise the cursor position may be invalid and a DBMS panic will occur.
       
   962 @param aTimeZone The time zone to write.
       
   963 @param aCity The city to write.
       
   964 @param aFrequentlyUsedZone The enum of the cached zone to write to.
       
   965 @internalTechnology
       
   966 */
       
   967 void CTzLocalizationDb::DoWriteFrequentlyUsedZoneL(RDbView& aZoneView, const CTzLocalizedTimeZoneRecord& aTimeZone,
       
   968 		const CTzLocalizedCityRecord& aCity)
       
   969 	{
       
   970 	CleanupStack::PushL(TCleanupItem(ReleaseMutex,&iZoneMutex));
       
   971 	aZoneView.UpdateL();  
       
   972 	aZoneView.SetColL(ETzZoneId, (TInt)aTimeZone.Id());
       
   973 	aZoneView.SetColL(ETzZoneStdName, aTimeZone.StandardName());
       
   974 	aZoneView.SetColL(ETzZoneDSTName, aTimeZone.DaylightName());
       
   975 	aZoneView.SetColL(ETzZoneShortStdName, aTimeZone.ShortStandardName());
       
   976 	aZoneView.SetColL(ETzZoneShortDSTName, aTimeZone.ShortDaylightName());
       
   977 	aZoneView.SetColL(ETzZoneCity, aCity.Name());
       
   978 	aZoneView.SetColL(ETzZoneGroupId, aCity.GroupId());
       
   979 	aZoneView.SetColL(ETzZoneResourceId, aTimeZone.ResourceId());
       
   980     if (aZoneView.ColCount() == ETzZoneCityIndex)
       
   981         {
       
   982         aZoneView.SetColL(ETzZoneCityIndex, aCity.Index());
       
   983         }
       
   984     aZoneView.PutL();
       
   985 	CleanupStack::Pop();
       
   986 	}
       
   987 
       
   988 TInt CTzLocalizationDb::GetTimeZoneIdFromTzServerL(CTzSystemDataDb& aSystemDataDb)
       
   989 	{
       
   990 	// Get current time zone using the current CTzId from the time zone server
       
   991 	TUint timeZoneIdInt = iServer.TimeZoneManager().GetTimeZoneIdL().TimeZoneNumericID();
       
   992 	
       
   993 	// Is the time zone ID the unknown/invalid ID?
       
   994 	// This is temporary measure that is required until PREQ 234' TzServer
       
   995 	// changes are introduced
       
   996 	const TUint32 KUnknownTZId = 0x0ffffff0;
       
   997 	if((TUint32)timeZoneIdInt == KUnknownTZId)
       
   998 		{
       
   999 		// Return the ID of the DEFAULT home zone instead
       
  1000 		CTzLocalizedTimeZoneRecord* homeZone = aSystemDataDb.ReadFrequentlyUsedZoneL(CTzLocalizedTimeZone::EHomeZone);
       
  1001 		CleanupStack::PushL(homeZone);
       
  1002 		timeZoneIdInt = homeZone->Id();
       
  1003 		CleanupStack::PopAndDestroy(homeZone);
       
  1004 		}
       
  1005 		
       
  1006 	return timeZoneIdInt;
       
  1007 	}
       
  1008 
       
  1009 void CTzLocalizationDb::NotifyUserTzNamesChangeL(TTzUserDataChange aChange)
       
  1010 	{
       
  1011 	// If an existing user-defined time zone is updated it means we may have
       
  1012 	// to refresh the data in the frequently used zones table but the city table
       
  1013 	// only contains the time zone id so there is nothing to update in there.
       
  1014 	
       
  1015 	// If an existing user-defined time zone is deleted it means we may have
       
  1016 	// to refresh the data in the frequently used zones table and the city table
       
  1017 	// because it may contain the time zone id that has been deleted.
       
  1018 	CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
       
  1019 	TBool frequentlyUsedZonesNeedUpdating = EFalse;
       
  1020 	RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
       
  1021 	CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
       
  1022 	RPointerArray<CTzLocalizedCityRecord> cachedCities;
       
  1023 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cachedCities));
       
  1024 	for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
  1025 		{
       
  1026 		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
       
  1027 		CTzLocalizedTimeZoneRecord* timeZoneRecord = ReadFrequentlyUsedZoneL(freqUsedZone);
       
  1028 		CleanupStack::PushL(timeZoneRecord);
       
  1029 		CTzLocalizedCityRecord* cityRecord = ReadCachedTimeZoneCityL(freqUsedZone);
       
  1030 		CleanupStack::PushL(cityRecord);
       
  1031 		
       
  1032 	 if (timeZoneRecord->Id() == aChange.iTzId || cityRecord->TzId() == aChange.iTzId)
       
  1033 		{
       
  1034 		if (aChange.iOperation == ETzUserDataUpdated)
       
  1035 			{
       
  1036 			CleanupStack::PopAndDestroy(cityRecord);
       
  1037 			cityRecord = NULL;
       
  1038 			CleanupStack::PopAndDestroy(timeZoneRecord);
       
  1039 			timeZoneRecord = NULL;
       
  1040 			UpdateTimeZoneAndCityRecordL(frequentlyUsedZones, cachedCities, aChange.iTzId);
       
  1041 			}
       
  1042 		else if (aChange.iOperation == ETzUserDataDeleted)
       
  1043 			{
       
  1044 			CleanupStack::PopAndDestroy(cityRecord);
       
  1045 			cityRecord = NULL;
       
  1046 			CleanupStack::PopAndDestroy(timeZoneRecord);
       
  1047 			timeZoneRecord = NULL;
       
  1048 			
       
  1049 			if(freqUsedZone != CTzLocalizedTimeZone::ECurrentZone)
       
  1050 				{
       
  1051 				// Put the default cached zone and its default city in the array instead
       
  1052 				timeZoneRecord = systemDataDb->ReadFrequentlyUsedZoneL(freqUsedZone);
       
  1053 				}
       
  1054 			else
       
  1055 				{
       
  1056 				// get the current zone from the time zone server
       
  1057 				TInt id = GetTimeZoneIdFromTzServerL(*systemDataDb);
       
  1058 				timeZoneRecord = systemDataDb->ReadTimeZoneL(id);
       
  1059 				}
       
  1060 			CleanupStack::PushL(timeZoneRecord);
       
  1061 			cityRecord = systemDataDb->ReadDefaultCityL(timeZoneRecord->Id());
       
  1062 			CleanupStack::PushL(cityRecord);
       
  1063 			
       
  1064 			cachedCities.AppendL(cityRecord);
       
  1065 			// ownership is transferred into the array
       
  1066 			CleanupStack::Pop(cityRecord);
       
  1067 			frequentlyUsedZones.AppendL(timeZoneRecord);
       
  1068 			// ownership is transferred into the array
       
  1069 			CleanupStack::Pop(timeZoneRecord);
       
  1070 			}
       
  1071 		frequentlyUsedZonesNeedUpdating = ETrue;
       
  1072 		}
       
  1073 	else
       
  1074 		{
       
  1075 		cachedCities.AppendL(cityRecord);
       
  1076 		// ownership is transferred into the array
       
  1077 		CleanupStack::Pop(cityRecord);
       
  1078 		frequentlyUsedZones.AppendL(timeZoneRecord);
       
  1079 		// ownership is transferred into the array
       
  1080 		CleanupStack::Pop(timeZoneRecord);
       
  1081 		}
       
  1082 	}
       
  1083 			
       
  1084 	if (frequentlyUsedZonesNeedUpdating)
       
  1085 		{
       
  1086 		WriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
       
  1087 		}
       
  1088 		
       
  1089 	if (aChange.iOperation == ETzUserDataDeleted)
       
  1090 		{
       
  1091 		DeleteCitiesL(aChange);
       
  1092 		iZoneMutex.Wait();
       
  1093 		iLocalizedTimeZoneDb.Compact();
       
  1094 		iZoneMutex.Signal();
       
  1095 		}
       
  1096 	CleanupStack::PopAndDestroy(&cachedCities); 
       
  1097 	CleanupStack::PopAndDestroy(&frequentlyUsedZones);
       
  1098 	CleanupStack::PopAndDestroy(systemDataDb);
       
  1099 	}
       
  1100 
       
  1101 void CTzLocalizationDb::UpdateTimeZoneAndCityRecordL(RPointerArray<CTzLocalizedTimeZoneRecord>& aFrequentlyUsedZones, RPointerArray<CTzLocalizedCityRecord>& aCachedCities, TInt aTzId)
       
  1102 	{
       
  1103 	CTzUserNames* names = iServer.UserTimeZoneDb().ReadTzNamesL(aTzId);
       
  1104 	CleanupStack::PushL(names);
       
  1105 
       
  1106 	CTzLocalizedTimeZoneRecord* timeZoneRecord = CTzLocalizedTimeZoneRecord::NewL(aTzId, names->StandardName(),
       
  1107 		names->DaylightSaveName(), names->ShortStandardName(), names->ShortDaylightSaveName(), 0);
       
  1108 	CleanupStack::PushL(timeZoneRecord);
       
  1109 	
       
  1110 	CTzLocalizedCityRecord* cityRecord = CTzLocalizedCityRecord::NewL(names->CityName(), 0, 0, aTzId, 0);
       
  1111 	CleanupStack::PushL(cityRecord);
       
  1112 
       
  1113 	aCachedCities.AppendL(cityRecord);
       
  1114 	// ownership is transferred into the array
       
  1115 	CleanupStack::Pop(cityRecord);
       
  1116 	aFrequentlyUsedZones.AppendL(timeZoneRecord);
       
  1117 	// ownership is transferred into the array
       
  1118 	CleanupStack::Pop(timeZoneRecord);
       
  1119 	CleanupStack::PopAndDestroy(names);
       
  1120 	}
       
  1121 
       
  1122 void CTzLocalizationDb::DeleteCitiesL(TTzUserDataChange aChange)
       
  1123 	{
       
  1124 	// Get the cities with the deleted time zone id
       
  1125 	RDbView cityView;
       
  1126 	CleanupClosePushL(cityView);
       
  1127 	if(aChange.iOperation == ETzUserDataDeleted)
       
  1128 		{
       
  1129 		HBufC* sqlStr = GetCityQueryLC(aChange.iTzId);
       
  1130 		PrepareCityViewL(cityView, *sqlStr);
       
  1131 		CleanupStack::PopAndDestroy(sqlStr);
       
  1132 		sqlStr = NULL;
       
  1133 		}
       
  1134 	else if(aChange.iOperation == ETzUserDataRestored)
       
  1135 		{
       
  1136 		_LIT(KSQLQueryLit,"SELECT * FROM UserCities");
       
  1137 		// Iterate through all the cities and delete them when
       
  1138 		// the corresponding tz id doesn't exist anymore
       
  1139 		PrepareCityViewL(cityView, KSQLQueryLit);
       
  1140 		}
       
  1141 	// Loop through the rowset and delete the cities
       
  1142 	for (cityView.FirstL(); cityView.AtRow(); cityView.NextL())
       
  1143 		{
       
  1144 		if(aChange.iOperation == ETzUserDataDeleted)
       
  1145 			{
       
  1146 			cityView.DeleteL();		
       
  1147 			}
       
  1148 		else if(aChange.iOperation == ETzUserDataRestored)
       
  1149 			{
       
  1150 			cityView.GetL();
       
  1151 			if (!iServer.TimeZoneManager().TzDataProvider().IsIdInDbL(cityView.ColUint16(ETzCityId)))
       
  1152 				{
       
  1153 				cityView.DeleteL();
       
  1154 				}
       
  1155 			}	
       
  1156 		}
       
  1157 	CleanupStack::PopAndDestroy(&cityView);
       
  1158 	}
       
  1159 
       
  1160 /**
       
  1161 Releases the mutex if leave occurs between wait and signal.
       
  1162 @internalTechnology
       
  1163 */
       
  1164 void CTzLocalizationDb::ReleaseMutex(TAny* iTarget)
       
  1165 	{
       
  1166 	RMutex* mutex = static_cast<RMutex*>(iTarget);	
       
  1167 	mutex->Signal();	
       
  1168 	}
       
  1169 
       
  1170 // Backup and restore operations
       
  1171 void CTzLocalizationDb::BackupBeginningL()
       
  1172 	{
       
  1173 	CloseDb();
       
  1174 	iLocked = ETrue;
       
  1175 	}
       
  1176 
       
  1177 void CTzLocalizationDb::BackupCompletedL()
       
  1178 	{
       
  1179 	OpenDbL();
       
  1180 	iLocked = EFalse;
       
  1181 	}
       
  1182 
       
  1183 void CTzLocalizationDb::RestoreBeginningL()
       
  1184 	{
       
  1185 	CloseDb();
       
  1186 	iLocked = ETrue;
       
  1187 	}
       
  1188 
       
  1189 void CTzLocalizationDb::RestoreDbL()
       
  1190 	{
       
  1191 	// When the Tz server is connected or a restore completes, we have to
       
  1192 	// refresh the data in the frequently used zones table and the city table
       
  1193 	// because it may contain the time zone id that has been deleted.  Or if the
       
  1194 	// time zone id is still there but the details of the rule has been changed.
       
  1195 
       
  1196 	CTzSystemDataDb* systemDataDb = CTzSystemDataDb::NewLC();
       
  1197 
       
  1198 	TBool frequentlyUsedZonesNeedUpdating = EFalse;
       
  1199 
       
  1200 	RPointerArray<CTzLocalizedTimeZoneRecord> frequentlyUsedZones;
       
  1201 	CleanupStack::PushL(TCleanupItem(CleanupTimeZonePointerArray,&frequentlyUsedZones));
       
  1202 
       
  1203 	RPointerArray<CTzLocalizedCityRecord> cachedCities;
       
  1204 	CleanupStack::PushL(TCleanupItem(CleanupCityPointerArray,&cachedCities));
       
  1205 
       
  1206 	for (TInt i = CTzLocalizedTimeZone::ECurrentZone; i < CTzLocalizedTimeZone::ECachedTimeZones; ++i)
       
  1207 		{//Loop through each record in frequently used table
       
  1208 		CTzLocalizedTimeZone::TTzFrequentlyUsedZone freqUsedZone = (CTzLocalizedTimeZone::TTzFrequentlyUsedZone)i;
       
  1209 		CTzLocalizedTimeZoneRecord* timeZoneRecord = DoReadFrequentlyUsedZoneL(freqUsedZone);
       
  1210 		TUint tzid = timeZoneRecord->Id();
       
  1211 		delete timeZoneRecord;
       
  1212 		TBool tzIdExistInDb = iServer.TimeZoneManager().TzDataProvider().IsIdInDbL(tzid);
       
  1213 		
       
  1214 		if(!tzIdExistInDb)
       
  1215 			{
       
  1216 			if(freqUsedZone == CTzLocalizedTimeZone::ECurrentZone)
       
  1217 				{
       
  1218 				tzid = GetTimeZoneIdFromTzServerL(*systemDataDb);
       
  1219 				}
       
  1220 			else
       
  1221 				{
       
  1222 				tzid = GetFrequentlyUsedDefaultZoneIdL(freqUsedZone, *systemDataDb);
       
  1223 				}
       
  1224 			}
       
  1225 		
       
  1226 		if (CTzId::IsUserTzId(tzid))
       
  1227 			{
       
  1228 			UpdateTimeZoneAndCityRecordL(frequentlyUsedZones, cachedCities, tzid);	
       
  1229 			}
       
  1230 		else
       
  1231 			{
       
  1232 			UpdateTimeZoneAndCityRecordForSystemDataL(frequentlyUsedZones, cachedCities, tzid, *systemDataDb);
       
  1233 			}
       
  1234 
       
  1235 		frequentlyUsedZonesNeedUpdating = ETrue;
       
  1236 		}
       
  1237 			
       
  1238 	if (frequentlyUsedZonesNeedUpdating)
       
  1239 		{
       
  1240 		//Update the frequently used zone table
       
  1241 		DoWriteAllFrequentlyUsedZonesL(frequentlyUsedZones, cachedCities);
       
  1242 		}
       
  1243 	
       
  1244 	TTzUserDataChange change;
       
  1245 	change.iOperation = ETzUserDataRestored;
       
  1246 	change.iTzId = KInvalidTzId;
       
  1247 	//Delete the city infomation if the associated time zone no longer exist.
       
  1248 	DeleteCitiesL(change);
       
  1249 	
       
  1250 	CleanupStack::PopAndDestroy(&cachedCities); 
       
  1251 	CleanupStack::PopAndDestroy(&frequentlyUsedZones);
       
  1252 	CleanupStack::PopAndDestroy(systemDataDb);
       
  1253 	}
       
  1254 
       
  1255 /**
       
  1256 Get the localized default time zone Id for the given frequently used time zone.
       
  1257 The default time zone for each of the possible frequently used time zones may be
       
  1258 specified in the TZ Server repository or in the TZ Localization resource file.
       
  1259 Check the possible sources in this order.
       
  1260 
       
  1261 @param aFreqUsedZone The frequently used time zone for which the localized
       
  1262 default time zone is required.
       
  1263 @param aSystemDataDb For TZ Localization database access.
       
  1264 
       
  1265 @return The localized default time zone Id for the given frequently used time zone.
       
  1266 */
       
  1267 TInt CTzLocalizationDb::GetFrequentlyUsedDefaultZoneIdL(
       
  1268 	CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone,
       
  1269 	CTzSystemDataDb& aSystemDataDb)
       
  1270 	{
       
  1271 	// Assume that we will not find the key in the repository or that we do find
       
  1272 	// the key but it has no value.  If either of these scenarios is true then
       
  1273 	// we will use the time zone identifier recorded in the resource file for
       
  1274 	// the default time zone.
       
  1275 	
       
  1276 	TUint32 defaultTimeZoneKey = GetFrequentlyUsedDefaultZoneCenRepKeyL(aFreqUsedZone);
       
  1277 	CRepository* tzRepository = CRepository::NewL(NTzUpdate::KPropertyCategory);
       
  1278 	CleanupStack::PushL(tzRepository);
       
  1279 	TInt defaultTimeZoneId = 0;
       
  1280 	TInt err = tzRepository->Get(defaultTimeZoneKey, defaultTimeZoneId);
       
  1281 	CleanupStack::PopAndDestroy(tzRepository);
       
  1282 	
       
  1283 	if(err != KErrNotFound)
       
  1284 		{
       
  1285 		User::LeaveIfError(err);
       
  1286 		}
       
  1287 	
       
  1288 	if(defaultTimeZoneId == 0)
       
  1289 		{
       
  1290 		defaultTimeZoneId = aSystemDataDb.ReadFrequentlyUsedZoneIdL(aFreqUsedZone);
       
  1291 		}
       
  1292 	
       
  1293 	return defaultTimeZoneId;
       
  1294 	}
       
  1295 
       
  1296 /**
       
  1297 Get the TZ Server's CenRep repository key for the given frequently used zone.
       
  1298 
       
  1299 @param aFreqUsedZone The frequently used time zone for which the TZ Server's
       
  1300 CenRep repository key is required.
       
  1301 
       
  1302 @return The TZ Server's CenRep repository key for the given frequently used
       
  1303 zone.
       
  1304 */
       
  1305 TUint32 CTzLocalizationDb::GetFrequentlyUsedDefaultZoneCenRepKeyL(CTzLocalizedTimeZone::TTzFrequentlyUsedZone aFreqUsedZone)
       
  1306 	{
       
  1307 	// These key values are copied from those defined in tzconfigagent.h.  We
       
  1308 	// want to keep the key values private - this is one way to do it.
       
  1309 	const TUint32 KDefaultHomeTimeZoneKey = 0x3UL;
       
  1310 	const TUint32 KDefaultInterestTimeZoneKey = 0x4UL;
       
  1311 	const TUint32 KDefaultRecent1TimeZoneKey = 0x5UL;
       
  1312 	const TUint32 KDefaultRecent2TimeZoneKey = 0x6UL;
       
  1313 
       
  1314 	TUint32 key = 0;
       
  1315 
       
  1316 	switch(aFreqUsedZone)
       
  1317 	    {
       
  1318 	    case CTzLocalizedTimeZone::EHomeZone:
       
  1319 	    	{
       
  1320 	    	key = KDefaultHomeTimeZoneKey;
       
  1321 	        }
       
  1322 	    break;
       
  1323 
       
  1324 	    case CTzLocalizedTimeZone::EInterestZone:
       
  1325 	    	{
       
  1326 	    	key = KDefaultInterestTimeZoneKey;
       
  1327 	        }
       
  1328 	    break;
       
  1329 
       
  1330 	    case CTzLocalizedTimeZone::ERecentZone1:
       
  1331 	    	{
       
  1332 	    	key = KDefaultRecent1TimeZoneKey;
       
  1333 	        }
       
  1334 	    break;
       
  1335 
       
  1336 	    case CTzLocalizedTimeZone::ERecentZone2:
       
  1337 	    	{
       
  1338 	    	key = KDefaultRecent2TimeZoneKey;
       
  1339 	        }
       
  1340 	    break;
       
  1341 	    
       
  1342 	    default:
       
  1343 	    	{
       
  1344 	    	User::Leave(KErrArgument);
       
  1345 	    	}
       
  1346 	    }
       
  1347 
       
  1348 	return key;
       
  1349     }
       
  1350 
       
  1351 void CTzLocalizationDb::RestoreCompletedL()
       
  1352 	{
       
  1353 	OpenDbL();
       
  1354 	iLocked = EFalse;
       
  1355 	RestoreDbL();
       
  1356 	}
       
  1357