--- /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
+