diff -r b13cd05eeb2f -r 57b735022c18 srsf/nssvascontacthdlr/src/nssvasccontacthandlerimpl.cpp --- a/srsf/nssvascontacthdlr/src/nssvasccontacthandlerimpl.cpp Mon Jan 18 20:20:30 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3429 +0,0 @@ -/* -* Copyright (c) 2005-2006 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: Responsible for maintaining synchronization between the contact DB -* and the VAS DB -* -*/ - - -/** @todo Read the whole contact in one go. - - Currently Contact handler usually opens the same contact (ReadContactL) two to - three times in order to read its data (mostly often three times). - One is in GetContactNickname - Second in GetContactTitle - Third in DoAddNamesL when deciding what number field should the voice tag - be trained for - If we could unite these reads, "reading contacts" phase will be 2-3 times faster. - It would make about 10-20% improvement for the training of some 300 contacts */ - -// INCLUDE FILES -#include "nssvasccontacthandlerimpl.h" -#include "nssvasctrainingparameters.h" -#include -#include -#include -#include -#include -#include -#include -#include "srsfprivatecrkeys.h" - -// Publish & Subscribe of the contact handler activity -#include - -#include -#include -#include "nssvasdatasyncwatcher.h" -#include "nsschbackupobserver.h" -#include -#include -#include -#include "rubydebug.h" - -// CONSTANTS -// Name of the context in the SIND DB. Voice tags for contacts are saved there -_LIT( KNssCHNameDialContext, "NAMEDIAL" ); - -// Languages which use lastname-firstname order -const TLanguage KSwappedLanguages[] = - { - ELangHungarian, // 17 - ELangTaiwanChinese, // 29 - ELangHongKongChinese, // 30 - ELangJapanese, // 32 - ELangPrcChinese, // 31 - ELangKorean, // 65 - ELangVietnamese // 96 - }; - -// Number of languages that use lastname-firstname order -const TInt KNumberOfSwappedLanguages = sizeof( KSwappedLanguages ) / sizeof ( TLanguage ); - - -// Maximal number of retrials to save tags -const TInt KVASCHMaxRetry = 2; - -// Size of the event 'pack'. Tags are added and deleted in groups. -// KMaxNamesAtOnce is the maximal size of a group -const TInt KMaxNamesAtOnce = 100; - -// Initial value of the time interval used to detect periodic action. In -// microseconds. If KEventMomentsSize events happened within the -// KInitialPeriodicActionInterval, we assume, that periodic action has started -const TInt KInitialPeriodicActionInterval = 15000000; - -// Time interval used to periodically check if there are pending -// events to process. In microseconds -const TInt KPeriodicTimerInterval = 1000000; - -// If there are this many consecutive full resyncs initiated by errors during -// handling normal changes (or during previous full resync), there is probably -// something consistently wrong at the lower layers. -// Full resync trials (and the whole contact handler) should be disabled until -// reboot after KMaxConsecutiveErrorFullResync consecutive unsuccessful trials -const TInt KMaxConsecutiveErrorFullResync = 2; - -// List of phonebook fields, that are supported by contact handler. -// I.e. fields, that can be dialed and voice tagged -/** @todo Consider using information from phonebook about which fields contain numbers -and using the following lists for priorities only */ -const TPbkFieldId KTaggableFields[] = - { - EPbkFieldIdPhoneNumberMobile, - EPbkFieldIdPhoneNumberGeneral, - EPbkFieldIdPhoneNumberStandard, - EPbkFieldIdPhoneNumberHome, - EPbkFieldIdPhoneNumberWork, - EPbkFieldIdPhoneNumberVideo, - EPbkFieldIdVOIP, - EPbkFieldIdXsp - }; -const TInt KTaggableFieldsCount = sizeof( KTaggableFields ) / sizeof ( TPbkFieldId ); - -// List of phonebook fields that are supported by video extension -const TPbkFieldId KVideoExtensionFields[] = - { - EPbkFieldIdPhoneNumberVideo, - EPbkFieldIdPhoneNumberMobile, - EPbkFieldIdPhoneNumberGeneral, - EPbkFieldIdPhoneNumberHome, - EPbkFieldIdPhoneNumberWork - }; -const TInt KVideoExtensionFieldsCount = sizeof( KVideoExtensionFields ) / sizeof ( TPbkFieldId ); - -// List of phonebook fields that are supported by message extension -const TPbkFieldId KMessageExtensionFields[] = - { - EPbkFieldIdPhoneNumberMobile, - EPbkFieldIdPhoneNumberGeneral, - EPbkFieldIdPhoneNumberHome, - EPbkFieldIdPhoneNumberWork, - EPbkFieldIdPhoneNumberVideo - }; -const TInt KMessageExtensionFieldsCount = sizeof( KMessageExtensionFields ) / sizeof ( TPbkFieldId ); - -// List of phonebook fields that are supported by VOIP extension -const TPbkFieldId KVOIPExtensionFields[] = - { - EPbkFieldIdVOIP, - EPbkFieldIdXsp - }; -const TInt KVOIPExtensionFieldsCount = sizeof( KVOIPExtensionFields ) / sizeof ( TPbkFieldId ); - -// Size of the client data per context. Is used to store the context language -// In bytes -const TInt KClientDataSize = sizeof(TNssContextClientData); - - -// Number of retries to try to lock the same contact -// 600 times should stand for 10 mins -// -1 means trying forever -const TInt KMaxContactLockRetrials = 600; - -// Interval between the ticks of the contact wait timer -// in microseconds -const TInt32 KContactWaitInterval = 1000000; - -// Bytes that should be free in the disk drive in addition to critical level -// before operation is started (100kB) -const TInt KIncreaseOfDatabaseSizes = 100000; - -// Define this if name free-order is enabled -//#define NSSVAS_CONTACTHANDLER_FREEORDER -// LOCAL FUNCTION DECLARATIONS - - -// ================= MEMBER FUNCTIONS ======================= - - -#ifdef _DEBUG -_LIT( KFile, "VasCContactHandlerImpl.cpp" ); -#endif - -/** -* Is used in DoHandleEventFailedL to *asynchronously* simulate successful tag -* deletion -*/ -NONSHARABLE_CLASS( CSuccessfulDeletionSimulator ) : public CAsyncOneShot - { - public: - CSuccessfulDeletionSimulator( CNssContactHandlerImplementation& aHost ); - ~CSuccessfulDeletionSimulator(); - protected: - /** Is called by the system after we asked it to Call() closer - */ - virtual void RunL(); - private: - CNssContactHandlerImplementation& iHost; - }; - -// ----------------------------------------------------------------------------- -// CSuccessfulDeletionSimulator::~CSuccessfulDeletionSimulator -// Destructor -// ----------------------------------------------------------------------------- -// -CSuccessfulDeletionSimulator::~CSuccessfulDeletionSimulator() - { - RUBY_DEBUG0( "~CSuccessfulDeletionSimulator" ); - if( IsAdded() ) - { - RUBY_DEBUG0( "~CSuccessfulDeletionSimulator Request is still in progress, deque it" ); - Deque(); - } - } - -// ----------------------------------------------------------------------------- -// CSuccessfulDeletionSimulator::CSuccessfulDeletionSimulator -// Constructor -// ----------------------------------------------------------------------------- -// -CSuccessfulDeletionSimulator::CSuccessfulDeletionSimulator( CNssContactHandlerImplementation& aHost ) : - CAsyncOneShot( CActive::EPriorityStandard ), - iHost( aHost ) - { - //nothing - } - -// ----------------------------------------------------------------------------- -// CAppCloser::RunL -// Will be called by the system and exits the application -// ----------------------------------------------------------------------------- -// -void CSuccessfulDeletionSimulator::RunL() - { - RUBY_DEBUG0( "CSuccessfulDeletionSimulator::RunL Start" ); - if( iStatus == KErrNone ) - { - CArrayPtrFlat* empty = new (ELeave) CArrayPtrFlat( 1 ); - iHost.DoRemoveNamesAfterGetTagList( empty ); - // empty will be destroyed in the DoRemoveNamesAfterGetTagList - } - else - { - RUBY_ERROR1( "CSuccessfulDeletionSimulator::RunL Unexpected iStatus [%d]", iStatus.Int() ); - } - RUBY_DEBUG0( "CSuccessfulDeletionSimulator::RunL End" ); - } - - - -// ----------------------------------------------------------------------------- -// CNssContactHandlerImplementation::CNssContactHandlerImplementation -// C++ default constructor can NOT contain any code, that -// might leave. -// ----------------------------------------------------------------------------- -// -CNssContactHandlerImplementation::CNssContactHandlerImplementation( ) -: iState( ECHInitializing ), - iSeparator( KNameSeparator()[0] ), - iEndOfPeriodicActionInterval( KInitialPeriodicActionInterval ) - { - iClientData.iLanguage = ELangNone; - - // initialize last RestartTimer calls to be long ago in - // the past (January 1st, 0 AD nominal Gregorian) - for( TInt i = 0; i < KEventMomentsSize; i++) - { - iEventMoments[i] = 0; - } - } - -// ----------------------------------------------------------------------------- -// CNssContactHandlerImplementation::ConstructL -// EPOC second phase constructor can leave. -// ----------------------------------------------------------------------------- -// -void CNssContactHandlerImplementation::ConstructL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::ConstructL" ); - - User::LeaveIfError( iFSession.Connect() ); - - // Sets up TLS, must be done before FeatureManager is used. - FeatureManager::InitializeLibL(); - iVoIPFeatureSupported = FeatureManager::FeatureSupported( KFeatureIdCommonVoip ); - iVideoCallFeatureSupported = FeatureManager::FeatureSupported( KFeatureIdCsVideoTelephony ); - // Frees the TLS! Must be done after FeatureManager is used. - FeatureManager::UnInitializeLib(); - - // Before enabling event, start monitoring the PC-suite state - iSyncBackupWaiter = new (ELeave) CActiveSchedulerWait; - - iDataSyncWatcher = CNssDataSyncWatcherFactory::ConstructDataSyncWatcherL( *this ); - - iBackupObserver = CNssChBackupObserver::NewL( *this ); - - iContactWaiter = new (ELeave) CActiveSchedulerWait; - - iDeletionSimulator = new (ELeave) CSuccessfulDeletionSimulator( *this ); - - EnableEventHandling(); - - iEventArray.Reset(); // Ready to be used - - TInt errProp = iBusyProperty.Define( KSINDUID, ETrainingContactsState, RProperty::EInt ); - if( ( errProp != KErrNone ) && ( errProp != KErrAlreadyExists ) ) - { - RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to define the property. Error [%d]", - errProp); - User::Leave( errProp ); - } - - // Publish contact handler as busy before the DB operations - errProp = iBusyProperty.Attach( KSINDUID, ETrainingContactsState ); - if( errProp != KErrNone ) - { - // KErrNotFound is also an error as we just defined the property - RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to attach to property. Error [%d]", - errProp); - User::Leave( errProp ); - } - - errProp = iBusyProperty.Set( EContactsTraining ); - if ( errProp != KErrNone ) - { - RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", - errProp ); - User::Leave( errProp ) ; - } - - - // central repository - iRepository = CRepository::NewL( KCRUidSRSFSettings ); - iRepositoryObserver = CCenRepNotifyHandler::NewL( *this, *iRepository, - CCenRepNotifyHandler::EIntKey, - KSRSFFullResyncNeeded ); - iRepositoryObserver->StartListeningL(); - - //Get VAS DB manager - iVasDbManager = CNssVASDBMgr::NewL(); - iVasDbManager->InitializeL(); - RUBY_DEBUG0( "CNssContactHandlerImplementation::ConstructL iVasDbManager initialized" ); - - //Get Tag Manager and Context Manager interfaces - iTagManager = iVasDbManager->GetTagMgr(); - iContextManager = iVasDbManager->GetContextMgr(); - - // Prepare training parameters - iTrainingParams = CNssTrainingParameters::NewL(); - - RUBY_DEBUG0( "CNssContactHandlerImplementation::ConstructL iTrainingParams prepared" ); - - // Set languages which have lastname-firstname order - for ( TInt iCounter = 0; iCounter < KNumberOfSwappedLanguages; iCounter++ ) - { - User::LeaveIfError( iSwappedLanguages.Append( KSwappedLanguages[iCounter] ) ); - } - -#ifdef __SINDE_TRAINING - // Main array for languages - RArray languages; - - // Languages for names - RArray nameLanguages; - User::LeaveIfError( nameLanguages.Append( User::Language() ) ); - User::LeaveIfError( nameLanguages.Append( ELangOther ) ); - User::LeaveIfError( languages.Append( nameLanguages ) ); - - // Languages for extensions - RArray extLanguages; - User::LeaveIfError( extLanguages.Append( User::Language() ) ); - User::LeaveIfError( languages.Append( extLanguages ) ); - - // Store languages to training parameters - iTrainingParams->SetSindeLanguages( languages ); - - // Close arrays, iTrainingParams has done a copy of these - extLanguages.Close(); - nameLanguages.Close(); - languages.Close(); - -#else - // Set the languages - RArray *languages = new (ELeave) RArray; - CleanupStack::PushL( languages ); - // Always generate a pronunciation in UI language - User::LeaveIfError( languages->Append( User::Language() ) ); - // give some extra languages, which can be selected in engine - User::LeaveIfError( languages->Append( ELangOther ) ); - iTrainingParams->SetLanguages( languages ); - CleanupStack::Pop( languages ); -#endif - - // The separator between the first name and the last name - iTrainingParams->SetSeparator( iSeparator ); - -#ifdef __SIND_EXTENSIONS - - ReadExtensionsL(); -#endif // __SIND_EXTENSIONS - - ConnectToPhonebookL(); - - TLitC<9> name = KNssCHNameDialContext; - - // Get context. - - // (1) if we have synced earlier -> we have created a context, and saved the language - // (2) if we haven't synced -> we need to create context - // - // In case (2), GetContext fails. - // We'll assume that GetContext is successful until it fails. - iHaveWeEverSynced = ETrue; - - TInt err = iContextManager->GetContext( this, name ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::ConstructL Requested GetContext. err [%d]", err); - - if ( err != KErrNone ) - { - // The same function is called, whether GetContext fails synchronously - // or asynchronously. - GetContextCompleted( NULL, KErrNotFound ); - } - iDeleteTagListArray = new (ELeave) CArrayPtrFlat(50); - - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::NewL -// Two-phased constructor. -// --------------------------------------------------------- -// -CNssContactHandlerImplementation* CNssContactHandlerImplementation::NewL( ) - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::NewL" ); - CNssContactHandlerImplementation* self = new (ELeave) CNssContactHandlerImplementation(); - - CleanupStack::PushL( self ); - self->ConstructL(); - CleanupStack::Pop( self ); - - return self; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::~CNssContactHandlerImplementation -// Destructor -// --------------------------------------------------------- -// -CNssContactHandlerImplementation::~CNssContactHandlerImplementation() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::~CNssContactHandlerImplementation FIXED" ); - - iFSession.Close(); - - iEventArray.Close(); // Close the RArray - - delete iDataSyncWatcher; - delete iBackupObserver; - - if ( iSyncBackupWaiter != NULL ) - { - if( iSyncBackupWaiter->IsStarted() ) - { - iSyncBackupWaiter->AsyncStop(); - } - } - delete iSyncBackupWaiter; - - if ( iContactWaiter != NULL ) - { - if( iContactWaiter->IsStarted() ) - { - iContactWaiter->AsyncStop(); - } - } - - - delete iContactWaiter; - delete iDeletionSimulator; - delete iPeriodicHandleEventTimer; - - delete iContext; - - delete iVasDbManager; - RProperty::Delete( KSINDUID, ETrainingContactsState ); - iBusyProperty.Close(); - - delete iRepositoryObserver; - delete iRepository; - - delete iTrainingParams; - iTagArray.ResetAndDestroy(); - - for( TInt k( 0 ); k < iContactQueue.Count(); k++ ) - { - delete iContactQueue[k].iTitle; - } - iContactQueue.Close(); - - iDelList.Close(); - iAddList.Close(); - iRemoveIconList.Close(); - iVoiceTagAddedList.Close(); - iSwappedLanguages.Close(); - - DisconnectFromPhonebook(); - -#ifdef __SIND_EXTENSIONS - - for ( TInt i(0); i < iExtensionList.Count(); i++ ) - { - delete iExtensionList[i].iText; - } - - iExtensionList.Close(); -#endif // __SIND_EXTENSIONS - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::HandleEventL -// Called by phonebook handler when a contact database event -// occurs -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::HandleEventL( const TPhonebookEvent& aEvent ) - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::HandleEventL" ); - RUBY_DEBUG2( "CNssContactHandlerImplementation::HandleEventL(). Contact id [%d], event type [%d]", aEvent.iContactId, aEvent.iType ); - - if ( aEvent.iType == EContactChanged || - aEvent.iType == EContactDeleted || - aEvent.iType == EContactAdded || - aEvent.iType == EUnknownChanges ) - { - if( !CausedByVoiceTagAddition( aEvent ) ) - { - // Check if operations can be finished - // There should be enough disk space - if ( NoDiskSpace() ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL not enough disk space, disabling event handling" ); - DisableEventHandling(); - } - else - { - TInt errProp = iBusyProperty.Set( EContactsTraining ); - if ( errProp != KErrNone ) - { - RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", - errProp ); - User::Leave( errProp ) ; - } - UpdatePeriodicActionVars(); - iEventArray.Append( aEvent ); - - if ( iState == ECHIdle ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL() iState == ECHIdle => DoHandleEvent" ); - - // Process the first new event from the queue - TRAPD( err, DoHandleEventsL() ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleEventL. Assert would fail and Panic IF err != KErrNone. err [%d]", err ); - RUBY_ASSERT_DEBUG( err == KErrNone, User::Panic( KFile, __LINE__ ) ); - - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::HandleEventL. Error [%d] in DoHandleEventsL", err ); - } - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleEventL() iState == [%d] => Do not handle the event right now", iState ); - } // if iState else - } - } // if caused be voice tag addition - else - { - RUBY_DEBUG2( "CNssContactHandlerImplementation::HandleEventL(). Event for Contact id [%d] was caused by a voice icon addition and will be ignored, eventArray size [%d]", aEvent.iContactId, iEventArray.Count() ); - if ( ( iVoiceTagAddedList.Count() == 0 ) && ( iState == ECHIdle ) && ( iEventArray.Count() == 0 ) ) - { - RUBY_DEBUG0( "HandleEventL No more voice icon events expected, nothing pending." ); - } - else - { - RUBY_DEBUG1( "HandleEventL [%d] voice icon events are still expected", iVoiceTagAddedList.Count() ); - } - } - } - else if ( aEvent.iType == EStoreRestoreBeginning ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL restore begin" ); - iRestoreRunning = ETrue; // set to differentiate ending of restore or backup - } - else if ( aEvent.iType == EStoreBackupRestoreCompleted && iRestoreRunning ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL restore end" ); - // Set value to make full resync - SetFullResyncCrFlagL( ETrue ); - iRestoreRunning = EFalse; - } // if event type - } - - - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoHandleEventL -// Process the Event from phonebook -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoHandleEventsL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoHandleEventsL" ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoHandleEventsL, eventArray size [%d]", iEventArray.Count() ); - - // If there is no lengthy higher level routine executed - if( !PeriodicAction() ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL !PeriodicAction()" ); - if ( iHandlerEnabled ) - { - if ( IsFullResyncNeeded() ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Full resync if needed. Setting iState to ECHFullResync" ); - SetState( ECHFullResync ); - - iEventArray.Close(); - - FullResyncStart(); - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Full resync if NOT needed. Setting iState to ECHHandlingNormalChanges" ); - SetState( ECHHandlingNormalChanges ); - - // There are 3 phases in handling events: - // (1) Make two lists: - // * Names to be added - // * Names to be deleted - CollectAddRemoveListsL(); - - // (2) Delete the names to be deleted. This operation is asynchronous. - DoRemoveNamesL(); - - // (3) After removing names, add the names to be added. - // DoRemoveNamesL() starts the step (3) - } - } - else - { - // In UREL, empty "else" branch will be eliminated by the compiler - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Handler was disabled" ); - } - - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() completed" ); - - }// if !PeriodicAction - - else - { - // In UREL, empty "else" branch will be eliminated by the compiler - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL PeriodicAction detected, DoHandleEventsL omitted" ); - } - - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DeleteTagCompleted -// Called when the deletion of a tag is completed successfully -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DeleteTagCompleted( TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DeleteTagCompleted. Assert iState == ECHHandlingNormalChanges. iState [%d]", iState); - RUBY_ASSERT_DEBUG( iState == ECHHandlingNormalChanges, User::Panic( KFile, __LINE__ ) ); - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteTagCompleted: tag deletion failed" ); - - iNormalChangesError = aErrorCode; - } - - DoRemoveNamesAfterDeleteTagCompleted(); - } - -// ----------------------------------------------------------------- -// CNssContactHandlerImplementation::GetTagCompleted -// Called by tag manager when getting of a tag list completes -// ----------------------------------------------------------------- -// -void CNssContactHandlerImplementation::GetTagListCompleted( - MNssTagListArray* aTagList, TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - if ( iState == ECHHandlingNormalChanges ) - { - DoRemoveNamesAfterGetTagList( aTagList ); - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::GetTagListCompleted : Unknown state(%d)\n", iState ); - } - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::GetTagListCompleted. Error [%d]", aErrorCode ); - - TRAPD( err, DoHandleEventFailedL() ); // Process the event fail - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::GetTagFailed. Error [%d] in DoHandleEventFailedL", err ); - } - } - } - - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DisableEventHandling -// Disables the event handling. Is used in case of unrecoverable error -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DisableEventHandling() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DisableEventHandling" ); - iHandlerEnabled = EFalse; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::EnableEventHandling -// Enables event handling -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::EnableEventHandling() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::EnableEventHandling" ); - iHandlerEnabled = ETrue; - } - - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::GetContextListCompleted -// Called by tag manager when GetContextList() completes successfully -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::GetContextListCompleted( - MNssContextListArray* /*aContextList*/, TInt /*aErrorCode*/ ) - { - RUBY_ERROR0( "CNssContactHandlerImplementation::GetContextListCompleted - this function should never be called." ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::CheckErrorSigns -// Compares client data (saved in VAS context) -// to state of the phonebook to find out if -// full synchronization is needed. -// -// If full resync is needed initiates it by saving into the event queue -// special 'full resync event' -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::CheckErrorSigns() - { - - RUBY_DEBUG0( "CNssContactHandlerImplementation::CheckErrorSigns" ); - TBool errorFound( EFalse ); - // Full resync, if this is the first time we launch. - // if the UI language has changed. - // if VAS Db and Contact Db time stamps do not match - if ( iClientData.iLanguage == ELangNone || - iClientData.iLanguage != User::Language() ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::CheckErrorSigns language changed." ); - errorFound = ETrue; - } - else - { - // check that is full resyncronization needed - iRepository->Get( KSRSFFullResyncNeeded, errorFound ); - } - - if ( errorFound ) - { - TPhonebookEvent event; - event.iType = ENullEvent; - event.iContactId = 0; - - if ( iEventArray.Append( event ) != KErrNone ) - { - RUBY_ERROR0( "CNssContactHandlerImplementation::CheckErrorSigns Failed to append to iEventArray" ); - } - } - - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::GetContextCompleted -// Called by tag manager, when GetContext() completes successfully -// -// Depending on the contact handler state, continues full resync sequence or -// sets the idle state -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::GetContextCompleted( - MNssContext* aContext, TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - RUBY_ASSERT_DEBUG( iState == ECHInitializing || iState == ECHFullResync, - User::Panic( KFile, __LINE__ ) ); - - RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted" ); - iContext = aContext; - TRAPD(err, - - iClientData.InternalizeL( iContext->ClientData() ); - - if ( iState == ECHInitializing ) - { - // If there are warning sings of error, - // do full resynchronization. - CheckErrorSigns(); - - SetState( ECHIdle ); - RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted. Setting iState to ECHIdle" ); - - if ( iEventArray.Count() ) // Verify whether more events in the queue - { - - RUBY_DEBUG1( "CNssContactHandlerImplementation::GetContextCompletedhere are still [%d] events in the queue. Call DoHandleEvents for them", iEventArray.Count() ); - - DoHandleEventsL(); // Process the 1st new event from the queue - } - } - else if ( iState == ECHFullResync ) - { - TRAPD( error, FullResyncCreateChangesL() ); - if( error != KErrNone ) - { - RUBY_ERROR1( "FullResyncCreateChangesL failed with [%d]. Panic, nothing can be done", error ); - RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) ); - } - } - else - { - RUBY_ERROR0( "CNssContactHandlerImplementation::GetContextCompleted Unexpected state" ); - RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) ); - } - ); // TRAPD - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::GetContextCompleted Leaves with [%d] inside", err ); - } - RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted completed" ); - } - - else // aErrorCode != KErrNone - { - RUBY_ASSERT_DEBUG( iState == ECHInitializing || iState == ECHFullResync, - User::Panic( KFile, __LINE__ ) ); - - if ( iState == ECHInitializing ) - { - iHaveWeEverSynced = EFalse; - SetState ( ECHFullResync ); - FullResyncStart(); - } - } - - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::SaveContextCompleted -// Called when SaveContext() completes successfully -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::SaveContextCompleted( TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - RUBY_ASSERT_DEBUG( iState == ECHInitializing || - iState == ECHFullResync, - User::Panic( KFile, __LINE__ ) ); - - iHaveWeEverSynced = ETrue; - - if ( iState == ECHInitializing ) - { - // Retrive the Context to get the new ContextId from VasDB - iContextManager->GetContext( this, KNssCHNameDialContext ); - } - else if ( iState == ECHFullResync ) - { - TRAPD( error, FullResyncCreateChangesL() ); - if ( error != KErrNone ) - { - RUBY_ERROR1( "SaveContextCompleted Failed to create full resync changes. Critical error [%d]", - error ); - DisableEventHandling(); - } // if error != KErrNone - } // else if ( iState == ECHFullResync ) - else - { - // we should never be here, because the condition is checked - // by ASSERT_DEBUG at the start of the function - RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted Unexpected state!" ); - } - } - - else // aErrorCode != KErrNone - { - // Failed to initialize will collect the events forever and will never process them - // Will try to initialize again after reboot - RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted failed. Staying forever in ECHFullResync" ); - RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted failed. Reboot to try initializing again" ); - DisableEventHandling(); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::SaveTagCompleted -// Called when SaveTag() completes -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::SaveTagCompleted( TInt aErrorCode ) - { - RUBY_ASSERT_DEBUG( iState == ECHHandlingNormalChanges, User::Panic( KFile, __LINE__ ) ); - - DoAddNamesSaveTagCompleted( aErrorCode ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::GetContactTitleL -// Populates aTitle with either "FirstName LastName" or "CompanyName". -// "CompanyName" is given only if both First and Last names are missing. -//--------------------------------------------------------- -// -HBufC* CNssContactHandlerImplementation::GetContactTitleL( TContactItemId aContactId, - TBool aUseDefaultOrder, - TBool& aBothFirstAndLastFound, - TVasTagType& aTagType ) - { - RUBY_DEBUG_BLOCKL( "CNssContactHandlerImplementation::GetContactTitleL" ); - // Find out if lastname-firstname should be used - TBool useLastFirstOrder = EFalse; - - // By default, this function returns firstname and/or lastname - aTagType = ETagTypeName; - - if ( aUseDefaultOrder ) - { - useLastFirstOrder = SwapNameOrder(); - } - else - { - useLastFirstOrder = !SwapNameOrder(); - } - WaitUntilNoSyncBackupIsRunning(); - ReadContactL( aContactId ); - - HBufC* firstNameText = NULL; - HBufC* lastNameText = NULL; - HBufC* companyNameText = NULL; - - TInt firstLength( 0 ); - TInt lastLength( 0 ); - TInt companyLength( 0 ); - - TInt error = KErrNone; - - // name reading fields are used in Japanese - TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdFirstNameReading ) ); - if ( error == KErrNotFound ) - { - // not found - TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdFirstName ) ); - } - - if ( error == KErrNone ) - { - firstNameText = iPbkHandler->TextL().AllocLC(); - TrimName( firstNameText ); - firstLength = firstNameText->Length(); - if ( firstLength == 0 ) - { - CleanupStack::PopAndDestroy( firstNameText ); - firstNameText = NULL; - } - } - - TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdLastNameReading ) ); - if ( error == KErrNotFound ) - { - // not found - TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdLastName ) ); - } - - if ( error == KErrNone ) - { - lastNameText = iPbkHandler->TextL().AllocLC(); - TrimName( lastNameText ); - lastLength = lastNameText->Length(); - if ( lastLength == 0 ) - { - CleanupStack::PopAndDestroy( lastNameText ); - lastNameText = NULL; - } - } - - TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdCompanyName ) ); - - if ( error == KErrNone ) - { - companyNameText = iPbkHandler->TextL().AllocLC(); - TrimName( companyNameText ); - companyLength = companyNameText->Length(); - if ( companyLength == 0 ) - { - CleanupStack::PopAndDestroy( companyNameText ); - companyNameText = NULL; - } - } - - // Use third parameter to return a flag if both lastname and firstname are found - if ( ( firstLength > 0 ) && ( lastLength > 0 ) ) - { - aBothFirstAndLastFound = ETrue; - } - else - { - aBothFirstAndLastFound = EFalse; - } - - HBufC* title( NULL ); - -#ifdef __SIND_EXTENSIONS - if ( firstLength + lastLength > 0 ) - { - TInt spaceForIndexes( 0 ); - // Find out how much more space is needed for "training indexes" - if ( aBothFirstAndLastFound ) - { - spaceForIndexes = 2 * KTrainingIndexSize; - } - else - { - spaceForIndexes = KTrainingIndexSize; - } - - title = HBufC::NewL( firstLength + lastLength + spaceForIndexes ); - - // Check the order - if ( useLastFirstOrder ) - { - // Lastname-firstname - if ( lastNameText ) - { - AppendName( title, lastNameText ); - } - - if ( firstNameText ) - { - AppendName( title, firstNameText ); - } - } - else - { - // Firstname-lastname - if ( firstNameText ) - { - AppendName( title, firstNameText ); - } - - if ( lastNameText ) - { - AppendName( title, lastNameText ); - } - } - } - // Try company name, if the personal name fails. - else if ( companyLength > 0 ) - { - aTagType = ETagTypeCompanyName; - title = HBufC::NewL( companyLength + KTrainingIndexSize ); - AppendName( title, companyNameText ); - } -#else - // Use personal name, if there is one. - if ( firstLength + lastLength > 0 ) - { - title = HBufC::NewL( firstLength + 1 + lastLength ); - - // Check the order - if ( useLastFirstOrder ) - { - // Lastname-firstname - if ( lastNameText ) - { - title->Des().Append( lastNameText->Des() ); - - if ( firstNameText ) - { - // Separator marker - title->Des().Append( iSeparator ); - } - } - - if ( firstNameText ) - { - title->Des().Append( firstNameText->Des() ); - } - - - } - else - { - // Firstname-lastname - if ( firstNameText ) - { - title->Des().Append( firstNameText->Des() ); - - if ( lastNameText ) - { - // Separator marker - title->Des().Append( iSeparator ); - } - } - - if ( lastNameText ) - { - title->Des().Append( lastNameText->Des() ); - } - - } - } - // Try company name, if the personal name fails. - else if ( companyLength > 0 ) - { - aTagType = ETagTypeCompanyName; - title = HBufC::NewL( companyLength ); - title->Des().Append( companyNameText->Des() ); - } -#endif // __SIND_EXTENSIONS - // It is possible to make a contact without a name. - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::ContactTitle: No name, ContactId=[%d]" , aContactId ); - } - - if ( companyNameText ) - { - CleanupStack::PopAndDestroy( companyNameText ); - } - - if ( lastNameText ) - { - CleanupStack::PopAndDestroy( lastNameText ); - } - - if ( firstNameText ) - { - CleanupStack::PopAndDestroy( firstNameText ); - } - - return title; - } - - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::SwapNameOrder -// Returns ETrue if name order for current UI language should -// be lastname-firstname, EFalse otherwise -//--------------------------------------------------------- -// -TBool CNssContactHandlerImplementation::SwapNameOrder() - { - // Find UI language - TLanguage uiLanguage = User::Language(); - - if ( iSwappedLanguages.Find( uiLanguage ) == KErrNotFound ) - { - return EFalse; - } - else - { - return ETrue; - } - } - - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::GetContactNicknameL -// Returns nickname for a given contact -//--------------------------------------------------------- -// -HBufC* CNssContactHandlerImplementation::GetContactNicknameL( TContactItemId aContactId ) - { - RUBY_DEBUG_BLOCKL( "CNssContactHandlerImplementation::GetContactNicknameL" ); - WaitUntilNoSyncBackupIsRunning(); - ReadContactL( aContactId ); - - // Get the nick name - iPbkHandler->FindFieldL( EPbkFieldIdSecondName ); - - // Get the length of the additional name. - TInt nickLength = iPbkHandler->TextL().Length(); - - HBufC* title = NULL; - -#ifdef __SIND_EXTENSIONS - // Use personal name, if there is one. - if ( nickLength > 0 ) - { - title = HBufC::NewL( nickLength + KTrainingIndexSize ); - - HBufC* nickName = iPbkHandler->TextL().AllocL(); - TrimName( nickName ); - AppendName( title, nickName ); - delete nickName; - } -#else - // Use personal name, if there is one. - if ( nickLength > 0 ) - { - title = HBufC::NewL( nickLength ); - title->Des().Append( iPbkHandler->TextL() ); - } -#endif // __SIND_EXTENSIONS - - return title; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoHandleEventFailed -// Routine to process when handling the contact event failed -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoHandleEventFailedL() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL start" ); - - // Errors are normal if user deletes contact without a voice tag - // E.g. because this contact had no number - if( ( iDeleteTagListArray != NULL ) && ( iDeleteTagListArray->Count() > 0 ) ) - { - // simulate successful deletion, just return no tags for further deletions - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL Deletion failed. Simulating successful empty deletion" ); - iDeletionSimulator->Call(); - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL Called deletion simulator" ); - } - else - { - - // Try full resync couple of times. If still fails, stop contact handler. - // When the phone is booted for the next time, try resyncing again - if( iConsecutiveErrorFullResync < KMaxConsecutiveErrorFullResync ) - { - iConsecutiveErrorFullResync++; - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoHandleEventFailedL Trying full resync for the [%d] time", iConsecutiveErrorFullResync); - // clean structures that might be already full - iTagArray.ResetAndDestroy(); - - for( TInt k( 0 ); k < iContactQueue.Count(); k++ ) - { - delete iContactQueue[k].iTitle; - } - iContactQueue.Close(); - - iDelList.Close(); - iAddList.Close(); - iVoiceTagAddedList.Close(); - // generate full resync event - TPhonebookEvent event; - event.iType = ENullEvent; - event.iContactId = 0; - iEventArray.Insert( event, 0 ); - // will start full resync - iTagArray.ResetAndDestroy(); - iSaveCallbackCounter = 0; // simulate completed action - RUBY_DEBUG0( "DoHandleEventFailedL No leaving in the FullResync branch, retrying" ); - DoHandleEventsL(); // No leaving in the FullResync branch - } - else - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoHandleEventFailedL Tried full resync for %d times. Disabling contact handler until reboot", KMaxConsecutiveErrorFullResync ); - // Tried several consecutive resyncs, didn't help - // Disable itself until reboot - DisableEventHandling(); - } - } // if deletion else - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL end" ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::PhonebookOrder -// TLinearOrder comparison function for sorting phonebook events -// according to their Phonebook ID. -//--------------------------------------------------------- -// -TInt CNssContactHandlerImplementation::PhonebookOrder( const TPhonebookEvent& a1, const TPhonebookEvent& a2 ) - { - if ( a1.iContactId != a2.iContactId ) - { - return( a1.iContactId - a2.iContactId ); - } - - if ( a1.iTime < a2.iTime ) - { - return( -1 ); - } - else if ( a1.iTime > a2.iTime ) - { - return( 1 ); - } - else{ - return( 0 ); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::IsFullResyncNeeded -// Checks if the event queue contains an event, which -// launches full resynchronization. If it does, there is -// no point in processing the other events. -// --------------------------------------------------------- -// -TBool CNssContactHandlerImplementation::IsFullResyncNeeded() - { - for( TInt k( 0 ); k < iEventArray.Count(); k++ ) - { - // Null event is used inside contact handler to signal full resync. - if ( iEventArray[k].iType == ENullEvent - || iEventArray[k].iType == EStoreBackupRestoreCompleted - || iEventArray[k].iType == EUnknownChanges ) - { - return ETrue; - } - } - - return EFalse; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::CollectAddRemoveListsL -// Given a list of Contact DB Events, this function compiles -// a list of ids to-be-deleted and ids to-be-added. -// A Contact DB Event contains: -// * Contact ID -// * Event type (added, modified, removed) -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::CollectAddRemoveListsL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::CollectAddRemoveListsL" ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). iEventArray.Count [%d]", iEventArray.Count() ); - TInt k( 0 ); - - RUBY_ASSERT_DEBUG( iAddList.Count() == 0, User::Panic( KFile, __LINE__ ) ); - RUBY_ASSERT_DEBUG( iDelList.Count() == 0, User::Panic( KFile, __LINE__ ) ); - - // We collect two lists: - // * Contacts to be deleted. - // * Contacts to be added. - - TLinearOrder order( PhonebookOrder ); - - // Sort events according to the phonebook ID. This way, the events - // modifying the same name are sequentially. - iEventArray.Sort( order ); - - - // If several events happen for the same contact, fuse them into one event. - for ( k = 0; k < iEventArray.Count() - 1; k++ ) - { - if ( iEventArray[k].iContactId == iEventArray[k+1].iContactId ) - { - // Sorting should have preserved the order of the events - RUBY_ASSERT_DEBUG(iEventArray[k+1].iTime >= iEventArray[k].iTime, User::Panic( KFile, __LINE__ ) ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). Fusing events for ContactId [%d]", iEventArray[k].iContactId ); - iEventArray[k+1].iType = EContactChanged; - iEventArray.Remove( k ); - - // We have removed an element - k--; - } - } - - RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). Events sorted and fused iEventArray.Count [%d]", iEventArray.Count() ); - - for( k = 0; k < iEventArray.Count() && k < KMaxNamesAtOnce; k++ ) - { - TPhonebookEvent* event = &iEventArray[k]; - - switch ( event->iType ) - { - case EContactChanged: - { - // events caused by saving voice tag field are skipped - // earlier, in HandleDatabaseEventL - - // We need to delete the old name - User::LeaveIfError( iDelList.Append( *event ) ); - // and after that, add the new name. - User::LeaveIfError( iAddList.Append( *event ) ); - break; - } - case EContactDeleted: - { - User::LeaveIfError( iDelList.Append( *event ) ); - break; - } - case EContactAdded: - { - User::LeaveIfError( iAddList.Append( *event ) ); - break; - } - default: - RUBY_ERROR1( "CNssContactHandlerImplementation::CollectAddRemoveListsL() Unkown event type: %d", event->iType ); - break; - } - } - - if ( k < KMaxNamesAtOnce ) - { - iEventArray.Close(); - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). k >= KMaxNamesAtOnce [%d]. Deleting first KMaxNamesAtOnce events, they've been sorted into corresponding lists already", - KMaxNamesAtOnce); - for ( k = 0; k < KMaxNamesAtOnce; k++ ) - { - iEventArray.Remove(0); - } - } - RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL() iEventArray.Count [%d]", - iEventArray.Count()); - RUBY_DEBUG2( "CNssContactHandlerImplementation::CollectAddRemoveListsL iDelList.Count() [%d], iAddList.Count() [%d]", iDelList.Count(), iAddList.Count()); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoRemoveNamesL -// Starts name removal sequence -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoRemoveNamesL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoRemoveNamesL" ); - if ( iDelList.Count() == 0 ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL Nothing to delete - skipping" ); - - RemovingNamesCompletedL(); - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL completed early <= nothing to remove" ); - return; - } - - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL - removing" ); - - // we have: a list of tag IDs, which should be removed - // we need: a list of tags, which should be removed. - - // First, we get the tags which correspond to the tag ids. - // We need k async calls to VAS, - // where k is the number of tag ids in iDelList. - // We get a list of k' tags, where k' >= k. - // If some tag has both proper name and a nickname, then k' > k. - - iContactId = iDelList[0].iContactId; - - if ( iDeleteTagListArray ) - { - iDeleteTagListArray->ResetAndDestroy(); - } - else - { - iDeleteTagListArray = new (ELeave) CArrayPtrFlat(50); - } - - TInt retCode = iTagManager->GetTagList( this, iContext, iContactId, 0 ); - - if ( retCode != KErrNone ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL failed to GetTagList" ); - // In the case of change event, try to add names even though they are not found - // Might happen in scenario like this: - // 1. User adds a name without any phone number -> no voice tag is created - // 2. Contact is modified by adding a phone number - iDelList.Close(); - DoAddNamesL(); - } - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL completed" ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList -// If contact database announces that n contacts need to be -// deleted, we do n calls to GetTagList (the first is from DoRemoveNamesL). -// Each callback returns 1 or more tags (name + nickname = 2 tags). -// This function processes the callbacks by adding the tags to the -// to-be-deleted list. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList( MNssTagListArray* aTagList ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList. iState [%d]", iState ); - - if ( iDelList.Count() == 0 ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList iDelList.Count() == 0" ); - } - - // Sieve out "false" tags: Those which have a wrong contact ID. - /** Why? Maybe user was fast enough to delete these contacts from the phonebook - * Anyway, why should we keep "false" tags in our db? - */ - for ( TInt i=0; i < aTagList->Count(); i++ ) - { - CArrayFixFlat* intArray = aTagList->At(i)->RRD()->IntArray(); - - RUBY_ASSERT_DEBUG( intArray->Count() > 0, User::Panic( KFile, __LINE__ ) ); - - if ( intArray->At(0) != iContactId ) - { - RUBY_ERROR2( "DoRemoveNamesAfterGetTagList expected contact id %d, but got contact id: %d", iContactId, intArray->At(0) ); - delete aTagList->At( i ); - aTagList->Delete( i ); - } - } - - TRAPD( err, // trapping is a fix to make the function non-leaving - - // Add the tags to the to-be-deleted list. - // (there are 1 or 2 tags in aTagList depending on - // whether nickname is also there or not) - for ( TInt k( 0 ); k < aTagList->Count(); k++ ) - { - iDeleteTagListArray->AppendL( (*aTagList)[k] ); - } - - // We have processed this ID - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Before removal. iDelList.Count [%d]", iDelList.Count() ); - if( iDelList.Count() > 0 ) - { - iDelList.Remove( 0 ); - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Empty iDelList!" ); - } - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList After removal. iDelList.Count [%d]", iDelList.Count() ); - - // If there are still more IDs, convert the next ID into a tag. - if ( iDelList.Count() > 0 ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList There are [%d] contacts to delete. Calling GetTagList for them", iDelList.Count() ); - iContactId = iDelList[0].iContactId; - - TInt retCode - = iTagManager->GetTagList( this, iContext, iContactId, 0 ); - - if ( retCode != KErrNone ) - { - RUBY_DEBUG0( "DoRemoveNamesAfterGetTagList Failed to GetTagList, going to DoHandleEventFailedL" ); - TRAP_IGNORE( DoHandleEventFailedL() ); // to handle the process event failed - /** @todo reengineer into single return path */ - // Destroy tag list - aTagList->Reset(); - delete aTagList; - aTagList = 0; - return; - } - } - - // If we just finished converting the last ID, move to the next phase. - else{ - RUBY_DEBUG0( "DoRemoveNamesAfterGetTagList Moving to the next phase" ); - DoRemoveNamesCallDeleteTag(); - } - ); // TRAPD - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Leaves with [%d] inside", err ); - } - // Destroy tag list - aTagList->Reset(); - delete aTagList; - aTagList = 0; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag -// Sends the DeleteTag() calls to lower layers when removing names. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag() - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag. iDeleteTagListArray->Count() [%d] Setting iDeleteCallbackCounter = 0", - iDeleteTagListArray->Count() ); - - if( iDeleteTagListArray->Count() > 0 ) - { - - iDeleteCallbackCounter = 0; - - for ( TInt k( 0 ); k < iDeleteTagListArray->Count(); k++ ) - { - TInt ret = - iTagManager->DeleteTag( this, (*iDeleteTagListArray)[k] ); - - if ( ret != KErrNone ) - { - TRAPD( err, DoHandleEventFailedL(); ); - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag Error handling Left with [%d]", err ); - } - return; /** @todo reengineer into single return path */ - } - } - } // if there are tags to delete - else - { - // if there were no tags to delete (attempt to delete non-existing tags) - // simulating callback from successful deletion of.. 0 tags - //iDeleteCallbackCounter = -1; - //DeleteTagCompleted(); - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag Here!" ); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted -// DeleteTag() callback calls this funciton. It counts -// the number of callbacks, and when all callbacks have arrived, -// goes to the next phase. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted() - { - iDeleteCallbackCounter++; - - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. iDeleteCallbackCounter [%d], Count() [%d]", iDeleteCallbackCounter, iDeleteTagListArray->Count() ); - - if ( iDeleteCallbackCounter == iDeleteTagListArray->Count() ) - { - if( iNormalChangesError == KErrNone ) - { - TRAPD( err, RemovingNamesCompletedL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. Error [%d] in RemovingNamesCompletedL", err ); - } - } - else - { - // There is not much we can do about the deletion error - // Retrying deletion can cause endless cycle - // Sometimes failed deletions are ok (if we tried to delete non-existing tag) - /** @todo reengineer SpeechItemTrainer (and/or SRS plugin) to report deletion - of non-existing tag as success. After all they are not in the DB */ - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted Deletion failed. Still simulating a successful one" ); - TRAPD( err, RemovingNamesCompletedL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. Error [%d] in RemovingNamesCompletedL", err ); - } - } // if (iNormalChangesError == KErrNone) else - } // if count - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::RemovingNamesCompletedL -// Cleans up after some names have been removed -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::RemovingNamesCompletedL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::RemovingNamesCompletedL" ); - iDelList.Close(); - - if ( iDeleteTagListArray ) - { - iDeleteTagListArray->ResetAndDestroy(); - iDeleteCallbackCounter = 0; - } - - DoAddNamesL(); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoAddNamesL -// Starts name addition sequence by fetching contacts data and ordering -// voice tags training -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoAddNamesL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoAddNamesL" ); - TInt k( 0 ); - - if ( iAddList.Count() == 0 ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL Nothing to add. Setting iState = ECHIdle. Return" ); - SetState ( ECHIdle ); - // If there are events on the list, DoAddNamesCompleted will fire them - DoAddNamesCompletedL(); - } - else - { - // Create new tags and train them. - for ( k = 0; k < iAddList.Count(); k++ ) - { - // 3 names may be created from one contact: - // * Main name (firstname + lastname XOR companyname) - // * Reversed order name (usually lastname + firstname, depends on the UI language) - // -> only if NSSVAS_CONTACTHANDLER_FREEORDER is defined - // * Nickname - - TContactData contactData; - - contactData.iID = iAddList[k].iContactId; - contactData.iSyncTime.UniversalTime(); - - // Nickname - contactData.iTitle = NULL; - TRAPD( err, contactData.iTitle = GetContactNicknameL( iAddList[k].iContactId ) ); - - if ( contactData.iTitle != NULL ) - { - CleanupStack::PushL( contactData.iTitle ); - contactData.iType = ETagTypeNickName; - User::LeaveIfError( iContactQueue.Append( contactData ) ); - CleanupStack::Pop( contactData.iTitle ); - } - - // Main name ( Using GetContactTitleL() ) - contactData.iTitle = NULL; - TBool bothFound = EFalse; - TVasTagType tagType( ETagTypeUnknown ); - TRAP( err, contactData.iTitle = GetContactTitleL( iAddList[k].iContactId, ETrue, bothFound, tagType ) ); - - // If all the name fields are empty, nothing - // can be done for the tag. We're finished. - if ( contactData.iTitle != NULL ) - { - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesL For Contact id [%d] title is: [%S]", iAddList[k].iContactId, contactData.iTitle ); - CleanupStack::PushL( contactData.iTitle ); - contactData.iType = tagType; - User::LeaveIfError( iContactQueue.Append( contactData ) ); - CleanupStack::Pop( contactData.iTitle ); - } - - #ifdef NSSVAS_CONTACTHANDLER_FREEORDER - // Default order added previously, now adding - // secondary order if both first and lastnames are found - if ( bothFound ) - { - contactData.iTitle = NULL; - TRAPD( err, contactData.iTitle = GetContactTitleL( iAddList[k].iContactId, EFalse, bothFound, tagType ) ); - if ( contactData.iTitle != NULL ) - { - CleanupStack::PushL( contactData.iTitle ); - contactData.iType = tagType; - User::LeaveIfError( iContactQueue.Append( contactData ) ); - CleanupStack::Pop( contactData.iTitle ); - } - } - #endif // NSSVAS_CONTACTHANDLER_FREEORDER - - } - - // No tag had any text. - if ( iContactQueue.Count() == 0 ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL. No tag had any text, return" ); - DoAddNamesCompletedL(); - } - else - { - // At least some tag has some text - RUBY_ASSERT_DEBUG( iTagArray.Count() == 0, User::Panic( KFile, __LINE__ ) ); - - for ( k = 0; k < iContactQueue.Count(); k++ ) - { - // (1) Create a new tag - if ( iNewTag != NULL ) - { - // If previous call to this function leaves, iNewTag can - // be not deleted - delete iNewTag; - iNewTag = NULL; - } - iNewTag = iTagManager->CreateTagL( iContext ); - - MNssRRD* rrd = iNewTag->RRD(); - MNssSpeechItem* speechItem = iNewTag->SpeechItem(); - - // (2) Fill RRD. RRD contains client-chosen data about the tag. - // In case of name dialing, RRD contains the contact ID, - // which is used later to get the phone number. - CArrayFixFlat *id = new (ELeave) CArrayFixFlat( 1 ); - - CleanupStack::PushL( id ); - - id->AppendL( iContactQueue[k].iID ); // ID - // select a number field for voice tag - // TInt fieldIndex( 0 ); - - WaitUntilNoSyncBackupIsRunning(); - TRAPD( err, ReadContactL( iContactQueue[k].iID ); ); - if ( err == KErrNone ) - { - // 1. Default voice call number set by the user - TInt found = KErrNotFound; - TRAP( found, iPbkHandler->FindDefaultContactFieldL( EDefaultCommand ) ); - - if ( found == KErrNotFound ) - { - for( TInt i = 0; i < KTaggableFieldsCount; i++) - { - TRAP( found, iPbkHandler->FindFieldL( KTaggableFields[i] ) ); - if( found == KErrNone && ( !iPbkHandler->IsFieldEmptyL() ) ) - { - break; // found field - } - else - { - // When field->IsEmptyOrAllSpaces(), it is the same for us as no field present - found = KErrNotFound; - } - } // for i < KTaggableFieldsCount - } - - if ( found == KErrNone ) // found and is not empty - { - id->AppendL( iPbkHandler->FieldIdL() ); // field ID to array - id->AppendL( EDial ); - id->AppendL( iContactQueue[k].iType ); - id->AppendL( EDefaultCommand ); - rrd->SetIntArrayL ( id ); - - // (3) Set the training text. - speechItem = iNewTag->SpeechItem(); - speechItem->SetTextL( *iContactQueue[k].iTitle ); - - User::LeaveIfError( iTagArray.Append( iNewTag ) ); - // Leave protection for iNewTag completed - // Ownership and deletion responsibility moved - // to iTagArray - iNewTag = NULL; - } - else - { - // field not found or is empty - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesL Did NOT identify a suitable voice dial field for contact id [%d]", iContactQueue[k].iID); - - - delete iNewTag; - iNewTag = NULL; - } // if field else -#ifdef __SIND_EXTENSIONS - - // this part creates separate voice tags for extensions - for ( TInt i(0); i < iExtensionList.Count(); i++ ) - { - found = KErrNotFound; - TVasExtensionAction action = iExtensionList[i].iAction; - TPbkFieldId fieldId = iExtensionList[i].iId; - - // default message number - // default video - // default e-mail - // default VOIP - if ( action == ENewMessage || - iExtensionList[i].iId == EPbkFieldIdPhoneNumberVideo || - iExtensionList[i].iId == EPbkFieldIdEmailAddress || - iExtensionList[i].iId == EPbkFieldIdVOIP ) - { - // @todo Should use DefaultMessageField or something similar!! - TRAP( found, - iPbkHandler->FindDefaultContactFieldL( iExtensionList[i].iCommand ) ); - } - - /*if ( extensionField == NULL ) - { - extensionField = item->FindField( iExtensionList[i].iId ); - } - - if ( extensionField == NULL && field != NULL - && ( action == ENewMessage ) ) - { - // if default neither default field or mobile field was not found - // message use normal SIND field - extensionField = field; - fieldId = field->FieldInfo().FieldId(); - }*/ - - // If field was not found, try to find it based on the priority lists - if ( found == KErrNotFound ) - { - found = FindExtensionField( action, iExtensionList[i].iId ); - // If field was found, check the field ID - if ( found == KErrNone ) - { - fieldId = iPbkHandler->FieldIdL(); - } - } - - if ( found == KErrNone ) - { - // create new tag - iNewTag = iTagManager->CreateTagL( iContext ); - - rrd = iNewTag->RRD(); - speechItem = iNewTag->SpeechItem(); - - // set RRD data - CArrayFixFlat *extIds = new (ELeave) CArrayFixFlat( 1 ); - CleanupStack::PushL( extIds ); - - extIds->AppendL( iContactQueue[k].iID ); - extIds->AppendL( fieldId ); - extIds->AppendL( action ); - extIds->AppendL( iContactQueue[k].iType ); - extIds->AppendL( iExtensionList[i].iCommand ); - - rrd->SetIntArrayL ( extIds ); - - // set the training text. - TPtr namePtr( iContactQueue[k].iTitle->Des() ); - TPtr extensionPtr( iExtensionList[i].iText->Des() ); - HBufC* tempTitle = HBufC::NewLC( namePtr.Length() + extensionPtr.Length() + KTrainingIndexSize ); - TPtr titlePtr( tempTitle->Des() ); - - //not work: titlePtr.AppendFormat( extensionPtr, namePtr ); - - titlePtr = extensionPtr; - AppendExtensionMarker( titlePtr ); - TInt index = titlePtr.Find( KExtensionFormatString ); - if ( index >= 0 ) - { - // replace %U with name - titlePtr.Delete( index, 2 ); // delete %U - titlePtr.Insert( index, namePtr ); - } - speechItem->SetTextL( titlePtr ); - - User::LeaveIfError( iTagArray.Append( iNewTag ) ); - iNewTag = NULL; //ownership changed - CleanupStack::PopAndDestroy( tempTitle ); - CleanupStack::PopAndDestroy( extIds ); - } - } - -#endif // __SIND_EXTENSIONS - // delete id - CleanupStack::PopAndDestroy( id ); - } - else - { - // Opening contact failed. E.g. if it was just deleted by user - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesL Failed to open contact id [%d]. Leave [%d]", iContactQueue[k].iID, err); - CleanupStack::PopAndDestroy( id ); - delete iNewTag; - iNewTag = NULL; - /** @todo Try reengineering duplicated cleanups into single piece - of the code */ - } - } // for k .. iContactQueue - - if ( iTagArray.Count() == 0 ) - { - // If there are events on the list, DoAddNamesCompleted will fire them - DoAddNamesCompletedL(); - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL. Returned from DoAddNamesCompleted. Setting iState = ECHIdle" ); - SetState ( ECHIdle ); - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesL Before training tags. TagCount = [%d]", - iTagArray.Count() ); - - iTrainCallbackCounter = 0; - for ( k = 0; k < iTagArray.Count(); k++ ) - { - MNssSpeechItem* speechItem = iTagArray[k]->SpeechItem(); - - MNssSpeechItem::TNssSpeechItemResult trainRet - = speechItem->TrainTextL( this, iTrainingParams ); - - if ( trainRet != MNssSpeechItem::EVasErrorNone ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL : TrainTextL call failed." ); - // Not much we can do except for timed retry. - // This stops the contact handler. - DoHandleEventFailedL(); - break; // no processing anymore. Quit function - } - } // for k < iTagArray.Count() - } // if iTagArrayCount != 0 - } - } // if ( iAddList.Count() != 0 ) - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoAddNamesTrainingFinished -// Called after training of a current pack of tags has finished. -// Starts saving tags. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoAddNamesTrainingFinished() - { - iSaveCallbackCounter = 0; - iRetry = 0; // retry, if save tag fails - iNormalChangesError = 0; // to record failures in save tag - - DoAddNamesSaveTag(); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoAddNamesSaveTag -// This function has two branches: -// (1) Initiate saving tags -// (1) After all tags have been saved, go to the next phase. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoAddNamesSaveTag() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag" ); - TInt retCode; - - // If all tags have been saved, go to the next phase. - if ( iSaveCallbackCounter == iTagArray.Count() ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag All tags have been saved, go to the next phase" ); - // Tags saved - go to the next phase - if ( iNormalChangesError == KErrNone ) - { - // This function is called once per 100 contacts -> It is ok to use TRAP - TRAPD( error, DoAddNamesCompletedL() ); - if( error != KErrNone ) - { - /** @todo Test this branch */ - // Some fatal error occured - RUBY_ERROR1( "DoAddNamesSaveTag DoAddNamesCompletedL failed with [%d]. Disabling SIND", - error ); - DisableEventHandling(); - } - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag Saving tags failed. Try again a few times" ); - // Saving tags failed. Try again a few times, and if it still - // doesn't work, go to fatal error handler. - if ( iRetry < KVASCHMaxRetry ) - { - iRetry++; - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesSaveTag Retried saving [%d] times. [%d] retries left", - iRetry, KVASCHMaxRetry - iRetry); - iSaveCallbackCounter = 0; - iNormalChangesError = KErrNone; - - DoAddNamesSaveTag(); - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTag Retried saving [%d] times. Still saving fails. Handling error", iRetry ); - NormalChangesHandleError(); - } - } - } // if ( iSaveCallbackCounter == iTagArray.Count() ) - - // If this is the first call to this function, - // make "save tag" calls. After that, wait for the callbacks. - else if ( iSaveCallbackCounter == 0 ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTag iSaveCallbackCounter == 0. Run SaveTag for [%d] contacts", - iTagArray.Count()); - for ( TInt k( 0 ); k < iTagArray.Count(); k++ ) - { - retCode = iTagManager->SaveTag( this, iTagArray[k] ); - - if ( retCode != KErrNone ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag - SaveTag failed." ); - TRAPD( err, DoHandleEventFailedL(); ); - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoAddNamesSaveTag handling error Left with [%d]", err ); - } - return; - } // if retCode - } // for iTagArray - } // else if iSaveCallbackCounter == 0 - else - { - // iSaveCallbackCounter != 0, but different from iTagArray.Count() - // This means, that SaveTag callbacks are still coming. We will wait for them - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag. iSaveCallbackCounter != 0, but different from iTagArray.Count()" ); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted -// Saving single tag has completed. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted( TInt aError ) - { - iSaveCallbackCounter++; - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted iSaveCallbackCounter became [%d]", - iSaveCallbackCounter); - // |= to let single KErrGeneral fail any number of KErrNone - iNormalChangesError |= aError; - - // Check if all tags have been saved. - DoAddNamesSaveTag(); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoAddNamesCompleted -// When adding names has successfully finished, clean up. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoAddNamesCompletedL() - { - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesCompleted. iDeleteCallbackCounter [%d], Count() [%d]", iDeleteCallbackCounter, iDeleteTagListArray->Count() ); - TInt initialDeleteTagListCount = iDeleteTagListArray->Count(); - - iSaveCallbackCounter = 0; - iTrainCallbackCounter = 0; - - // DoAddNamesCompleted if often called after voice tags have been added => - // Nothing has to be done at all - TBool changedDatabase = EFalse; - -#ifndef __SIND_EXTENSIONS -// Set VAS_SETS_VOICETAG on if old behaviour is needed. -// That is, VAS sets on the voice tag field to Phonebook engine and Phonebook UI checks the contacts DB for voice tags. -// Off means that VAS does not set voice tag field but instead Phonebook asks from VAS. -#ifdef VAS_SETS_VOICETAG - // add voice tag fields - // iTagArray contains only successfully trained tags. - // Failed items are removed. - for ( TInt i( 0 ); i < iTagArray.Count(); i++ ) - { - MNssRRD* rrd = iTagArray[i]->RRD(); - CArrayFixFlat* intArray = rrd->IntArray(); - RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) ); - if ( intArray->Count() >= 2 ) - { - TBool committed( EFalse ); // ETrue if contact is committed already - TInt contactId( intArray->At( 0 ) ); - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted. Working on contact id [%d]", - contactId); - TInt fieldId( intArray->At( 1 ) ); - - WaitUntilNoSyncBackupIsRunning(); - // Open contact item based on id - TRAPD( errFor, - OpenContactL( contactId ); - - RUBY_DEBUG1( "DoAddNamesCompleted Opened contact [%d]", contactId ); - TInt found == KErrNotFound; - TRAP( found, iPbkHandler->FindDefaultContactFieldL( EDefaultCommand ) ); - if ( found == KErrNotFound ) - { - TRAP( found, iPbkHandler->FindFieldL( fieldId ) ); - } - // field - field, that SHOULD have voice tag attached - - if ( found == KErrNone ) - { - TRAP( error, iPbkHandler->ChangeVoiceTagFieldL( ETrue ) ); - if ( error == KErrNone ) - { - RUBY_DEBUG1("DoAddNamesCompleted Successfully added icon to the contact [%d]", - contactId); - iPbkHandler->CloseContactL( ETrue ); - RUBY_DEBUG1("DoAddNamesCompleted Successfully committed contact [%d]", - contactId); - iVoiceTagAddedList.Append( contactId ); - changedDatabase = ETrue; - committed = ETrue; - } - } - else - { - // field not found anymore - RUBY_DEBUG2("DoAddNamesCompleted Field [%d] not found in (already deleted from?) contact [%d]", - fieldId, contactId ); - iDeleteTagListArray->AppendL( NULL ); // One DeleteTag will generate one callback - iTagManager->DeleteTag( this, iTagArray[i] ); - } - if ( !committed ) - { - RUBY_DEBUG1("DoAddNamesCompleted Did not change contact [%d]. Closing without committing", - contactId); - iPbkHandler->CloseContactL( EFalse ); - } - ); // TRAPD errFor - if ( errFor != KErrNone ) - { - RUBY_DEBUG2("CNssContactHandlerImplementation::DoAddNamesCompleted Failed to add icon for contact [%d]. Error [%d]", - contactId, errFor); - // voice tag was not in the contacts database, delete it from VAS - // One DeleteTag will generate one callback - iDeleteTagListArray->AppendL( NULL ); - iTagManager->DeleteTag( this, iTagArray[i] ); - } - } // if intArray->Count() >= 2 - } // for iTagArray -#endif // VAS_SETS_VOICETAG -#endif //__SIND_EXTENSIONS - - iTagArray.ResetAndDestroy(); - - iAddList.Close(); - -#ifndef __SIND_EXTENSIONS -#ifdef VAS_SETS_VOICETAG - // Remove voice tag icons for contacts, that failed to be trained or saved - for( TInt l = 0 ; l < iRemoveIconList.Count(); l++ ) - { - WaitUntilNoSyncBackupIsRunning(); - TRAPD( error, OpenContactL( iRemoveIconList[l] ) ); - if ( error != KErrNone ) - { - RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to open contact [%d]. Error [%d]", iRemoveIconList[l], error); - } - else - { - TRAP( error, iPbkHandler->ChangeVoiceTagFieldL( EFalse ) ); - if ( error == KErrNotFound ) - { - // Nothing to remove. Already no voice tag icon - TRAP( error, iPbkHandler->CloseContactL( EFalse ) ); - if ( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to close contact [%d]. Error [%d]", iRemoveIconList[l], error); - } - } - else if ( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to remove voice tag icon for contact [%d]. Error [%d]", iRemoveIconList[l], error); - TRAP( error, iPbkHandler->CloseContactL( EFalse ) ); - if ( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to close contact [%d]. Error [%d]", iRemoveIconList[l], error); - } - } - else - { - iVoiceTagAddedList.Append( iRemoveIconList[l] ); - TRAP( error, iPbkHandler->CloseContactL( ETrue ) ); - if ( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to commit contact [%d]. Error [%d]", iRemoveIconList[l], error); - } - } - - } // if opened contact successfully - - } -#endif // VAS_SETS_VOICETAG -#endif //__SIND_EXTENSIONS - - iRemoveIconList.Close(); - - for( TInt k( 0 ); k < iContactQueue.Count(); k++ ) - { - delete iContactQueue[k].iTitle; - iContactQueue[k].iTitle = NULL; - } - iContactQueue.Close(); - - if( changedDatabase ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted changed DBx" ); - WaitUntilNoSyncBackupIsRunning(); - TRAPD(err, iPbkHandler->CompressL() ); - if ( err ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted Contacts DB compression failed. Error [%d]", - err); - } - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted did NOT change DB" ); - } - - // full resyncs are always tag additions - if( initialDeleteTagListCount == iDeleteTagListArray->Count() ) - { - SetState( ECHIdle ); - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted Syncing with phonebook generated NO deletions" ); - // then full resync will not be initiated - iConsecutiveErrorFullResync = 0; - if ( iEventArray.Count() > 0 ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted There are still [%d] events in the queue. Call DoHandleEvents for them", - iEventArray.Count() ); - TRAPD( err, DoHandleEventsL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoAddNamesCompleted. Error [%d] in DoHandleEventsL", err ); - } - } - else - { - // No self-generated events, and no pending events to handle - // This is the only place in the code, where everything is completed - // and nothing is pending - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted All the updates completed. No DB event is pending" ); - - } - } - else - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted Generated [%d] deletions. Starting to wait for callbacks", - iDeleteTagListArray->Count() - initialDeleteTagListCount); - } - - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted completed" ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::NormalChangesHandleError -// Handle errors which happend when updating normal changes -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::NormalChangesHandleError() - { - // We can't know, what went wrong. - // Stop contact handler, so that the next time the phone is booted - // full synchronization happens. - RUBY_DEBUG0( "CNssContactHandlerImplementation::NormalChangesHandleError " ); - TRAPD( err, DoHandleEventFailedL(); ); - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::NormalChangesHandleError DoHandleEventFailedL Left with [%d]", err ); - } - } - -//--------------------------------------------------------- -// CNssContactHandlerImplementation::HandleTrainComplete -// Saves the tag after successful training. -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::HandleTrainComplete( TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - RUBY_DEBUG1( "Training OK for %d:th name.", iTrainCallbackCounter ); - - RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainComplete. iState [%d]", iState); - RUBY_ASSERT_DEBUG( iState == ECHInitializing || - iState == ECHHandlingNormalChanges, - User::Panic( KFile, __LINE__ ) ); - - iTrainCallbackCounter++; - - if ( iTrainCallbackCounter == iTagArray.Count() ) - { - if ( iState != ECHInitializing ) - { - // assert at the beginning of the function guarantees, - // that iState == ECHHandlingNormalChanges - DoAddNamesTrainingFinished(); - } - } - } - - else // aErrorCode != KErrNone - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainComplete. Training failed for %d:th name.\n", - iTrainCallbackCounter ); - - RUBY_ASSERT_DEBUG( iState == ECHInitializing || - iState == ECHHandlingNormalChanges, - User::Panic( KFile, __LINE__ ) ); - - // Order removal of voice tag icon if present - MNssRRD* rrd = iTagArray[iTrainCallbackCounter]->RRD(); - CArrayFixFlat* intArray = rrd->IntArray(); - RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) ); - if ( intArray->Count() >= 2 ) - { - TInt error = iRemoveIconList.Append( intArray->At(0) ); - if( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError Failed to insert [%d] into iRemoveIconList. Error [%d]", - intArray->At(0), error); - } - } - else - { - RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainComplete rrd->IntArray()->Count [%d] for iTrainCallbackCounter [%d]", - intArray->Count(), iTrainCallbackCounter); - } - - - delete iTagArray[ iTrainCallbackCounter ]; - iTagArray.Remove( iTrainCallbackCounter ); - - if ( iTrainCallbackCounter == iTagArray.Count() ) - { - if ( iState == ECHHandlingNormalChanges ) - { - DoAddNamesTrainingFinished(); - } - else - { - RUBY_ERROR1( "CNssContactHandlerImplementation::HandleTrainComplete Unexpected state [%d]", iState); - } - } - } - } - -//--------------------------------------------------------- -// CNssContactHandlerImplementation::HandleTrainError -// Handles single tag training failure -//--------------------------------------------------------- -// -/*void CNssContactHandlerImplementation::HandleTrainError( enum MNssTrainTextEventHandler::TNssTrainResult ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainError Training failed for %d:th name.\n", - iTrainCallbackCounter ); - - RUBY_ASSERT_DEBUG( iState == ECHInitializing || - iState == ECHHandlingNormalChanges, - User::Panic( KFile, __LINE__ ) ); - - // Order removal of voice tag icon if present - MNssRRD* rrd = iTagArray[iTrainCallbackCounter]->RRD(); - CArrayFixFlat* intArray = rrd->IntArray(); - RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) ); - if ( intArray->Count() >= 2 ) - { - TInt error = iRemoveIconList.Append( intArray->At(0) ); - if( error != KErrNone ) - { - RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError Failed to insert [%d] into iRemoveIconList. Error [%d]", - intArray->At(0), error); - } - } - else - { - RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError rrd->IntArray()->Count [%d] for iTrainCallbackCounter [%d]", - intArray->Count(), iTrainCallbackCounter); - } - - - delete iTagArray[ iTrainCallbackCounter ]; - iTagArray.Remove( iTrainCallbackCounter ); - - if ( iTrainCallbackCounter == iTagArray.Count() ) - { - if ( iState == ECHHandlingNormalChanges ) - { - DoAddNamesTrainingFinished(); - } - else - { - RUBY_ERROR1( "CNssContactHandlerImplementation::HandleTrainError Unexpected state [%d]", iState); - } - } - }*/ - -//--------------------------------------------------------- -// CNssContactHandlerImplementation::FullResyncStart -// Starts a full synchronization -//--------------------------------------------------------- -// -void CNssContactHandlerImplementation::FullResyncStart() - { - // If we have synchronized earlier, we must delete the old context. - if ( iHaveWeEverSynced ) - { - iContextManager->DeleteContext( this, iContext ); - } - else - { - TRAPD( err, FullResyncCreateContextL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::FullResyncStart. Error [%d] in FullResyncCreateContextL", err ); - } - } - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::FullResyncCreateContextL -// Full resync: Create a new context -// (prev: Destroy old context, next:populate the context with tags) -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::FullResyncCreateContextL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::FullResyncCreateContextL" ); - if ( iContext != 0 ) - { - delete iContext; - iContext = 0; - } - - iContext = iContextManager->CreateContextL(); - iContext->SetNameL( KNssCHNameDialContext ); - iContext->SetGlobal( ETrue ); - - TBuf8 clientDataBuf; - iClientData.iLanguage = User::Language(); - iClientData.iContactSyncId = KErrNotFound; - - TRAPD( error, iClientData.ExternalizeL( clientDataBuf ) ); - if ( !error ) - { - iContext->SetClientData( clientDataBuf ); - iContextManager->SaveContext( this, iContext ); - } - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::FullResyncCreateChanges -// Create tags and send training requests to VAS. -// VAS trains them and calls back when it's ready -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::FullResyncCreateChangesL() - { - RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::FullResyncCreateChangesL" ); - - WaitUntilNoSyncBackupIsRunning(); - - CContactIdArray* ids = iPbkHandler->ContactIdArrayLC(); - - RUBY_DEBUG0( "CNssContactHandlerImplementation::FullResyncCreateChanges. iContactQueue.Count() == 0" ); - RUBY_ASSERT_DEBUG( iContactQueue.Count() == 0, User::Panic( KFile, __LINE__ ) ); - // Create change events for training - for ( TInt k( 0 ); k < ids->Count(); k++ ) - { - TPhonebookEvent event; - event.iContactId = (*ids)[k]; - event.iType = EContactAdded; - iEventArray.Append( event ); - } - - CleanupStack::PopAndDestroy( ids ); // Cleanup stack: empty - - // go to processing events - SetState ( ECHIdle ); - TRAPD( err, DoHandleEventsL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::FullResyncCreateChanges. Error [%d] in DoHandleEventsL", err ); - } - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::DeleteContextCompleted -// DeleteContext callback. Deleting a context is part of -// full synchronization. -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::DeleteContextCompleted( TInt aErrorCode ) - { - if( aErrorCode == KErrNone ) - { - // Go to the next phase of full synchronization - RUBY_DEBUG1( "CNssContactHandlerImplementation::DeleteContextCompleted. iState == ECHFullResync, iState [%d]", iState ); - RUBY_ASSERT_DEBUG( iState == ECHFullResync, User::Panic( KFile, __LINE__ ) ); - TRAPD( err, FullResyncCreateContextL() ); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DeleteContextCompleted. Error [%d] in FullResyncCreateContextL", err ); - } - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteContextCompleted failed" ); - RUBY_ASSERT_DEBUG( iState == ECHFullResync, User::Panic( KFile, __LINE__ ) ); - - RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteContextCompleted - can't handle, stopping." ); - TRAPD( err, DoHandleEventFailedL(); ); - if( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DeleteContextCompleted Left with [%d]", err); - } - } - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::CausedByVoiceTagAddition -// Check if the event was caused by voice tag field adding -// ------------------------------------------------------------ -// -TBool CNssContactHandlerImplementation::CausedByVoiceTagAddition( const TPhonebookEvent& aEvent ) - { - TBool isVoiceTagAddedEvent (EFalse); - if( EContactChanged == aEvent.iType ) - { - for ( TInt i = 0; i < iVoiceTagAddedList.Count(); i++ ) - { - if ( aEvent.iContactId == iVoiceTagAddedList[i] ) - { - isVoiceTagAddedEvent = ETrue; - iVoiceTagAddedList.Remove( i-- ); // "i--" because of removal - // Continue iterations. We are not sure if voice tag for the given - // contact could be changed twice - } - } // for - } // if event type - return isVoiceTagAddedEvent; - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::PeriodicCallback -// Static callback required by Symbian Timer services. -// ------------------------------------------------------------ -// -TInt CNssContactHandlerImplementation::PeriodicCallback( TAny* pX ) - { - ((CNssContactHandlerImplementation*)pX)->DoPeriodicCallback(); - return KErrNone; // useless for CPeriodic - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::DoPeriodicCallback -// Periodically check if there are some events to process -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::DoPeriodicCallback() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoPeriodicCallback" ); - // Check is needed to eliminate unnesessary TRAP and 64 bit time operations - // Note, that we are not checking for PeriodicAction(), but for iPeriodicHandleEventTimer == NULL - // PeriodicAction() is a method for detection of start of the action, - // while iPeriodicHandleEventTimer == NULL says if periodic action is being executed - // right *now* - - if ( ( iState == ECHIdle ) && ( iEventArray.Count() > 0 ) && ( !PeriodicAction() ) ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::DoPeriodicCallback. iState is ECHIdle, there are [%d] events to handle and no periodic action in progress", iEventArray.Count()); - TRAPD( err, DoHandleEventsL()); - if ( err != KErrNone ) - { - RUBY_ERROR1( "CNssContactHandlerImplementation::DoPeriodicCallback. Error [%d] in DoHandleEventsL", err ); - } - } // if there are some events - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::DoPeriodicCallback No events to handle" ); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::PeriodicAction -// Detects periodic action. -// Checks if many events have been received "lately" -// --------------------------------------------------------- -// -TBool CNssContactHandlerImplementation::PeriodicAction() - { - // index of the first recorded call - TInt checkedIndex = iEventMomentIndex + 1; - checkedIndex = checkedIndex < KEventMomentsSize ? checkedIndex : 0; - TTime& checkedTime = iEventMoments[checkedIndex]; - - // Check if the first recorded call happened "lately" = within last - // KPeriodicActionInterval seconds - TTime currentTime; - currentTime.UniversalTime(); - TTimeIntervalMicroSeconds diff = currentTime.MicroSecondsFrom( checkedTime ); - TBool result = diff < iEndOfPeriodicActionInterval; - if ( result == EFalse ) - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction. Periodic action completed." ); - RUBY_DEBUG2( "CNssContactHandlerImplementation::PeriodicAction. Periodic action completed. iEventMomentIndex [%d], checkedIndex [%d]", iEventMomentIndex, checkedIndex ); - RUBY_DEBUG1( "currentTime [%d]", I64INT(currentTime.Int64())); - RUBY_DEBUG2( "CNssContactHandlerImplementation::PeriodicAction. diff [%d], iEndOfPeriodicActionInterval [%d]", I64INT(diff.Int64()), I64INT(iEndOfPeriodicActionInterval.Int64() ) ); - - for( TInt i = 0; i < KEventMomentsSize; i++ ) - { - RUBY_DEBUG2( "checkedIndex[%d] = [%d]", i, I64INT(iEventMoments[i].Int64() ) ); - } - - // Periodic action completed. Or hasn't even been started - // Restore timeout values - // iEndOfPeriodicActionInterval = KInitialPeriodicActionInterval; - if ( iPeriodicHandleEventTimer != NULL ) - { - // stop the timer, it was started, when periodic action was started - RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction Stopping the periodic action timer" ); - iPeriodicHandleEventTimer->Cancel(); - delete iPeriodicHandleEventTimer; - iPeriodicHandleEventTimer = NULL; - } - } - else - { - // Periodic action detected - // start the timer if it is not running yet - if( iPeriodicHandleEventTimer == NULL ) - { - TRAPD( err, iPeriodicHandleEventTimer = CPeriodic::NewL( EPriorityNormal ) ); - if( err != KErrNone ) - { - // This is a bad situation, but not the fatal one. - // If we cannot use timer to detect end of periodic action, - // Let's disable periodic action detection at all - RUBY_DEBUG1( "CNssContactHandlerImplementation::PeriodicAction. PeriodicTimer creation failed. Error [%d]. Disabling periodic actions", err); - result = EFalse; - } - else - { // Timer was created successfully - RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction Starting the periodic action timer" ); - iPeriodicHandleEventTimer->Start( KPeriodicTimerInterval, KPeriodicTimerInterval, TCallBack( PeriodicCallback, this ) ); - } - } - } - return result; - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::UpdatePeriodicActionVars -// Update variables, used to detect if periodic action is happening -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::UpdatePeriodicActionVars() - { - if ( ++iEventMomentIndex >= KEventMomentsSize ) - { - iEventMomentIndex = 0; - } - iEventMoments[iEventMomentIndex].UniversalTime(); - - // Update values used to detect end of periodic action - TTimeIntervalMicroSeconds32 currInterval = MaximalInterval( iEventMoments, KEventMomentsSize, iEventMomentIndex ); - // 8 times. At the end of action, this would typically be no longer, than 0.5secs - // Note, that this is the interval fo KEventMomentsSize events - if ( ( currInterval.Int() << 3 ) >= ( KInitialPeriodicActionInterval ) ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::UpdatePeriodicActionVars. Calculated interval is too big. Reverting periodic interval to the max [%d] mcs", KInitialPeriodicActionInterval); - iEndOfPeriodicActionInterval = KInitialPeriodicActionInterval; - } - else - { - currInterval = currInterval.Int() << 3; - RUBY_DEBUG1( "CNssContactHandlerImplementation::UpdatePeriodicActionVars. Adjusting periodic interval to [%d] mcs", currInterval.Int() ); - iEndOfPeriodicActionInterval = currInterval.Int(); - } - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::MaximalInterval -// Return maximal interval from the array of time moments -// ------------------------------------------------------------ -// -TTimeIntervalMicroSeconds32 CNssContactHandlerImplementation::MaximalInterval( const TTime aMoments[], const TInt aMomentsLength, const TInt aLastMomentIndex ) - { - RUBY_ASSERT_DEBUG( aMomentsLength > 1, User::Panic( KFile, __LINE__ ) ); - TInt currIndex( aLastMomentIndex ); - TInt prevIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1; - TTimeIntervalMicroSeconds32 result( 0 ); - TTimeIntervalMicroSeconds currInterval; - - for ( TInt i = 0; i < aMomentsLength - 1; i++ ) - { - currInterval = aMoments[currIndex].MicroSecondsFrom( aMoments[prevIndex] ); - const TInt64& currIntVal = currInterval.Int64(); - TBool tooBigValue = currIntVal > KMaxTInt; - - // if high != 0, aMoments were filled in the incorrect way - // but we should not bug the user about it - if ( tooBigValue ) - { - // this cannot be a negative value.. if moments are recorded in the correct order. - // Then non-zero high means, that interval is too big to fit into - // TTimeIntervalMicroSeconds32 - RUBY_DEBUG0( "CNssContactHandlerImplementation::MaximalInterval. Maximal interval is out of bounds" ); - result = TTimeIntervalMicroSeconds32( KMaxTInt ); - break; - } - else - { - // normal size value - // casting is safe - we checked, that it fits into TInt - TTimeIntervalMicroSeconds32 currInterval32 ( (TInt)currIntVal ); - - if ( currInterval32 > result ) - { - result = currInterval32; - } - } - currIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1; - prevIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1; - } // for - return result; - } - -// ------------------------------------------------------------ -// CNssContactHandlerImplementation::SetState -// Sets the contact handler state. -// In debug, panics (via asserts) if state change is not legal -// ------------------------------------------------------------ -// -void CNssContactHandlerImplementation::SetState( TContactHandlerState aState ) - { - RUBY_DEBUG2( "CNssContactHandlerImplementation::SetState from [%d] to [%d]", iState, aState); - switch( aState ) - { - case ECHFullResync: - // no pending events - RUBY_ASSERT_DEBUG( ( iDeleteTagListArray == NULL ) || ( iDeleteCallbackCounter == iDeleteTagListArray->Count() ), User::Panic( KFile, __LINE__ ) ); - RUBY_ASSERT_DEBUG( iSaveCallbackCounter == iTagArray.Count(), User::Panic( KFile, __LINE__ ) ); - - // full resyncronization needed again if this full resyncronization fails - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) ); - break; - case ECHHandlingNormalChanges: - RUBY_ASSERT_DEBUG( iState == ECHIdle, User::Panic( KFile, __LINE__ ) ); - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) ); - break; - case ECHIdle: - if ( iDeleteTagListArray != NULL ) - { - RUBY_ASSERT_DEBUG( (iSaveCallbackCounter == iTagArray.Count() ) || ( iDeleteCallbackCounter == iDeleteTagListArray->Count() ), User::Panic( KFile, __LINE__ ) ); - } - else - { - RUBY_ASSERT_DEBUG( ( iSaveCallbackCounter == iTagArray.Count() ) , User::Panic( KFile, __LINE__ ) ); - } - if( iEventArray.Count() == 0 ) - { - // Idle state and no pending events mean, that contact handler - // completed its operations for now - TInt errProp = iBusyProperty.Set( EContactsNoTraining ); - if ( errProp != KErrNone ) - { - RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", - errProp ); - // @todo Not a leaving function -> leave commented out - //User::Leave( errProp ) ; - } - } - - // all changes done, no need for resyncronization - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( EFalse ) ); - - break; - default: - RUBY_ERROR0( "CNssContactHandlerImplementation::SetState Unexpected or unknown state" ); - RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) ); - - // failure, full resyncronization needed - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) ); - break; - } - // actually switch state - iState = aState; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DataSyncStateChanged -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DataSyncStateChanged( TBool aRunning ) - { - if( !aRunning && ( iSyncBackupWaiter->IsStarted() ) ) - { - RUBY_DEBUG0( "DataSyncStateChanged Sync became inactive and CH was waiting for it" ); - iSyncBackupWaiter->AsyncStop(); - } - } - -// --------------------------------------------------------- -// Is called when backup/restore status is changed and when backup/restore -// state observation was just started -// @param aRunning ETrue if some backup/restore action is in progress -// EFalse otherwise -// @param aRestoreType ETrue if the event is restore related -// EFalse if the event is backup related -// @see CNssChBackupObserver -// --------------------------------------------------------- -void CNssContactHandlerImplementation::BackupRestoreStateChanged( TBool aRestoreType, - TBool aRunning ) - { - RUBY_DEBUG2( "BackupRestoreStateChanged aRestoreType [%d], aRunning [%d]", - aRestoreType, aRunning ); - - if( aRestoreType && aRunning ) - { - RUBY_DEBUG0( "Setting the Full Resync CR flag" ); - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) ); - } - - if( !aRunning && ( iSyncBackupWaiter->IsStarted() ) ) - { - RUBY_DEBUG0( "BackupRestoreStateChanged b/r became inactive and CH was waiting for it" ); - iSyncBackupWaiter->AsyncStop(); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::HandleNotifyInt -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::HandleNotifyInt( TUint32 aId, TInt aNewValue ) - { - RUBY_DEBUG0( "" ); - - if ( aId == KSRSFFullResyncNeeded ) - { - if ( aNewValue == KImmediateResync ) - { - RUBY_DEBUG0( "Immediate full resync requested" ); - - // Write the previous value back to the cenrep - TRAP_IGNORE( SetFullResyncCrFlagL( iResyncAtBoot ) ); - - // Create an event that will launch full resync - TPhonebookEvent event; - event.iType = ENullEvent; - event.iContactId = 0; - - iEventArray.Append( event ); - - // Start resync if nothing is ongoing - if ( iState == ECHIdle ) - { - TRAP_IGNORE( DoHandleEventsL() ); - } - } - } - } - -// --------------------------------------------------------- -// Sets the central repository full resync flag -// --------------------------------------------------------- -void CNssContactHandlerImplementation::SetFullResyncCrFlagL( TBool aResyncNeeded ) - { - RUBY_DEBUG_BLOCKL(""); - User::LeaveIfError( iRepository->Set( KSRSFFullResyncNeeded, aResyncNeeded ) ); - iResyncAtBoot = aResyncNeeded; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::WaitUntilNoSyncBackupIsRunning -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::WaitUntilNoSyncBackupIsRunning() - { - RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning start" ); - RUBY_ASSERT_DEBUG( !iSyncBackupWaiter->IsStarted(), User::Panic( KFile, __LINE__ ) ); - - // Disconnection from phonebook should happen only once and only if b/r is running - TBool disconnectedFromPb = EFalse; - - // Check the values until both data sync and backup/restore are not active - while( iDataSyncWatcher->InProgress() || iBackupObserver->InProgress() ) - { - RUBY_DEBUG2( "WaitUntilNoSyncBackupIsRunning Have to wait. data sync [%d], backup/restore [%d]", - iDataSyncWatcher->InProgress(), iBackupObserver->InProgress() ); - if( !iSyncBackupWaiter->IsStarted() ) - { - if( (!disconnectedFromPb) && iBackupObserver->InProgress() ) - { - RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning Disconnecting from phonebook" ); - DisconnectFromPhonebook(); - disconnectedFromPb = ETrue; - } - iSyncBackupWaiter->Start(); - } - else - { - RUBY_ERROR0( "WaitUntilNoSyncBackupIsRunning Attempt to start already active iSyncBackupWaiter. Huge error!" ); - } - } - - if( disconnectedFromPb ) - { - RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning Reconnecting to phonebook" ); - TRAP_IGNORE( ConnectToPhonebookL() ); - } - - RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning end" ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::GetContactL -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::GetContactL( TContactItemId aContactId, TBool aReadContact ) - { - RUBY_DEBUG1( "CNssContactHandlerImplementation::GetContactL. contact id [%d]", aContactId ); - TInt err = KErrNone; - // Number of attempts tries - TInt attemptsTried( 0 ); - do - { - if( err == KErrInUse ) // i.e. not the first cycle iteration - { - RUBY_DEBUG2( "GetContactL Contact [%d] is locked. Waiting one more second. Retrial [%d]", - aContactId, attemptsTried); - // start periodic timer - if( attemptsTried == 1) // i.e exactly the second cycle iteration - { - RUBY_DEBUG0( "GetContactL Creating periodic timer" ); - iContactWaitTimer = CPeriodic::NewL( EPriorityNormal ); - iContactWaitTimer->Start( KContactWaitInterval, KContactWaitInterval, TCallBack( ContactWaitCallback, this ) ); - } - RUBY_DEBUG0( "GetContactL Starting the inner cycle waiting" ); - iContactWaiter->Start( ); - RUBY_DEBUG0( "GetContactL Waiting completed, trying to open contact again" ); - } - - TRAP( err, iPbkHandler->FindContactL( aContactId, aReadContact ) ); - - attemptsTried++; - // -1 means forever - if( ( KMaxContactLockRetrials != -1 ) && ( attemptsTried >= KMaxContactLockRetrials ) ) - { - RUBY_DEBUG1( "GetContactL Tried for [%d] times, still no success", attemptsTried ); - break; - } - } - while( err == KErrInUse ); - if( iContactWaitTimer != NULL ) - { - iContactWaitTimer->Cancel(); - delete iContactWaitTimer; - iContactWaitTimer = NULL; - } - // Propagate all the leaves, BUT KErrInUse - if( ( err != KErrInUse ) && ( err != KErrNone ) ) - { - User::LeaveIfError( err ); - } - if( err == KErrInUse ) - { - RUBY_DEBUG1( "GetContactL Failed to lock contact [%d]. Disabling CH, will resync on reboot", aContactId ); - DisableEventHandling(); - User::Leave( KErrInUse ); - } - RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContactL completed" ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::ReadContactL -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::ReadContactL( TContactItemId aContactId ) - { - GetContactL( aContactId, ETrue ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::OpenContactL -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::OpenContactL( TContactItemId aContactId ) - { - GetContactL( aContactId, EFalse ); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::ContactWaitCallback -// -// --------------------------------------------------------- -// -TInt CNssContactHandlerImplementation::ContactWaitCallback( TAny* pX ) - { - ((CNssContactHandlerImplementation*)pX)->DoContactWaitCallback(); - return KErrNone; // useless for CPeriodic - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::DoContactWaitCallback -// -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::DoContactWaitCallback() - { - iContactWaiter->AsyncStop(); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::NoDiskSpace -// Checks if there is not enough disk space to finish the -// operation. Returns ETrue if there is no space. -// --------------------------------------------------------- -// -TBool CNssContactHandlerImplementation::NoDiskSpace() - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace" ); - TBool diskSpace( EFalse ); - TRAP_IGNORE( diskSpace = SysUtil::FFSSpaceBelowCriticalLevelL( &iFSession, KIncreaseOfDatabaseSizes ) ); - - if ( diskSpace ) - { - RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) ); - RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace NOT enough disk space available" ); - return ETrue; - } - else - { - RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace There is enough disk space" ); - return EFalse; - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::TrimName -// Substitutes separator characters in descriptor with -// white spaces. Removes extra withspaces. -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::TrimName( HBufC* aBuf ) - { - TPtr ptr = aBuf->Des(); - - for ( TInt findIndex = 0; findIndex < aBuf->Des().Length(); findIndex++ ) - { - if ( ptr[findIndex] == iSeparator ) - { - ptr[findIndex] = ' '; - } - } - - ptr.TrimAll(); - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::AppendName -// Appends name to given buffer -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::AppendName( HBufC* aBuf, HBufC* aName ) - { - if ( aName->Length() != 0 ) - { - aBuf->Des().Append( iSeparator ); - aBuf->Des().Append( KNameTrainingIndex ); - aBuf->Des().Append( aName->Des() ); - } - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::AppendExtensionMarker -// Appends marker for the extensions -// Parameters should be in format "%U text message" -// In which case output is "%U_2text message" -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::AppendExtensionMarker( TDes& aDes ) - { - if ( aDes.Length() > 0 ) - { - TInt insertPosition( 0 ); - if ( aDes.Find( KExtensionFormatString ) == 0 ) - { - // Find the first space and insert marker to that position - TInt firstSpace( 0 ); - firstSpace = aDes.Find( _L(" ") ); - if ( firstSpace == 2 ) // Next character after KExtensionFormatString - { - aDes.Delete( firstSpace, 1 ); - } - insertPosition = 2; - } - // Insert marker - aDes.Insert( insertPosition, KExtensionTrainingIndex ); - aDes.Insert( insertPosition, KNameSeparator ); - } - } - -/** -* Establishes the connection to the contact engine and -* starts listening to it -*/ -void CNssContactHandlerImplementation::ConnectToPhonebookL() - { - RUBY_ASSERT_DEBUG( (!iPbkHandler), User::Leave( KErrNotReady ) ); - iPbkHandler = CVasVPbkHandler::NewL(); - iPbkHandler->InitializeL(); - iPbkHandler->CreateContactObserverL( this ); - } - -/** -* Clears the connection to the contact engine -*/ -void CNssContactHandlerImplementation::DisconnectFromPhonebook() - { - delete iPbkHandler; - iPbkHandler = NULL; - } - -#ifdef __SIND_EXTENSIONS - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::ReadExtensionsL -// Reads the extension resource file -// --------------------------------------------------------- -// -void CNssContactHandlerImplementation::ReadExtensionsL() - { - // using StringLoader should be used, but there is no - // access to CCoeEnv - - - // letters for drives in search order - const TBuf<1> KResourceDrivers = _L("z"); - _LIT( KResourceFileName, "nssvascontacthandler.rsc" ); - - // number of extension commands in the resource file - const TInt KExtensionCommandCount = 8; - - // load resources - RResourceFile resourceFile; - RFs fs; - CleanupClosePushL( fs ); - TBool found( EFalse ); - User::LeaveIfError( fs.Connect() ); - - - TFileName name; - TInt i( 0 ); - // use the first drive - name.Append( KResourceDrivers[i] ); - name.Append(':'); - name.Append( KDC_RESOURCE_FILES_DIR ); - name.Append( KResourceFileName ); - - while ( !found && i < KResourceDrivers.Length() ) - { - name[0] = KResourceDrivers[i++]; - - BaflUtils::NearestLanguageFile( fs, name ); - - if ( BaflUtils::FileExists(fs, name) ) - { - // open resource - resourceFile.OpenL( fs, name ); - CleanupClosePushL( resourceFile ); - resourceFile.ConfirmSignatureL(); - found = ETrue; - } - } - - if ( !found ) - { - User::Leave( KErrNotFound ); - } - - for ( TInt extensionIndex( 0 ); extensionIndex < KExtensionCommandCount; extensionIndex++ ) - { - TExtension extension; - TResourceReader reader; - TBool extentionSupported( ETrue ); - - switch ( extensionIndex ) - { - - case 0: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_MOBILE ) ); - extension.iId = EPbkFieldIdPhoneNumberMobile; - extension.iAction = EDial; - extension.iCommand = EMobileCommand; - break; - - case 1: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_MESSAGE ) ); - extension.iId = EPbkFieldIdPhoneNumberMobile; - extension.iAction = ENewMessage; - extension.iCommand = EMessageCommand; - break; - - case 2: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_GENERAL ) ); - extension.iId = EPbkFieldIdPhoneNumberGeneral; - extension.iAction = EDial; - extension.iCommand = EGeneralCommand; - break; - - case 3: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_WORK ) ); - extension.iId = EPbkFieldIdPhoneNumberWork; - extension.iAction = EDial; - extension.iCommand = EWorkCommand; - break; - - case 4: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_HOME ) ); - extension.iId = EPbkFieldIdPhoneNumberHome; - extension.iAction = EDial; - extension.iCommand = EHomeCommand; - break; - - case 5: - if ( iVideoCallFeatureSupported ) - { - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_VIDEO ) ); - extension.iId = EPbkFieldIdPhoneNumberVideo; - extension.iAction = EDial; - extension.iCommand = EVideoCommand; - } - else - { - extentionSupported = EFalse; - } - break; - - case 6: - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_EMAIL ) ); - extension.iId =EPbkFieldIdEmailAddress ; - extension.iAction = ENewEmail; - extension.iCommand = EEmailCommand; - break; - - case 7: - if ( iVoIPFeatureSupported ) - { - reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_VOIP ) ); - extension.iId = EPbkFieldIdVOIP; - extension.iAction = EDial; - extension.iCommand = EVoipCommand; - } - else - { - extentionSupported = EFalse; - } - break; - - default: - User::Leave( KErrGeneral ); // !!! @todo: PANIC - } - - if ( extentionSupported ) - { - extension.iText = reader.ReadHBufCL(); - CleanupStack::PushL( extension.iText ); - User::LeaveIfError( iExtensionList.Append( extension ) ); - CleanupStack::Pop( extension.iText ); - CleanupStack::PopAndDestroy(); // AllocReadLC - } - } - - CleanupStack::PopAndDestroy( &resourceFile ); - CleanupStack::PopAndDestroy( &fs ); - - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::FindExtensionField -// Finds the extension field based on priority lists -// --------------------------------------------------------- -// -TInt CNssContactHandlerImplementation::FindExtensionField( TVasExtensionAction aAction, - TPbkFieldId aDefaultFieldId ) - { - TInt found = KErrNotFound; - - switch ( aDefaultFieldId ) - { - case EPbkFieldIdPhoneNumberVideo: - { - // Use defaults for video extension - found = ExtensionFieldFindLoop( KVideoExtensionFields, KVideoExtensionFieldsCount ); - break; - } - - case EPbkFieldIdPhoneNumberMobile: - { - if ( aAction == ENewMessage ) - { - // Use defaults for message extension - found = ExtensionFieldFindLoop( KMessageExtensionFields, KMessageExtensionFieldsCount ); - } - else - { - TRAP( found, iPbkHandler->FindFieldL( aDefaultFieldId ) ); - } - - break; - } - - case EPbkFieldIdVOIP: - { - // Use defaults for VOIP extension - found = ExtensionFieldFindLoop( KVOIPExtensionFields, KVOIPExtensionFieldsCount ); - - break; - } - - default: - { - TRAP( found, iPbkHandler->FindFieldL( aDefaultFieldId ) ); - break; - } - } - return found; - } - -// --------------------------------------------------------- -// CNssContactHandlerImplementation::ExtensionFieldFindLoop -// Finds the extension from the prioroty list arrays -// --------------------------------------------------------- -// -TInt CNssContactHandlerImplementation::ExtensionFieldFindLoop( const TPbkFieldId* const aArray, - TInt aCount ) - { - TInt found = KErrNotFound; - - for ( TInt iCounter = 0; iCounter < aCount; iCounter++ ) - { - TRAP( found, iPbkHandler->FindFieldL( aArray[iCounter] ) ); - if ( found == KErrNone ) - { - break; - } - } - return found; - } - -#endif // __SIND_EXTENSIONS - -// End of File