pimprotocols/phonebooksync/Server/phbksyncsvr.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimprotocols/phonebooksync/Server/phbksyncsvr.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,2747 @@
+// Copyright (c) 2002-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:
+// Implementation of the CPhoneBookServer class which is the front-end server,
+// responsible for processing all short and quick requests, and for passing
+// longer requests to the engine.
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <connect/sbdefs.h>
+#include <commsdattypesv1_1.h>
+#include <cdblen.h>
+
+#include "common.h"
+#include "PhonebookManager.h"
+#include "SyncContactICCEntry.h"
+#include "phbksynclog.h"
+#include "phbksyncsvr.h"
+#include "phbksyncsess.h"
+#include "SyncEngineRequest.h"
+#include "ActiveNotifications.h"
+
+
+using namespace CommsDat;
+
+
+/**
+ * Number of retries for connecting to Etel.
+ */
+const TInt KMaxConnectToEtelRetries = 3;
+
+
+//
+//  Definition of iPolicy dictating the capability checking for phbksyncsvr...
+//
+const TUint iRangeCount = 10;
+
+const TInt CPhoneBookServer::iRanges[iRangeCount] = 
+	{
+	0,		//range is 0
+	1,		//range is 1-3 inclusive
+	4,		//range is 4-5 inclusive
+	6,		//range is 6
+	7,		//range is 7-13 inclusive
+	14,		//range is 14
+	15,		//range is 15-16 inclusive
+	17,		//range is 17-24 inclusive
+	25,		//range is 25 inclusive
+	26,		//range is 26-KMaxTInt inclusive
+	};
+
+const TUint8 CPhoneBookServer::iElementsIndex[iRangeCount] = 
+	{
+	0,
+	1,
+	2,
+	3,
+	4,
+	5,
+	6,
+	7,
+	8,
+	CPolicyServer::ENotSupported,
+	};
+
+const CPolicyServer::TPolicyElement CPhoneBookServer::iElements[] = 
+	{
+	{ _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData), CPolicyServer::EFailClient},	// policy 0:  range 0 - 0
+	{ _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient},	// policy 1:  range 1 - 3
+	{ _INIT_SECURITY_POLICY_C1( ECapabilityWriteUserData), CPolicyServer::EFailClient},	// policy 2:  range 4 - 5
+	{ _INIT_SECURITY_POLICY_C1( ECapabilityReadUserData), CPolicyServer::EFailClient},	// policy 3:  range 6 - 6
+	{ _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient},	// policy 4:  range 7 - 13
+	{ _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData), CPolicyServer::EFailClient},	// policy 5:  range 14 - 14
+	{ _INIT_SECURITY_POLICY_C1( ECapabilityWriteUserData), CPolicyServer::EFailClient},	// policy 6:  range 15 - 16
+	{ _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient},	// policy 7:  range 17 - 24
+#ifdef _DEBUG
+	{ _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient}, // policy 8: range 25
+#else
+	{ _INIT_SECURITY_POLICY_FAIL}, // policy 8: range 25
+#endif
+	};
+
+const CPolicyServer::TPolicy CPhoneBookServer::iPolicy = 
+	{
+	CPolicyServer::EAlwaysPass,
+	iRangeCount,
+	iRanges,
+	iElementsIndex,
+	iElements
+	};
+
+
+/**
+ *  Static factory method used to create a CPhoneBookServer object.
+ *
+ *  @return  Pointer to the created CPhoneBookServer object, or NULL.
+ */
+CPhoneBookServer* CPhoneBookServer::NewL()
+	{
+	LOGSERVER1(_L8("NewL()"));
+	CPhoneBookServer* self = new (ELeave) CPhoneBookServer();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+
+	return self;
+	} // CPhoneBookServer::NewL
+
+
+/**
+ *  Standard constructor.
+ */
+CPhoneBookServer::CPhoneBookServer()
+	: CPolicyServer(EPriorityNormal, iPolicy, ESharableSessions), 
+	iServerConfigLevel(EServerConfigurationNone),
+	iICCCaps(RMobilePhone::KCapsSimAccessSupported), 
+	iPhonebookManager(NULL),
+	iShouldShutdownServer(EFalse),
+	iShouldShutdownUnconditionally(EFalse)
+	{
+	__DECLARE_NAME(_L("CPhoneBookServer"));
+	} // CPhoneBookServer::CPhoneBookServer
+
+
+/**
+ *  Second phase constructor. Ensures the server is created and ready to run.
+ */
+void CPhoneBookServer::ConstructL()
+	{
+	StartL(PHBKSYNC_SERVER_NAME);
+	} // CPhoneBookServer::ConstructL
+
+
+/**
+ *  Destructor.
+ */
+CPhoneBookServer::~CPhoneBookServer()
+	{
+	//
+	// Stop the server from starting if it has initiated a startup.
+	//
+	delete iPhoneBookSyncStarter;
+	iPhoneBookSyncStarter = NULL;
+	
+	//
+	// Unconfigure the server if needed...
+	//
+	TRAP_IGNORE(ConfigureServerL(EServerConfigurationNone));
+
+	iCacheStateNotificationArray.Reset();
+	iSyncEngineRequestArray.ResetAndDestroy();
+	iSessionArray.Reset();
+	} // CPhoneBookServer::~CPhoneBookServer
+
+
+/**
+ *  Attempts to configure or unconfigure the server as specified. If this
+ *  function leaves, the configuration state will be invalid. This function
+ *  is therefore a private function and callers should use ConfigureServerL()
+ *  instead which protects against such problems.
+ *  
+ *  @param aLevel  The desired configuration level to initialise the server to.
+ */
+void CPhoneBookServer::AttemptToConfigureServerL(TServerConfiguration aLevel)
+	{
+	LOGSERVER2(_L8("AttemptToConfigureServerL() to level %d"), aLevel);
+
+	//
+	// Are we configuring or unconfiguring?
+	//
+	if (iServerConfigLevel < aLevel)
+		{
+		//
+		// Configure from level 'None' to 'Idle'...
+		//
+		if (iServerConfigLevel == EServerConfigurationNone)
+			{
+			iServerConfigLevel = EServerConfigurationConfiguringToIdle;
+			LOGSERVER1(_L8("Configuration changed from 'None' to 'ConfiguringToIdle'."));
+
+			iNotifyBackupAndRestore = CNotifyBackupAndRestore::NewL(*this);
+			User::LeaveIfError(iNotifyBackupAndRestore->Start());
+
+			iServerConfigLevel = EServerConfigurationIdle;
+			LOGSERVER1(_L8("Configuration changed from 'ConfiguringToIdle' to 'Idle'."));
+			}
+
+		//
+		// Configure from level 'Idle' to 'Full'...
+		//
+		if (iServerConfigLevel < aLevel  &&
+			iServerConfigLevel == EServerConfigurationIdle)
+			{
+			iServerConfigLevel = EServerConfigurationConfiguringToFull;
+			LOGSERVER1(_L8("Configuration changed from 'Idle' to 'ConfiguringToFull'."));
+
+			//
+			// Connect to ETel...
+			//
+			TInt  etelErr(KErrNone), retryCount;
+
+   			for (retryCount = 0;  retryCount < KMaxConnectToEtelRetries;  retryCount++)
+   				{
+   				TRAP(etelErr, ConnectToEtelL());	//This can leave due to a denied access 										
+													//to CommDb or Etel
+   				if (etelErr == KErrNone)
+					{
+   					break;
+					}
+
+				if (retryCount < KMaxConnectToEtelRetries - 1)
+					{
+   					User::After(1000000);
+					}
+   				}
+   			User::LeaveIfError(etelErr);
+
+			//
+			// Setup the phonebook parameters and create the Phonebook Manager.
+			// This will also read the settings from the INI file.
+			//
+			if (iPhone.GetIccAccessCaps(iICCCaps) != KErrNone)
+				{
+				iICCCaps = RMobilePhone::KCapsSimAccessSupported;
+				}
+
+			iPhonebookManager = CPhoneBookManager::NewL(iICCCaps);
+
+			//
+			// Initialise and start the Active Objects...
+			//
+			iGetPhoneStoreInfo = CGetPhoneStoreInfo::NewL(*this,
+														  *iPhonebookManager,
+														  iPhone);
+			User::LeaveIfError(iGetPhoneStoreInfo->Start());
+
+			iNotifyLockInfoChange = CNotifyLockInfoChange::NewL(*this, iPhone);
+			User::LeaveIfError(iNotifyLockInfoChange->Start());
+
+			iGetSecurityEvent = CNotifySecurityEvent::NewL(*this, iPhone);
+			User::LeaveIfError(iGetSecurityEvent->Start());
+
+			if (IsUsimAppTsy()  &&
+				(iICCCaps & RMobilePhone::KCapsUSimAccessSupported))
+				{
+				iNotifyAppInfoChange = CNotifyAppInfoChange::NewL(*this, iPhone);
+				User::LeaveIfError(iNotifyAppInfoChange->Start());
+				}
+
+			if (iIsSatSupported)
+				{
+				iNotifySatUpdates = CNotifySATUpdates::NewL(*this, iSat);
+	 			User::LeaveIfError(iNotifySatUpdates->Start());
+				}
+
+			//
+			// Start the Sync Engine...
+			//
+			User::LeaveIfError(iSyncEngine.Connect(iPhonebookManager));
+
+			iServerConfigLevel = EServerConfigurationFull;
+			LOGSERVER1(_L8("Configuration changed from 'ConfiguringToFull' to 'Full'."));
+			}
+		}
+	else if (iServerConfigLevel > aLevel)
+		{
+		//
+		// Unconfigure from level 'Full' to 'Idle'...
+		//
+		if (iServerConfigLevel == EServerConfigurationFull  ||
+			iServerConfigLevel == EServerConfigurationConfiguringToFull)
+			{
+			iCacheStateNotificationArray.Reset();
+			iSyncEngineRequestArray.ResetAndDestroy();
+
+			iSyncEngine.Close();
+
+			delete iNotifySatUpdates;
+			iNotifySatUpdates = NULL;
+
+			delete iGetSecurityEvent;
+			iGetSecurityEvent = NULL;
+
+			delete iNotifyLockInfoChange;
+			iNotifyLockInfoChange = NULL;
+
+			delete iGetPhoneStoreInfo;
+			iGetPhoneStoreInfo = NULL;
+
+			delete iPhonebookManager;
+			iPhonebookManager = NULL;
+
+			delete iNotifyAppInfoChange;
+			iNotifyAppInfoChange = NULL;
+
+			iSat.Close();
+			iPhone.Close();
+			iEtelServer.Close();
+				
+			iServerConfigLevel = EServerConfigurationIdle;
+			LOGSERVER1(_L8("Configuration changed to 'Idle'."));
+			}
+		//
+		// Unconfigure from level 'Idle' to 'None'...
+		//
+		if (iServerConfigLevel > aLevel  &&
+			(iServerConfigLevel == EServerConfigurationIdle  ||
+			 iServerConfigLevel == EServerConfigurationConfiguringToIdle))
+			{
+			delete iNotifyBackupAndRestore;
+			iNotifyBackupAndRestore = NULL;
+
+			iServerConfigLevel = EServerConfigurationNone;
+			LOGSERVER1(_L8("Configuration changed to 'None'."));
+			}
+		}
+	} // CPhoneBookServer::AttemptToConfigureServerL
+
+
+/**
+ *  Configures or unconfigures the server as specified.
+ *  
+ *  @param aLevel  The desired configuration level to initialise the server to.
+ */
+void CPhoneBookServer::ConfigureServerL(TServerConfiguration aLevel)
+	{
+	//
+	// Check parameter is valid...
+	//
+	if (aLevel != EServerConfigurationNone  &&
+		aLevel != EServerConfigurationIdle  &&
+		aLevel != EServerConfigurationFull)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	//
+	// Save the current configuration level in case AttemptToConfigureServerL()
+	// leaves.
+	//
+	TServerConfiguration  oldConfigLevel = iServerConfigLevel;
+
+	TRAPD(configErr, AttemptToConfigureServerL(aLevel));
+
+	//
+	// If the attempt to configure the server failed, then reset the config
+	// state and leave.
+	//
+	if (configErr != KErrNone)
+		{
+		LOGSERVER2(_L8("ConfigureServerL: Could not config server (Error %d)."),
+			     configErr);
+
+		TRAPD(unconfigErr, AttemptToConfigureServerL(oldConfigLevel));
+		if (unconfigErr != KErrNone)
+			{
+			LOGSERVER2(_L8("ConfigureServerL: Could not unconfig server either (Error %d)."),
+				     unconfigErr);
+			}
+
+		iServerConfigLevel = oldConfigLevel;
+
+		User::Leave(configErr);
+		}
+	} // CPhoneBookServer::ConfigureServerL
+
+
+/**
+ *  This method is called by the system to indicate that a backup or restore has
+ *  started.
+ */
+void CPhoneBookServer::HandleBackupOrRestoreStarting()
+	{
+	LOGSERVER1(_L8("HandleBackupOrRestoreStarting()"));
+
+	TRAPD(err, ConfigureServerL(EServerConfigurationIdle));
+	if (err != KErrNone)
+		{
+		LOGSERVER2(_L8("ConfigureServerL() failed with error %d."), err);
+		}
+	} // CPhoneBookServer::HandleBackupOrRestoreStarting
+
+
+/**
+ *  This method is called by the system to indicate that a backup or restore has
+ *  completed.
+ */
+void CPhoneBookServer::HandleBackupOrRestoreComplete()
+	{
+	LOGSERVER1(_L8("HandleBackupOrRestoreComplete()"));
+
+	TRAPD(err, ConfigureServerL(EServerConfigurationFull));
+	if (err != KErrNone)
+		{
+		LOGSERVER2(_L8("ConfigureServerL() failed with error %d."), err);
+		}
+	} // CPhoneBookServer::HandleBackupOrRestoreComplete
+
+
+/**
+ *  Create a new client session.
+ *
+ *  @note You can not create a new session if the server is shuting down
+ *        unconditionally.
+ */
+CSession2* CPhoneBookServer::NewSessionL(const TVersion&, const RMessage2& /*aMessage*/) const
+	{
+	LOGSERVER1(_L8("NewSessionL"));
+
+	if (iShouldShutdownUnconditionally)
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	return new(ELeave) CPhoneBookSession();
+	} // CPhoneBookServer::NewSessionL
+
+
+/**
+ *  Called by the session class when it is being created.
+ *
+ *  @param aSession  Server side session.
+ */
+void CPhoneBookServer::AddSessionL(CPhoneBookSession* aSession)
+	{
+	LOGSERVER1(_L8("AddSession"));
+
+	//
+	// Store this session in the list of sessions...
+	//
+	iSessionArray.Append(aSession);
+
+	//
+	// Queue an Active Object to configure the server straight after this
+	// session is created.
+	//
+	if (iPhoneBookSyncStarter == NULL  &&
+	    iServerConfigLevel == EServerConfigurationNone)
+		{
+		iPhoneBookSyncStarter = new (ELeave) CPhoneBookSyncStarter(*this);
+		iPhoneBookSyncStarter->Call();
+		}
+	} // CPhoneBookServer::AddSessionL
+
+
+/**
+ *  Called by the session class when it is being destroyed.
+ *
+ *  @param aSession  Server side session.
+ */
+void CPhoneBookServer::DropSession(CPhoneBookSession* aSession)
+	{
+	LOGSERVER1(_L8("DropSession"));
+
+	//
+	// Remove this session from the session array list...
+	//
+	TInt  position;
+	
+	position = iSessionArray.Find(aSession);
+ 	if (position != KErrNotFound) 
+		{
+ 		iSessionArray.Remove(position);
+ 		
+ 		// 
+ 		// Also remove any outstanding notifications owned by this session
+ 		//
+		for (TInt index = 0;  index < iCacheStateNotificationArray.Count();  index++)
+			{
+			TCacheStateNotification  notifyRequest = iCacheStateNotificationArray[index];
+
+			if (notifyRequest.iSession == aSession)
+				{
+				//
+				// If it is in the list then just remove and complete it since session has been closed...
+				//
+				aSession->CompleteRequest(notifyRequest.iMessage, KErrDisconnected);
+				iCacheStateNotificationArray.Remove(index);
+				index--;
+				}
+			} 		
+		}
+
+	//
+	// If we are shuting down then unconfigure and stop...
+	//
+	if (iSessionArray.Count() == 0  &&  iShouldShutdownServer)
+		{
+		TRAP_IGNORE(ConfigureServerL(EServerConfigurationNone));
+		CActiveScheduler::Stop();
+		}
+	} // CPhoneBookServer::DropSession
+
+
+/**
+ *  Requests a synchronisation from the engine. This is an asynchronous
+ *  request that will result in an engine request being posted to the engine.
+ *
+ *  @param aSession       A reference to the client session.
+ *  @param aMessage       A reference to the client request.
+ *  @param aPhonebookUid  UID of the ICC phonebook to perform the operation on.
+ */
+void CPhoneBookServer::DoSynchronisationL(CPhoneBookSession& aSession,
+										  const RMessage2& aMessage,
+										  TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("DoSynchronisationL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotReady);
+		return;
+		}
+
+	//
+	// Validate the phonebook UID to ensure sync requests can only be posted
+	// for valid phonebooks. Although no harm would come of sending the engine
+	// a sync request with an invalid UID (it will check it as well) we can
+	// easily check it now, and reduce the load on the engine.
+	//
+	if (iPhonebookManager->ValidatePhonebookUid(aPhonebookUid) != KErrNone)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotSupported);
+		return;
+		}
+	
+	//
+	// Check a sync request is not in progress or queued for this phonebook...
+	//
+	if (IsEngineRequestQueued(ESyncDoSynchronisation, aPhonebookUid, ETrue, ETrue))
+		{
+		aSession.CompleteRequest(aMessage, KErrInUse);
+		return;
+		}
+
+	//
+	// Queue the request to the engine...
+	//
+	QueueEngineRequestL(ESyncDoSynchronisation, aPhonebookUid, KNullContactId,
+						&aSession, aMessage);
+	} // CPhoneBookServer::DoSynchronisationL
+	
+	
+/**
+ *  Requests the supported phonebook field formats for the specified phonebook.
+ *
+ *  @param aPhonebookUid   UID of the ICC phonebook to perform the operation on.
+ *  @param aContactFields  The returned contact fields.
+ *
+ *  @return KErrNone if successful, a system-wide error code if not.
+ */
+TInt CPhoneBookServer::GetContactFormatL(TUid aPhonebookUid,
+										 RPhoneBookSession::TContactFieldsV3& aContactFields)
+	{
+	LOGSERVER2(_L8("GetContactFormatL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return(KErrNotReady);
+		}
+
+	//	
+	// Get the Contact Fields from the phonebook via the Phonebook Manager.
+	//
+	TInt result = iPhonebookManager->GetContactFields(aPhonebookUid,
+													  aContactFields);
+	
+	return(result);
+	} // CPhoneBookServer::GetContactFormatL
+
+
+/**
+ *  Return the current setting for the Synchronisation Mode for the specified
+ *  phonebook. The request will complete with KErrNone if the setting is
+ *  successfully returned.
+ * 
+ *  @param aPhonebookUid  UID of the ICC phonebook to perform the operation on.
+ *  @param aSyncMode      The returned sync mode.
+ *
+ *  @return KErrNone if successful, a system-wide error code if not.
+ */
+TInt CPhoneBookServer::GetSyncModeL(TUid aPhonebookUid,
+									RPhoneBookSession::TPhonebookSyncMode& aSyncMode)
+	{
+	LOGSERVER2(_L8("GetSyncModeL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return(KErrNotReady);
+		}
+
+	//	
+	// Get the Sync Mode from the Phonebook via the Phonebook Manager.
+	//
+	TInt  result = iPhonebookManager->GetSyncMode(aPhonebookUid, aSyncMode);
+	
+	return result;
+	} // CPhoneBookServer::GetSyncModeL
+
+
+/**
+ *  Set the Synchronisation Mode for the specified phonebook.
+ *
+ *  If the mode is changing to EAutoCurrentIcc and no sync has yet been performed,
+ *  then an automatic sync will be performed.
+ * 
+ *  @param aPhonebookUid  UID of the ICC phonebook to perform the operation on.
+ *  @param aSyncMode      The new sync mode.
+ *
+ *  @return KErrNone if successful, a system-wide error code if not.
+ */
+TInt CPhoneBookServer::SetSyncModeL(TUid aPhonebookUid,
+									RPhoneBookSession::TPhonebookSyncMode aSyncMode)
+	{
+	LOGSERVER2(_L8("SetSyncModeL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return(KErrNotReady);
+		}
+
+	//
+	// If the new sync mode is EAutoCurrentIcc then get the current Sync
+	// Mode and Sync State. This will determine if an AutoSync should be
+	// queued following the change.
+	//
+	TBool  autoSyncNeeded(EFalse);
+	TInt  result(KErrUnknown);
+
+	if (aSyncMode == RPhoneBookSession::EAutoCurrentIcc)
+		{
+		//
+		// Get the current sync mode...
+		//
+		RPhoneBookSession::TPhonebookSyncMode  oldSyncMode;
+
+		result = iPhonebookManager->GetSyncMode(aPhonebookUid,
+												oldSyncMode);
+		if (result != KErrNone)
+			{
+			return result;
+			}
+		
+		//
+		// Get the current sync state...
+		//
+		RPhoneBookSession::TSyncState  syncState;
+
+		result = iPhonebookManager->GetSyncState(aPhonebookUid,
+												 syncState);
+		if (result != KErrNone)
+			{
+			return result;
+			}
+		
+		//
+		// Find out if the phonebook info has been retrieved...
+		//
+		TInt  phBkInfoRetrievedResult;
+		
+		result = iPhonebookManager->GetPhBkInfoRetrievedResult(aPhonebookUid,
+														       phBkInfoRetrievedResult);
+		if (result != KErrNone)
+			{
+			return result;
+			}
+		
+		//
+		// If the sync mode is changing, the phonebook was previously
+		// unsynchronised and the phonebook info is retrieved then
+		// an auto-sync will be needed.
+		//
+		if (oldSyncMode != RPhoneBookSession::EAutoCurrentIcc  &&
+			syncState == RPhoneBookSession::EUnsynchronised  &&
+			phBkInfoRetrievedResult != KErrNotReady)
+			{
+			autoSyncNeeded = ETrue;
+			}
+		}
+
+	//
+	// Set the Sync Mode in the Phonebook via the Phonebook Manager.
+	//
+	result = iPhonebookManager->SetSyncMode(aPhonebookUid, aSyncMode);
+
+	//
+	// Queue an auto sync if needed...
+	//
+	if (autoSyncNeeded)
+		{
+		QueueAutoSyncRequest(aPhonebookUid);
+		}
+
+	return result;
+	} // CPhoneBookServer::SetSyncModeL
+
+
+/**
+ *  Delete an entry specified by aContactId from the ICC phonebook store
+ *  it exists in.  This is an asynchronous request that will result in an
+ *  engine request being posted to the engine.
+ *
+ *  If a DoSynchronisation or an existing DeleteCntFromICC request has already
+ *  been posted for the same phonebook, KErrInUse will be returned.
+ *
+ *  @param aSession    A reference to the client session.
+ *  @param aMessage    A reference to the client request.
+ *  @param aContactId  ID of the contact to delete.
+ */
+void CPhoneBookServer::DeleteCntFromICCL(CPhoneBookSession& aSession,
+										 const RMessage2& aMessage,
+										 TContactItemId aContactId)
+	{
+	LOGSERVER2(_L8("DeleteCntFromICCL(0%d)"), aContactId);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotReady);
+		return;
+		}
+
+	//
+	// Get the phonebook UID from the contact UID.
+	//
+	TUid phonebookUid = iPhonebookManager->GetPhonebookUidFromContactId(aContactId);
+
+	if (phonebookUid == KUidIccPhonebookNotSpecified)
+		{
+		aSession.CompleteRequest(aMessage, KErrArgument);
+		return;
+		}
+
+	//
+	// Check a sync or delete request is not in progress or queued for this
+	// phonebook...
+	//
+	if (IsEngineRequestQueued(ESyncDoSynchronisation, phonebookUid, ETrue, ETrue)  ||
+		IsEngineRequestQueued(ESyncDeleteCntFromICC, phonebookUid, ETrue, ETrue))
+		{
+		aSession.CompleteRequest(aMessage, KErrInUse);
+		return;
+		}
+
+	QueueEngineRequestL(ESyncDeleteCntFromICC, phonebookUid, aContactId,
+						&aSession, aMessage);
+	} // CPhoneBookServer::DeleteCntFromICCL
+
+
+/**
+ *  Write an entry to a specified ICC phonebook store. This is an asynchronous
+ *  request that will result in an engine request being posted to the engine.
+ *
+ *  If a DoSynchronisation or WriteCntToICCL request has already been posted
+ *  for the same phonebook then KErrInUse will be returned.
+ *
+ *  @param aSession     A reference to the client session.
+ *  @param aMessage     A reference to the client request.
+ *  @param aSlotNum     The desired slot number or KSyncIndexNotSupplied.
+ *  @param aTemplateId  ID of the contact template to base the entry on.
+ */
+void CPhoneBookServer::WriteCntToICCL(CPhoneBookSession& aSession,
+									  const RMessage2& aMessage,
+									  TInt aSlotNum,
+									  TContactItemId aTemplateId)
+	{
+	LOGSERVER2(_L8("WriteCntToICCL(%d)"), aTemplateId);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotReady);
+		return;
+		}
+	
+	//
+	// Check a sync or write request is not in progress or queued for this
+	// phonebook...
+	//
+	TUid  phonebookUid = iPhonebookManager->GetPhonebookUidFromTemplateId(aTemplateId);
+
+	if (IsEngineRequestQueued(ESyncDoSynchronisation, phonebookUid, ETrue, ETrue)  ||
+		IsEngineRequestQueued(ESyncWriteCntToICC, phonebookUid, ETrue, ETrue))
+		{
+		aSession.CompleteRequest(aMessage, KErrInUse);
+		return;
+		}
+
+	//
+	// This request can only proceed if the cache is valid. Since no sync
+	// requests are pending or in progress, we can check this now.
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(phonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		aSession.CompleteRequest(aMessage, result);
+		return;
+		}
+	
+	if (syncState != RPhoneBookSession::ECacheValid)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotReady);
+		return;
+		}
+
+	//
+	// If a slot number is supplied, check it is valid. Again we can do this
+	// now as it won't change...
+	//
+	if (aSlotNum != KSyncIndexNotSupplied)
+		{
+		RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+		TInt  result;
+		
+		result = iPhonebookManager->GetPhoneBookInfo(phonebookUid, phBkInfo);
+		if (result != KErrNone)
+			{
+			aSession.CompleteRequest(aMessage, result);
+			return;
+			}
+
+		if (aSlotNum < 1  ||  aSlotNum > phBkInfo.iTotalEntries)
+			{
+			aSession.CompleteRequest(aMessage, KErrArgument);
+			return;
+			}
+		}
+
+	//
+	// Queue the request for the engine...
+	//
+	QueueEngineRequestL(ESyncWriteCntToICC, phonebookUid, KNullContactId,
+						&aSession, aMessage);
+	} // CPhoneBookServer::WriteCntToICCL
+
+
+/**
+ *  Check whether an ICC entry is allowed to be read/write/edit on behalf of
+ *  the client. The request will complete with KErrNone if the operation could
+ *  be performed.
+ * 
+ *  @param aContactId   Contact Item ID
+ *  @param aValidateOp  Type of operation that needs to be validated
+ *
+ *  @return KErrNone if validation was successful, otherwise returns an error.
+ */
+TInt CPhoneBookServer::ValidateContactL(TContactItemId aContactId,
+									    MContactSynchroniser::TValidateOperation aValidateOp)
+	{
+	LOGSERVER2(_L8("ValidateContactL(%d)"), aContactId);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Get the contact UID from the phonebook...
+	//
+	TUid  phonebookUid = iPhonebookManager->GetPhonebookUidFromContactId(aContactId);
+
+	if (phonebookUid == KUidIccPhonebookNotSpecified)
+		{
+		return KErrNotFound;
+		}
+
+	//
+	// This request can only proceed if the cache is valid...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(phonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+	
+	if (syncState != RPhoneBookSession::ECacheValid)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// First check whether phonebook can be accessed, i.e. whether ICC is
+	// pin-locked/blocked...
+	//
+	if (iPhonebookManager->IsPin1Valid() == EFalse  ||
+		(phonebookUid == KUidUsimAppAdnPhonebook  &&
+		 iPhonebookManager->IsUsimAppPinValid() == EFalse))
+		{
+		return KErrAccessDenied;
+		}
+
+	//
+	// Check the available types of access...
+	//
+	RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+	
+	result = iPhonebookManager->GetPhoneBookInfo(phonebookUid, phBkInfo);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	switch (aValidateOp)
+		{
+		case MContactSynchroniser::ERead:
+		case MContactSynchroniser::ESearch:
+			{
+			if (phBkInfo.iCaps & RMobilePhoneStore::KCapsReadAccess == 0)
+				{
+				return KErrAccessDenied;
+				}
+			}
+			break;
+
+		case MContactSynchroniser::EEdit:
+			{
+			if (phBkInfo.iCaps & RMobilePhoneStore::KCapsWriteAccess == 0)
+				{
+				return KErrAccessDenied;
+				}
+			
+			 //
+			 // For FDN Phonebook, can only edit if PIN2 is set
+			 //
+			 if (phonebookUid == KUidIccGlobalFdnPhonebook  &&
+			 	 iPhonebookManager->IsPin2Valid() == EFalse)
+				{
+				return KErrAccessDenied;
+				}
+			}	
+			break;
+
+		default:
+			{
+			return(KErrNotSupported);
+			}
+		}
+
+	//
+	// Finally, check whether the entry exists in the Look-Up Table...
+	//
+	return iPhonebookManager->IsEntryInTable(phonebookUid, aContactId);
+	} // CPhoneBookServer::ValidateContactL
+
+
+/**
+ *  Update an entry in the Phonebook Sync's look-up table for the specified
+ *  phonebook by adding the Contacts ID supplied by the client (Contacts Model)
+ *  into the specified slot number.
+ *
+ *  @param aPhonebookUid  UID of the ICC phonebook to perform the operation on.
+ *  @param aContactId     Contact Item ID
+ *  @param aSlotNum       The slot number of the entry.
+ *
+ *  @return KErrNone if the table was updated successfully, otherwise returns an error.
+ */
+TInt CPhoneBookServer::UpdateLookupTableL(TUid aPhonebookUid,
+										  TContactItemId aContactId,
+									      TInt aSlotNum)
+	{
+	LOGSERVER2(_L8("UpdateLookupTableL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// This request can only proceed if the cache is valid...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(aPhonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	if (syncState != RPhoneBookSession::ECacheValid)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Update the entry in the loop-up-table...
+	//
+	result = iPhonebookManager->UpdateEntryInTable(aPhonebookUid,
+												   aSlotNum, aContactId);
+
+	return result;
+	} // CPhoneBookServer::UpdateLookupTableL
+
+
+/**
+ *  Return the ICC entry template or group ID for a specified phonebook.
+ *
+ *  @param aPhonebookUid   UID of the ICC phonebook to perform the operation on.
+ *  @param aSyncIdType     Either ESyncTemplateId or ESyncGroupId.
+ *  @param aContactItemId  Returned contact ID.
+ *
+ *  @return KErrNone if the ID was returned successfully, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetPhoneBookIdL(TUid aPhonebookUid,
+								       RPhoneBookSession::TSyncIdType aSyncIdType,
+									   TContactItemId& aContactItemId)
+	{
+	LOGSERVER2(_L8("GetPhoneBookIdL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+	
+	//
+	// Get the required contact ID...
+	//
+	TInt  result(KErrArgument);
+	
+	if (aSyncIdType == RPhoneBookSession::ESyncTemplateId)
+		{
+		result = iPhonebookManager->GetTemplateId(aPhonebookUid,
+												  aContactItemId);
+		}
+	else if (aSyncIdType == RPhoneBookSession::ESyncGroupId)
+		{
+		result = iPhonebookManager->GetGroupId(aPhonebookUid,
+											   aContactItemId);
+		}
+
+	return(result);
+	} // CPhoneBookServer::GetPhoneBookIdL
+
+
+/**
+ *  Return the current phonebook server cache state.
+ * 
+ *  @param aPhonebookUid   UID of the ICC phonebook to perform the operation on.
+ *  @param aContactItemId  Returned cache state.
+ *
+ *  @return KErrNone if the cache state was returned successfully, otherwise returns
+ *          an error.
+ */
+TInt CPhoneBookServer::GetCacheStateL(TUid aPhonebookUid,
+								      RPhoneBookSession::TSyncState& aSyncState)
+	{
+	LOGSERVER2(_L8("GetCacheStateL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Check if the phonebook is supported...
+	//
+	TInt  result, phBkInfoRetrievedResult;
+	
+	result = iPhonebookManager->GetPhBkInfoRetrievedResult(aPhonebookUid,
+														   phBkInfoRetrievedResult);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+	
+	if (phBkInfoRetrievedResult != KErrNone)
+		{
+		return phBkInfoRetrievedResult;
+		}
+
+	return iPhonebookManager->GetSyncState(aPhonebookUid, aSyncState);
+	} // CPhoneBookServer::GetCacheStateL
+
+
+/**
+ *  Marks the start of checking the server's and engine's heap. 
+ *  This function only works in debug releases.
+ *
+ *  Calls to this function can be nested but each call must be matched by
+ *  corresponding DbgMarkEnd().
+ *
+ *  @return  KErrNone.
+ */
+TInt CPhoneBookServer::DbgMarkHeap() const
+	{
+#ifdef _DEBUG
+	__UHEAP_MARK;
+#endif
+
+	return(KErrNone);
+	} // CPhoneBookServer::DbgMarkHeap
+
+
+/**
+ *  Checks that the number of allocated cells at the current nested level on
+ *  the server's and engine's heaps are the same as the specified value.
+ *  This function only works for debug builds.
+ *
+ *  @param aCount  The number of heap cells expected to be allocated at
+ *                 the current nest level.
+ *
+ *  @return  KErrNone.
+ */
+TInt CPhoneBookServer::DbgCheckHeap(TInt aCount) const
+	{
+#ifdef _DEBUG 
+	__UHEAP_CHECK(aCount);
+#else
+	(void) aCount;
+#endif
+
+	return(KErrNone);
+	} // CPhoneBookServer::DbgCheckHeap
+
+
+/**
+ *  Marks the end of checking the current server's and engine's heap. 
+ *
+ *  The function expects aCount heap cells to remain allocated at the
+ *  current nest level. This function must match an earlier call to
+ *  DbgMarkHeap() and only functions on debug releases.
+ *
+ *  @param aCount  The number of heap cells expected to remain allocated
+ *                 at the current nest level.
+ *
+ *  @return  KErrNone.
+ */
+TInt CPhoneBookServer::DbgMarkEnd(TInt aCount) const
+	{
+#ifdef _DEBUG
+	__UHEAP_MARKENDC(aCount);
+#else
+	(void) aCount;
+#endif
+
+	return(KErrNone);
+	} // CPhoneBookServer::DbgMarkEnd
+
+
+/**
+ *  Simulates heap allocation failure for the sever and engine.
+ *
+ *  The failure occurs on the next call to new or any of the functions which 
+ *  allocate memory from the heap. This is defined only for debug builds.
+ *
+ *  @param aCount  Determines when the allocation will fail.
+ *
+ *  @return  KErrNone.
+ */
+TInt CPhoneBookServer::DbgFailNext(TInt aCount) const
+	{
+#ifdef _DEBUG
+	if (aCount == 0)
+		{
+		__UHEAP_RESET;
+		}
+	else
+		{
+		__UHEAP_FAILNEXT(aCount);
+		}
+#else
+	(void) aCount;
+#endif
+
+	return(KErrNone);
+	} // CPhoneBookServer::DbgFailNext
+
+
+/**
+ *  Cancel a previous synchronisation request.
+ *
+ *  @param aSession       Reference to the client's session.
+ *  @param aPhonebookUid  UID of the ICC phonebook to cancel the sync request.
+ *
+ *  @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CPhoneBookServer::DoSynchronisationCancelL(CPhoneBookSession& aSession,
+												TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("DoSynchronisationCancelL(): 0x%08x"), aPhonebookUid);
+
+	CancelEngineRequest(ESyncDoSynchronisation, aPhonebookUid,
+						KNullContactId, &aSession);
+
+	return(KErrNone);
+	} // CPhoneBookServer::DoSynchronisationCancelL
+
+
+/**
+ *  Cancel a previous delete contact request.
+ *
+ *  @param aSession       Reference to the client's session.
+ *  @param aPhonebookUid  UID of the ICC phonebook to cancel the delete request.
+ *
+ *  @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CPhoneBookServer::DeleteCntFromICCCancelL(CPhoneBookSession& aSession,
+												TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("DeleteCntFromICCCancelL(0x%08x)"), aPhonebookUid);
+
+	CancelEngineRequest(ESyncDeleteCntFromICC, aPhonebookUid,
+						KNullContactId, &aSession);
+
+	return(KErrNone);
+	} // CPhoneBookServer::DeleteCntFromICCCancelL
+
+
+/**
+ *  Cancel a previous write contact request.
+ *
+ *  @param aSession       Reference to the client's session.
+ *  @param aPhonebookUid  UID of the ICC phonebook to cancel the write request.
+ *
+ *  @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CPhoneBookServer::WriteCntToICCCancelL(CPhoneBookSession& aSession,
+											TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("WriteCntToICCCancelL(0x%08x)"), aPhonebookUid);
+
+	CancelEngineRequest(ESyncDoSynchronisation, aPhonebookUid,
+						KNullContactId, &aSession);
+
+	return(KErrNone);
+	} // CPhoneBookServer::WriteCntToICCCancelL
+
+
+/**
+ *  Stores the current message for later completion when the cache state of the
+ *  specified phonebook changes.
+ *
+ *  @param aSession       Reference to the client's session.
+ *  @param aMessage       Reference to the client's request.
+ *  @param aPhonebookUid  UID of the ICC phonebook to monitor.
+ */
+void CPhoneBookServer::NotifyCacheStateChangeL(CPhoneBookSession& aSession,
+											   const RMessage2& aMessage,
+											   TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("NotifyCacheStateChangeL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		aSession.CompleteRequest(aMessage, KErrNotReady);
+		return;
+		}
+
+	//	
+	// Validate the phonebook UID to ensure notifications can only be posted
+	// for valid phonebooks.
+	//
+	TInt  result;
+
+	result = iPhonebookManager->ValidatePhonebookUid(aPhonebookUid);
+	if (result != KErrNone)
+		{
+		aSession.CompleteRequest(aMessage, result);
+		return;
+		}
+
+	//
+	// Create Notification Request Object and add to the array...
+	//
+	TCacheStateNotification  notifyRequest;
+
+	notifyRequest.iSession      = &aSession;
+	notifyRequest.iMessage      = aMessage;
+	notifyRequest.iPhonebookUid = aPhonebookUid;
+
+	result = iCacheStateNotificationArray.Append(notifyRequest);
+	if (result != KErrNone)
+		{
+		aSession.CompleteRequest(aMessage, result);
+		return;
+		}
+	} // CPhoneBookServer::NotifyCacheStateChangeL
+
+
+/**
+ *  Cancel a previous notify state change request.
+ *
+ *  @param aSession       Reference to the client's session.
+ *  @param aPhonebookUid  UID of the ICC phonebook to cancel the notify request.
+ *
+ *  @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CPhoneBookServer::NotifyCacheStateChangeCancelL(CPhoneBookSession& aSession,
+													 TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("NotifyCacheStateChangeCancelL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+	
+	//
+	// Cancel the notification by completing the request with KErrCancel...
+	//
+	for (TInt index = 0;  index < iCacheStateNotificationArray.Count();  index++)
+		{
+		TCacheStateNotification  notifyRequest = iCacheStateNotificationArray[index];
+
+		if (notifyRequest.iSession == &aSession  &&
+			notifyRequest.iPhonebookUid == aPhonebookUid)
+			{
+			//
+			// If it is in the list then cancel it, and remove it...
+			//
+			aSession.CompleteRequest(notifyRequest.iMessage, KErrCancel);
+
+			iCacheStateNotificationArray.Remove(index);
+			index--;
+			}
+		}
+
+	return(KErrNone);
+	} // CPhoneBookServer::NotifyCacheStateChangeCancelL
+
+
+/**
+ *  Returns the last error found during synchronisation on the specified phonebook.
+ *
+ *  @param aPhonebookUid   UID of the ICC phonebook to examine.
+ *  @param aLastSyncError  Returned value of the last error.
+ *
+ *  @return KErrNone if the last error was returned, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetLastSyncErrorL(TUid aPhonebookUid,
+										 TInt& aLastSyncError)
+	{
+	LOGSERVER2(_L8("GetLastSyncErrorL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// This request can only proceed if a sync request has been actioned...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(aPhonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+	
+	if (syncState == RPhoneBookSession::EUnsynchronised)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Get the last sync error form the phonebook parameters.
+	//
+	iPhonebookManager->GetLastSyncError(aPhonebookUid, aLastSyncError);
+
+	return KErrNone;
+	} // CPhoneBookServer::GetLastSyncErrorL
+
+
+/**
+ *  Returns the total number of slots for a specified phonebook.
+ *
+ *  @param aPhonebookUid  UID of the ICC phonebook to examine.
+ *  @param aNumSlots      Returned value of the number of slots.
+ *
+ *  @return KErrNone if the value was returned, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetNumSlotsL(TUid aPhonebookUid, TInt& aNumSlots)
+	{
+	LOGSERVER2(_L8("GetNumSlotsL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Make sure we do not complete with the default value...
+	//
+	TInt  phBkInfoRetrievedResult;
+	TInt  result;
+
+	result = iPhonebookManager->GetPhBkInfoRetrievedResult(aPhonebookUid,
+														   phBkInfoRetrievedResult);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	if (phBkInfoRetrievedResult != KErrNone)
+		{
+		return phBkInfoRetrievedResult;
+		}
+
+	//
+	// This information can be obtained from the Phonebook Info data
+	// (TMobilePhoneBookInfoV5) or the RMobilePhoneStore data (which populates)
+	// the Look-Up Table size. Since the first option is not always supported,
+	// it's easiest (and quickest) to return the Loop-Up Table size...
+	//
+	result = iPhonebookManager->GetLookUpTableSize(aPhonebookUid, aNumSlots);
+	
+	return result;
+	} // CPhoneBookServer::GetNumSlotsL
+
+
+/**
+ *  Return number of free slots for a specified phonebook.
+ *
+ *  @param aPhonebookUid  UID of the ICC phonebook to examine.
+ *  @param aNumFreeSlots  Returned value of the number of free slots.
+ *
+ *  @return KErrNone if the value was returned, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetNumFreeSlotsL(TUid aPhonebookUid,
+										TInt& aNumFreeSlots)
+	{
+	LOGSERVER2(_L8("GetNumFreeSlotsL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Get the current sync state for this phonebook...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(aPhonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	//
+	// If the phone book is synchronised then take the value from the LUT.
+	// Otherwise, take the value from the phone info structure. However, 
+	// the phone may not support returning this information.
+	//
+	if (syncState == RPhoneBookSession::ECacheValid)
+		{
+		result = iPhonebookManager->GetNumFreeSlots(aPhonebookUid, aNumFreeSlots);
+		if (result != KErrNone)
+			{
+			return result;
+			}
+		}
+	else
+		{
+		RMobilePhoneBookStore::TMobilePhoneBookInfoV5  phBkInfo;
+		
+		result = iPhonebookManager->GetPhoneBookInfo(aPhonebookUid, phBkInfo);
+	
+		if (phBkInfo.iTotalEntries < 0  ||  phBkInfo.iUsedEntries < 0)
+			{
+			//
+			// The TSY does not support this information.
+			//
+			return KErrUnknown;
+			}
+			
+		aNumFreeSlots = phBkInfo.iTotalEntries - phBkInfo.iUsedEntries;
+		}
+	
+	return KErrNone;
+	} // CPhoneBookServer::GetNumFreeSlotsL
+
+
+/**
+ *  Return an array of free slot numbers for a specified phonebook.
+ *
+ *  @param aPhonebookUid  UID of the ICC phonebook to examine.
+ *  @param aFreeSlots     Returned list of free slots.
+ *
+ *  @return KErrNone if the list was returned, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetFreeSlotsL(TUid aPhonebookUid,
+									 RArray<TInt>& aFreeSlots)
+	{
+	LOGSERVER2(_L8("GetFreeSlotsL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// This request can only proceed if the cache is valid...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(aPhonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	if (syncState != RPhoneBookSession::ECacheValid)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Return the list of free slots...
+	//
+	result = iPhonebookManager->GetMatchingEntries(aPhonebookUid, ESlotEmpty,
+												   aFreeSlots);
+	
+	return result;
+	} // CPhoneBookServer::GetFreeSlotsL
+	
+
+/**
+ *  Return the contact ID assigned to an entry at a given slot in a specified
+ *  phonebook.
+ *
+ *  @param aPhonebookUid   UID of the ICC phonebook to examine.
+ *  @param aSlotNum        Slot number to examine.
+ *  @param aContactItemId  Returned contact ID.
+ *
+ *  @return KErrNone if the contact ID was returned, otherwise returns an error.
+ */
+TInt CPhoneBookServer::GetSlotIdL(TUid aPhonebookUid, TInt aSlotNum,
+								  TContactItemId& aContactItemId)
+	{
+	LOGSERVER2(_L8("GetSlotIdL(0x%08x)"), aPhonebookUid);
+
+	//
+	// Is the server configured for use?
+	//
+	if (iServerConfigLevel != EServerConfigurationFull)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// This request can only proceed if the cache is valid...
+	//
+	RPhoneBookSession::TSyncState  syncState;
+	TInt  result;
+	
+	result = iPhonebookManager->GetSyncState(aPhonebookUid, syncState);
+	if (result != KErrNone)
+		{
+		return result;
+		}
+
+	if (syncState != RPhoneBookSession::ECacheValid)
+		{
+		return KErrNotReady;
+		}
+
+	//
+	// Get the ID from the phonebook's Look Up Table...
+	//
+	result = iPhonebookManager->GetContactIdFromSlotNum(aPhonebookUid,
+														aSlotNum,
+														aContactItemId);
+	
+	return result;
+	} // CPhoneBookServer::GetSlotIdL
+
+
+/**
+ *  Requests the server to shut down when it no longer has any connected
+ *  sessions. This procedure is only premitted in debug builds and is provided
+ *  for testing purposes.
+ *
+ *  The server will shutdown when the last session disconnects.
+ *
+ *  @param aUnconditionally  If True it allows future connects to the server up
+ *                           until the last session disconnects.
+ *
+ *  @return KErrNone if the shutdown request was accepted, otherwise returns
+ *          an error.
+ */
+TInt CPhoneBookServer::ShutdownServer(TBool aUnconditionally)
+	{
+	LOGSERVER1(_L8("ShutdownServer()"));
+
+	iShouldShutdownServer          = ETrue;
+	iShouldShutdownUnconditionally = aUnconditionally;
+
+	//
+	// Unconfigure the server now. Otherwise the engine may be holding a
+	// handle on the Contacts DB, which could be holding a handle on the
+	// PhBkSync plugin, which could be holding the last session on PhBkSync
+	// and prevent the server from unconfiguring the engine, etc.
+	//
+	TRAP_IGNORE(ConfigureServerL(EServerConfigurationNone));
+	
+	return(KErrNone);
+	} // CPhoneBookServer::ShutdownServer
+
+
+/**
+ *  If a notification request is outstanding for the specified phonebook it is
+ *  completed.
+ *
+ *  @param aPhonebookUid  The phonebook for which the sync state has changed.
+ */
+void CPhoneBookServer::CompleteNotifyStateChange(TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("CompleteNotifyStateChange(): 0x%08x"), aPhonebookUid);
+
+	for (TInt index = 0;  index < iCacheStateNotificationArray.Count();  index++)
+		{
+		TCacheStateNotification  notifyRequest = iCacheStateNotificationArray[index];
+
+		if (notifyRequest.iPhonebookUid == aPhonebookUid)
+			{
+			//
+			// If it is in the list then  complete the message and then remove
+			// from the list.
+			//
+			notifyRequest.iSession->CompleteRequest(notifyRequest.iMessage,
+												    KErrNone);
+
+			iCacheStateNotificationArray.Remove(index);
+			index--;
+			}
+		}
+	} // CPhoneBookServer::CompleteNotifyStateChange
+
+
+/**
+ *  Connect to the ETel Sever, obtains the name of the currently selected TSY and
+ *  then loads the TSY.
+ */
+void CPhoneBookServer::ConnectToEtelL()
+	{
+	LOGSERVER1(_L8("Connect to ETel")); 
+	// Obtain the name of the currently selected TSY 	
+	
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+	CMDBSession* db = CMDBSession::NewLC(KCDVersion1_2);
+#else
+	CMDBSession* db = CMDBSession::NewLC(KCDVersion1_1);
+#endif
+	
+	CMDBField<TUint32>* globalSettingField = new(ELeave) CMDBField<TUint32>(KCDTIdModemPhoneServicesSMS);
+	CleanupStack::PushL(globalSettingField);
+
+	globalSettingField->SetRecordId(1);
+	globalSettingField->LoadL(*db);
+	TUint32 modemId = *globalSettingField;
+
+	CMDBField<TDesC>* tsyField = new(ELeave) CMDBField<TDesC>(KCDTIdTsyName);
+	CleanupStack::PushL(tsyField);
+
+	tsyField->SetRecordId(modemId);
+	TRAPD(err, tsyField->LoadL(*db));
+	if (err != KErrNone)
+		{
+		LOGSERVER1(_L8("Unable to get default TSY"));
+		}
+	User::LeaveIfError(err);
+
+	TBuf<KCommsDbSvrMaxFieldLength> tsyName;
+	tsyName = *tsyField;
+
+	CleanupStack::PopAndDestroy(3, db); // db, tsyField & globalSettingField
+	
+	TInt ret(iEtelServer.Connect()); // First connect to the ETel server
+	if(ret==KErrNone)
+		{
+		LOGSERVER1(_L8("Loading TSY")); // Now load the TSY 
+		ret=iEtelServer.LoadPhoneModule(tsyName);
+		RTelServer::TPhoneInfo phoneInfo;
+		if(ret==KErrNone)
+			{
+			// Determine if TSY supports V2 functionality
+			// in event of a problem here assume that it does not
+			ret = iEtelServer.IsSupportedByModule(tsyName, KETelExtMultimodeV2, iIsV2Tsy);
+			if (ret != KErrNone)
+				{
+				iIsV2Tsy = EFalse;
+				}
+
+			// Determine if TSY supports V5 functionality
+ 			// in event of a problem here assume that it does not
+ 			ret = iEtelServer.IsSupportedByModule(tsyName, KEtelExtMultimodeV5, iIsV5Tsy);
+ 			if (ret != KErrNone)
+ 				{
+ 				iIsV5Tsy = EFalse;
+ 				}
+
+			// Determine if TSY supports USIM Apps
+			// in event of a problem here assume that it does not
+			ret = iEtelServer.IsSupportedByModule(tsyName, KEtelFuncMobileUSIMApplications, iIsUsimAppTsy);
+			if (ret != KErrNone)
+				{
+				iIsUsimAppTsy = EFalse;
+				}
+
+			TInt phoneIndex(0);
+			iEtelServer.EnumeratePhones(phoneIndex); // Get total number of phones supported by all currently loaded TSY modules
+			while(phoneIndex-->0)
+				{
+				TName searchTsyName;
+				// Check whether this phone belongs to loaded TSY
+				if((iEtelServer.GetTsyName(phoneIndex,searchTsyName)==KErrNone) && (searchTsyName.CompareF(tsyName)==KErrNone)) 
+					break;
+				}
+			iEtelServer.GetPhoneInfo(phoneIndex,phoneInfo); // Get information associated with specified phone
+
+			LOGSERVER1(_L8("Open the phone"));
+			ret = iPhone.Open(iEtelServer,phoneInfo.iName); // Open and intialise the phone
+			if (ret==KErrNone)
+				{
+				RPhone::TStatus phoneStatus;
+				iPhone.GetStatus(phoneStatus); 
+				if(phoneStatus.iMode==RPhone::EModeUnknown) // Check whether phone has already been initialised
+					{	
+					ret=iPhone.Initialise();
+					
+					if(ret!=KErrNone)
+						{	
+						LOGSERVER2(_L8("Phone initialisation failed - closing phone (ret=%d)"), ret);
+						iPhone.Close();
+						}
+					}
+
+				if(ret==KErrNone) // Do not even try to open SAT if phone not successfully initialised
+					{
+					TInt retSat=iSat.Open(iPhone);
+					if(retSat==KErrNone)
+						{
+						iIsSatSupported=ETrue; // SAT supported by TSY so proceed with SAT processing
+						// Determine if TSY supports V2 SAT - in event of a problem assume that it does not
+						ret = iEtelServer.IsSupportedByModule(tsyName, KETelExtSatV2, iIsV2SAT);
+						if (ret != KErrNone)
+							{
+							iIsV2SAT = EFalse;
+							}
+						}
+					else
+						{
+						LOGSERVER2(_L8("Could not start ETel SAT (retSat=%d)"), retSat);
+						iIsSatSupported = EFalse;
+						}
+					}
+				}
+			}
+		else
+			{
+			LOGSERVER2(_L8("Could not load the TSY (ret=%d)"), ret);
+			}
+		}
+	else
+		{
+		LOGSERVER2(_L8("Could not connect to ETel (ret=%d)"), ret);
+		}
+
+	User::LeaveIfError(ret);
+	} // CPhoneBookServer::ConnectToEtelL
+
+
+/**
+ *  Complete an outstanding GetPhoneStoreInfo request.
+ *
+ *  @note  Any errors will cause the phonebook setup to be ignored. This puts
+ *         the phonebook in limbo as it is supported but not usable.
+ *
+ *  @param aRetVal        Result of the request.
+ *  @param aStoreInfo     Phonebook store information containing the phonebook ID.
+ *  @param aPhonebookUid  Type of the ICC phonebook used internally by the server 
+ */
+void CPhoneBookServer::CompleteGetPhoneStoreInfo(TInt aRetVal, 
+											     RMobilePhoneBookStore::TMobilePhoneBookInfoV5& aStoreInfo, 
+					 							 TUid aPhonebookUid)
+	{
+	LOGSERVER4(_L8("CompleteGetPhoneStoreInfo(): retVal=%d phonebook=0x%08x "
+				   "Identity=\"%S\""), aRetVal, aPhonebookUid,
+				   &aStoreInfo.iIdentity);
+
+	if (aRetVal == KErrNone)
+		{
+		//
+		// First log the structure as the contents have been the cause of a
+		// number of defects so far...
+		//		
+#ifdef _DEBUG
+		TBuf8<RMobilePhone::KMaxMobileNameSize>  nameIn8bit;
+		nameIn8bit.Copy(aStoreInfo.iName);
+#endif
+
+		LOGSERVER2(_L8("PhoneBookInfo: iExtensionId=%d"), aStoreInfo.ExtensionId());
+		LOGSERVER2(_L8("PhoneBookInfo: iType=%d"), aStoreInfo.iType);
+		LOGSERVER2(_L8("PhoneBookInfo: iTotalEntries=%d"), aStoreInfo.iTotalEntries);
+		LOGSERVER2(_L8("PhoneBookInfo: iUsedEntries=%d"), aStoreInfo.iUsedEntries);
+		LOGSERVER2(_L8("PhoneBookInfo: iCaps=0x%08x"), aStoreInfo.iCaps);
+		LOGSERVER2(_L8("PhoneBookInfo: iName=\"%S\""), &nameIn8bit);
+
+		if (aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV1  ||
+			aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV2  ||
+			aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV5)
+			{
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxNumLength=%d"), aStoreInfo.iMaxNumLength);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxTextLength=%d"), aStoreInfo.iMaxTextLength);
+			LOGSERVER2(_L8("PhoneBookInfo: iLocation=%d"), (TInt) aStoreInfo.iLocation);
+			LOGSERVER2(_L8("PhoneBookInfo: iChangeCounter=%d"), (TInt) aStoreInfo.iChangeCounter);
+			LOGSERVER2(_L8("PhoneBookInfo: iIdentity=\"%S\""), &aStoreInfo.iIdentity);
+			}
+		
+		if (aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV2  ||
+			aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV5)
+			{
+#ifdef _DEBUG
+			TBuf8<KMaxName>  phBkModeIn8bit;
+			phBkModeIn8bit.Copy(aStoreInfo.iPhBkMode);
+#endif
+
+			LOGSERVER2(_L8("PhoneBookInfo: iPhBkMode=\"%S\""), &phBkModeIn8bit);
+			}
+		
+		if (aStoreInfo.ExtensionId() == RMobilePhoneBookStore::KETelMobilePhonebookStoreV5)
+			{
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxSecondNames=%d"), aStoreInfo.iMaxSecondNames);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxTextLengthSecondName=%d"), aStoreInfo.iMaxTextLengthSecondName);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxAdditionalNumbers=%d"), aStoreInfo.iMaxAdditionalNumbers);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxNumLengthAdditionalNumber=%d"), aStoreInfo.iMaxNumLengthAdditionalNumber);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxTextLengthAdditionalNumber=%d"), aStoreInfo.iMaxTextLengthAdditionalNumber);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxGroupNames=%d"), aStoreInfo.iMaxGroupNames);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxTextLengthGroupName=%d"), aStoreInfo.iMaxTextLengthGroupName);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxEmailAddr=%d"), aStoreInfo.iMaxEmailAddr);
+			LOGSERVER2(_L8("PhoneBookInfo: iMaxTextLengthEmailAddr=%d"), aStoreInfo.iMaxTextLengthEmailAddr);
+			}
+		
+		//
+		// Should a TSY return iTotalEntries as 0 for ADN then we are in big trouble and
+		// no sync will be possible. It is an error in the TSY so we must panic.
+		//
+		if (aPhonebookUid == KUidIccGlobalAdnPhonebook  &&
+			aStoreInfo.iTotalEntries == 0)
+			{
+			PhBkSyncPanic(EPhBkSyncPanicGetPhoneStoreInfoError);
+			}
+		
+		//
+		// Create the default contacts field structure for this phonebook.
+		// These are default settings for all phonebooks regardless of type
+		// of ICC.
+		//
+		RPhoneBookSession::TContactFieldsV3  contactFieldsV3;
+		TInt  result;
+	
+		contactFieldsV3.iNameField.iLength    = aStoreInfo.iMaxTextLength;
+		contactFieldsV3.iNameField.iCount     = 1;
+		contactFieldsV3.iNameField.iDisplayed = ETrue;
+
+		contactFieldsV3.iNumberField.iLength    = aStoreInfo.iMaxNumLength;
+		contactFieldsV3.iNumberField.iCount     = 1;
+		contactFieldsV3.iNumberField.iDisplayed = ETrue;
+	
+		contactFieldsV3.iIccSlotField.iLength    = -1;
+		contactFieldsV3.iIccSlotField.iCount     = 1;
+		contactFieldsV3.iIccSlotField.iDisplayed = ETrue;
+	
+		contactFieldsV3.iPhonebook = aPhonebookUid;
+
+		if (iICCCaps & RMobilePhone::KCapsUSimAccessSupported)
+			{
+			//
+			// Set up the 3G ICC contact settings.  There are additional fields
+			// for ADN and USIM App phonebooks.
+			//
+			if (aPhonebookUid == KUidIccGlobalAdnPhonebook  || 
+				aPhonebookUid == KUidUsimAppAdnPhonebook)
+				{
+				if (aStoreInfo.ExtensionId()==RMobilePhoneBookStore::KETelMobilePhonebookStoreV5)
+					{
+			 		contactFieldsV3.iAdditionalNumString.iLength    = aStoreInfo.iMaxNumLengthAdditionalNumber;
+			 		contactFieldsV3.iAdditionalNumString.iCount     = aStoreInfo.iMaxAdditionalNumbers;
+			 		contactFieldsV3.iAdditionalNumString.iDisplayed = ETrue;
+			 
+			 		contactFieldsV3.iAdditionalNumAlphaString.iLength    = aStoreInfo.iMaxTextLengthAdditionalNumber;
+			 		contactFieldsV3.iAdditionalNumAlphaString.iCount     = aStoreInfo.iMaxAdditionalNumbers;
+			 		contactFieldsV3.iAdditionalNumAlphaString.iDisplayed = ETrue;
+			 
+			 		contactFieldsV3.iGroupField.iLength    = aStoreInfo.iMaxTextLengthGroupName;
+			 		contactFieldsV3.iGroupField.iCount     = aStoreInfo.iMaxGroupNames;
+			 		contactFieldsV3.iGroupField.iDisplayed = ETrue;
+			 
+			 		contactFieldsV3.iEmailField.iLength    = aStoreInfo.iMaxTextLengthEmailAddr;
+			 		contactFieldsV3.iEmailField.iCount     = aStoreInfo.iMaxEmailAddr;
+			 		contactFieldsV3.iEmailField.iDisplayed = ETrue;
+			 
+			 		contactFieldsV3.iSecondNameField.iLength    = aStoreInfo.iMaxTextLengthSecondName;
+			 		contactFieldsV3.iSecondNameField.iCount     = aStoreInfo.iMaxSecondNames;
+			 		contactFieldsV3.iSecondNameField.iDisplayed = ETrue;
+			 		}
+			 	else
+			 		{
+					contactFieldsV3.iAdditionalNumString.iLength    = aStoreInfo.iMaxTextLength;
+					contactFieldsV3.iAdditionalNumString.iCount     = -1;
+					contactFieldsV3.iAdditionalNumString.iDisplayed = ETrue;
+
+					contactFieldsV3.iAdditionalNumAlphaString.iLength    = aStoreInfo.iMaxTextLength;
+					contactFieldsV3.iAdditionalNumAlphaString.iCount     = -1;
+					contactFieldsV3.iAdditionalNumAlphaString.iDisplayed = ETrue;
+
+					contactFieldsV3.iGroupField.iLength    = aStoreInfo.iMaxTextLength;
+					contactFieldsV3.iGroupField.iCount     = -1;
+					contactFieldsV3.iGroupField.iDisplayed = ETrue;
+
+					contactFieldsV3.iEmailField.iLength    = aStoreInfo.iMaxTextLength;
+					contactFieldsV3.iEmailField.iCount     = -1;
+					contactFieldsV3.iEmailField.iDisplayed = ETrue;			 		
+
+					contactFieldsV3.iSecondNameField.iLength    = aStoreInfo.iMaxTextLength;
+					contactFieldsV3.iSecondNameField.iCount     = -1;
+					contactFieldsV3.iSecondNameField.iDisplayed = ETrue;
+			 		}
+				}
+			}
+		
+		result = iPhonebookManager->SetContactFields(aPhonebookUid, contactFieldsV3);
+		if (result != KErrNone)
+			{
+			return;
+			}
+
+		//
+		// Initialise the Look Up Table...
+		//
+		result = iPhonebookManager->SetLookUpTableSize(aPhonebookUid, aStoreInfo.iTotalEntries);
+		if (result != KErrNone)
+			{
+			return;
+			}
+
+		//
+		// Get the current sync mode. This is used later and also to decide if
+		// we need to get the previous phonebook info...
+		//
+		RPhoneBookSession::TPhonebookSyncMode  syncMode;
+		
+		result = iPhonebookManager->GetSyncMode(aPhonebookUid, syncMode);
+		if (result != KErrNone)
+			{
+			return;
+			}
+		
+		//
+		// Get the previous phonebook info if we need it...
+		//
+		RMobilePhoneBookStore::TMobilePhoneBookInfoV5  oldPhBkInfo;
+
+		if (syncMode == RPhoneBookSession::EAutoSameIcc)
+			{
+			result = iPhonebookManager->GetPhoneBookInfo(aPhonebookUid, oldPhBkInfo);
+			if (result != KErrNone)
+				{
+				return;
+				}
+			}
+		
+		//
+		// Store the new phonebook info...
+		//
+		iPhonebookManager->SetPhoneBookInfo(aPhonebookUid, aStoreInfo);
+		iPhonebookManager->SetPhBkInfoRetrievedResult(aPhonebookUid, aRetVal);
+		
+		//
+		// If the phonebook is in auto-sync mode then queue a sync request...
+		//
+		if (syncMode == RPhoneBookSession::EAutoCurrentIcc  ||
+		    (syncMode == RPhoneBookSession::EAutoSameIcc  &&  aStoreInfo.iIdentity == oldPhBkInfo.iIdentity))
+			{
+			QueueAutoSyncRequest(aPhonebookUid);
+			}
+		}
+	else
+		{
+		//
+		// The phonebook is not available or supported.
+		//
+		iPhonebookManager->SetPhBkInfoRetrievedResult(aPhonebookUid, aRetVal);
+
+		//
+		// If the sync mode is auto-sync current then perform an auto sync in
+		// case any entries exist in the database from previous syncs. The
+		// sync will fail, but the engine will silently clear the entries out.
+		//
+		RPhoneBookSession::TPhonebookSyncMode  syncMode;
+		TInt  result;
+		
+		result = iPhonebookManager->GetSyncMode(aPhonebookUid, syncMode);
+		if (result == KErrNone  &&
+		    syncMode == RPhoneBookSession::EAutoCurrentIcc)
+			{
+			QueueAutoSyncRequest(aPhonebookUid);
+			}
+
+		}
+	} // CPhoneBookServer::CompleteGetPhoneStoreInfo
+
+
+/**
+ *  Complete an outstanding NotifySecurityEvent request. The Active Notification Base
+ *  class is responsible for reposting the notification.
+ *
+ *  @param aRetVal         Result of the notification request.
+ *  @param aSecurityEvent  Type of Security Event received.
+ */
+void CPhoneBookServer::CompleteNotifySecurityEvent(TInt aRetVal,
+												   RMobilePhone::TMobilePhoneSecurityEvent aSecurityEvent)
+	{
+	if (aRetVal == KErrNone)
+		{
+#ifdef _DEBUG
+		const char*  KEventNames[23] = {"ENoICCFound", "EICCTerminated",
+									    "EPin1Required", "EPuk1Required",
+									    "EPin2Required", "EPuk2Required",
+									    "EPhonePasswordRequired",
+									    "ESPCRequired", "EPin1Verified",
+									    "EPin2Verified", "EPuk1Verified",
+									    "EPuk2Verified",
+									    "EPhonePasswordVerified", "ESPCVerified",
+									    "EHiddenKeyRequired", "EHiddenKeyVerified",
+									    "EUSIMAppPinRequired", "EUSIMAppPinVerified",
+									    "ESecondUSIMAppPinRequired",
+									    "ESecondUSIMAppPinVerified",
+									    "EUniversalPinRequired",
+									    "EUniversalPinVerified",
+									    "ESPCChanged"};
+#endif
+
+		LOGSERVER2(_L8("CompleteNotifySecurityEvent(): %s."), KEventNames[aSecurityEvent]);
+
+		iPhonebookManager->RecordSecurityEvent(aSecurityEvent);
+		}
+	} // CPhoneBookServer::CompleteNotifySecurityEvent
+
+
+/**
+ *  Complete an outstanding NotifyLockInfoChange request. The Active Notification Base
+ *  class is responsible for reposting the notification.
+ *
+ *  @param aRetVal    Result of the notification request.
+ *  @param aLock      Mobile phone lock.
+ *  @param aLockInfo  Status of the changed lock.
+ */
+void CPhoneBookServer::CompleteNotifyLockInfoChange(TInt aRetVal,
+													RMobilePhone::TMobilePhoneLock& aLock,
+		                                            RMobilePhone::TMobilePhoneLockInfoV1& aLockInfo)
+	{
+	if (aRetVal == KErrNone)
+		{
+#ifdef _DEBUG
+		const char*  KStatusNames[4] = {"unknown", "locked", "unlocked", "blocked"};
+		const char*  KSettingNames[4] = {"unknown", "enabled", "disabled", "replaced"};
+#endif
+
+		if (aLock == RMobilePhone::ELockICC)
+			{
+			LOGSERVER3(_L8("Lock Info: PIN1 lock is %s and %s."),
+					 KStatusNames[aLockInfo.iStatus], KSettingNames[aLockInfo.iSetting]);
+			iPhonebookManager->SetPin1LockStatus(aLockInfo.iStatus);
+
+			//
+			// If the status has become unlocked, then ensure all phonebooks that
+			// have previously attempted to be sync'd (and failed) are sync'd now.
+			//
+			if (aLockInfo.iStatus == RMobilePhone::EStatusUnlocked)
+				{
+				TInt  phonebookCount(iPhonebookManager->GetPhonebookCount());
+
+				for(TInt phonebook = 0;  phonebook < phonebookCount;  phonebook++)
+					{
+					TUid  phonebookUid;
+					TInt  result = iPhonebookManager->GetPhonebookUid(phonebook, phonebookUid);
+					
+					if (result == KErrNone)
+						{
+						RPhoneBookSession::TSyncState  syncState;
+
+						result = iPhonebookManager->GetSyncState(phonebookUid, syncState);
+			
+						if (result == KErrNone  &&
+						    syncState != RPhoneBookSession::EUnsynchronised)
+							{
+							iPhonebookManager->SetSyncState(phonebookUid,
+							                                RPhoneBookSession::EUnsynchronised);
+							QueueAutoSyncRequest(phonebookUid);
+							}
+						}
+					}
+				}
+			}
+		else if (aLock == RMobilePhone::ELockPin2)
+			{
+			LOGSERVER3(_L8("Lock Info: PIN2 lock is %s and %s."),
+					 KSettingNames[aLockInfo.iStatus], KStatusNames[aLockInfo.iSetting]);
+			iPhonebookManager->SetPin2LockStatus(aLockInfo.iStatus);
+			}
+		else if (aLock == RMobilePhone::ELockHiddenKey)
+			{
+			LOGSERVER3(_L8("Lock Info: Hidden key lock is %s and %s."),
+					 KSettingNames[aLockInfo.iStatus], KStatusNames[aLockInfo.iSetting]);
+			iPhonebookManager->SetHiddenKeyLockStatus(aLockInfo.iStatus);
+
+			if (aLockInfo.iStatus != RMobilePhone::EStatusLockUnknown)
+				{
+				//
+				// If the USIM ADN phonebook is currently synchronised, or
+				// being synchronised, then re-sync it.
+				//
+				RPhoneBookSession::TSyncState  syncState;
+				TInt  result;
+			
+				result = iPhonebookManager->GetSyncState(KUidUsimAppAdnPhonebook,
+														 syncState);
+			
+				if ((result == KErrNone  &&
+				    syncState != RPhoneBookSession::EUnsynchronised)  ||
+				    IsEngineRequestQueued(ESyncDoSynchronisation,
+										  KUidUsimAppAdnPhonebook,
+										  ETrue, ETrue))
+					{
+					QueueAutoSyncRequest(KUidUsimAppAdnPhonebook);
+					}
+				}
+			}
+		else if (aLock == RMobilePhone::ELockUSimApp)
+			{
+			LOGSERVER3(_L8("Lock Info: USim App lock is %s and %s."),
+					 KSettingNames[aLockInfo.iStatus], KStatusNames[aLockInfo.iSetting]);
+			iPhonebookManager->SetUsimAppLockStatus(aLockInfo.iStatus);
+			}
+		else if (aLock == RMobilePhone::ELockUniversalPin)
+			{
+			LOGSERVER3(_L8("Lock Info: USim Universal PIN is %s and %s."),
+					 KSettingNames[aLockInfo.iStatus], KStatusNames[aLockInfo.iSetting]);
+			iPhonebookManager->SetUsimUniversalPinLockStatus(aLockInfo.iStatus);
+			}
+		else
+			{
+			LOGSERVER3(_L8("Lock Info: Unknown lock is %s (%s)."),
+					 KStatusNames[aLockInfo.iStatus], KSettingNames[aLockInfo.iSetting]);
+			}
+		}
+	} // CPhoneBookServer::CompleteNotifyLockInfoChange
+
+
+/**
+ *  Complete an outstanding NotifySATUpdates request. The Active Notification Base
+ *  class is responsible for reposting the notification.
+ *
+ *  @param aRetVal         Result of the notification request.
+ *  @param aRefreshType    Type of SAT refresh.
+ *  @param aPhonebookList  List of phonebooks affected the update. 
+ */
+void CPhoneBookServer::CompleteNotifySATUpdates(TInt aRetVal,
+												RSat::TRefreshType aRefreshType,
+												RArray<TUid>& aPhonebookList)
+	{
+	LOGSERVER2(_L8("CompleteNotifySATUpdates(): %d"), aRetVal);
+
+	if (aRetVal == KErrNone)
+		{
+		//
+		// Is a full re-synchronisation needed???
+		//
+		if (aRefreshType == RSat::EFileChangeNotification  || 
+			aRefreshType == RSat::ESimInitFileChangeNotification)
+			{
+			//
+			// Set cache state to unsynchronised for all affected phonebooks
+			// from phonebook list and queue new sync requests...
+			//
+			TInt  phonebookCount(aPhonebookList.Count());
+
+			for(TInt phonebook = 0;  phonebook < phonebookCount;  phonebook++)
+				{
+				TUid  phonebookUid = aPhonebookList[phonebook];
+				
+				iPhonebookManager->SetSyncState(phonebookUid, RPhoneBookSession::EUnsynchronised);
+				CompleteNotifyStateChange(phonebookUid);
+				iGetPhoneStoreInfo->QueueGetInfoAndSync(phonebookUid);
+				}
+			}
+		else if (aRefreshType == RSat::ESimInitFullFileChangeNotification)
+			{
+			//
+			// Set cache state to unsynchronised for all phonebooks and
+			// then sync them all...
+			//
+			TInt phonebookCount(iPhonebookManager->GetPhonebookCount());
+			TUid phonebookUid;
+
+			for(TInt phonebook = 0; phonebook < phonebookCount; phonebook++)
+				{
+				TInt  err = iPhonebookManager->GetPhonebookUid(phonebook, phonebookUid);
+				
+				if (err == KErrNone)
+					{
+					iPhonebookManager->SetSyncState(phonebookUid,RPhoneBookSession::EUnsynchronised);
+					CompleteNotifyStateChange(phonebookUid);
+					iGetPhoneStoreInfo->QueueGetInfoAndSync(phonebookUid);
+					}
+				}
+			}
+		}
+	} // CPhoneBookServer::CompleteNotifySATUpdates
+
+
+/**
+ *  Complete an outstanding NotifyAppInfoChange request by passing the AID of
+ *  the currently active  USIM application in the aActiveUsimAID parameter. The
+ *  Active Notification Base class is responsible for reposting the notification.
+ *
+ *  If the Active App has changed and the USIM App phonebook is synchronised (or
+ *  has attempted to be synchronised) this a re-synchornisation is performed.
+ *
+ *  @param aRetVal         Result of the notification request.
+ *  @param aInitialValue   True if this is the first value, false if it is an update.
+ *  @param aActiveUsimAID  The AID of the currently active USIM Application.
+ */
+void CPhoneBookServer::CompleteNotifyAppInfoChange(TInt aRetVal,
+												   TBool aInitialValue,
+												   RMobilePhone::TAID& aActiveUsimAID)
+	{
+	LOGSERVER2(_L8("CompleteNotifyAppInfoChange(): aRetVal=%d"), aRetVal);
+
+	if (aRetVal == KErrNone)
+		{
+		LOGSERVER2(_L8("CompleteNotifyAppInfoChange(): aActiveUsimAID=\"%S\""),
+				   &aActiveUsimAID);
+
+		//
+		// Is this the initial value or an update?
+		//
+		if (aInitialValue)
+			{
+			iActiveUsimAID = aActiveUsimAID;
+			}
+		else
+			{
+			//
+			// The App may have been updated, so see if it has changed...
+			//
+			if (iActiveUsimAID.CompareF(aActiveUsimAID) != 0)
+				{
+				//
+				// If the USIM ADN phonebook is currently synchronised, or being
+				// synchronised then re-sync it.
+				//
+				RPhoneBookSession::TSyncState  syncState;
+				TInt  result;
+
+				result = iPhonebookManager->GetSyncState(KUidUsimAppAdnPhonebook,
+														 syncState);
+
+				if ((result == KErrNone  &&
+				    syncState != RPhoneBookSession::EUnsynchronised)  ||
+				    IsEngineRequestQueued(ESyncDoSynchronisation,
+										  KUidUsimAppAdnPhonebook,
+										  ETrue, ETrue))
+					{
+					QueueAutoSyncRequest(KUidUsimAppAdnPhonebook);
+					}
+
+				iActiveUsimAID = aActiveUsimAID;
+				}
+			}
+		}
+	} // CPhoneBookServer::CompleteNotifyAppInfoChange
+
+
+/**
+ *  Standard Active Object RunError() method, called when the RunL() method
+ *  leaves, which will be when the CPhoneBookSession::ServiceL() leaves.
+ *
+ *  Find the current message and complete it before restarting the server.
+ *
+ *  @param aError  Leave code from CPhoneBookSession::ServiceL().
+ *
+ *  @return KErrNone
+ */
+TInt CPhoneBookServer::RunError(TInt aError)
+	{
+	LOGSERVER2(_L8("RunError %d"), aError);
+
+	//
+	// Complete the request with the available error code.
+	//
+	if (Message().IsNull() == EFalse)
+		{
+		Message().Complete(aError);
+		}
+
+	//
+	// The leave will result in an early return from CServer::RunL(), skipping
+	// the call to request another message. So do that now in order to keep the
+	// server running.
+	//
+	ReStart();
+
+	return KErrNone;
+	} // CPhoneBookServer::RunError
+
+
+/**
+ *  Queues an engine request. The request will be sent to the engine when the
+ *  engine is not busy.
+ *
+ *  @param aPhonebookSyncRequest  Function request to queue.
+ *  @param aPhonebookUid          Phonebook to perform the request on.
+ *  @param aContactId             Optional Contact ID parameter.
+ *  @param aClientSession         Pointer to the client session, or NULL.
+ *  @param aClientMessage         The client message request.
+ */
+void CPhoneBookServer::QueueEngineRequestL(TPhonebookSyncRequest aPhonebookSyncRequest,
+										   TUid aPhonebookUid,
+										   TContactItemId aContactId,
+										   CPhoneBookSession* aClientSession,
+										   const RMessage2& aClientMessage)
+	{
+	LOGSERVER5(_L8("QueueEngineRequest(): IPC=%d Phonebook=0x%08x Contact=0x%08x "
+				   "Session=0x%08x"),
+			   aPhonebookSyncRequest, aPhonebookUid, aContactId,
+			   (TInt) aClientSession);
+
+	//
+	// Create a new request and append it to the list of requests...
+	//
+	CSyncEngineRequest*  request = CSyncEngineRequest::NewL(*this, iSyncEngine,
+															aPhonebookSyncRequest,
+															aPhonebookUid, aContactId,
+															aClientSession, aClientMessage);
+	CleanupStack::PushL(request);
+	iSyncEngineRequestArray.AppendL(request);
+	CleanupStack::Pop(request);
+	
+	//
+	// Ensure that the request runs if nothing else is waiting...
+	//
+	StartNextEngineRequest();
+	} // CPhoneBookServer::QueueEngineRequest
+
+
+/**
+ *  Start the next engine request if one is available and the engine is not
+ *  busy.
+ */
+void CPhoneBookServer::StartNextEngineRequest()
+	{
+	LOGSERVER1(_L8("StartNextEngineRequest()"));
+
+	//
+	// If the next request in the queue is not running then start it...
+	//
+	if (iSyncEngineRequestArray.Count() > 0  &&
+	    iSyncEngineRequestArray[0]->IsActive() == EFalse)
+		{
+		iSyncEngineRequestArray[0]->StartRequest();
+		}
+	} // CPhoneBookServer::StartNextEngineRequest
+
+
+/**
+ *  Completes an Engine Request. This method is called be the Engine Request
+ *  itself when it finishes. This will cause the request to be removed from
+ *  the queue, and a new request to be started if one is available.
+ *
+ *  @param aEngineRequest  Reference to the Engine Request.
+ */
+void CPhoneBookServer::CompleteEngineRequest(CSyncEngineRequest& aEngineRequest)
+	{
+	LOGSERVER4(_L8("CompleteEngineRequest(): IPC=%d Phonebook=0x%08x "
+				   "Session=0x%08x"),
+			   aEngineRequest.PhonebookSyncRequest(),
+			   aEngineRequest.PhonebookUid(),
+			   (TInt) aEngineRequest.ClientSession());
+
+	//
+	// Remove this request from the list...
+	//
+	TInt  position = iSyncEngineRequestArray.Find(&aEngineRequest);
+	
+	if (position != KErrNotFound)
+		{
+		iSyncEngineRequestArray.Remove(position);
+		}
+	
+	//
+	// Start any queued requests that can now begin since the engine finished
+	// the last request...
+	//
+	StartNextEngineRequest();
+	} // CPhoneBookServer::CompleteEngineRequest
+
+
+/**
+ *  Cancel a previous engine request. A request that is in progress is cancelled,
+ *  while a request that has not reached the engine will be deleted from the queue.
+ *
+ *  @param aPhonebookSyncRequest  Function request to cancel.
+ *  @param aPhonebookUid          Phonebook UID used in the request.
+ *  @param aContactId             Optional Contact ID parameter.
+ *  @param aClientSession         Pointer to the client session, or NULL.
+ */
+void CPhoneBookServer::CancelEngineRequest(TPhonebookSyncRequest aPhonebookSyncRequest,
+										   TUid aPhonebookUid,
+										   TContactItemId aContactId,
+										   CPhoneBookSession* aClientSession)
+	{
+	LOGSERVER5(_L8("CancelEngineRequest(): IPC=%d Phonebook=0x%08x Contact=0x%08x "
+				   "Session=0x%08x"), aPhonebookSyncRequest, aPhonebookUid,
+			   aContactId, (TInt) aClientSession);
+
+	//
+	// Search through the list of engine requests and if we find this request,
+	// then cancel it.
+	//
+	TInt  requestCount(iSyncEngineRequestArray.Count());
+
+	for (TInt index = 0;  index < requestCount;  index++)
+		{
+		CSyncEngineRequest*  request = iSyncEngineRequestArray[index];
+		
+		if (request->PhonebookSyncRequest() == aPhonebookSyncRequest  &&
+			request->PhonebookUid() == aPhonebookUid  &&
+			request->ContactId() == aContactId  &&
+			request->ClientSession() == aClientSession)
+			{
+			if (request->IsActive())
+				{
+				//
+				// The request is running, so cancel it.
+				//
+				request->DoCancel();
+				}
+			else
+				{
+				//
+				// The request never ran so we need to pretend it was cancelled.
+				//
+				request->iStatus = KErrCancel;
+				TRAP_IGNORE(request->CompleteClientRequestL());
+				}
+
+			break;
+			}
+		}
+	} // CPhoneBookServer::CompleteEngineRequest
+
+
+/**
+ *  Checks if a previous engine request is queued.
+ *
+ *  @param aPhonebookSyncRequest   Function request to look for.
+ *  @param aPhonebookUid           Phonebook UID used in the request.
+ *  @param aIncludeUserRequests    If true then requests from the client
+ *                                 should be included in the search.
+ *  @param aIncludeActiveRequests  If true then currently executing requests
+ *                                 should be included in the search.
+ */
+TBool CPhoneBookServer::IsEngineRequestQueued(TPhonebookSyncRequest aPhonebookSyncRequest,
+											  TUid aPhonebookUid,
+											  TBool aIncludeUserRequests,
+											  TBool aIncludeActiveRequests)
+	{
+	LOGSERVER5(_L8("IsEngineRequestQueued(): %d 0x%08x %d %d"),
+			   aPhonebookSyncRequest, aPhonebookUid, aIncludeUserRequests,
+			   aIncludeActiveRequests);
+	
+	//
+	// Search through the list of engine requests and looking for the request,
+	// including active and user requests if required.
+	//
+	TInt  requestCount(iSyncEngineRequestArray.Count());
+
+	for (TInt index = 0;  index < requestCount;  index++)
+		{
+		CSyncEngineRequest*  request = iSyncEngineRequestArray[index];
+		
+		if (request->PhonebookSyncRequest() == aPhonebookSyncRequest  &&
+			request->PhonebookUid() == aPhonebookUid  &&
+			(aIncludeUserRequests  ||  request->ClientSession() == NULL)  &&
+			(aIncludeActiveRequests  ||  request->IsActive() == EFalse))
+			{
+			LOGSERVER1(_L8("IsEngineRequestQueued(): Found"));
+			return ETrue;
+			}
+		}
+
+	LOGSERVER1(_L8("IsEngineRequestQueued(): Not found"));
+	return EFalse;
+	} // CPhoneBookServer::IsEngineRequestQueued
+
+
+/**
+ *  Queue an automatic synchronisation to the engine.
+ *
+ *  @param aPhonebookUid   Phonebook to synchronise.
+ */
+void CPhoneBookServer::QueueAutoSyncRequest(TUid aPhonebookUid)
+	{
+	LOGSERVER2(_L8("QueueAutoSyncRequest(): 0x%08x"), aPhonebookUid);
+
+	//
+	// First check if a request has already been made for an auto-sync on the
+	// same phonebook (excluding user requests and requests in progress).
+	// If a request already exists then we can ignore this request.
+	//
+	if (IsEngineRequestQueued(ESyncDoSynchronisation, aPhonebookUid,
+							  EFalse, EFalse))
+		{
+		return;
+		}
+
+	//
+	// Queue an engine request for a synchronisation...
+	//
+	TRAPD(err, QueueEngineRequestL(ESyncDoSynchronisation, aPhonebookUid,
+						           KNullContactId, NULL, RMessage2()));
+	if (err != KErrNone)
+		{
+		//
+		// The request could not be queued!!!
+		//
+		LOGSERVER2(_L8("QueueAutoSyncRequest(): Error %d"), err);
+
+		iPhonebookManager->SetLastSyncError(aPhonebookUid, err);
+		iPhonebookManager->SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+		CompleteNotifyStateChange(aPhonebookUid);
+		}
+	} // CPhoneBookServer::QueueAutoSyncRequest
+
+
+/**
+ *  Factory method for producing a CPhoneBookSyncScheduler object. This creates
+ *  and installs the Active Scheduler object.
+ *
+ *  @return Returns a pointer to the CPhoneBookSyncScheduler object or NULL.
+ */
+CPhoneBookSyncScheduler* CPhoneBookSyncScheduler::NewL()
+	{
+	LOGSERVER1(_L8("CPhoneBookSyncScheduler::NewL()"));
+
+	CPhoneBookSyncScheduler*  self = new(ELeave) CPhoneBookSyncScheduler();
+	CPhoneBookSyncScheduler::Install(self);
+
+	return self;
+	} // CPhoneBookSyncScheduler::NewL
+
+
+/**
+ *  Standard Active Scheduler Error() method. This is called if any of the
+ *  RunErrorL() functions leave. Hopefully this should not happen!
+ *
+ *  @param aError  Leave code from the RunErrorL() function.
+ */
+void CPhoneBookSyncScheduler::Error(TInt aError) const
+	{
+#ifdef _DEBUG
+	LOGSERVER2(_L8("CPhoneBookSyncScheduler::Error %d"), aError);
+#else
+	(void) aError;
+#endif
+
+	PhBkSyncPanic(EPhBkSyncPanicUnexpectedLeave);
+	} // CPhoneBookSyncScheduler::Error
+
+
+/**
+ *  Standard constructor.
+ *
+ *  @param aServer  Reference to the main server.
+ */
+CPhoneBookSyncStarter::CPhoneBookSyncStarter(CPhoneBookServer& aServer)
+  : CAsyncOneShot(EPriorityHigh),
+    iServer(aServer)
+	{
+	// NOP
+	} // CPhoneBookSyncStarter::CPhoneBookSyncStarter
+
+
+/**
+ *  RunL() for the starter object. This configures the server fully or
+ *  shuts it down.
+ */
+void CPhoneBookSyncStarter::RunL()
+	{
+	LOGSERVER2(_L8("CPhoneBookSyncStarter::RunL(): iStatus=%d."), iStatus.Int());
+
+	//
+	// Configure the server...
+	//
+	TRAPD(configErr, iServer.ConfigureServerL(CPhoneBookServer::EServerConfigurationFull));
+	if (configErr != KErrNone)
+		{
+		LOGSERVER2(_L8("ConfigureServerL() failed with error %d."), configErr);
+
+		//
+		// Shutdown the server in this case, so it can be restarted later.
+		//
+		TRAP_IGNORE(iServer.ConfigureServerL(CPhoneBookServer::EServerConfigurationNone));
+		CActiveScheduler::Stop();
+		}
+	} // CPhoneBookSyncStarter::RunL
+
+
+/**
+ *  Perform all server initialisation, in particular creation of the
+ *  scheduler and server and then run the scheduler.
+ */
+static void RunServerL()
+	{
+	//
+	// Naming the server thread after the server helps to debug panics.
+	//
+	User::LeaveIfError(User::RenameThread(PHBKSYNC_SERVER_NAME));
+
+	//	
+	// Create a new Active Scheduler...
+	//
+	CPhoneBookSyncScheduler*  scheduler = CPhoneBookSyncScheduler::NewL();
+	CleanupStack::PushL(scheduler);	
+	
+	//
+	// Create a new PhoneBookServer...
+	//
+	CPhoneBookServer*  server = CPhoneBookServer::NewL();
+	CleanupStack::PushL(server);
+	
+	//
+	// Initialisation complete, now signal the client thread...
+	//
+	LOGSERVER1(_L8("RunServerL(): Meeting Rendezvous..."));
+	RProcess::Rendezvous(KErrNone);
+
+	//
+	// Run the server...
+	//
+	LOGSERVER1(_L8("RunServerL(): Starting server..."));
+	CPhoneBookSyncScheduler::Start();
+	
+	CleanupStack::PopAndDestroy(2, scheduler);
+	} // RunServerL
+
+
+/**
+ *  Server process entry-point.
+ *
+ *  @return  KErrNone or a standard Symbian error code.
+ */
+TInt E32Main()
+	{
+	__UHEAP_MARK;
+
+	CTrapCleanup* cleanup=CTrapCleanup::New();
+	TInt ret(KErrNone);
+	if (cleanup)
+		{
+		TRAP(ret,RunServerL());
+		delete cleanup;
+		}
+	else
+		{
+		ret = KErrNoMemory;
+		}
+
+	__UHEAP_MARKEND;
+	return ret;
+	} // E32Main
+