diff -r 000000000000 -r e686773b3f54 pimprotocols/phonebooksync/Server/phbksyncsvr.cpp --- /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 +#include +#include + +#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& 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* globalSettingField = new(ELeave) CMDBField(KCDTIdModemPhoneServicesSMS); + CleanupStack::PushL(globalSettingField); + + globalSettingField->SetRecordId(1); + globalSettingField->LoadL(*db); + TUint32 modemId = *globalSettingField; + + CMDBField* tsyField = new(ELeave) CMDBField(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 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 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 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& 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 +