srsf/nssvascontacthdlr/src/nssvasccontacthandlerimpl.cpp
branchRCL_3
changeset 19 e36f3802f733
child 20 bf318c0ae8c0
equal deleted inserted replaced
18:cad71a31b7fc 19:e36f3802f733
       
     1 /*
       
     2 * Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Responsible for maintaining synchronization between the contact DB
       
    15 *               and the VAS DB
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 /** @todo Read the whole contact in one go.
       
    21 
       
    22   Currently Contact handler usually opens the same contact (ReadContactL) two to 
       
    23   three times in order to read its data (mostly often three times).
       
    24   One is in GetContactNickname
       
    25   Second in GetContactTitle
       
    26   Third in DoAddNamesL when deciding what number field should the voice tag 
       
    27         be trained for
       
    28   If we could unite these reads, "reading contacts" phase will be 2-3 times faster.
       
    29   It would make about 10-20% improvement for the training of some 300 contacts */
       
    30 
       
    31 // INCLUDE FILES
       
    32 #include "nssvasccontacthandlerimpl.h"
       
    33 #include "nssvasctrainingparameters.h"
       
    34 #include <nssvascvasdbmgr.h>
       
    35 #include <centralrepository.h>
       
    36 #include <f32file.h>
       
    37 #include <bautils.h>
       
    38 #include <barsc.h>
       
    39 #include <barsread.h>
       
    40 #include <sysutil.h>
       
    41 #include "srsfprivatecrkeys.h"
       
    42 
       
    43 // Publish & Subscribe of the contact handler activity
       
    44 #include <nssvascoreconstant.h>
       
    45 
       
    46 #include <vascvpbkhandler.h>
       
    47 #include <featmgr.h>
       
    48 #include "nssvasdatasyncwatcher.h"
       
    49 #include "nsschbackupobserver.h"
       
    50 #include <StringLoader.h> 
       
    51 #include <nssvascontacthandler.rsg>
       
    52 #include <data_caging_path_literals.hrh>
       
    53 #include "rubydebug.h"
       
    54 
       
    55 // CONSTANTS
       
    56 // Name of the context in the SIND DB. Voice tags for contacts are saved there
       
    57 _LIT( KNssCHNameDialContext, "NAMEDIAL" );
       
    58 
       
    59 // Languages which use lastname-firstname order
       
    60 const TLanguage KSwappedLanguages[] = 
       
    61     {
       
    62     ELangHungarian,       // 17
       
    63     ELangTaiwanChinese,   // 29
       
    64     ELangHongKongChinese, // 30
       
    65     ELangJapanese,        // 32
       
    66     ELangPrcChinese,      // 31
       
    67     ELangKorean,          // 65
       
    68     ELangVietnamese       // 96
       
    69     };
       
    70 
       
    71 // Number of languages that use lastname-firstname order
       
    72 const TInt KNumberOfSwappedLanguages = sizeof( KSwappedLanguages ) / sizeof ( TLanguage );
       
    73 
       
    74 
       
    75 // Maximal number of retrials to save tags
       
    76 const TInt KVASCHMaxRetry = 2;
       
    77 
       
    78 // Size of the event 'pack'. Tags are added and deleted in groups.
       
    79 // KMaxNamesAtOnce is the maximal size of a group
       
    80 const TInt KMaxNamesAtOnce = 100;
       
    81 
       
    82 // Initial value of the time interval used to detect periodic action. In 
       
    83 // microseconds. If KEventMomentsSize events happened  within the 
       
    84 // KInitialPeriodicActionInterval, we assume, that periodic action has started
       
    85 const TInt KInitialPeriodicActionInterval = 15000000;
       
    86 
       
    87 // Time interval used to periodically check if there are pending 
       
    88 // events to process. In microseconds
       
    89 const TInt KPeriodicTimerInterval = 1000000;
       
    90 
       
    91 // If there are this many consecutive full resyncs initiated by errors during
       
    92 // handling normal changes (or during previous full resync), there is probably
       
    93 // something consistently wrong at the lower layers. 
       
    94 // Full resync trials (and the whole contact handler) should be disabled until
       
    95 // reboot after KMaxConsecutiveErrorFullResync consecutive unsuccessful trials
       
    96 const TInt KMaxConsecutiveErrorFullResync = 2;
       
    97 
       
    98 // List of phonebook fields, that are supported by contact handler.
       
    99 // I.e. fields, that can be dialed and voice tagged
       
   100 /** @todo Consider using information from phonebook about which fields contain numbers
       
   101 and using the following lists for priorities only */
       
   102 const TPbkFieldId KTaggableFields[] = 
       
   103     { 
       
   104     EPbkFieldIdPhoneNumberMobile, 
       
   105     EPbkFieldIdPhoneNumberGeneral,
       
   106     EPbkFieldIdPhoneNumberStandard, 
       
   107     EPbkFieldIdPhoneNumberHome,
       
   108     EPbkFieldIdPhoneNumberWork, 
       
   109     EPbkFieldIdPhoneNumberVideo,
       
   110     EPbkFieldIdVOIP,
       
   111     EPbkFieldIdXsp
       
   112     };
       
   113 const TInt KTaggableFieldsCount = sizeof( KTaggableFields ) / sizeof ( TPbkFieldId );
       
   114 
       
   115 // List of phonebook fields that are supported by video extension
       
   116 const TPbkFieldId KVideoExtensionFields[] = 
       
   117     {
       
   118     EPbkFieldIdPhoneNumberVideo,
       
   119     EPbkFieldIdPhoneNumberMobile,
       
   120     EPbkFieldIdPhoneNumberGeneral,
       
   121     EPbkFieldIdPhoneNumberHome,
       
   122     EPbkFieldIdPhoneNumberWork
       
   123     };
       
   124 const TInt KVideoExtensionFieldsCount = sizeof( KVideoExtensionFields ) / sizeof ( TPbkFieldId );
       
   125 
       
   126 // List of phonebook fields that are supported by message extension
       
   127 const TPbkFieldId KMessageExtensionFields[] = 
       
   128     {
       
   129     EPbkFieldIdPhoneNumberMobile,
       
   130     EPbkFieldIdPhoneNumberGeneral,
       
   131     EPbkFieldIdPhoneNumberHome,
       
   132     EPbkFieldIdPhoneNumberWork,
       
   133     EPbkFieldIdPhoneNumberVideo
       
   134     };
       
   135 const TInt KMessageExtensionFieldsCount = sizeof( KMessageExtensionFields ) / sizeof ( TPbkFieldId );   
       
   136 
       
   137 // List of phonebook fields that are supported by VOIP extension
       
   138 const TPbkFieldId KVOIPExtensionFields[] = 
       
   139     {
       
   140     EPbkFieldIdVOIP,
       
   141     EPbkFieldIdXsp
       
   142     };
       
   143 const TInt KVOIPExtensionFieldsCount = sizeof( KVOIPExtensionFields ) / sizeof ( TPbkFieldId ); 
       
   144 
       
   145 // Size of the client data per context. Is used to store the context language
       
   146 // In bytes
       
   147 const TInt KClientDataSize = sizeof(TNssContextClientData);
       
   148 
       
   149 
       
   150 // Number of retries to try to lock the same contact
       
   151 // 600 times should stand for 10 mins
       
   152 // -1 means trying forever
       
   153 const TInt KMaxContactLockRetrials = 600;
       
   154 
       
   155 // Interval between the ticks of the contact wait timer
       
   156 // in microseconds
       
   157 const TInt32 KContactWaitInterval = 1000000;
       
   158 
       
   159 // Bytes that should be free in the disk drive in addition to critical level 
       
   160 // before operation is started (100kB)
       
   161 const TInt KIncreaseOfDatabaseSizes = 100000;
       
   162 
       
   163 // Define this if name free-order is enabled
       
   164 //#define NSSVAS_CONTACTHANDLER_FREEORDER
       
   165 // LOCAL FUNCTION DECLARATIONS
       
   166 
       
   167 
       
   168 // ================= MEMBER FUNCTIONS =======================
       
   169 
       
   170 
       
   171 #ifdef _DEBUG
       
   172 _LIT( KFile, "VasCContactHandlerImpl.cpp" );
       
   173 #endif
       
   174 
       
   175 /**
       
   176 * Is used in DoHandleEventFailedL to *asynchronously* simulate successful tag
       
   177 *  deletion
       
   178 */
       
   179 NONSHARABLE_CLASS( CSuccessfulDeletionSimulator ) : public CAsyncOneShot 
       
   180 	{
       
   181 	public:
       
   182 		CSuccessfulDeletionSimulator( CNssContactHandlerImplementation& aHost );
       
   183 		~CSuccessfulDeletionSimulator();
       
   184 	protected:
       
   185 	    /** Is called by the system after we asked it to Call() closer
       
   186 	    */
       
   187 		virtual void RunL();
       
   188     private:
       
   189         CNssContactHandlerImplementation& iHost;
       
   190 	};
       
   191 
       
   192 // -----------------------------------------------------------------------------
       
   193 // CSuccessfulDeletionSimulator::~CSuccessfulDeletionSimulator
       
   194 // Destructor
       
   195 // -----------------------------------------------------------------------------
       
   196 //	
       
   197 CSuccessfulDeletionSimulator::~CSuccessfulDeletionSimulator() 
       
   198     {
       
   199     RUBY_DEBUG0( "~CSuccessfulDeletionSimulator" );
       
   200     if( IsAdded() ) 
       
   201         {
       
   202         RUBY_DEBUG0( "~CSuccessfulDeletionSimulator Request is still in progress, deque it" );
       
   203         Deque();
       
   204         }
       
   205     }
       
   206 
       
   207 // -----------------------------------------------------------------------------
       
   208 // CSuccessfulDeletionSimulator::CSuccessfulDeletionSimulator
       
   209 // Constructor
       
   210 // -----------------------------------------------------------------------------
       
   211 //
       
   212 CSuccessfulDeletionSimulator::CSuccessfulDeletionSimulator( CNssContactHandlerImplementation& aHost ) :
       
   213 	CAsyncOneShot( CActive::EPriorityStandard ),
       
   214 	iHost( aHost )
       
   215 	{
       
   216 	//nothing
       
   217 	}
       
   218 	
       
   219 // -----------------------------------------------------------------------------
       
   220 //  CAppCloser::RunL
       
   221 //  Will be called by the system and exits the application
       
   222 // -----------------------------------------------------------------------------
       
   223 //
       
   224 void CSuccessfulDeletionSimulator::RunL() 
       
   225 	{
       
   226 	RUBY_DEBUG0( "CSuccessfulDeletionSimulator::RunL Start" );
       
   227 	if( iStatus == KErrNone ) 
       
   228 		{
       
   229 		CArrayPtrFlat<MNssTag>* empty = new (ELeave) CArrayPtrFlat<MNssTag>( 1 );
       
   230     	iHost.DoRemoveNamesAfterGetTagList( empty );
       
   231     	// empty will be destroyed in the DoRemoveNamesAfterGetTagList
       
   232 		}
       
   233 	else 
       
   234 		{
       
   235 		RUBY_ERROR1( "CSuccessfulDeletionSimulator::RunL Unexpected iStatus [%d]", iStatus.Int() );
       
   236 		}
       
   237 	RUBY_DEBUG0( "CSuccessfulDeletionSimulator::RunL End" );
       
   238 	}
       
   239 	
       
   240 
       
   241 
       
   242 // -----------------------------------------------------------------------------
       
   243 // CNssContactHandlerImplementation::CNssContactHandlerImplementation
       
   244 // C++ default constructor can NOT contain any code, that
       
   245 // might leave.
       
   246 // -----------------------------------------------------------------------------
       
   247 //
       
   248 CNssContactHandlerImplementation::CNssContactHandlerImplementation( )
       
   249 : iState( ECHInitializing ),
       
   250   iSeparator( KNameSeparator()[0] ),
       
   251   iEndOfPeriodicActionInterval( KInitialPeriodicActionInterval )
       
   252     {
       
   253     iClientData.iLanguage = ELangNone;
       
   254     
       
   255     // initialize last RestartTimer calls to be long ago in 
       
   256     // the past (January 1st, 0 AD nominal Gregorian)
       
   257     for( TInt i = 0; i < KEventMomentsSize; i++)
       
   258     	{
       
   259     	iEventMoments[i] = 0;
       
   260     	}
       
   261     }
       
   262 
       
   263 // -----------------------------------------------------------------------------
       
   264 // CNssContactHandlerImplementation::ConstructL
       
   265 // EPOC second phase constructor can leave.
       
   266 // -----------------------------------------------------------------------------
       
   267 //
       
   268 void CNssContactHandlerImplementation::ConstructL()
       
   269     {
       
   270     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::ConstructL" );
       
   271 
       
   272     User::LeaveIfError( iFSession.Connect() );
       
   273 
       
   274     // Sets up TLS, must be done before FeatureManager is used.
       
   275     FeatureManager::InitializeLibL();
       
   276     iVoIPFeatureSupported = FeatureManager::FeatureSupported( KFeatureIdCommonVoip );
       
   277     iVideoCallFeatureSupported = FeatureManager::FeatureSupported( KFeatureIdCsVideoTelephony );
       
   278     // Frees the TLS! Must be done after FeatureManager is used.
       
   279     FeatureManager::UnInitializeLib();
       
   280 
       
   281     // Before enabling event, start monitoring the PC-suite state
       
   282     iSyncBackupWaiter = new (ELeave) CActiveSchedulerWait;
       
   283     
       
   284     iDataSyncWatcher = CNssDataSyncWatcherFactory::ConstructDataSyncWatcherL( *this );
       
   285     
       
   286     iBackupObserver = CNssChBackupObserver::NewL( *this );
       
   287     
       
   288     iContactWaiter = new (ELeave) CActiveSchedulerWait;
       
   289     
       
   290     iDeletionSimulator = new (ELeave) CSuccessfulDeletionSimulator( *this );
       
   291 
       
   292     EnableEventHandling();
       
   293 
       
   294     iEventArray.Reset();    // Ready to be used
       
   295 
       
   296     TInt errProp = iBusyProperty.Define( KSINDUID, ETrainingContactsState, RProperty::EInt );
       
   297     if( ( errProp != KErrNone ) && ( errProp != KErrAlreadyExists ) ) 
       
   298         {
       
   299         RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to define the property. Error [%d]", 
       
   300                     errProp);
       
   301         User::Leave( errProp );
       
   302         }
       
   303         
       
   304     // Publish contact handler as busy before the DB operations
       
   305     errProp = iBusyProperty.Attach( KSINDUID, ETrainingContactsState );
       
   306     if( errProp != KErrNone ) 
       
   307         {
       
   308         // KErrNotFound is also an error as we just defined the property
       
   309         RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to attach to property. Error [%d]", 
       
   310                     errProp);
       
   311         User::Leave( errProp );
       
   312         }
       
   313         
       
   314     errProp = iBusyProperty.Set( EContactsTraining );
       
   315     if ( errProp != KErrNone )
       
   316         {
       
   317         RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", 
       
   318                      errProp );
       
   319         User::Leave( errProp )  ;
       
   320         }
       
   321 
       
   322     
       
   323     // central repository
       
   324     iRepository = CRepository::NewL( KCRUidSRSFSettings );
       
   325     iRepositoryObserver = CCenRepNotifyHandler::NewL( *this, *iRepository,
       
   326                                                       CCenRepNotifyHandler::EIntKey,
       
   327                                                       KSRSFFullResyncNeeded );
       
   328     iRepositoryObserver->StartListeningL();
       
   329     
       
   330 	//Get VAS DB manager
       
   331 	iVasDbManager = CNssVASDBMgr::NewL();
       
   332 	iVasDbManager->InitializeL();
       
   333 	RUBY_DEBUG0( "CNssContactHandlerImplementation::ConstructL iVasDbManager initialized" );
       
   334 
       
   335 	//Get Tag Manager and Context Manager interfaces
       
   336 	iTagManager = iVasDbManager->GetTagMgr();
       
   337 	iContextManager = iVasDbManager->GetContextMgr();
       
   338 
       
   339     // Prepare training parameters
       
   340     iTrainingParams = CNssTrainingParameters::NewL();
       
   341     
       
   342     RUBY_DEBUG0( "CNssContactHandlerImplementation::ConstructL iTrainingParams prepared" );
       
   343 
       
   344     // Set languages which have lastname-firstname order
       
   345     for ( TInt iCounter = 0; iCounter < KNumberOfSwappedLanguages; iCounter++ )
       
   346         {
       
   347         User::LeaveIfError( iSwappedLanguages.Append( KSwappedLanguages[iCounter] ) );
       
   348         }
       
   349 
       
   350 #ifdef __SINDE_TRAINING
       
   351     // Main array for languages
       
   352     RArray<RTrainingLanguageArray> languages;
       
   353     
       
   354     // Languages for names
       
   355     RArray<TLanguage> nameLanguages;
       
   356     User::LeaveIfError( nameLanguages.Append( User::Language() ) );
       
   357     User::LeaveIfError( nameLanguages.Append( ELangOther ) );
       
   358     User::LeaveIfError( languages.Append( nameLanguages ) );
       
   359     
       
   360     // Languages for extensions
       
   361     RArray<TLanguage> extLanguages;
       
   362     User::LeaveIfError( extLanguages.Append( User::Language() ) );
       
   363     User::LeaveIfError( languages.Append( extLanguages ) );
       
   364     
       
   365     // Store languages to training parameters
       
   366     iTrainingParams->SetSindeLanguages( languages );
       
   367 
       
   368     // Close arrays, iTrainingParams has done a copy of these
       
   369     extLanguages.Close();
       
   370     nameLanguages.Close();
       
   371     languages.Close();
       
   372     
       
   373 #else
       
   374     // Set the languages
       
   375     RArray<TLanguage> *languages = new (ELeave) RArray<TLanguage>;
       
   376     CleanupStack::PushL( languages );
       
   377     // Always generate a pronunciation in UI language
       
   378     User::LeaveIfError( languages->Append( User::Language() ) );
       
   379     // give some extra languages, which can be selected in engine
       
   380     User::LeaveIfError( languages->Append( ELangOther ) );
       
   381     iTrainingParams->SetLanguages( languages );
       
   382     CleanupStack::Pop( languages );
       
   383 #endif
       
   384     
       
   385     // The separator between the first name and the last name
       
   386     iTrainingParams->SetSeparator( iSeparator );
       
   387     
       
   388 #ifdef __SIND_EXTENSIONS
       
   389 
       
   390     ReadExtensionsL();
       
   391 #endif // __SIND_EXTENSIONS    	
       
   392 
       
   393 	ConnectToPhonebookL();
       
   394 	
       
   395     TLitC<9> name = KNssCHNameDialContext;
       
   396 
       
   397     // Get context.
       
   398 
       
   399     // (1) if we have synced earlier -> we have created a context, and saved the language
       
   400     // (2) if we haven't synced      -> we need to create context
       
   401     //
       
   402     // In case (2), GetContext fails.
       
   403     // We'll assume that GetContext is successful until it fails.
       
   404     iHaveWeEverSynced = ETrue;
       
   405 
       
   406     TInt err = iContextManager->GetContext( this, name );
       
   407     RUBY_DEBUG1( "CNssContactHandlerImplementation::ConstructL Requested GetContext. err [%d]", err);
       
   408 
       
   409     if ( err != KErrNone )
       
   410         {
       
   411         // The same function is called, whether GetContext fails synchronously
       
   412         // or asynchronously.
       
   413         GetContextCompleted( NULL, KErrNotFound );
       
   414         }
       
   415    	iDeleteTagListArray = new (ELeave) CArrayPtrFlat<MNssTag>(50);
       
   416    	
       
   417     }
       
   418 
       
   419 // ---------------------------------------------------------
       
   420 // CNssContactHandlerImplementation::NewL
       
   421 // Two-phased constructor.
       
   422 // ---------------------------------------------------------
       
   423 // 
       
   424 CNssContactHandlerImplementation* CNssContactHandlerImplementation::NewL( )
       
   425     {
       
   426     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::NewL" );
       
   427     CNssContactHandlerImplementation* self = new (ELeave) CNssContactHandlerImplementation();
       
   428 
       
   429     CleanupStack::PushL( self );
       
   430     self->ConstructL();
       
   431     CleanupStack::Pop( self );
       
   432 
       
   433     return self;
       
   434     }
       
   435 
       
   436 // ---------------------------------------------------------
       
   437 // CNssContactHandlerImplementation::~CNssContactHandlerImplementation
       
   438 // Destructor
       
   439 // ---------------------------------------------------------
       
   440 // 
       
   441 CNssContactHandlerImplementation::~CNssContactHandlerImplementation()
       
   442    {
       
   443    RUBY_DEBUG0( "CNssContactHandlerImplementation::~CNssContactHandlerImplementation FIXED" );
       
   444    
       
   445    iFSession.Close();
       
   446 
       
   447    iEventArray.Close();     // Close the RArray
       
   448 
       
   449    delete iDataSyncWatcher;
       
   450    delete iBackupObserver;
       
   451    
       
   452    if ( iSyncBackupWaiter != NULL )
       
   453        {
       
   454        if( iSyncBackupWaiter->IsStarted() ) 
       
   455            {
       
   456            iSyncBackupWaiter->AsyncStop();
       
   457            }
       
   458        }
       
   459    delete iSyncBackupWaiter;
       
   460    
       
   461    if ( iContactWaiter != NULL )
       
   462        {
       
   463        if( iContactWaiter->IsStarted() ) 
       
   464            {
       
   465            iContactWaiter->AsyncStop();
       
   466            }
       
   467        }
       
   468    
       
   469 
       
   470    delete iContactWaiter;
       
   471    delete iDeletionSimulator;
       
   472    delete iPeriodicHandleEventTimer;
       
   473 
       
   474    delete iContext;
       
   475 
       
   476    delete iVasDbManager;
       
   477    RProperty::Delete( KSINDUID, ETrainingContactsState );
       
   478    iBusyProperty.Close();
       
   479    
       
   480    delete iRepositoryObserver;
       
   481    delete iRepository;
       
   482    
       
   483    delete iTrainingParams;
       
   484    iTagArray.ResetAndDestroy();
       
   485 
       
   486    for( TInt k( 0 ); k < iContactQueue.Count(); k++ )
       
   487        {
       
   488        delete iContactQueue[k].iTitle;
       
   489        }
       
   490    iContactQueue.Close();
       
   491 
       
   492    iDelList.Close();
       
   493    iAddList.Close();
       
   494    iRemoveIconList.Close();
       
   495    iVoiceTagAddedList.Close();
       
   496    iSwappedLanguages.Close();
       
   497    
       
   498    DisconnectFromPhonebook();
       
   499    
       
   500 #ifdef __SIND_EXTENSIONS
       
   501     
       
   502     for ( TInt i(0); i < iExtensionList.Count(); i++ )
       
   503        {
       
   504        delete iExtensionList[i].iText;
       
   505        }
       
   506 
       
   507     iExtensionList.Close();
       
   508 #endif // __SIND_EXTENSIONS    
       
   509    }
       
   510 
       
   511 // ---------------------------------------------------------
       
   512 // CNssContactHandlerImplementation::HandleEventL
       
   513 // Called by phonebook handler when a contact database event
       
   514 // occurs
       
   515 // ---------------------------------------------------------
       
   516 //
       
   517 void CNssContactHandlerImplementation::HandleEventL( const TPhonebookEvent& aEvent )
       
   518     {
       
   519     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::HandleEventL" );
       
   520     RUBY_DEBUG2( "CNssContactHandlerImplementation::HandleEventL(). Contact id [%d], event type [%d]", aEvent.iContactId, aEvent.iType );
       
   521     
       
   522     if ( aEvent.iType == EContactChanged ||
       
   523          aEvent.iType == EContactDeleted ||
       
   524          aEvent.iType == EContactAdded   ||
       
   525          aEvent.iType == EUnknownChanges )
       
   526         {
       
   527         if( !CausedByVoiceTagAddition( aEvent ) )
       
   528         	{
       
   529         	// Check if operations can be finished
       
   530         	// There should be enough disk space
       
   531         	if ( NoDiskSpace() )
       
   532         	    {
       
   533         	    RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL not enough disk space, disabling event handling" );
       
   534         	    DisableEventHandling();
       
   535         	    }
       
   536         	else
       
   537         	    {
       
   538                 TInt errProp = iBusyProperty.Set( EContactsTraining );
       
   539                 if ( errProp != KErrNone )
       
   540                     {
       
   541                     RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", 
       
   542                                  errProp );
       
   543                     User::Leave( errProp )  ;
       
   544                     }
       
   545         	    UpdatePeriodicActionVars();
       
   546 	            iEventArray.Append( aEvent );
       
   547 
       
   548     	        if ( iState == ECHIdle )
       
   549         	     	{
       
   550             	    RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL() iState == ECHIdle => DoHandleEvent" );
       
   551 
       
   552             	    // Process the first new event from the queue
       
   553             	    TRAPD( err, DoHandleEventsL() );
       
   554             	    RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleEventL. Assert would fail and Panic IF err != KErrNone. err [%d]", err );
       
   555                     RUBY_ASSERT_DEBUG( err == KErrNone, User::Panic( KFile, __LINE__ ) );
       
   556                 
       
   557                     if ( err != KErrNone )
       
   558                         {
       
   559                         RUBY_ERROR1( "CNssContactHandlerImplementation::HandleEventL. Error [%d] in DoHandleEventsL", err );
       
   560                         }
       
   561                     }
       
   562          	    else 
       
   563 	        	    {
       
   564 	        	    RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleEventL() iState == [%d] => Do not handle the event right now", iState );
       
   565 	        	    } // if iState else
       
   566         	    }
       
   567             }  // if caused be voice tag addition
       
   568 	    else
       
   569         	{
       
   570 			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() );
       
   571 			if ( ( iVoiceTagAddedList.Count() == 0 ) && ( iState == ECHIdle ) && ( iEventArray.Count() == 0 ) )  
       
   572 			    {
       
   573 			    RUBY_DEBUG0( "HandleEventL No more voice icon events expected, nothing pending." );
       
   574 			    }
       
   575 			else 
       
   576 			    {
       
   577 			    RUBY_DEBUG1( "HandleEventL [%d] voice icon events are still expected", iVoiceTagAddedList.Count() );
       
   578 			    }
       
   579         	}
       
   580         }
       
   581     else if ( aEvent.iType == EStoreRestoreBeginning )
       
   582         {
       
   583         RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL restore begin" );
       
   584         iRestoreRunning = ETrue; // set to differentiate ending of restore or backup
       
   585         }
       
   586     else if ( aEvent.iType == EStoreBackupRestoreCompleted && iRestoreRunning )
       
   587         {
       
   588         RUBY_DEBUG0( "CNssContactHandlerImplementation::HandleEventL restore end" );
       
   589         // Set value to make full resync
       
   590         SetFullResyncCrFlagL( ETrue );
       
   591         iRestoreRunning = EFalse;
       
   592         } // if event type
       
   593     }
       
   594 
       
   595 
       
   596 
       
   597 // ---------------------------------------------------------
       
   598 // CNssContactHandlerImplementation::DoHandleEventL
       
   599 // Process the Event from phonebook
       
   600 // ---------------------------------------------------------
       
   601 //
       
   602 void CNssContactHandlerImplementation::DoHandleEventsL()
       
   603 	{
       
   604 	RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoHandleEventsL" );
       
   605 	RUBY_DEBUG1( "CNssContactHandlerImplementation::DoHandleEventsL, eventArray size [%d]", iEventArray.Count() );
       
   606 
       
   607 	// If there is no lengthy higher level routine executed
       
   608 	if( !PeriodicAction() ) 
       
   609 		{
       
   610 		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL !PeriodicAction()" );
       
   611 		if ( iHandlerEnabled )
       
   612         	{
       
   613    	    	if ( IsFullResyncNeeded() )
       
   614        		   	{
       
   615        			RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Full resync if needed. Setting iState to ECHFullResync" );
       
   616 				SetState( ECHFullResync );
       
   617            		
       
   618             	iEventArray.Close();
       
   619 	
       
   620    	        	FullResyncStart();
       
   621        	    	}
       
   622    			else
       
   623        	   		{
       
   624        			RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Full resync if NOT needed. Setting iState to ECHHandlingNormalChanges" );
       
   625        			SetState( ECHHandlingNormalChanges );
       
   626 
       
   627        			// There are 3 phases in handling events:
       
   628 	          	// (1) Make two lists:
       
   629    	     	 	//  * Names to be added
       
   630        	  		//  * Names to be deleted
       
   631           		CollectAddRemoveListsL();
       
   632 
       
   633    	      		// (2) Delete the names to be deleted. This operation is asynchronous.
       
   634        	  		DoRemoveNamesL();
       
   635 
       
   636        			// (3) After removing names, add the names to be added.
       
   637                 // DoRemoveNamesL() starts the step (3)
       
   638          		}
       
   639     		}
       
   640     	else 
       
   641     		{
       
   642     		// In UREL, empty "else" branch will be eliminated by the compiler
       
   643 			RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() Handler was disabled" );
       
   644     		}
       
   645 		
       
   646    		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL() completed" );
       
   647 		
       
   648 		}// if !PeriodicAction
       
   649 		
       
   650 	else 
       
   651 		{
       
   652 		// In UREL, empty "else" branch will be eliminated by the compiler
       
   653 		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventsL PeriodicAction detected, DoHandleEventsL omitted" );
       
   654 		}
       
   655 		
       
   656     }
       
   657 
       
   658 // ---------------------------------------------------------
       
   659 // CNssContactHandlerImplementation::DeleteTagCompleted
       
   660 // Called when the deletion of a tag is completed successfully
       
   661 // ---------------------------------------------------------
       
   662 //
       
   663 void CNssContactHandlerImplementation::DeleteTagCompleted( TInt aErrorCode )
       
   664 	{
       
   665 	if( aErrorCode == KErrNone )
       
   666 	    {
       
   667     	RUBY_DEBUG1( "CNssContactHandlerImplementation::DeleteTagCompleted. Assert iState == ECHHandlingNormalChanges. iState [%d]", iState);
       
   668         RUBY_ASSERT_DEBUG( iState == ECHHandlingNormalChanges, User::Panic( KFile, __LINE__ ) );	    
       
   669 	    }
       
   670     else
       
   671         {
       
   672     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteTagCompleted: tag deletion failed" );
       
   673     	
       
   674     	iNormalChangesError = aErrorCode;
       
   675         }	
       
   676     
       
   677     DoRemoveNamesAfterDeleteTagCompleted();
       
   678 	}
       
   679 
       
   680 // -----------------------------------------------------------------
       
   681 // CNssContactHandlerImplementation::GetTagCompleted
       
   682 // Called by tag manager when getting of a tag list completes
       
   683 // -----------------------------------------------------------------
       
   684 //
       
   685 void CNssContactHandlerImplementation::GetTagListCompleted(
       
   686     MNssTagListArray* aTagList, TInt aErrorCode )
       
   687     {
       
   688     if( aErrorCode == KErrNone )
       
   689         {
       
   690         if ( iState == ECHHandlingNormalChanges )
       
   691             {
       
   692             DoRemoveNamesAfterGetTagList( aTagList );
       
   693             }
       
   694         else
       
   695             {
       
   696             RUBY_DEBUG1( "CNssContactHandlerImplementation::GetTagListCompleted : Unknown state(%d)\n", iState );
       
   697     		}
       
   698         }
       
   699     else
       
   700         {
       
   701         RUBY_DEBUG1( "CNssContactHandlerImplementation::GetTagListCompleted. Error [%d]", aErrorCode );
       
   702         
       
   703         TRAPD( err, DoHandleEventFailedL() );    // Process the event fail
       
   704         if ( err != KErrNone )
       
   705             {
       
   706             RUBY_ERROR1( "CNssContactHandlerImplementation::GetTagFailed. Error [%d] in DoHandleEventFailedL", err );
       
   707             }
       
   708         }
       
   709 	}
       
   710 
       
   711 
       
   712 // ---------------------------------------------------------
       
   713 // CNssContactHandlerImplementation::DisableEventHandling
       
   714 // Disables the event handling. Is used in case of unrecoverable error
       
   715 // ---------------------------------------------------------
       
   716 //
       
   717 void CNssContactHandlerImplementation::DisableEventHandling()
       
   718    {
       
   719    RUBY_DEBUG0( "CNssContactHandlerImplementation::DisableEventHandling" );
       
   720    iHandlerEnabled = EFalse;
       
   721    }
       
   722 
       
   723 // ---------------------------------------------------------
       
   724 // CNssContactHandlerImplementation::EnableEventHandling
       
   725 // Enables event handling
       
   726 //---------------------------------------------------------
       
   727 //
       
   728 void CNssContactHandlerImplementation::EnableEventHandling()
       
   729    {
       
   730    RUBY_DEBUG0( "CNssContactHandlerImplementation::EnableEventHandling" );
       
   731    iHandlerEnabled = ETrue;
       
   732    }
       
   733 
       
   734 
       
   735 // ---------------------------------------------------------
       
   736 // CNssContactHandlerImplementation::GetContextListCompleted
       
   737 // Called by tag manager when GetContextList() completes successfully
       
   738 //---------------------------------------------------------
       
   739 //
       
   740 void CNssContactHandlerImplementation::GetContextListCompleted(
       
   741     MNssContextListArray*  /*aContextList*/, TInt /*aErrorCode*/ )
       
   742     {
       
   743     RUBY_ERROR0( "CNssContactHandlerImplementation::GetContextListCompleted - this function should never be called." );
       
   744     }
       
   745 
       
   746 // ---------------------------------------------------------
       
   747 // CNssContactHandlerImplementation::CheckErrorSigns
       
   748 // Compares client data (saved in VAS context)
       
   749 // to state of the phonebook to find out if
       
   750 // full synchronization is needed.
       
   751 //
       
   752 // If full resync is needed initiates it by saving into the event queue
       
   753 // special 'full resync event'
       
   754 //---------------------------------------------------------
       
   755 //
       
   756 void CNssContactHandlerImplementation::CheckErrorSigns()
       
   757     {
       
   758     
       
   759     RUBY_DEBUG0( "CNssContactHandlerImplementation::CheckErrorSigns" );
       
   760     TBool errorFound( EFalse );
       
   761     // Full resync, if this is the first time we launch.
       
   762     //              if the UI language has changed.
       
   763     //              if VAS Db and Contact Db time stamps do not match
       
   764     if  ( iClientData.iLanguage == ELangNone ||
       
   765         iClientData.iLanguage != User::Language() )
       
   766         {
       
   767         RUBY_DEBUG0( "CNssContactHandlerImplementation::CheckErrorSigns language changed." );
       
   768         errorFound = ETrue;
       
   769         }
       
   770     else
       
   771         {
       
   772         // check that is full resyncronization needed
       
   773         iRepository->Get( KSRSFFullResyncNeeded, errorFound );
       
   774         }
       
   775         
       
   776     if ( errorFound )
       
   777         {
       
   778         TPhonebookEvent event;
       
   779        	event.iType = ENullEvent;
       
   780        	event.iContactId = 0;
       
   781         
       
   782         if ( iEventArray.Append( event ) != KErrNone )
       
   783             {
       
   784             RUBY_ERROR0( "CNssContactHandlerImplementation::CheckErrorSigns Failed to append to iEventArray" );
       
   785             }        
       
   786         }
       
   787     
       
   788     }
       
   789 
       
   790 // ---------------------------------------------------------
       
   791 // CNssContactHandlerImplementation::GetContextCompleted
       
   792 // Called by tag manager, when GetContext() completes successfully
       
   793 //
       
   794 // Depending on the contact handler state, continues full resync sequence or
       
   795 // sets the idle state
       
   796 //---------------------------------------------------------
       
   797 //
       
   798 void CNssContactHandlerImplementation::GetContextCompleted(
       
   799     MNssContext* aContext, TInt aErrorCode )
       
   800 	{
       
   801 	if( aErrorCode == KErrNone )
       
   802 	    {
       
   803         RUBY_ASSERT_DEBUG( iState == ECHInitializing || iState == ECHFullResync,
       
   804                         User::Panic( KFile, __LINE__ ) );
       
   805 
       
   806     	RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted" );
       
   807         iContext = aContext;
       
   808         TRAPD(err,
       
   809 
       
   810             iClientData.InternalizeL( iContext->ClientData() );
       
   811 
       
   812     	    if ( iState == ECHInitializing )
       
   813     	        {
       
   814     	        // If there are warning sings of error,
       
   815     	        // do full resynchronization.
       
   816     	        CheckErrorSigns();
       
   817 
       
   818     	        SetState( ECHIdle );
       
   819     	        RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted. Setting iState to ECHIdle" );
       
   820     		
       
   821     	        if ( iEventArray.Count() ) // Verify whether more events in the queue
       
   822     	            {
       
   823     	            
       
   824     	    		RUBY_DEBUG1( "CNssContactHandlerImplementation::GetContextCompletedhere are still [%d] events in the queue. Call DoHandleEvents for them", iEventArray.Count() );
       
   825     				
       
   826     	            DoHandleEventsL(); // Process the 1st new event from the queue
       
   827     	            }
       
   828     	        }
       
   829     	    else if ( iState == ECHFullResync )
       
   830     	        {
       
   831     	        TRAPD( error,  FullResyncCreateChangesL() );
       
   832     	        if( error != KErrNone ) 
       
   833     	            {
       
   834     	            RUBY_ERROR1( "FullResyncCreateChangesL failed with [%d]. Panic, nothing can be done", error );
       
   835     	            RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) );
       
   836     	            }
       
   837     	        }
       
   838     	    else 
       
   839     	    	{
       
   840     	    	RUBY_ERROR0( "CNssContactHandlerImplementation::GetContextCompleted Unexpected state" );
       
   841     	    	RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) );
       
   842     	    	}
       
   843     	    );  // TRAPD
       
   844     	if( err != KErrNone ) 
       
   845     		{
       
   846     		RUBY_ERROR1( "CNssContactHandlerImplementation::GetContextCompleted Leaves with [%d] inside", err );
       
   847     		}
       
   848         RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContextCompleted completed" );	    
       
   849 	    }
       
   850 	    
       
   851 	else // aErrorCode != KErrNone
       
   852 	    {
       
   853         RUBY_ASSERT_DEBUG( iState == ECHInitializing || iState == ECHFullResync,
       
   854                         User::Panic( KFile, __LINE__ ) );
       
   855 
       
   856         if ( iState == ECHInitializing )
       
   857             {
       
   858             iHaveWeEverSynced = EFalse;
       
   859             SetState ( ECHFullResync );
       
   860             FullResyncStart();
       
   861             }	    
       
   862 	    }
       
   863 
       
   864 	}
       
   865 
       
   866 // ---------------------------------------------------------
       
   867 // CNssContactHandlerImplementation::SaveContextCompleted
       
   868 // Called when SaveContext() completes successfully
       
   869 //---------------------------------------------------------
       
   870 //
       
   871 void CNssContactHandlerImplementation::SaveContextCompleted( TInt aErrorCode )
       
   872     {
       
   873     if( aErrorCode == KErrNone )
       
   874         {
       
   875         RUBY_ASSERT_DEBUG( iState == ECHInitializing || 
       
   876                         iState == ECHFullResync,
       
   877                         User::Panic( KFile, __LINE__ ) );
       
   878 
       
   879         iHaveWeEverSynced = ETrue;
       
   880 
       
   881         if ( iState == ECHInitializing )
       
   882             {
       
   883             // Retrive the Context to get the new ContextId from VasDB
       
   884             iContextManager->GetContext( this, KNssCHNameDialContext );
       
   885             }
       
   886         else if ( iState == ECHFullResync )
       
   887             {
       
   888             TRAPD( error, FullResyncCreateChangesL() );
       
   889             if ( error != KErrNone ) 
       
   890                 {
       
   891                 RUBY_ERROR1( "SaveContextCompleted Failed to create full resync changes. Critical error [%d]", 
       
   892                             error );
       
   893                 DisableEventHandling();
       
   894                 }  // if error != KErrNone
       
   895             }  // else if ( iState == ECHFullResync )
       
   896         else 
       
   897         	{
       
   898         	// we should never be here, because the condition is checked 
       
   899         	// by ASSERT_DEBUG at the start of the function
       
   900         	RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted Unexpected state!" );
       
   901         	}        
       
   902         }
       
   903         
       
   904     else // aErrorCode != KErrNone
       
   905         {
       
   906         // Failed to initialize will collect the events forever and will never process them
       
   907         // Will try to initialize again after reboot
       
   908         RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted failed. Staying forever in ECHFullResync" );
       
   909         RUBY_ERROR0( "CNssContactHandlerImplementation::SaveContextCompleted failed. Reboot to try initializing again" );
       
   910         DisableEventHandling();        
       
   911         }
       
   912     }
       
   913 
       
   914 // ---------------------------------------------------------
       
   915 // CNssContactHandlerImplementation::SaveTagCompleted
       
   916 // Called when SaveTag() completes
       
   917 //---------------------------------------------------------
       
   918 //
       
   919 void CNssContactHandlerImplementation::SaveTagCompleted( TInt aErrorCode )
       
   920     {
       
   921     RUBY_ASSERT_DEBUG( iState == ECHHandlingNormalChanges, User::Panic( KFile, __LINE__ ) );
       
   922     
       
   923     DoAddNamesSaveTagCompleted( aErrorCode );
       
   924     }
       
   925 
       
   926 // ---------------------------------------------------------
       
   927 // CNssContactHandlerImplementation::GetContactTitleL
       
   928 // Populates aTitle with either "FirstName LastName" or "CompanyName".
       
   929 // "CompanyName" is given only if both First and Last names are missing.
       
   930 //---------------------------------------------------------
       
   931 //
       
   932 HBufC* CNssContactHandlerImplementation::GetContactTitleL( TContactItemId aContactId, 
       
   933                                                            TBool aUseDefaultOrder,
       
   934                                                            TBool& aBothFirstAndLastFound,
       
   935                                                            TVasTagType& aTagType )
       
   936 	{
       
   937 	RUBY_DEBUG_BLOCKL( "CNssContactHandlerImplementation::GetContactTitleL" );
       
   938     // Find out if lastname-firstname should be used
       
   939     TBool useLastFirstOrder = EFalse;
       
   940     
       
   941     // By default, this function returns firstname and/or lastname
       
   942     aTagType = ETagTypeName;
       
   943 
       
   944     if ( aUseDefaultOrder )
       
   945         {
       
   946         useLastFirstOrder = SwapNameOrder();
       
   947         }
       
   948     else
       
   949         {
       
   950         useLastFirstOrder = !SwapNameOrder();
       
   951         }
       
   952     WaitUntilNoSyncBackupIsRunning();
       
   953     ReadContactL( aContactId );
       
   954     
       
   955     HBufC* firstNameText = NULL;
       
   956     HBufC* lastNameText = NULL;
       
   957     HBufC* companyNameText = NULL;
       
   958     
       
   959     TInt firstLength( 0 );
       
   960     TInt lastLength( 0 );
       
   961     TInt companyLength( 0 );    
       
   962     
       
   963     TInt error = KErrNone;
       
   964     
       
   965     // name reading fields are used in Japanese
       
   966 	TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdFirstNameReading ) );
       
   967     if ( error == KErrNotFound ) 
       
   968         {
       
   969         // not found
       
   970         TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdFirstName ) );
       
   971         }
       
   972         
       
   973     if ( error == KErrNone )
       
   974         {
       
   975         firstNameText = iPbkHandler->TextL().AllocLC();
       
   976         TrimName( firstNameText );
       
   977         firstLength = firstNameText->Length();
       
   978         if ( firstLength == 0 )
       
   979             {
       
   980             CleanupStack::PopAndDestroy( firstNameText );
       
   981             firstNameText = NULL;
       
   982             }
       
   983         }
       
   984 
       
   985     TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdLastNameReading ) );
       
   986     if ( error == KErrNotFound ) 
       
   987         {
       
   988         // not found
       
   989         TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdLastName ) );
       
   990         }
       
   991         
       
   992     if ( error == KErrNone )
       
   993         {
       
   994         lastNameText = iPbkHandler->TextL().AllocLC();
       
   995         TrimName( lastNameText );
       
   996         lastLength = lastNameText->Length();
       
   997         if ( lastLength == 0 )
       
   998             {
       
   999             CleanupStack::PopAndDestroy( lastNameText );
       
  1000             lastNameText = NULL;
       
  1001             }        
       
  1002         }
       
  1003 
       
  1004     TRAP( error, iPbkHandler->FindFieldL( EPbkFieldIdCompanyName ) );
       
  1005     
       
  1006     if ( error == KErrNone )
       
  1007         {
       
  1008         companyNameText = iPbkHandler->TextL().AllocLC();
       
  1009         TrimName( companyNameText );
       
  1010         companyLength = companyNameText->Length();
       
  1011         if ( companyLength == 0 )
       
  1012             {
       
  1013             CleanupStack::PopAndDestroy( companyNameText );
       
  1014             companyNameText = NULL;
       
  1015             }         
       
  1016         }
       
  1017 
       
  1018     // Use third parameter to return a flag if both lastname and firstname are found
       
  1019     if ( ( firstLength > 0 ) && ( lastLength > 0 ) )
       
  1020         {
       
  1021         aBothFirstAndLastFound = ETrue;
       
  1022         }
       
  1023     else
       
  1024         {
       
  1025         aBothFirstAndLastFound = EFalse;
       
  1026         }
       
  1027 
       
  1028     HBufC* title( NULL );
       
  1029 
       
  1030 #ifdef __SIND_EXTENSIONS
       
  1031     if ( firstLength + lastLength > 0 )
       
  1032         {
       
  1033         TInt spaceForIndexes( 0 );
       
  1034         // Find out how much more space is needed for "training indexes"
       
  1035         if ( aBothFirstAndLastFound )
       
  1036             {
       
  1037             spaceForIndexes = 2 * KTrainingIndexSize;
       
  1038             }
       
  1039         else
       
  1040             {
       
  1041             spaceForIndexes = KTrainingIndexSize;
       
  1042             }
       
  1043             
       
  1044         title = HBufC::NewL( firstLength + lastLength + spaceForIndexes );
       
  1045         
       
  1046         // Check the order 
       
  1047         if ( useLastFirstOrder )
       
  1048             {
       
  1049             // Lastname-firstname
       
  1050             if ( lastNameText ) 
       
  1051                 {
       
  1052                 AppendName( title, lastNameText );
       
  1053                 }
       
  1054             
       
  1055             if ( firstNameText )
       
  1056                 {
       
  1057                 AppendName( title, firstNameText );
       
  1058                 }
       
  1059             }
       
  1060         else
       
  1061             {
       
  1062             // Firstname-lastname
       
  1063             if ( firstNameText )
       
  1064                 {
       
  1065                 AppendName( title, firstNameText );
       
  1066                 }
       
  1067                 
       
  1068             if ( lastNameText ) 
       
  1069                 {
       
  1070                 AppendName( title, lastNameText );
       
  1071                 }
       
  1072             }
       
  1073         }
       
  1074     // Try company name, if the personal name fails.
       
  1075     else if ( companyLength > 0 )
       
  1076         {
       
  1077         aTagType = ETagTypeCompanyName;
       
  1078         title = HBufC::NewL( companyLength + KTrainingIndexSize );
       
  1079         AppendName( title, companyNameText );
       
  1080         }
       
  1081 #else
       
  1082     // Use personal name, if there is one.
       
  1083     if ( firstLength + lastLength > 0 )
       
  1084         {
       
  1085         title = HBufC::NewL( firstLength + 1 + lastLength );
       
  1086 
       
  1087         // Check the order 
       
  1088         if ( useLastFirstOrder )
       
  1089             {
       
  1090             // Lastname-firstname
       
  1091             if ( lastNameText ) 
       
  1092                 {
       
  1093                 title->Des().Append( lastNameText->Des() );
       
  1094 
       
  1095                 if ( firstNameText )
       
  1096                     {
       
  1097                     // Separator marker
       
  1098                     title->Des().Append( iSeparator );
       
  1099                     }
       
  1100                 }
       
  1101             
       
  1102             if ( firstNameText )
       
  1103                 {
       
  1104                 title->Des().Append( firstNameText->Des() );
       
  1105                 }
       
  1106 
       
  1107 
       
  1108             }
       
  1109         else
       
  1110             {
       
  1111             // Firstname-lastname
       
  1112             if ( firstNameText ) 
       
  1113                 {
       
  1114                 title->Des().Append( firstNameText->Des() );
       
  1115 
       
  1116                 if ( lastNameText )
       
  1117                     {
       
  1118                     // Separator marker
       
  1119                     title->Des().Append( iSeparator );
       
  1120                     }
       
  1121                 }
       
  1122                 
       
  1123             if ( lastNameText )
       
  1124                 {
       
  1125                 title->Des().Append( lastNameText->Des() );
       
  1126                 }
       
  1127 
       
  1128             }
       
  1129         }
       
  1130     // Try company name, if the personal name fails.
       
  1131     else if ( companyLength > 0 )
       
  1132         {
       
  1133         aTagType = ETagTypeCompanyName;
       
  1134         title = HBufC::NewL( companyLength );
       
  1135         title->Des().Append( companyNameText->Des() );
       
  1136         }
       
  1137 #endif // __SIND_EXTENSIONS
       
  1138     // It is possible to make a contact without a name.
       
  1139     else
       
  1140         {
       
  1141         RUBY_DEBUG1( "CNssContactHandlerImplementation::ContactTitle: No name, ContactId=[%d]" , aContactId );
       
  1142         }
       
  1143 
       
  1144     if ( companyNameText )
       
  1145         {
       
  1146         CleanupStack::PopAndDestroy( companyNameText );
       
  1147         }
       
  1148         
       
  1149     if ( lastNameText )
       
  1150         {
       
  1151         CleanupStack::PopAndDestroy( lastNameText );
       
  1152         }
       
  1153         
       
  1154     if ( firstNameText )
       
  1155         {
       
  1156         CleanupStack::PopAndDestroy( firstNameText );
       
  1157         }
       
  1158     
       
  1159     return title;
       
  1160 	}
       
  1161 
       
  1162 
       
  1163 // ---------------------------------------------------------
       
  1164 // CNssContactHandlerImplementation::SwapNameOrder
       
  1165 // Returns ETrue if name order for current UI language should
       
  1166 // be lastname-firstname, EFalse otherwise
       
  1167 //---------------------------------------------------------
       
  1168 //
       
  1169 TBool CNssContactHandlerImplementation::SwapNameOrder()
       
  1170     {
       
  1171     // Find UI language
       
  1172     TLanguage uiLanguage = User::Language();
       
  1173 
       
  1174     if ( iSwappedLanguages.Find( uiLanguage ) == KErrNotFound )
       
  1175         {
       
  1176         return EFalse;
       
  1177         }
       
  1178     else
       
  1179         {
       
  1180         return ETrue;
       
  1181         }
       
  1182     }
       
  1183 
       
  1184 
       
  1185 // ---------------------------------------------------------
       
  1186 // CNssContactHandlerImplementation::GetContactNicknameL
       
  1187 // Returns nickname for a given contact
       
  1188 //---------------------------------------------------------
       
  1189 //
       
  1190 HBufC* CNssContactHandlerImplementation::GetContactNicknameL( TContactItemId aContactId )
       
  1191 	{
       
  1192 	RUBY_DEBUG_BLOCKL( "CNssContactHandlerImplementation::GetContactNicknameL" );
       
  1193 	WaitUntilNoSyncBackupIsRunning();
       
  1194     ReadContactL( aContactId );
       
  1195 
       
  1196 	// Get the nick name
       
  1197 	iPbkHandler->FindFieldL( EPbkFieldIdSecondName );
       
  1198 
       
  1199     // Get the length of the additional name.
       
  1200     TInt nickLength = iPbkHandler->TextL().Length();
       
  1201 
       
  1202     HBufC* title = NULL;
       
  1203 
       
  1204 #ifdef __SIND_EXTENSIONS
       
  1205     // Use personal name, if there is one.
       
  1206     if ( nickLength > 0 )
       
  1207         {
       
  1208         title = HBufC::NewL( nickLength + KTrainingIndexSize );
       
  1209         
       
  1210         HBufC* nickName = iPbkHandler->TextL().AllocL();
       
  1211         TrimName( nickName );
       
  1212         AppendName( title, nickName );
       
  1213         delete nickName;
       
  1214         }
       
  1215 #else
       
  1216     // Use personal name, if there is one.
       
  1217     if ( nickLength > 0 )
       
  1218         {
       
  1219         title = HBufC::NewL( nickLength );
       
  1220         title->Des().Append( iPbkHandler->TextL() );
       
  1221         }
       
  1222 #endif // __SIND_EXTENSIONS
       
  1223 
       
  1224     return title;
       
  1225 	}
       
  1226 
       
  1227 // ---------------------------------------------------------
       
  1228 // CNssContactHandlerImplementation::DoHandleEventFailed
       
  1229 // Routine to process when handling the contact event failed
       
  1230 //---------------------------------------------------------
       
  1231 //
       
  1232 void CNssContactHandlerImplementation::DoHandleEventFailedL()
       
  1233     {
       
  1234     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL start" );
       
  1235     
       
  1236     // Errors are normal if user deletes contact without a voice tag
       
  1237     // E.g. because this contact had no number
       
  1238     if( ( iDeleteTagListArray != NULL ) && ( iDeleteTagListArray->Count() > 0 ) ) 
       
  1239     	{
       
  1240     	// simulate successful deletion, just return no tags for further deletions
       
  1241     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL Deletion failed. Simulating successful empty deletion" );
       
  1242     	iDeletionSimulator->Call();
       
  1243     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL Called deletion simulator" );
       
  1244     	}
       
  1245     else 
       
  1246     	{
       
  1247     	
       
  1248 	    // Try full resync couple of times. If still fails, stop contact handler. 
       
  1249 	    // When the phone is booted for the next time, try resyncing again
       
  1250     	if( iConsecutiveErrorFullResync < KMaxConsecutiveErrorFullResync ) 
       
  1251     		{
       
  1252     		iConsecutiveErrorFullResync++;
       
  1253     		RUBY_DEBUG1( "CNssContactHandlerImplementation::DoHandleEventFailedL Trying full resync for the [%d] time", iConsecutiveErrorFullResync);
       
  1254     		// clean structures that might be already full
       
  1255     		iTagArray.ResetAndDestroy();
       
  1256 
       
  1257 		    for( TInt k( 0 ); k < iContactQueue.Count(); k++ )
       
  1258 		    	{
       
  1259 		       	delete iContactQueue[k].iTitle;
       
  1260 		       	}
       
  1261 		   	iContactQueue.Close();
       
  1262 
       
  1263 		   	iDelList.Close();
       
  1264 		   	iAddList.Close();
       
  1265 		   	iVoiceTagAddedList.Close();
       
  1266     		// generate full resync event
       
  1267     		TPhonebookEvent event;
       
  1268         	event.iType = ENullEvent;
       
  1269         	event.iContactId = 0;
       
  1270         	iEventArray.Insert( event, 0 );
       
  1271         	// will start full resync
       
  1272         	iTagArray.ResetAndDestroy();
       
  1273         	iSaveCallbackCounter = 0; // simulate completed action
       
  1274         	RUBY_DEBUG0( "DoHandleEventFailedL No leaving in the FullResync branch, retrying" );
       
  1275         	DoHandleEventsL(); // No leaving in the FullResync branch
       
  1276     		} 
       
  1277     	else
       
  1278 	    	{
       
  1279 	    	RUBY_ERROR1( "CNssContactHandlerImplementation::DoHandleEventFailedL Tried full resync for %d times. Disabling contact handler until reboot", KMaxConsecutiveErrorFullResync );
       
  1280     		// Tried several consecutive resyncs, didn't help
       
  1281     		// Disable itself until reboot
       
  1282     		DisableEventHandling();
       
  1283     		}  
       
  1284     	}  // if deletion else
       
  1285     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoHandleEventFailedL end" );
       
  1286     }
       
  1287 
       
  1288 // ---------------------------------------------------------
       
  1289 // CNssContactHandlerImplementation::PhonebookOrder
       
  1290 // TLinearOrder comparison function for sorting phonebook events
       
  1291 // according to their Phonebook ID.
       
  1292 //---------------------------------------------------------
       
  1293 //
       
  1294 TInt CNssContactHandlerImplementation::PhonebookOrder( const TPhonebookEvent& a1, const TPhonebookEvent& a2 )
       
  1295     {
       
  1296     if ( a1.iContactId != a2.iContactId )
       
  1297         {
       
  1298         return( a1.iContactId - a2.iContactId );
       
  1299         }
       
  1300 
       
  1301     if ( a1.iTime < a2.iTime )
       
  1302         {
       
  1303         return( -1 );
       
  1304         }
       
  1305     else if ( a1.iTime > a2.iTime )
       
  1306         {
       
  1307         return( 1 );
       
  1308         }
       
  1309     else{
       
  1310         return( 0 );
       
  1311         }
       
  1312     }
       
  1313 
       
  1314 // ---------------------------------------------------------
       
  1315 // CNssContactHandlerImplementation::IsFullResyncNeeded
       
  1316 // Checks if the event queue contains an event, which
       
  1317 // launches full resynchronization. If it does, there is
       
  1318 // no point in processing the other events.
       
  1319 // ---------------------------------------------------------
       
  1320 //
       
  1321 TBool CNssContactHandlerImplementation::IsFullResyncNeeded()
       
  1322     {
       
  1323     for( TInt k( 0 ); k < iEventArray.Count(); k++ )
       
  1324         {
       
  1325         // Null event is used inside contact handler to signal full resync.
       
  1326         if ( iEventArray[k].iType == ENullEvent
       
  1327              || iEventArray[k].iType == EStoreBackupRestoreCompleted 
       
  1328              || iEventArray[k].iType == EUnknownChanges )
       
  1329             {
       
  1330             return ETrue;
       
  1331             }
       
  1332         }
       
  1333 
       
  1334     return EFalse;
       
  1335     }
       
  1336 
       
  1337 // ---------------------------------------------------------
       
  1338 // CNssContactHandlerImplementation::CollectAddRemoveListsL
       
  1339 // Given a list of Contact DB Events, this function compiles
       
  1340 // a list of ids to-be-deleted and ids to-be-added.
       
  1341 // A Contact DB Event contains:
       
  1342 //  * Contact ID
       
  1343 //  * Event type (added, modified, removed)
       
  1344 // ---------------------------------------------------------
       
  1345 //
       
  1346 void CNssContactHandlerImplementation::CollectAddRemoveListsL()
       
  1347     {
       
  1348     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::CollectAddRemoveListsL" );
       
  1349     RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). iEventArray.Count [%d]", iEventArray.Count() );
       
  1350     TInt k( 0 );
       
  1351 	
       
  1352 	RUBY_ASSERT_DEBUG( iAddList.Count() == 0, User::Panic( KFile, __LINE__ ) );
       
  1353     RUBY_ASSERT_DEBUG( iDelList.Count() == 0, User::Panic( KFile, __LINE__ ) );
       
  1354 
       
  1355     // We collect two lists:
       
  1356     //  * Contacts to be deleted.
       
  1357     //  * Contacts to be added.
       
  1358 
       
  1359     TLinearOrder<TPhonebookEvent> order( PhonebookOrder );
       
  1360 
       
  1361     // Sort events according to the phonebook ID. This way, the events
       
  1362     // modifying the same name are sequentially.
       
  1363     iEventArray.Sort( order );
       
  1364 	
       
  1365 
       
  1366     // If several events happen for the same contact, fuse them into one event.
       
  1367     for ( k = 0; k < iEventArray.Count() - 1; k++ )
       
  1368         {
       
  1369         if ( iEventArray[k].iContactId == iEventArray[k+1].iContactId )
       
  1370             {
       
  1371             // Sorting should have preserved the order of the events
       
  1372             RUBY_ASSERT_DEBUG(iEventArray[k+1].iTime >= iEventArray[k].iTime, User::Panic( KFile, __LINE__ ) );
       
  1373             RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). Fusing events for ContactId [%d]", iEventArray[k].iContactId );
       
  1374             iEventArray[k+1].iType = EContactChanged;
       
  1375             iEventArray.Remove( k );
       
  1376 
       
  1377             // We have removed an element
       
  1378             k--;
       
  1379             }
       
  1380         }
       
  1381 
       
  1382 	RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). Events sorted and fused iEventArray.Count [%d]", iEventArray.Count() );
       
  1383 
       
  1384     for( k = 0; k < iEventArray.Count() && k < KMaxNamesAtOnce; k++ )
       
  1385         {
       
  1386         TPhonebookEvent* event = &iEventArray[k];
       
  1387 
       
  1388         switch ( event->iType )
       
  1389             {
       
  1390             case EContactChanged:
       
  1391                 {
       
  1392                 // events caused by saving voice tag field are skipped 
       
  1393                 // earlier, in HandleDatabaseEventL
       
  1394 
       
  1395                 // We need to delete the old name
       
  1396                 User::LeaveIfError( iDelList.Append( *event ) ); 
       
  1397                 // and after that, add the new name.
       
  1398                 User::LeaveIfError( iAddList.Append( *event ) ); 
       
  1399                 break;
       
  1400                 }
       
  1401             case EContactDeleted:
       
  1402                 {
       
  1403                 User::LeaveIfError( iDelList.Append( *event ) );
       
  1404                 break;
       
  1405                 }
       
  1406             case EContactAdded:
       
  1407                 {
       
  1408                 User::LeaveIfError( iAddList.Append( *event ) );
       
  1409                 break;
       
  1410                 }
       
  1411             default:
       
  1412                 RUBY_ERROR1( "CNssContactHandlerImplementation::CollectAddRemoveListsL() Unkown event type: %d", event->iType );
       
  1413                 break;
       
  1414             }
       
  1415         }
       
  1416 
       
  1417     if ( k < KMaxNamesAtOnce )
       
  1418         {
       
  1419         iEventArray.Close();
       
  1420         }
       
  1421     else
       
  1422         {
       
  1423     	RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL(). k >= KMaxNamesAtOnce [%d]. Deleting first KMaxNamesAtOnce events, they've been sorted into corresponding lists already",
       
  1424     	            KMaxNamesAtOnce);
       
  1425         for ( k = 0; k < KMaxNamesAtOnce; k++ )
       
  1426             {
       
  1427             iEventArray.Remove(0);
       
  1428             }
       
  1429         }
       
  1430     RUBY_DEBUG1( "CNssContactHandlerImplementation::CollectAddRemoveListsL() iEventArray.Count [%d]",
       
  1431                 iEventArray.Count());
       
  1432 	RUBY_DEBUG2( "CNssContactHandlerImplementation::CollectAddRemoveListsL iDelList.Count() [%d], iAddList.Count() [%d]", iDelList.Count(), iAddList.Count());
       
  1433     }
       
  1434 
       
  1435 // ---------------------------------------------------------
       
  1436 // CNssContactHandlerImplementation::DoRemoveNamesL
       
  1437 // Starts name removal sequence
       
  1438 // ---------------------------------------------------------
       
  1439 //
       
  1440 void CNssContactHandlerImplementation::DoRemoveNamesL()
       
  1441     {
       
  1442     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoRemoveNamesL" );
       
  1443     if ( iDelList.Count() == 0 )
       
  1444         {
       
  1445         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL Nothing to delete - skipping" );
       
  1446 
       
  1447         RemovingNamesCompletedL();
       
  1448         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL completed early <= nothing to remove" );
       
  1449         return;
       
  1450         }
       
  1451 
       
  1452     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL - removing" );
       
  1453 
       
  1454     // we have: a list of tag IDs, which should be removed
       
  1455     // we need: a list of tags, which should be removed.
       
  1456 
       
  1457     // First, we get the tags which correspond to the tag ids.
       
  1458     // We need k async calls to VAS,
       
  1459     // where k is the number of tag ids in iDelList.
       
  1460     // We get a list of k' tags, where k' >= k.
       
  1461     // If some tag has both proper name and a nickname, then k' > k.
       
  1462     
       
  1463     iContactId = iDelList[0].iContactId;
       
  1464 
       
  1465     if ( iDeleteTagListArray )
       
  1466         {
       
  1467         iDeleteTagListArray->ResetAndDestroy();
       
  1468         }
       
  1469     else
       
  1470         {
       
  1471         iDeleteTagListArray = new (ELeave) CArrayPtrFlat<MNssTag>(50);
       
  1472         }
       
  1473 
       
  1474     TInt retCode = iTagManager->GetTagList( this, iContext, iContactId, 0 );
       
  1475 
       
  1476     if ( retCode != KErrNone )
       
  1477         {
       
  1478         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL failed to GetTagList" );
       
  1479         // In the case of change event, try to add names even though they are not found
       
  1480         // Might happen in scenario like this:
       
  1481         // 1. User adds a name without any phone number -> no voice tag is created
       
  1482         // 2. Contact is modified by adding a phone number
       
  1483         iDelList.Close();
       
  1484         DoAddNamesL();
       
  1485         }
       
  1486     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesL completed" );
       
  1487     }
       
  1488 
       
  1489 // ---------------------------------------------------------
       
  1490 // CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList
       
  1491 // If contact database announces that n contacts need to be
       
  1492 // deleted, we do n calls to GetTagList (the first is from DoRemoveNamesL). 
       
  1493 // Each callback returns 1 or more tags (name + nickname = 2 tags). 
       
  1494 // This function processes the callbacks by adding the tags to the 
       
  1495 // to-be-deleted list.
       
  1496 // ---------------------------------------------------------
       
  1497 //
       
  1498 void CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList( MNssTagListArray* aTagList )
       
  1499     {
       
  1500     RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList. iState [%d]", iState );
       
  1501 
       
  1502     if ( iDelList.Count() == 0 ) 
       
  1503 		{
       
  1504 		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList iDelList.Count() == 0" );
       
  1505 		}
       
  1506 
       
  1507     // Sieve out "false" tags: Those which have a wrong contact ID.
       
  1508     /** Why? Maybe user was fast enough to delete these contacts from the phonebook 
       
  1509     *   Anyway, why should we keep "false" tags in our db?
       
  1510     */
       
  1511     for ( TInt i=0; i < aTagList->Count(); i++ )
       
  1512         {
       
  1513         CArrayFixFlat<TInt>* intArray = aTagList->At(i)->RRD()->IntArray();
       
  1514 	
       
  1515         RUBY_ASSERT_DEBUG( intArray->Count() > 0, User::Panic( KFile, __LINE__ ) );
       
  1516 
       
  1517         if ( intArray->At(0) != iContactId )
       
  1518             {
       
  1519             RUBY_ERROR2( "DoRemoveNamesAfterGetTagList expected contact id %d, but got contact id: %d", iContactId, intArray->At(0) );
       
  1520             delete aTagList->At( i );
       
  1521             aTagList->Delete( i );
       
  1522             }
       
  1523         }
       
  1524         
       
  1525     TRAPD( err, // trapping is a fix to make the function non-leaving
       
  1526 
       
  1527 	    // Add the tags to the to-be-deleted list.
       
  1528 	    // (there are 1 or 2 tags in aTagList depending on
       
  1529 	    //  whether nickname is also there or not)
       
  1530 	    for ( TInt k( 0 ); k < aTagList->Count(); k++ )
       
  1531 	        {
       
  1532 	        iDeleteTagListArray->AppendL( (*aTagList)[k] );
       
  1533 	        }
       
  1534 
       
  1535 	    // We have processed this ID
       
  1536 	    RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Before removal. iDelList.Count [%d]", iDelList.Count() );
       
  1537 	    if( iDelList.Count() > 0 ) 
       
  1538 	    	{
       
  1539 	    	iDelList.Remove( 0 );
       
  1540 	    	} 
       
  1541 	    else 
       
  1542 	    	{
       
  1543 	    	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Empty iDelList!" );
       
  1544 	    	}
       
  1545 	    RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList After removal. iDelList.Count [%d]", iDelList.Count() );
       
  1546 
       
  1547 	    // If there are still more IDs, convert the next ID into a tag.
       
  1548 	    if ( iDelList.Count() > 0 )
       
  1549 	        {
       
  1550 	        RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList There are [%d] contacts to delete. Calling GetTagList for them", iDelList.Count() );
       
  1551 	        iContactId = iDelList[0].iContactId;
       
  1552 
       
  1553 	        TInt retCode 
       
  1554 	            = iTagManager->GetTagList( this, iContext, iContactId, 0 );
       
  1555 
       
  1556 	        if ( retCode != KErrNone )
       
  1557 	            {
       
  1558 	            RUBY_DEBUG0( "DoRemoveNamesAfterGetTagList Failed to GetTagList, going to DoHandleEventFailedL" );
       
  1559 	            TRAP_IGNORE( DoHandleEventFailedL() );      // to handle the process event failed
       
  1560 	            /** @todo reengineer into single return path */
       
  1561 	            // Destroy tag list
       
  1562 	    		aTagList->Reset();
       
  1563 	    		delete aTagList;
       
  1564 	    		aTagList = 0;
       
  1565 	            return;
       
  1566 	            }
       
  1567 	        }
       
  1568 	        
       
  1569 	    // If we just finished converting the last ID, move to the next phase.
       
  1570 	    else{
       
  1571 	        RUBY_DEBUG0( "DoRemoveNamesAfterGetTagList Moving to the next phase" );
       
  1572 	        DoRemoveNamesCallDeleteTag();
       
  1573 	        }
       
  1574         );  // TRAPD
       
  1575         if( err != KErrNone ) 
       
  1576         	{
       
  1577         	RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterGetTagList Leaves with [%d] inside", err );
       
  1578         	}
       
  1579 		// Destroy tag list
       
  1580 	    aTagList->Reset();
       
  1581 	    delete aTagList;
       
  1582 	    aTagList = 0;
       
  1583     }
       
  1584 
       
  1585 // ---------------------------------------------------------
       
  1586 // CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag
       
  1587 // Sends the DeleteTag() calls to lower layers when removing names.
       
  1588 // ---------------------------------------------------------
       
  1589 //
       
  1590 void CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag()
       
  1591     {
       
  1592     RUBY_DEBUG1( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag. iDeleteTagListArray->Count() [%d] Setting iDeleteCallbackCounter = 0", 
       
  1593                 iDeleteTagListArray->Count() );
       
  1594     
       
  1595     if( iDeleteTagListArray->Count() > 0 ) 
       
  1596     	{
       
  1597     	
       
  1598 	    iDeleteCallbackCounter = 0;
       
  1599 
       
  1600 	    for ( TInt k( 0 ); k < iDeleteTagListArray->Count(); k++ )
       
  1601 	        {
       
  1602 	        TInt ret = 
       
  1603 	            iTagManager->DeleteTag( this, (*iDeleteTagListArray)[k] );
       
  1604 
       
  1605 	        if ( ret != KErrNone )
       
  1606 	            {
       
  1607 	            TRAPD( err, DoHandleEventFailedL(); );
       
  1608 	            if( err != KErrNone ) 
       
  1609 	            	{
       
  1610 	            	RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag Error handling Left with [%d]", err );
       
  1611 	            	}
       
  1612 	            return;  /** @todo reengineer into single return path */
       
  1613 	            }
       
  1614 	        }
       
  1615     	} // if there are tags to delete
       
  1616     else
       
  1617     	{
       
  1618     	// if there were no tags to delete (attempt to delete non-existing tags)
       
  1619     	// simulating callback from successful deletion of.. 0 tags
       
  1620     	//iDeleteCallbackCounter = -1;
       
  1621     	//DeleteTagCompleted();
       
  1622     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesCallDeleteTag Here!" );
       
  1623     	}
       
  1624     }
       
  1625 
       
  1626 // ---------------------------------------------------------
       
  1627 // CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted
       
  1628 // DeleteTag() callback calls this funciton. It counts
       
  1629 // the number of callbacks, and when all callbacks have arrived,
       
  1630 // goes to the next phase.
       
  1631 // ---------------------------------------------------------
       
  1632 //
       
  1633 void CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted()
       
  1634 	{
       
  1635     iDeleteCallbackCounter++;
       
  1636     
       
  1637     RUBY_DEBUG2( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. iDeleteCallbackCounter [%d], Count() [%d]", iDeleteCallbackCounter, iDeleteTagListArray->Count() );
       
  1638     
       
  1639     if ( iDeleteCallbackCounter == iDeleteTagListArray->Count() )
       
  1640         {
       
  1641         if( iNormalChangesError == KErrNone ) 
       
  1642         	{
       
  1643         	TRAPD( err, RemovingNamesCompletedL() );
       
  1644     		if ( err != KErrNone )
       
  1645         		{
       
  1646         		RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. Error [%d] in RemovingNamesCompletedL", err );
       
  1647         		}
       
  1648         	}
       
  1649         else 
       
  1650         	{
       
  1651         	// There is not much we can do about the deletion error
       
  1652         	// Retrying deletion can cause endless cycle
       
  1653         	// Sometimes failed deletions are ok (if we tried to delete non-existing tag)
       
  1654         	/** @todo reengineer SpeechItemTrainer (and/or SRS plugin) to report deletion 
       
  1655         	    of non-existing tag as success. After all they are not in the DB */
       
  1656         	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted Deletion failed. Still simulating a successful one" );
       
  1657         	TRAPD( err, RemovingNamesCompletedL() );
       
  1658     		if ( err != KErrNone )
       
  1659         		{
       
  1660         		RUBY_ERROR1( "CNssContactHandlerImplementation::DoRemoveNamesAfterDeleteTagCompleted. Error [%d] in RemovingNamesCompletedL", err );
       
  1661         		}
       
  1662         	}  // if (iNormalChangesError == KErrNone) else
       
  1663         }  // if count
       
  1664     }
       
  1665 
       
  1666 // ---------------------------------------------------------
       
  1667 // CNssContactHandlerImplementation::RemovingNamesCompletedL
       
  1668 // Cleans up after some names have been removed
       
  1669 // ---------------------------------------------------------
       
  1670 //
       
  1671 void CNssContactHandlerImplementation::RemovingNamesCompletedL()
       
  1672     {
       
  1673 	RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::RemovingNamesCompletedL" );
       
  1674     iDelList.Close();
       
  1675 
       
  1676     if ( iDeleteTagListArray )
       
  1677         {
       
  1678         iDeleteTagListArray->ResetAndDestroy();
       
  1679         iDeleteCallbackCounter = 0;
       
  1680         }
       
  1681 
       
  1682     DoAddNamesL();
       
  1683     }
       
  1684 
       
  1685 // ---------------------------------------------------------
       
  1686 // CNssContactHandlerImplementation::DoAddNamesL
       
  1687 // Starts name addition sequence by fetching contacts data and ordering
       
  1688 // voice tags training
       
  1689 // ---------------------------------------------------------
       
  1690 //
       
  1691 void CNssContactHandlerImplementation::DoAddNamesL()
       
  1692     {
       
  1693     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::DoAddNamesL" );
       
  1694     TInt k( 0 );
       
  1695 
       
  1696     if ( iAddList.Count() == 0 )
       
  1697         {
       
  1698         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL Nothing to add. Setting iState = ECHIdle. Return" );
       
  1699     	SetState ( ECHIdle );
       
  1700     	// If there are events on the list, DoAddNamesCompleted will fire them
       
  1701         DoAddNamesCompletedL();  
       
  1702         }
       
  1703     else 
       
  1704         {
       
  1705         // Create new tags and train them.
       
  1706         for ( k = 0; k < iAddList.Count(); k++ )
       
  1707             {
       
  1708             // 3 names may be created from one contact:
       
  1709             //  * Main name (firstname + lastname XOR companyname)
       
  1710             //  * Reversed order name (usually lastname + firstname, depends on the UI language)
       
  1711             //      -> only if NSSVAS_CONTACTHANDLER_FREEORDER is defined
       
  1712             //  * Nickname
       
  1713 
       
  1714             TContactData contactData;
       
  1715 
       
  1716             contactData.iID = iAddList[k].iContactId;
       
  1717             contactData.iSyncTime.UniversalTime();
       
  1718 
       
  1719             // Nickname
       
  1720             contactData.iTitle = NULL;
       
  1721             TRAPD( err, contactData.iTitle = GetContactNicknameL( iAddList[k].iContactId ) );
       
  1722 
       
  1723             if ( contactData.iTitle != NULL )
       
  1724                 {
       
  1725                 CleanupStack::PushL( contactData.iTitle );
       
  1726                 contactData.iType = ETagTypeNickName;
       
  1727                 User::LeaveIfError( iContactQueue.Append( contactData ) );
       
  1728                 CleanupStack::Pop( contactData.iTitle );
       
  1729                 }
       
  1730 
       
  1731             // Main name ( Using GetContactTitleL() )
       
  1732             contactData.iTitle = NULL;
       
  1733             TBool bothFound = EFalse;
       
  1734             TVasTagType tagType( ETagTypeUnknown );
       
  1735             TRAP( err, contactData.iTitle = GetContactTitleL( iAddList[k].iContactId, ETrue, bothFound, tagType ) );
       
  1736 
       
  1737             // If all the name fields are empty, nothing
       
  1738             // can be done for the tag. We're finished.
       
  1739             if ( contactData.iTitle != NULL )
       
  1740                 {
       
  1741                 RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesL For Contact id [%d] title is: [%S]", iAddList[k].iContactId, contactData.iTitle );
       
  1742                 CleanupStack::PushL( contactData.iTitle );
       
  1743                 contactData.iType = tagType;
       
  1744                 User::LeaveIfError( iContactQueue.Append( contactData ) );
       
  1745                 CleanupStack::Pop( contactData.iTitle );
       
  1746                 }
       
  1747 
       
  1748     #ifdef NSSVAS_CONTACTHANDLER_FREEORDER
       
  1749             // Default order added previously, now adding
       
  1750             // secondary order if both first and lastnames are found
       
  1751             if ( bothFound )
       
  1752                 {
       
  1753                 contactData.iTitle = NULL;
       
  1754                 TRAPD( err, contactData.iTitle = GetContactTitleL( iAddList[k].iContactId, EFalse, bothFound, tagType ) );
       
  1755                 if ( contactData.iTitle != NULL )
       
  1756                     {
       
  1757                     CleanupStack::PushL( contactData.iTitle );
       
  1758                     contactData.iType = tagType;
       
  1759                     User::LeaveIfError( iContactQueue.Append( contactData ) );
       
  1760                     CleanupStack::Pop( contactData.iTitle );
       
  1761                     }
       
  1762                 }
       
  1763     #endif // NSSVAS_CONTACTHANDLER_FREEORDER
       
  1764 
       
  1765             }
       
  1766 
       
  1767         // No tag had any text.
       
  1768         if ( iContactQueue.Count() == 0 )
       
  1769             {
       
  1770             RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL. No tag had any text, return" );
       
  1771             DoAddNamesCompletedL();
       
  1772             }
       
  1773         else 
       
  1774             {
       
  1775             // At least some tag has some text
       
  1776             RUBY_ASSERT_DEBUG( iTagArray.Count() == 0, User::Panic( KFile, __LINE__ ) );
       
  1777 
       
  1778             for ( k = 0; k < iContactQueue.Count(); k++ )
       
  1779                 {
       
  1780                 // (1) Create a new tag
       
  1781                 if ( iNewTag != NULL ) 
       
  1782                     {
       
  1783                     // If previous call to this function leaves, iNewTag can 
       
  1784                     // be not deleted
       
  1785                     delete iNewTag;
       
  1786                     iNewTag = NULL;
       
  1787                     }
       
  1788                 iNewTag = iTagManager->CreateTagL( iContext );
       
  1789 
       
  1790                 MNssRRD* rrd = iNewTag->RRD();
       
  1791                 MNssSpeechItem* speechItem = iNewTag->SpeechItem();
       
  1792 
       
  1793                 // (2) Fill RRD. RRD contains client-chosen data about the tag.
       
  1794                 //     In case of name dialing, RRD contains the contact ID,
       
  1795                 //     which is used later to get the phone number.
       
  1796                 CArrayFixFlat<TInt> *id = new (ELeave) CArrayFixFlat<TInt>( 1 );
       
  1797 
       
  1798                 CleanupStack::PushL( id );
       
  1799 
       
  1800                 id->AppendL( iContactQueue[k].iID ); // ID
       
  1801                 // select a number field for voice tag
       
  1802                 // TInt fieldIndex( 0 );
       
  1803 
       
  1804         		WaitUntilNoSyncBackupIsRunning();
       
  1805                 TRAPD( err, ReadContactL( iContactQueue[k].iID ); );
       
  1806                 if ( err == KErrNone )
       
  1807                     {
       
  1808                     // 1. Default voice call number set by the user
       
  1809                     TInt found = KErrNotFound;
       
  1810                     TRAP( found, iPbkHandler->FindDefaultContactFieldL( EDefaultCommand ) );
       
  1811                     
       
  1812                     if ( found == KErrNotFound )
       
  1813                         {
       
  1814                         for( TInt i = 0; i < KTaggableFieldsCount; i++) 
       
  1815                             {
       
  1816                             TRAP( found, iPbkHandler->FindFieldL( KTaggableFields[i] ) );
       
  1817                             if( found == KErrNone && ( !iPbkHandler->IsFieldEmptyL() ) )
       
  1818                                 {
       
  1819                                 break;  // found field
       
  1820                                 }
       
  1821                             else 
       
  1822                                 {
       
  1823                                 // When field->IsEmptyOrAllSpaces(), it is the same for us as no field present
       
  1824                                 found = KErrNotFound;
       
  1825                                 }
       
  1826                             }  // for i < KTaggableFieldsCount
       
  1827                         }
       
  1828 
       
  1829                     if ( found == KErrNone ) // found and is not empty
       
  1830                         {
       
  1831                         id->AppendL( iPbkHandler->FieldIdL() ); // field ID to array
       
  1832                         id->AppendL( EDial );
       
  1833                         id->AppendL( iContactQueue[k].iType );
       
  1834                         id->AppendL( EDefaultCommand );
       
  1835                         rrd->SetIntArrayL ( id );
       
  1836                                                 
       
  1837                         // (3) Set the training text.
       
  1838                         speechItem = iNewTag->SpeechItem();
       
  1839                         speechItem->SetTextL( *iContactQueue[k].iTitle );
       
  1840                  
       
  1841                         User::LeaveIfError( iTagArray.Append( iNewTag ) );
       
  1842                         // Leave protection for iNewTag completed
       
  1843                         // Ownership and deletion responsibility moved
       
  1844                         // to iTagArray
       
  1845                         iNewTag = NULL;
       
  1846                         }
       
  1847                     else
       
  1848                         {
       
  1849                         // field not found or is empty
       
  1850                         RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesL Did NOT identify a suitable voice dial field for contact id [%d]", iContactQueue[k].iID);
       
  1851                         
       
  1852                         
       
  1853                         delete iNewTag;
       
  1854                         iNewTag = NULL;
       
  1855                         }  // if field else
       
  1856 #ifdef __SIND_EXTENSIONS
       
  1857                     
       
  1858                     // this part creates separate voice tags for extensions
       
  1859                     for ( TInt i(0); i < iExtensionList.Count(); i++ )
       
  1860                         {
       
  1861                         found = KErrNotFound;
       
  1862                         TVasExtensionAction action = iExtensionList[i].iAction;
       
  1863                         TPbkFieldId fieldId = iExtensionList[i].iId;
       
  1864                         
       
  1865                         // default message number
       
  1866                         // default video
       
  1867                         // default e-mail
       
  1868                         // default VOIP  
       
  1869                         if ( action == ENewMessage ||
       
  1870                              iExtensionList[i].iId == EPbkFieldIdPhoneNumberVideo ||
       
  1871                              iExtensionList[i].iId == EPbkFieldIdEmailAddress ||
       
  1872                              iExtensionList[i].iId == EPbkFieldIdVOIP )
       
  1873                             {
       
  1874                             // @todo Should use DefaultMessageField or something similar!!
       
  1875                             TRAP( found,
       
  1876                                 iPbkHandler->FindDefaultContactFieldL( iExtensionList[i].iCommand ) );
       
  1877                             }
       
  1878                             
       
  1879                         /*if ( extensionField == NULL )
       
  1880                             {
       
  1881                             extensionField = item->FindField( iExtensionList[i].iId );
       
  1882                             }
       
  1883                             
       
  1884                         if ( extensionField == NULL && field != NULL 
       
  1885                              && ( action == ENewMessage ) )
       
  1886                             {
       
  1887                             // if default neither default field or mobile field was not found
       
  1888                             // message use normal SIND field
       
  1889                             extensionField = field;
       
  1890                             fieldId = field->FieldInfo().FieldId();
       
  1891                             }*/
       
  1892                             
       
  1893                         // If field was not found, try to find it based on the priority lists
       
  1894                         if ( found == KErrNotFound )
       
  1895                             {
       
  1896                             found = FindExtensionField( action, iExtensionList[i].iId );
       
  1897                             // If field was found, check the field ID
       
  1898                             if ( found == KErrNone )
       
  1899                                 {
       
  1900                                 fieldId = iPbkHandler->FieldIdL();
       
  1901                                 }
       
  1902                             }
       
  1903                             
       
  1904                         if ( found == KErrNone )
       
  1905                             {
       
  1906                             // create new tag
       
  1907                             iNewTag = iTagManager->CreateTagL( iContext );
       
  1908 
       
  1909                             rrd = iNewTag->RRD();
       
  1910                             speechItem = iNewTag->SpeechItem();
       
  1911                             
       
  1912                             // set RRD data
       
  1913                             CArrayFixFlat<TInt> *extIds = new (ELeave) CArrayFixFlat<TInt>( 1 );
       
  1914                             CleanupStack::PushL( extIds );
       
  1915 
       
  1916                             extIds->AppendL( iContactQueue[k].iID ); 
       
  1917                             if ( iExtensionList[i].iCommand == EMessageCommand ||
       
  1918                                   iExtensionList[i].iCommand == EVideoCommand )
       
  1919                                 {
       
  1920                                 TInt id = iPbkHandler->FieldIdL();
       
  1921                                 if ( id )
       
  1922                                     {
       
  1923                                     extIds->AppendL( id );
       
  1924                                     }
       
  1925                                 else
       
  1926                                     {
       
  1927                                     extIds->AppendL( fieldId );
       
  1928                                     }
       
  1929                                 }
       
  1930                             else
       
  1931                                 {
       
  1932                                 extIds->AppendL( fieldId );
       
  1933                                 }
       
  1934                             extIds->AppendL( action );
       
  1935                             extIds->AppendL( iContactQueue[k].iType );
       
  1936                             extIds->AppendL( iExtensionList[i].iCommand );
       
  1937 
       
  1938                             rrd->SetIntArrayL ( extIds );
       
  1939                                                 
       
  1940                             // set the training text.
       
  1941                             TPtr namePtr( iContactQueue[k].iTitle->Des() );
       
  1942                             TPtr extensionPtr( iExtensionList[i].iText->Des() );
       
  1943                             HBufC* tempTitle = HBufC::NewLC( namePtr.Length() + extensionPtr.Length() + KTrainingIndexSize );
       
  1944                             TPtr titlePtr( tempTitle->Des() );                                                           
       
  1945                             
       
  1946                             //not work: titlePtr.AppendFormat( extensionPtr, namePtr ); 
       
  1947                             
       
  1948                             titlePtr = extensionPtr;
       
  1949                             AppendExtensionMarker( titlePtr );
       
  1950                             TInt index = titlePtr.Find( KExtensionFormatString );
       
  1951                             if ( index >= 0 )
       
  1952                                 {
       
  1953                                 // replace %U with name
       
  1954                                 titlePtr.Delete( index, 2 ); // delete %U
       
  1955                                 titlePtr.Insert( index, namePtr ); 
       
  1956                                 }
       
  1957                             speechItem->SetTextL( titlePtr );
       
  1958                         
       
  1959                             User::LeaveIfError( iTagArray.Append( iNewTag ) );
       
  1960                             iNewTag = NULL; //ownership changed
       
  1961                             CleanupStack::PopAndDestroy( tempTitle );  
       
  1962                             CleanupStack::PopAndDestroy( extIds );  
       
  1963                             }
       
  1964                         }
       
  1965 
       
  1966 #endif // __SIND_EXTENSIONS                       
       
  1967                     // delete id
       
  1968                     CleanupStack::PopAndDestroy( id );
       
  1969                     }
       
  1970                 else 
       
  1971                     {
       
  1972                     // Opening contact failed. E.g. if it was just deleted by user	
       
  1973                     RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesL Failed to open contact id [%d]. Leave [%d]", iContactQueue[k].iID, err);
       
  1974                     CleanupStack::PopAndDestroy( id );
       
  1975                     delete iNewTag;
       
  1976                     iNewTag = NULL;
       
  1977                     /** @todo Try reengineering duplicated cleanups into single piece 
       
  1978                     of the code */
       
  1979                     }
       
  1980                 }  // for k .. iContactQueue
       
  1981 
       
  1982             if ( iTagArray.Count() == 0 )
       
  1983                 {
       
  1984                 // If there are events on the list, DoAddNamesCompleted will fire them
       
  1985                 DoAddNamesCompletedL();  
       
  1986                 RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL. Returned from DoAddNamesCompleted. Setting iState = ECHIdle" );
       
  1987         		SetState ( ECHIdle );
       
  1988                 }
       
  1989             else 
       
  1990                 {
       
  1991                 RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesL Before training tags. TagCount = [%d]",
       
  1992         	            iTagArray.Count() );
       
  1993 
       
  1994                 iTrainCallbackCounter = 0;
       
  1995                 for ( k = 0; k < iTagArray.Count(); k++ )
       
  1996                     {
       
  1997                     MNssSpeechItem* speechItem = iTagArray[k]->SpeechItem();
       
  1998 
       
  1999                     MNssSpeechItem::TNssSpeechItemResult trainRet 
       
  2000                     = speechItem->TrainTextL( this, iTrainingParams );
       
  2001 
       
  2002                     if ( trainRet != MNssSpeechItem::EVasErrorNone )
       
  2003                         {
       
  2004                         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesL : TrainTextL call failed." );
       
  2005                         // Not much we can do except for timed retry.
       
  2006                         // This stops the contact handler.
       
  2007                         DoHandleEventFailedL();
       
  2008                         break;  // no processing anymore. Quit function
       
  2009                         }
       
  2010                     }  // for k < iTagArray.Count()
       
  2011                 }  // if iTagArrayCount != 0
       
  2012             }
       
  2013         }  // if ( iAddList.Count() != 0 )
       
  2014     }
       
  2015 
       
  2016 // ---------------------------------------------------------
       
  2017 // CNssContactHandlerImplementation::DoAddNamesTrainingFinished
       
  2018 // Called after training of a current pack of tags has finished. 
       
  2019 // Starts saving tags.
       
  2020 // ---------------------------------------------------------
       
  2021 //
       
  2022 void CNssContactHandlerImplementation::DoAddNamesTrainingFinished()
       
  2023     {
       
  2024     iSaveCallbackCounter = 0;
       
  2025     iRetry = 0; // retry, if save tag fails
       
  2026     iNormalChangesError = 0; // to record failures in save tag
       
  2027 
       
  2028     DoAddNamesSaveTag();
       
  2029     }
       
  2030 
       
  2031 // ---------------------------------------------------------
       
  2032 // CNssContactHandlerImplementation::DoAddNamesSaveTag
       
  2033 // This function has two branches:
       
  2034 // (1) Initiate saving tags
       
  2035 // (1) After all tags have been saved, go to the next phase.
       
  2036 // ---------------------------------------------------------
       
  2037 //
       
  2038 void CNssContactHandlerImplementation::DoAddNamesSaveTag()
       
  2039     {
       
  2040     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag" );
       
  2041     TInt retCode;
       
  2042 
       
  2043     // If all tags have been saved, go to the next phase.
       
  2044     if ( iSaveCallbackCounter == iTagArray.Count() )
       
  2045         {
       
  2046         RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag All tags have been saved, go to the next phase" );
       
  2047         // Tags saved - go to the next phase
       
  2048         if ( iNormalChangesError == KErrNone )
       
  2049             {
       
  2050             // This function is called once per 100 contacts -> It is ok to use TRAP
       
  2051             TRAPD( error, DoAddNamesCompletedL() );
       
  2052             if( error != KErrNone ) 
       
  2053                 {
       
  2054                 /** @todo Test this branch */
       
  2055                 // Some fatal error occured
       
  2056                 RUBY_ERROR1( "DoAddNamesSaveTag DoAddNamesCompletedL failed with [%d]. Disabling SIND",
       
  2057                             error );
       
  2058                 DisableEventHandling();
       
  2059                 }
       
  2060             }
       
  2061         else
       
  2062             {
       
  2063             RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag Saving tags failed. Try again a few times" );
       
  2064             // Saving tags failed. Try again a few times, and if it still
       
  2065             // doesn't work, go to fatal error handler.
       
  2066             if ( iRetry < KVASCHMaxRetry )
       
  2067                 {
       
  2068                 iRetry++;
       
  2069                 RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesSaveTag Retried saving [%d] times. [%d] retries left",
       
  2070                             iRetry, KVASCHMaxRetry - iRetry);
       
  2071                 iSaveCallbackCounter = 0;
       
  2072                 iNormalChangesError = KErrNone;
       
  2073                 
       
  2074                 DoAddNamesSaveTag();
       
  2075                 }
       
  2076             else
       
  2077                 {
       
  2078                 RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTag Retried saving [%d] times. Still saving fails. Handling error", iRetry );
       
  2079                 NormalChangesHandleError();
       
  2080                 }
       
  2081             }
       
  2082         }  // if ( iSaveCallbackCounter == iTagArray.Count() )
       
  2083     
       
  2084     // If this is the first call to this function,
       
  2085     // make "save tag" calls. After that, wait for the callbacks.
       
  2086     else if ( iSaveCallbackCounter == 0 )
       
  2087         {
       
  2088         RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTag iSaveCallbackCounter == 0. Run SaveTag for [%d] contacts",
       
  2089                     iTagArray.Count());
       
  2090         for ( TInt k( 0 ); k < iTagArray.Count(); k++ )
       
  2091             {
       
  2092             retCode = iTagManager->SaveTag( this, iTagArray[k] );
       
  2093 
       
  2094             if ( retCode != KErrNone )
       
  2095                 {
       
  2096                 RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag - SaveTag failed." );
       
  2097 				TRAPD( err, DoHandleEventFailedL(); );
       
  2098 				if( err != KErrNone ) 
       
  2099 					{
       
  2100 					RUBY_ERROR1( "CNssContactHandlerImplementation::DoAddNamesSaveTag handling error Left with [%d]", err );
       
  2101 					}
       
  2102                 return;
       
  2103                 }  // if retCode
       
  2104             }  // for iTagArray
       
  2105         }  // else if iSaveCallbackCounter == 0
       
  2106     else 
       
  2107     	{
       
  2108     	// iSaveCallbackCounter != 0, but different from iTagArray.Count()
       
  2109     	// This means, that SaveTag callbacks are still coming. We will wait for them
       
  2110     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesSaveTag. iSaveCallbackCounter != 0, but different from iTagArray.Count()" );
       
  2111         }
       
  2112     } 
       
  2113 
       
  2114 // ---------------------------------------------------------
       
  2115 // CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted
       
  2116 // Saving single tag has completed. 
       
  2117 // ---------------------------------------------------------
       
  2118 //
       
  2119 void CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted( TInt aError )
       
  2120     {
       
  2121     iSaveCallbackCounter++;
       
  2122     RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesSaveTagCompleted iSaveCallbackCounter became [%d]",
       
  2123                 iSaveCallbackCounter);
       
  2124 	// |= to let single KErrGeneral fail any number of KErrNone
       
  2125     iNormalChangesError |= aError;
       
  2126 
       
  2127     // Check if all tags have been saved.
       
  2128     DoAddNamesSaveTag();
       
  2129     }
       
  2130 
       
  2131 // ---------------------------------------------------------
       
  2132 // CNssContactHandlerImplementation::DoAddNamesCompleted
       
  2133 // When adding names has successfully finished, clean up.
       
  2134 // ---------------------------------------------------------
       
  2135 //
       
  2136 void CNssContactHandlerImplementation::DoAddNamesCompletedL()
       
  2137     {
       
  2138     RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesCompleted. iDeleteCallbackCounter [%d], Count() [%d]", iDeleteCallbackCounter, iDeleteTagListArray->Count() );
       
  2139 	TInt initialDeleteTagListCount = iDeleteTagListArray->Count();    
       
  2140     
       
  2141     iSaveCallbackCounter = 0;
       
  2142     iTrainCallbackCounter = 0;
       
  2143     
       
  2144     // DoAddNamesCompleted if often called after voice tags have been added =>
       
  2145     // Nothing has to be done at all
       
  2146     TBool changedDatabase = EFalse;  
       
  2147 
       
  2148 #ifndef __SIND_EXTENSIONS
       
  2149 // Set VAS_SETS_VOICETAG on if old behaviour is needed.
       
  2150 // That is, VAS sets on the voice tag field to Phonebook engine and Phonebook UI checks the contacts DB for voice tags.
       
  2151 // Off means that VAS does not set voice tag field but instead Phonebook asks from VAS.
       
  2152 #ifdef VAS_SETS_VOICETAG
       
  2153     // add voice tag fields
       
  2154     // iTagArray contains only successfully trained tags.
       
  2155     // Failed items are removed.
       
  2156     for ( TInt i( 0 ); i < iTagArray.Count(); i++ )
       
  2157         {
       
  2158         MNssRRD* rrd = iTagArray[i]->RRD();
       
  2159         CArrayFixFlat<TInt>* intArray = rrd->IntArray();
       
  2160         RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) );
       
  2161         if ( intArray->Count() >= 2 )
       
  2162             {
       
  2163             TBool committed( EFalse ); // ETrue if contact is committed already
       
  2164             TInt contactId( intArray->At( 0 ) );
       
  2165             RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted. Working on contact id [%d]",
       
  2166                         contactId);
       
  2167             TInt fieldId( intArray->At( 1 ) );
       
  2168 
       
  2169             WaitUntilNoSyncBackupIsRunning();
       
  2170             // Open contact item based on id
       
  2171             TRAPD( errFor,
       
  2172                 OpenContactL( contactId );
       
  2173                 
       
  2174                 RUBY_DEBUG1( "DoAddNamesCompleted Opened contact [%d]", contactId );
       
  2175     			TInt found == KErrNotFound;
       
  2176     			TRAP( found, iPbkHandler->FindDefaultContactFieldL( EDefaultCommand ) );
       
  2177                 if ( found == KErrNotFound )
       
  2178                     {
       
  2179                     TRAP( found, iPbkHandler->FindFieldL( fieldId ) );
       
  2180                     }
       
  2181     					// field - field, that SHOULD have voice tag attached
       
  2182                         	
       
  2183                 if ( found == KErrNone )
       
  2184                     {
       
  2185                     TRAP( error, iPbkHandler->ChangeVoiceTagFieldL( ETrue ) );
       
  2186                     if ( error == KErrNone )
       
  2187                         {
       
  2188                         RUBY_DEBUG1("DoAddNamesCompleted  Successfully added icon to the contact [%d]", 
       
  2189                                     contactId);
       
  2190                         iPbkHandler->CloseContactL( ETrue );
       
  2191                         RUBY_DEBUG1("DoAddNamesCompleted  Successfully committed contact [%d]", 
       
  2192                                     contactId);
       
  2193                         iVoiceTagAddedList.Append( contactId );
       
  2194                         changedDatabase = ETrue;
       
  2195                         committed = ETrue;
       
  2196                         }
       
  2197                     }
       
  2198                 else
       
  2199                     {
       
  2200                     // field not found anymore
       
  2201                     RUBY_DEBUG2("DoAddNamesCompleted Field [%d] not found in (already deleted from?) contact [%d]",
       
  2202                                 fieldId, contactId );
       
  2203                     iDeleteTagListArray->AppendL( NULL ); // One DeleteTag will generate one callback
       
  2204                     iTagManager->DeleteTag( this, iTagArray[i] );
       
  2205                     }
       
  2206                 if ( !committed )
       
  2207                     {
       
  2208                     RUBY_DEBUG1("DoAddNamesCompleted Did not change contact [%d]. Closing without committing", 
       
  2209                        	            contactId);
       
  2210                     iPbkHandler->CloseContactL( EFalse );
       
  2211                     }
       
  2212             );  // TRAPD errFor
       
  2213             if ( errFor != KErrNone ) 
       
  2214                 {
       
  2215                 RUBY_DEBUG2("CNssContactHandlerImplementation::DoAddNamesCompleted Failed to add icon for contact [%d]. Error [%d]",
       
  2216                             contactId, errFor);
       
  2217                     // voice tag was not in the contacts database, delete it from VAS
       
  2218                     // One DeleteTag will generate one callback
       
  2219                 iDeleteTagListArray->AppendL( NULL );
       
  2220                 iTagManager->DeleteTag( this, iTagArray[i] );
       
  2221                 }
       
  2222             }  // if intArray->Count() >= 2
       
  2223         }  // for  iTagArray
       
  2224 #endif // VAS_SETS_VOICETAG
       
  2225 #endif //__SIND_EXTENSIONS        
       
  2226 
       
  2227     iTagArray.ResetAndDestroy();
       
  2228 
       
  2229     iAddList.Close();
       
  2230     
       
  2231 #ifndef __SIND_EXTENSIONS
       
  2232 #ifdef VAS_SETS_VOICETAG
       
  2233     // Remove voice tag icons for contacts, that failed to be trained or saved
       
  2234     for( TInt l = 0 ; l < iRemoveIconList.Count(); l++ ) 
       
  2235         {
       
  2236         WaitUntilNoSyncBackupIsRunning();
       
  2237         TRAPD( error, OpenContactL( iRemoveIconList[l] ) );
       
  2238         if ( error != KErrNone ) 
       
  2239             {
       
  2240             RUBY_DEBUG2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to open contact [%d]. Error [%d]", iRemoveIconList[l], error);
       
  2241             }
       
  2242         else 
       
  2243             {           
       
  2244             TRAP( error, iPbkHandler->ChangeVoiceTagFieldL( EFalse ) );
       
  2245             if ( error == KErrNotFound )
       
  2246                 {
       
  2247                 // Nothing to remove. Already no voice tag icon
       
  2248                 TRAP( error, iPbkHandler->CloseContactL( EFalse ) );
       
  2249                 if ( error != KErrNone ) 
       
  2250                     {
       
  2251                     RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to close contact [%d]. Error [%d]", iRemoveIconList[l], error);
       
  2252                     }
       
  2253                 }
       
  2254             else if ( error != KErrNone )
       
  2255                 {
       
  2256                 RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted  Failed to remove voice tag icon for contact [%d]. Error [%d]", iRemoveIconList[l], error);
       
  2257                 TRAP( error, iPbkHandler->CloseContactL( EFalse ) );
       
  2258                 if ( error != KErrNone ) 
       
  2259                     {
       
  2260                     RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to close contact [%d]. Error [%d]", iRemoveIconList[l], error);
       
  2261                     }
       
  2262                 }
       
  2263             else
       
  2264                 {
       
  2265                 iVoiceTagAddedList.Append( iRemoveIconList[l] );
       
  2266                 TRAP( error, iPbkHandler->CloseContactL( ETrue ) );
       
  2267                 if ( error != KErrNone ) 
       
  2268                     {
       
  2269                     RUBY_ERROR2( "CNssContactHandlerImplementation::DoAddNamesCompleted Failed to commit contact [%d]. Error [%d]", iRemoveIconList[l], error);
       
  2270                     }
       
  2271                 }            
       
  2272             
       
  2273             }  // if opened contact successfully
       
  2274         
       
  2275         }
       
  2276 #endif // VAS_SETS_VOICETAG
       
  2277 #endif //__SIND_EXTENSIONS
       
  2278         
       
  2279     iRemoveIconList.Close();
       
  2280 
       
  2281     for( TInt k( 0 ); k < iContactQueue.Count(); k++ )
       
  2282         {
       
  2283         delete iContactQueue[k].iTitle;
       
  2284         iContactQueue[k].iTitle = NULL;
       
  2285         }
       
  2286     iContactQueue.Close();
       
  2287     
       
  2288     if( changedDatabase ) 
       
  2289     	{
       
  2290     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted changed DBx" );
       
  2291     	WaitUntilNoSyncBackupIsRunning();
       
  2292 	    TRAPD(err, iPbkHandler->CompressL() );
       
  2293 	    if ( err )
       
  2294     		{
       
  2295     		RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted Contacts DB compression failed. Error [%d]", 
       
  2296     		            err);
       
  2297     		}
       
  2298     	}
       
  2299     else 
       
  2300     	{
       
  2301     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted did NOT change DB" );
       
  2302     	}
       
  2303     	
       
  2304     	// full resyncs are always tag additions
       
  2305     if( initialDeleteTagListCount == iDeleteTagListArray->Count() ) 
       
  2306     	{
       
  2307     	SetState( ECHIdle );
       
  2308     	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted Syncing with phonebook generated NO deletions" );
       
  2309     	// then full resync will not be initiated
       
  2310     	iConsecutiveErrorFullResync = 0;
       
  2311 	    if ( iEventArray.Count() > 0 )
       
  2312         	{
       
  2313     		RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted There are still [%d] events in the queue. Call DoHandleEvents for them",
       
  2314     		            iEventArray.Count() );
       
  2315         	TRAPD( err, DoHandleEventsL() );
       
  2316         	if ( err != KErrNone )
       
  2317 	            {
       
  2318 	            RUBY_ERROR1( "CNssContactHandlerImplementation::DoAddNamesCompleted. Error [%d] in DoHandleEventsL", err );
       
  2319             	}
       
  2320         	}
       
  2321     	else 
       
  2322        		{
       
  2323        		// No self-generated events, and no pending events to handle
       
  2324        		// This is the only place in the code, where everything is completed 
       
  2325        		// and nothing is pending
       
  2326        		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted All the updates completed. No DB event is pending" );
       
  2327        		
       
  2328        		}
       
  2329     	} 
       
  2330     else 
       
  2331     	{
       
  2332     	RUBY_DEBUG1( "CNssContactHandlerImplementation::DoAddNamesCompleted Generated [%d] deletions. Starting to wait for callbacks", 
       
  2333     		iDeleteTagListArray->Count() - initialDeleteTagListCount);
       
  2334     	}
       
  2335        	
       
  2336     RUBY_DEBUG0( "CNssContactHandlerImplementation::DoAddNamesCompleted completed" );
       
  2337     }
       
  2338 
       
  2339 // ---------------------------------------------------------
       
  2340 // CNssContactHandlerImplementation::NormalChangesHandleError
       
  2341 // Handle errors which happend when updating normal changes
       
  2342 // ---------------------------------------------------------
       
  2343 //
       
  2344 void CNssContactHandlerImplementation::NormalChangesHandleError()
       
  2345     {
       
  2346     // We can't know, what went wrong.
       
  2347     // Stop contact handler, so that the next time the phone is booted
       
  2348     // full synchronization happens.
       
  2349     RUBY_DEBUG0( "CNssContactHandlerImplementation::NormalChangesHandleError " );
       
  2350     TRAPD( err, DoHandleEventFailedL(); );
       
  2351     if( err != KErrNone ) 
       
  2352         {
       
  2353         RUBY_ERROR1( "CNssContactHandlerImplementation::NormalChangesHandleError DoHandleEventFailedL Left with [%d]", err );
       
  2354         }
       
  2355     }
       
  2356 
       
  2357 //---------------------------------------------------------
       
  2358 // CNssContactHandlerImplementation::HandleTrainComplete
       
  2359 // Saves the tag after successful training.
       
  2360 //---------------------------------------------------------
       
  2361 //
       
  2362 void CNssContactHandlerImplementation::HandleTrainComplete( TInt aErrorCode )
       
  2363     {
       
  2364     if( aErrorCode == KErrNone )
       
  2365         {
       
  2366         RUBY_DEBUG1( "Training OK for %d:th name.", iTrainCallbackCounter );
       
  2367 
       
  2368         RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainComplete. iState [%d]", iState);
       
  2369         RUBY_ASSERT_DEBUG( iState == ECHInitializing || 
       
  2370                         iState == ECHHandlingNormalChanges,
       
  2371                         User::Panic( KFile, __LINE__ ) );
       
  2372 
       
  2373         iTrainCallbackCounter++;
       
  2374 
       
  2375         if ( iTrainCallbackCounter == iTagArray.Count() )
       
  2376             {
       
  2377             if ( iState != ECHInitializing )
       
  2378                 {
       
  2379                 // assert at the beginning of the function guarantees, 
       
  2380                 // that iState == ECHHandlingNormalChanges 
       
  2381                 DoAddNamesTrainingFinished();
       
  2382                 }
       
  2383             }        
       
  2384         }
       
  2385     
       
  2386     else // aErrorCode != KErrNone
       
  2387         {
       
  2388         RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainComplete. Training failed for %d:th name.\n",
       
  2389                     iTrainCallbackCounter );
       
  2390 
       
  2391         RUBY_ASSERT_DEBUG( iState == ECHInitializing || 
       
  2392                         iState == ECHHandlingNormalChanges,
       
  2393                         User::Panic( KFile, __LINE__ ) );
       
  2394 
       
  2395     	// Order removal of voice tag icon if present
       
  2396     	MNssRRD* rrd = iTagArray[iTrainCallbackCounter]->RRD();
       
  2397         CArrayFixFlat<TInt>* intArray = rrd->IntArray();
       
  2398         RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) );
       
  2399         if ( intArray->Count() >= 2 )
       
  2400         	{
       
  2401         	TInt error = iRemoveIconList.Append( intArray->At(0) );
       
  2402         	if( error != KErrNone ) 
       
  2403         		{
       
  2404         		RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError Failed to insert [%d] into iRemoveIconList. Error [%d]",
       
  2405         					intArray->At(0), error);
       
  2406         		}
       
  2407             }
       
  2408       	else
       
  2409             {
       
  2410             RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainComplete rrd->IntArray()->Count [%d] for iTrainCallbackCounter [%d]", 
       
  2411             			intArray->Count(), iTrainCallbackCounter);   	
       
  2412             }
       
  2413                 
       
  2414 
       
  2415         delete iTagArray[ iTrainCallbackCounter ];
       
  2416         iTagArray.Remove( iTrainCallbackCounter );
       
  2417 
       
  2418         if ( iTrainCallbackCounter == iTagArray.Count() )
       
  2419             {
       
  2420             if ( iState == ECHHandlingNormalChanges )
       
  2421                 {
       
  2422                 DoAddNamesTrainingFinished();
       
  2423                 }
       
  2424             else 
       
  2425             	{
       
  2426             	RUBY_ERROR1( "CNssContactHandlerImplementation::HandleTrainComplete Unexpected state [%d]", iState);
       
  2427             	}
       
  2428             }        
       
  2429         }
       
  2430     }
       
  2431 
       
  2432 //---------------------------------------------------------
       
  2433 // CNssContactHandlerImplementation::HandleTrainError
       
  2434 // Handles single tag training failure
       
  2435 //---------------------------------------------------------
       
  2436 //
       
  2437 /*void CNssContactHandlerImplementation::HandleTrainError( enum MNssTrainTextEventHandler::TNssTrainResult )
       
  2438     {
       
  2439     RUBY_DEBUG1( "CNssContactHandlerImplementation::HandleTrainError Training failed for %d:th name.\n",
       
  2440                 iTrainCallbackCounter );
       
  2441 
       
  2442     RUBY_ASSERT_DEBUG( iState == ECHInitializing || 
       
  2443                     iState == ECHHandlingNormalChanges,
       
  2444                     User::Panic( KFile, __LINE__ ) );
       
  2445 
       
  2446 	// Order removal of voice tag icon if present
       
  2447 	MNssRRD* rrd = iTagArray[iTrainCallbackCounter]->RRD();
       
  2448     CArrayFixFlat<TInt>* intArray = rrd->IntArray();
       
  2449     RUBY_ASSERT_DEBUG( intArray->Count() >= 2, User::Panic( KFile, __LINE__ ) );
       
  2450     if ( intArray->Count() >= 2 )
       
  2451     	{
       
  2452     	TInt error = iRemoveIconList.Append( intArray->At(0) );
       
  2453     	if( error != KErrNone ) 
       
  2454     		{
       
  2455     		RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError Failed to insert [%d] into iRemoveIconList. Error [%d]",
       
  2456     					intArray->At(0), error);
       
  2457     		}
       
  2458         }
       
  2459   	else
       
  2460         {
       
  2461         RUBY_ERROR2( "CNssContactHandlerImplementation::HandleTrainError rrd->IntArray()->Count [%d] for iTrainCallbackCounter [%d]", 
       
  2462         			intArray->Count(), iTrainCallbackCounter);   	
       
  2463         }
       
  2464             
       
  2465 
       
  2466     delete iTagArray[ iTrainCallbackCounter ];
       
  2467     iTagArray.Remove( iTrainCallbackCounter );
       
  2468 
       
  2469     if ( iTrainCallbackCounter == iTagArray.Count() )
       
  2470         {
       
  2471         if ( iState == ECHHandlingNormalChanges )
       
  2472             {
       
  2473             DoAddNamesTrainingFinished();
       
  2474             }
       
  2475         else 
       
  2476         	{
       
  2477         	RUBY_ERROR1( "CNssContactHandlerImplementation::HandleTrainError Unexpected state [%d]", iState);
       
  2478         	}
       
  2479         }
       
  2480     }*/
       
  2481 
       
  2482 //---------------------------------------------------------
       
  2483 // CNssContactHandlerImplementation::FullResyncStart
       
  2484 // Starts a full synchronization
       
  2485 //---------------------------------------------------------
       
  2486 //
       
  2487 void CNssContactHandlerImplementation::FullResyncStart()
       
  2488     {
       
  2489     // If we have synchronized earlier, we must delete the old context.
       
  2490     if ( iHaveWeEverSynced )
       
  2491         {
       
  2492         iContextManager->DeleteContext( this, iContext );
       
  2493         }
       
  2494     else
       
  2495         {
       
  2496         TRAPD( err, FullResyncCreateContextL() );
       
  2497         if ( err != KErrNone )
       
  2498             {
       
  2499             RUBY_ERROR1( "CNssContactHandlerImplementation::FullResyncStart. Error [%d] in FullResyncCreateContextL", err );
       
  2500             }
       
  2501         }
       
  2502     }
       
  2503 
       
  2504 // ------------------------------------------------------------
       
  2505 // CNssContactHandlerImplementation::FullResyncCreateContextL
       
  2506 // Full resync: Create a new context
       
  2507 // (prev: Destroy old context, next:populate the context with tags)
       
  2508 // ------------------------------------------------------------
       
  2509 //
       
  2510 void CNssContactHandlerImplementation::FullResyncCreateContextL()
       
  2511     {
       
  2512     RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::FullResyncCreateContextL" );
       
  2513     if ( iContext != 0 )
       
  2514         {
       
  2515         delete iContext;
       
  2516         iContext = 0;
       
  2517         }
       
  2518 
       
  2519     iContext = iContextManager->CreateContextL();
       
  2520     iContext->SetNameL( KNssCHNameDialContext );
       
  2521     iContext->SetGlobal( ETrue );
       
  2522 
       
  2523     TBuf8<KClientDataSize> clientDataBuf;
       
  2524     iClientData.iLanguage = User::Language();
       
  2525     iClientData.iContactSyncId = KErrNotFound;
       
  2526     	
       
  2527     TRAPD( error, iClientData.ExternalizeL( clientDataBuf ) );
       
  2528     if ( !error )
       
  2529         {
       
  2530         iContext->SetClientData( clientDataBuf );
       
  2531         iContextManager->SaveContext( this, iContext );
       
  2532         }
       
  2533     }
       
  2534 
       
  2535 // ------------------------------------------------------------
       
  2536 // CNssContactHandlerImplementation::FullResyncCreateChanges
       
  2537 // Create tags and send training requests to VAS.
       
  2538 // VAS trains them and calls back when it's ready
       
  2539 // ------------------------------------------------------------
       
  2540 //
       
  2541 void CNssContactHandlerImplementation::FullResyncCreateChangesL()
       
  2542     {
       
  2543 	RUBY_DEBUG_BLOCK( "CNssContactHandlerImplementation::FullResyncCreateChangesL" );
       
  2544 
       
  2545     WaitUntilNoSyncBackupIsRunning();
       
  2546 
       
  2547     CContactIdArray* ids = iPbkHandler->ContactIdArrayLC();
       
  2548 	
       
  2549 	RUBY_DEBUG0( "CNssContactHandlerImplementation::FullResyncCreateChanges. iContactQueue.Count() == 0" );
       
  2550     RUBY_ASSERT_DEBUG( iContactQueue.Count() == 0, User::Panic( KFile, __LINE__ ) );
       
  2551     // Create change events for training
       
  2552     for ( TInt k( 0 ); k < ids->Count(); k++ )
       
  2553         {
       
  2554         TPhonebookEvent event;
       
  2555         event.iContactId = (*ids)[k];
       
  2556         event.iType = EContactAdded;
       
  2557         iEventArray.Append( event );
       
  2558         }
       
  2559 
       
  2560     CleanupStack::PopAndDestroy( ids ); // Cleanup stack: empty
       
  2561 
       
  2562     // go to processing events
       
  2563     SetState ( ECHIdle );
       
  2564     TRAPD( err, DoHandleEventsL() );
       
  2565     if ( err != KErrNone )
       
  2566         {
       
  2567         RUBY_ERROR1( "CNssContactHandlerImplementation::FullResyncCreateChanges. Error [%d] in DoHandleEventsL", err );
       
  2568         }
       
  2569     }
       
  2570 
       
  2571 // ------------------------------------------------------------    
       
  2572 // CNssContactHandlerImplementation::DeleteContextCompleted
       
  2573 // DeleteContext callback. Deleting a context is part of
       
  2574 // full synchronization.
       
  2575 // ------------------------------------------------------------
       
  2576 //
       
  2577 void CNssContactHandlerImplementation::DeleteContextCompleted( TInt aErrorCode )
       
  2578     {
       
  2579     if( aErrorCode == KErrNone )
       
  2580         {
       
  2581         // Go to the next phase of full synchronization
       
  2582         RUBY_DEBUG1( "CNssContactHandlerImplementation::DeleteContextCompleted. iState == ECHFullResync, iState [%d]", iState );
       
  2583         RUBY_ASSERT_DEBUG( iState == ECHFullResync, User::Panic( KFile, __LINE__ ) );
       
  2584         TRAPD( err, FullResyncCreateContextL() );
       
  2585         if ( err != KErrNone )
       
  2586             {
       
  2587             RUBY_ERROR1( "CNssContactHandlerImplementation::DeleteContextCompleted. Error [%d] in FullResyncCreateContextL", err );
       
  2588             }        
       
  2589         }
       
  2590     else
       
  2591         {
       
  2592         RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteContextCompleted failed" );
       
  2593         RUBY_ASSERT_DEBUG( iState == ECHFullResync, User::Panic( KFile, __LINE__ ) );
       
  2594 
       
  2595         RUBY_DEBUG0( "CNssContactHandlerImplementation::DeleteContextCompleted - can't handle, stopping." );
       
  2596     	TRAPD( err, DoHandleEventFailedL(); );
       
  2597     	if( err != KErrNone ) 
       
  2598     		{
       
  2599     		RUBY_ERROR1( "CNssContactHandlerImplementation::DeleteContextCompleted Left with [%d]", err);
       
  2600     		}        
       
  2601         }
       
  2602     }
       
  2603 
       
  2604 // ------------------------------------------------------------
       
  2605 // CNssContactHandlerImplementation::CausedByVoiceTagAddition
       
  2606 // Check if the event was caused by voice tag field adding
       
  2607 // ------------------------------------------------------------
       
  2608 //
       
  2609 TBool CNssContactHandlerImplementation::CausedByVoiceTagAddition( const TPhonebookEvent& aEvent )
       
  2610 	{
       
  2611 	TBool isVoiceTagAddedEvent (EFalse);
       
  2612 	if( EContactChanged == aEvent.iType )
       
  2613 		{
       
  2614 		for ( TInt i = 0; i < iVoiceTagAddedList.Count(); i++ )
       
  2615         	{
       
  2616         	if ( aEvent.iContactId == iVoiceTagAddedList[i] )
       
  2617         		{
       
  2618             	isVoiceTagAddedEvent = ETrue;
       
  2619             	iVoiceTagAddedList.Remove( i-- );  // "i--" because of removal
       
  2620             	// Continue iterations. We are not sure if voice tag for the given 
       
  2621             	// contact could be changed twice
       
  2622             	}
       
  2623         	}  // for
       
  2624 		}  // if event type
       
  2625 	return isVoiceTagAddedEvent;
       
  2626 	}
       
  2627 
       
  2628 // ------------------------------------------------------------
       
  2629 // CNssContactHandlerImplementation::PeriodicCallback
       
  2630 // Static callback required by Symbian Timer services.
       
  2631 // ------------------------------------------------------------
       
  2632 //
       
  2633 TInt CNssContactHandlerImplementation::PeriodicCallback( TAny* pX )
       
  2634 	{
       
  2635 	((CNssContactHandlerImplementation*)pX)->DoPeriodicCallback();
       
  2636 	return KErrNone;  // useless for CPeriodic
       
  2637 	}
       
  2638     
       
  2639 // ------------------------------------------------------------
       
  2640 // CNssContactHandlerImplementation::DoPeriodicCallback
       
  2641 // Periodically check if there are some events to process
       
  2642 // ------------------------------------------------------------
       
  2643 //
       
  2644 void CNssContactHandlerImplementation::DoPeriodicCallback()
       
  2645 	{
       
  2646 	RUBY_DEBUG0( "CNssContactHandlerImplementation::DoPeriodicCallback" );
       
  2647 	// Check is needed to eliminate unnesessary TRAP and 64 bit time operations
       
  2648 	// Note, that we are not checking for PeriodicAction(), but for iPeriodicHandleEventTimer == NULL
       
  2649 	// PeriodicAction() is a method for detection of start of the action,
       
  2650 	// while iPeriodicHandleEventTimer == NULL says if periodic action is being executed
       
  2651 	// right *now*
       
  2652 	
       
  2653 	if ( ( iState == ECHIdle ) && ( iEventArray.Count() > 0 ) && ( !PeriodicAction() ) ) 
       
  2654 		{
       
  2655 		RUBY_DEBUG1( "CNssContactHandlerImplementation::DoPeriodicCallback. iState is ECHIdle, there are [%d] events to handle and no periodic action in progress", iEventArray.Count());
       
  2656 		TRAPD( err, DoHandleEventsL());
       
  2657         if ( err != KErrNone )
       
  2658             {
       
  2659             RUBY_ERROR1( "CNssContactHandlerImplementation::DoPeriodicCallback. Error [%d] in DoHandleEventsL", err );
       
  2660             }
       
  2661         }  // if there are some events
       
  2662 	else
       
  2663 		{
       
  2664 		RUBY_DEBUG0( "CNssContactHandlerImplementation::DoPeriodicCallback No events to handle"  );
       
  2665 		}
       
  2666 	}
       
  2667 	
       
  2668 // ---------------------------------------------------------
       
  2669 // CNssContactHandlerImplementation::PeriodicAction
       
  2670 // Detects periodic action.
       
  2671 // Checks if many events have been received "lately"
       
  2672 // ---------------------------------------------------------
       
  2673 //
       
  2674 TBool CNssContactHandlerImplementation::PeriodicAction()
       
  2675     {
       
  2676     // index of the first recorded call
       
  2677     TInt checkedIndex = iEventMomentIndex + 1;
       
  2678     checkedIndex = checkedIndex < KEventMomentsSize ? checkedIndex : 0;
       
  2679     TTime& checkedTime = iEventMoments[checkedIndex];
       
  2680     
       
  2681     // Check if the first recorded call happened "lately" = within last 
       
  2682     // KPeriodicActionInterval seconds
       
  2683     TTime currentTime;
       
  2684     currentTime.UniversalTime();
       
  2685     TTimeIntervalMicroSeconds diff = currentTime.MicroSecondsFrom( checkedTime );
       
  2686     TBool result = diff < iEndOfPeriodicActionInterval;
       
  2687     if ( result == EFalse ) 
       
  2688         {
       
  2689         RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction. Periodic action completed." );
       
  2690         RUBY_DEBUG2( "CNssContactHandlerImplementation::PeriodicAction. Periodic action completed. iEventMomentIndex [%d], checkedIndex [%d]", iEventMomentIndex, checkedIndex );
       
  2691         RUBY_DEBUG1( "currentTime [%d]", I64INT(currentTime.Int64()));
       
  2692         RUBY_DEBUG2( "CNssContactHandlerImplementation::PeriodicAction. diff [%d], iEndOfPeriodicActionInterval [%d]", I64INT(diff.Int64()), I64INT(iEndOfPeriodicActionInterval.Int64() ) );
       
  2693         
       
  2694         for( TInt i = 0; i < KEventMomentsSize; i++ ) 
       
  2695             {
       
  2696             RUBY_DEBUG2( "checkedIndex[%d] = [%d]", i, I64INT(iEventMoments[i].Int64() ) );
       
  2697             }
       
  2698         
       
  2699         // Periodic action completed. Or hasn't even been started
       
  2700         // Restore timeout values
       
  2701         // iEndOfPeriodicActionInterval = KInitialPeriodicActionInterval;
       
  2702         if ( iPeriodicHandleEventTimer != NULL ) 
       
  2703             {
       
  2704             // stop the timer, it was started, when periodic action was started
       
  2705             RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction Stopping the periodic action timer" );
       
  2706             iPeriodicHandleEventTimer->Cancel();
       
  2707             delete iPeriodicHandleEventTimer;
       
  2708             iPeriodicHandleEventTimer = NULL;
       
  2709             }
       
  2710         }
       
  2711     else 
       
  2712         {
       
  2713         // Periodic action detected
       
  2714         // start the timer if it is not running yet
       
  2715         if( iPeriodicHandleEventTimer == NULL ) 
       
  2716             {
       
  2717             TRAPD( err, iPeriodicHandleEventTimer = CPeriodic::NewL( EPriorityNormal ) );
       
  2718             if( err != KErrNone ) 
       
  2719                 {
       
  2720                 // This is a bad situation, but not the fatal one.
       
  2721                 // If we cannot use timer to detect end of periodic action,
       
  2722                 // Let's disable periodic action detection at all
       
  2723                 RUBY_DEBUG1( "CNssContactHandlerImplementation::PeriodicAction. PeriodicTimer creation failed. Error [%d]. Disabling periodic actions", err);
       
  2724                 result = EFalse;
       
  2725                 }
       
  2726             else 
       
  2727                 {  // Timer was created successfully
       
  2728                 RUBY_DEBUG0( "CNssContactHandlerImplementation::PeriodicAction Starting the periodic action timer" );
       
  2729                 iPeriodicHandleEventTimer->Start( KPeriodicTimerInterval, KPeriodicTimerInterval, TCallBack( PeriodicCallback, this ) );
       
  2730                 }
       
  2731             }
       
  2732         }
       
  2733     return result;
       
  2734     }
       
  2735 	
       
  2736 // ------------------------------------------------------------
       
  2737 // CNssContactHandlerImplementation::UpdatePeriodicActionVars
       
  2738 // Update variables, used to detect if periodic action is happening
       
  2739 // ------------------------------------------------------------
       
  2740 //
       
  2741 void CNssContactHandlerImplementation::UpdatePeriodicActionVars()
       
  2742     {
       
  2743     if ( ++iEventMomentIndex >= KEventMomentsSize )
       
  2744         {
       
  2745         iEventMomentIndex = 0;
       
  2746         }
       
  2747     iEventMoments[iEventMomentIndex].UniversalTime();
       
  2748     
       
  2749     // Update values used to detect end of periodic action
       
  2750     TTimeIntervalMicroSeconds32 currInterval = MaximalInterval( iEventMoments, KEventMomentsSize, iEventMomentIndex );
       
  2751     // 8 times. At the end of action, this would typically be no longer, than 0.5secs
       
  2752     // Note, that this is the interval fo KEventMomentsSize events
       
  2753     if ( ( currInterval.Int() << 3 ) >= ( KInitialPeriodicActionInterval ) ) 
       
  2754         {
       
  2755         RUBY_DEBUG1( "CNssContactHandlerImplementation::UpdatePeriodicActionVars. Calculated interval is too big. Reverting periodic interval to the max [%d] mcs", KInitialPeriodicActionInterval);
       
  2756         iEndOfPeriodicActionInterval = KInitialPeriodicActionInterval;
       
  2757         }
       
  2758     else 
       
  2759         {
       
  2760         currInterval = currInterval.Int() << 3;  
       
  2761         RUBY_DEBUG1( "CNssContactHandlerImplementation::UpdatePeriodicActionVars. Adjusting periodic interval to [%d] mcs", currInterval.Int() );
       
  2762         iEndOfPeriodicActionInterval = currInterval.Int();
       
  2763         }
       
  2764     }
       
  2765 
       
  2766 // ------------------------------------------------------------
       
  2767 // CNssContactHandlerImplementation::MaximalInterval
       
  2768 // Return maximal interval from the array of time moments
       
  2769 // ------------------------------------------------------------
       
  2770 //
       
  2771 TTimeIntervalMicroSeconds32 CNssContactHandlerImplementation::MaximalInterval( const TTime aMoments[], const TInt aMomentsLength, const TInt aLastMomentIndex )
       
  2772     {
       
  2773     RUBY_ASSERT_DEBUG( aMomentsLength > 1, User::Panic( KFile, __LINE__ ) );
       
  2774     TInt currIndex( aLastMomentIndex );
       
  2775     TInt prevIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1;
       
  2776     TTimeIntervalMicroSeconds32 result( 0 );
       
  2777     TTimeIntervalMicroSeconds currInterval;
       
  2778     
       
  2779     for ( TInt i = 0; i < aMomentsLength - 1; i++ ) 
       
  2780         {
       
  2781         currInterval = aMoments[currIndex].MicroSecondsFrom( aMoments[prevIndex] );
       
  2782         const TInt64& currIntVal = currInterval.Int64();
       
  2783         TBool tooBigValue = currIntVal > KMaxTInt;
       
  2784         
       
  2785         // if high != 0, aMoments were filled in the incorrect way
       
  2786         // but we should not bug the user about it
       
  2787         if ( tooBigValue ) 
       
  2788             {
       
  2789             // this cannot be a negative value.. if moments are recorded in the correct order.
       
  2790             // Then non-zero high means, that interval is too big to fit into
       
  2791             // TTimeIntervalMicroSeconds32
       
  2792             RUBY_DEBUG0( "CNssContactHandlerImplementation::MaximalInterval. Maximal interval is out of bounds" );
       
  2793             result = TTimeIntervalMicroSeconds32( KMaxTInt );
       
  2794             break;
       
  2795             }
       
  2796         else 
       
  2797             {
       
  2798             // normal size value
       
  2799             // casting is safe - we checked, that it fits into TInt
       
  2800             TTimeIntervalMicroSeconds32 currInterval32 ( (TInt)currIntVal );
       
  2801             
       
  2802             if ( currInterval32 > result ) 
       
  2803                 {
       
  2804                 result = currInterval32;
       
  2805                 }
       
  2806             }
       
  2807         currIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1;
       
  2808         prevIndex = currIndex - 1 < 0 ? aMomentsLength - 1 : currIndex - 1;
       
  2809         }  // for
       
  2810     return result;
       
  2811     }
       
  2812 
       
  2813 // ------------------------------------------------------------
       
  2814 // CNssContactHandlerImplementation::SetState
       
  2815 // Sets the contact handler state. 
       
  2816 // In debug, panics (via asserts) if state change is not legal
       
  2817 // ------------------------------------------------------------
       
  2818 //
       
  2819 void CNssContactHandlerImplementation::SetState( TContactHandlerState aState )
       
  2820 	{
       
  2821     RUBY_DEBUG2( "CNssContactHandlerImplementation::SetState from [%d] to [%d]", iState, aState);
       
  2822     switch( aState ) 
       
  2823         {
       
  2824         case ECHFullResync:
       
  2825             // no pending events
       
  2826             RUBY_ASSERT_DEBUG( ( iDeleteTagListArray == NULL ) || ( iDeleteCallbackCounter == iDeleteTagListArray->Count() ), User::Panic( KFile, __LINE__ ) );
       
  2827             RUBY_ASSERT_DEBUG( iSaveCallbackCounter == iTagArray.Count(), User::Panic( KFile, __LINE__ ) );
       
  2828             
       
  2829             // full resyncronization needed again if this full resyncronization fails
       
  2830             RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) );
       
  2831             break;
       
  2832         case ECHHandlingNormalChanges:
       
  2833             RUBY_ASSERT_DEBUG( iState == ECHIdle, User::Panic( KFile, __LINE__ ) );
       
  2834             RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) );
       
  2835             break;
       
  2836         case ECHIdle:
       
  2837             if ( iDeleteTagListArray != NULL ) 
       
  2838                 {
       
  2839                 RUBY_ASSERT_DEBUG( (iSaveCallbackCounter == iTagArray.Count() ) || ( iDeleteCallbackCounter == iDeleteTagListArray->Count() ), User::Panic( KFile, __LINE__ ) );
       
  2840                 }
       
  2841             else 
       
  2842                 {
       
  2843                 RUBY_ASSERT_DEBUG( ( iSaveCallbackCounter == iTagArray.Count() ) , User::Panic( KFile, __LINE__ ) );
       
  2844                 }
       
  2845             if( iEventArray.Count() == 0 ) 
       
  2846                 {
       
  2847                     // Idle state and no pending events mean, that contact handler
       
  2848                     // completed its operations for now
       
  2849                     TInt errProp = iBusyProperty.Set( EContactsNoTraining );
       
  2850                     if ( errProp != KErrNone )
       
  2851                         {
       
  2852                         RUBY_ERROR1("CNssContactHandlerImplementation::ConstructL() Failed to set property. Error [%d]", 
       
  2853                                     errProp );
       
  2854                         // @todo Not a leaving function -> leave commented out
       
  2855                         //User::Leave( errProp )  ;
       
  2856                         }
       
  2857                 }
       
  2858                 
       
  2859             // all changes done, no need for resyncronization
       
  2860             RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( EFalse ) );
       
  2861             
       
  2862             break;
       
  2863         default:
       
  2864             RUBY_ERROR0( "CNssContactHandlerImplementation::SetState Unexpected or unknown state" );
       
  2865             RUBY_ASSERT_DEBUG( EFalse, User::Panic( KFile, __LINE__ ) );
       
  2866             
       
  2867             // failure, full resyncronization needed
       
  2868             RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) );
       
  2869             break;
       
  2870         }
       
  2871     // actually switch state
       
  2872     iState = aState;
       
  2873     }
       
  2874 
       
  2875 // ---------------------------------------------------------
       
  2876 // CNssContactHandlerImplementation::DataSyncStateChanged
       
  2877 //
       
  2878 // ---------------------------------------------------------
       
  2879 //
       
  2880 void CNssContactHandlerImplementation::DataSyncStateChanged( TBool aRunning )
       
  2881     {
       
  2882     if( !aRunning && ( iSyncBackupWaiter->IsStarted() ) )
       
  2883         {
       
  2884         RUBY_DEBUG0( "DataSyncStateChanged Sync became inactive and CH was waiting for it" );
       
  2885         iSyncBackupWaiter->AsyncStop();
       
  2886         }
       
  2887     }
       
  2888     
       
  2889 // ---------------------------------------------------------
       
  2890 //  Is called when backup/restore status is changed and when backup/restore
       
  2891 //  state observation was just started
       
  2892 //  @param aRunning ETrue if some backup/restore action is in progress
       
  2893 //                  EFalse otherwise
       
  2894 //  @param aRestoreType ETrue if the event is restore related
       
  2895 //                      EFalse if the event is backup related
       
  2896 //  @see CNssChBackupObserver
       
  2897 // ---------------------------------------------------------
       
  2898 void CNssContactHandlerImplementation::BackupRestoreStateChanged( TBool aRestoreType, 
       
  2899                                                                   TBool aRunning )
       
  2900 	{
       
  2901     RUBY_DEBUG2( "BackupRestoreStateChanged aRestoreType [%d], aRunning [%d]", 
       
  2902                   aRestoreType, aRunning );
       
  2903     
       
  2904     if( aRestoreType && aRunning )
       
  2905         {
       
  2906         RUBY_DEBUG0( "Setting the Full Resync CR flag" );
       
  2907         RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) );
       
  2908         }
       
  2909     
       
  2910     if( !aRunning && ( iSyncBackupWaiter->IsStarted() ) )
       
  2911         {
       
  2912         RUBY_DEBUG0( "BackupRestoreStateChanged b/r became inactive and CH was waiting for it" );
       
  2913         iSyncBackupWaiter->AsyncStop();
       
  2914         }	
       
  2915 	}
       
  2916 
       
  2917 // ---------------------------------------------------------
       
  2918 // CNssContactHandlerImplementation::HandleNotifyInt
       
  2919 //
       
  2920 // ---------------------------------------------------------
       
  2921 // 	
       
  2922 void CNssContactHandlerImplementation::HandleNotifyInt( TUint32 aId, TInt aNewValue )
       
  2923     {
       
  2924     RUBY_DEBUG0( "" );
       
  2925     
       
  2926     if ( aId == KSRSFFullResyncNeeded )
       
  2927         {
       
  2928         if ( aNewValue == KImmediateResync )
       
  2929             {
       
  2930             RUBY_DEBUG0( "Immediate full resync requested" );
       
  2931             
       
  2932             // Write the previous value back to the cenrep
       
  2933             TRAP_IGNORE( SetFullResyncCrFlagL( iResyncAtBoot ) );
       
  2934             
       
  2935             // Create an event that will launch full resync
       
  2936             TPhonebookEvent event;
       
  2937             event.iType = ENullEvent;
       
  2938             event.iContactId = 0;
       
  2939         
       
  2940             iEventArray.Append( event );
       
  2941             
       
  2942             // Start resync if nothing is ongoing
       
  2943             if ( iState == ECHIdle )
       
  2944                 {
       
  2945                 TRAP_IGNORE( DoHandleEventsL() );
       
  2946                 }
       
  2947             }
       
  2948         }
       
  2949     }
       
  2950     
       
  2951 // ---------------------------------------------------------
       
  2952 // Sets the central repository full resync flag
       
  2953 // ---------------------------------------------------------
       
  2954 void CNssContactHandlerImplementation::SetFullResyncCrFlagL( TBool aResyncNeeded )
       
  2955     {
       
  2956     RUBY_DEBUG_BLOCKL("");
       
  2957     User::LeaveIfError( iRepository->Set( KSRSFFullResyncNeeded, aResyncNeeded ) );
       
  2958     iResyncAtBoot = aResyncNeeded;
       
  2959     }
       
  2960 
       
  2961 // ---------------------------------------------------------
       
  2962 // CNssContactHandlerImplementation::WaitUntilNoSyncBackupIsRunning
       
  2963 //
       
  2964 // ---------------------------------------------------------
       
  2965 //    
       
  2966 void CNssContactHandlerImplementation::WaitUntilNoSyncBackupIsRunning()
       
  2967     {
       
  2968     RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning start" );
       
  2969     RUBY_ASSERT_DEBUG( !iSyncBackupWaiter->IsStarted(), User::Panic( KFile, __LINE__ ) );
       
  2970     
       
  2971     // Disconnection from phonebook should happen only once and only if b/r is running
       
  2972     TBool disconnectedFromPb = EFalse;
       
  2973     
       
  2974     // Check the values until both data sync and backup/restore are not active
       
  2975     while( iDataSyncWatcher->InProgress() || iBackupObserver->InProgress() )
       
  2976     	{
       
  2977     	RUBY_DEBUG2( "WaitUntilNoSyncBackupIsRunning Have to wait. data sync [%d], backup/restore [%d]",
       
  2978     				 iDataSyncWatcher->InProgress(), iBackupObserver->InProgress() );
       
  2979     	if( !iSyncBackupWaiter->IsStarted() ) 
       
  2980             {
       
  2981             if( (!disconnectedFromPb) && iBackupObserver->InProgress() )
       
  2982             	{
       
  2983             	RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning Disconnecting from phonebook" );
       
  2984             	DisconnectFromPhonebook();
       
  2985             	disconnectedFromPb = ETrue;
       
  2986             	}
       
  2987             iSyncBackupWaiter->Start();
       
  2988             }
       
  2989         else 
       
  2990             {
       
  2991             RUBY_ERROR0( "WaitUntilNoSyncBackupIsRunning Attempt to start already active iSyncBackupWaiter. Huge error!" );
       
  2992             }
       
  2993     	}
       
  2994     	
       
  2995     if( disconnectedFromPb )
       
  2996     	{
       
  2997     	RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning Reconnecting to phonebook" );
       
  2998     	TRAP_IGNORE( ConnectToPhonebookL() );
       
  2999     	}
       
  3000             
       
  3001     RUBY_DEBUG0( "WaitUntilNoSyncBackupIsRunning end" );
       
  3002     }
       
  3003 
       
  3004 // ---------------------------------------------------------
       
  3005 // CNssContactHandlerImplementation::GetContactL
       
  3006 //
       
  3007 // ---------------------------------------------------------
       
  3008 //        
       
  3009 void CNssContactHandlerImplementation::GetContactL( TContactItemId aContactId, TBool aReadContact ) 
       
  3010     {
       
  3011     RUBY_DEBUG1( "CNssContactHandlerImplementation::GetContactL. contact id [%d]", aContactId );
       
  3012     TInt err = KErrNone;
       
  3013     // Number of attempts tries
       
  3014     TInt attemptsTried( 0 );
       
  3015     do 
       
  3016         {
       
  3017         if( err == KErrInUse ) // i.e. not the first cycle iteration
       
  3018             {
       
  3019             RUBY_DEBUG2( "GetContactL Contact [%d] is locked. Waiting one more second. Retrial [%d]", 
       
  3020                          aContactId, attemptsTried);
       
  3021             // start periodic timer
       
  3022             if( attemptsTried == 1)   // i.e exactly the second cycle iteration
       
  3023                 {
       
  3024                 RUBY_DEBUG0( "GetContactL Creating periodic timer" );
       
  3025                 iContactWaitTimer = CPeriodic::NewL( EPriorityNormal );
       
  3026                 iContactWaitTimer->Start( KContactWaitInterval, KContactWaitInterval, TCallBack( ContactWaitCallback, this ) );
       
  3027                 }
       
  3028             RUBY_DEBUG0( "GetContactL Starting the inner cycle waiting" );
       
  3029             iContactWaiter->Start( );
       
  3030             RUBY_DEBUG0( "GetContactL Waiting completed, trying to open contact again" );
       
  3031             }
       
  3032             
       
  3033         TRAP( err, iPbkHandler->FindContactL( aContactId, aReadContact ) );
       
  3034 
       
  3035         attemptsTried++;
       
  3036         // -1 means forever
       
  3037         if( ( KMaxContactLockRetrials != -1 ) && ( attemptsTried >= KMaxContactLockRetrials ) ) 
       
  3038             {
       
  3039             RUBY_DEBUG1( "GetContactL Tried for [%d] times, still no success", attemptsTried );
       
  3040             break;
       
  3041             }
       
  3042         }
       
  3043     while( err == KErrInUse );
       
  3044     if( iContactWaitTimer != NULL ) 
       
  3045         {
       
  3046         iContactWaitTimer->Cancel();
       
  3047         delete iContactWaitTimer;
       
  3048         iContactWaitTimer = NULL;
       
  3049         }
       
  3050     // Propagate all the leaves, BUT KErrInUse
       
  3051     if( ( err != KErrInUse ) && ( err != KErrNone ) )
       
  3052         {
       
  3053         User::LeaveIfError( err );
       
  3054         }
       
  3055     if( err == KErrInUse ) 
       
  3056         {
       
  3057         RUBY_DEBUG1( "GetContactL Failed to lock contact [%d]. Disabling CH, will resync on reboot", aContactId );
       
  3058         DisableEventHandling();
       
  3059         User::Leave( KErrInUse );
       
  3060         }
       
  3061     RUBY_DEBUG0( "CNssContactHandlerImplementation::GetContactL completed" );
       
  3062     }
       
  3063 
       
  3064 // ---------------------------------------------------------
       
  3065 // CNssContactHandlerImplementation::ReadContactL
       
  3066 //
       
  3067 // ---------------------------------------------------------
       
  3068 //     
       
  3069 void CNssContactHandlerImplementation::ReadContactL( TContactItemId aContactId )
       
  3070     {
       
  3071     GetContactL( aContactId, ETrue );
       
  3072     }
       
  3073     
       
  3074 // ---------------------------------------------------------
       
  3075 // CNssContactHandlerImplementation::OpenContactL
       
  3076 //
       
  3077 // ---------------------------------------------------------
       
  3078 //     
       
  3079 void CNssContactHandlerImplementation::OpenContactL( TContactItemId aContactId )
       
  3080     {
       
  3081     GetContactL( aContactId, EFalse );
       
  3082     }
       
  3083     
       
  3084 // ---------------------------------------------------------
       
  3085 // CNssContactHandlerImplementation::ContactWaitCallback
       
  3086 //
       
  3087 // ---------------------------------------------------------
       
  3088 //     
       
  3089 TInt CNssContactHandlerImplementation::ContactWaitCallback( TAny* pX )
       
  3090     {
       
  3091 	((CNssContactHandlerImplementation*)pX)->DoContactWaitCallback();
       
  3092 	return KErrNone;  // useless for CPeriodic    
       
  3093     }
       
  3094 
       
  3095 // ---------------------------------------------------------
       
  3096 // CNssContactHandlerImplementation::DoContactWaitCallback
       
  3097 //
       
  3098 // ---------------------------------------------------------
       
  3099 //             
       
  3100 void CNssContactHandlerImplementation::DoContactWaitCallback()
       
  3101     {
       
  3102     iContactWaiter->AsyncStop();
       
  3103     }
       
  3104 
       
  3105 // ---------------------------------------------------------
       
  3106 // CNssContactHandlerImplementation::NoDiskSpace
       
  3107 // Checks if there is not enough disk space to finish the
       
  3108 // operation. Returns ETrue if there is no space.
       
  3109 // ---------------------------------------------------------
       
  3110 //    
       
  3111 TBool CNssContactHandlerImplementation::NoDiskSpace()
       
  3112     {
       
  3113     RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace" );
       
  3114     TBool diskSpace( EFalse );
       
  3115     TRAP_IGNORE( diskSpace = SysUtil::FFSSpaceBelowCriticalLevelL( &iFSession, KIncreaseOfDatabaseSizes ) );
       
  3116     
       
  3117     if ( diskSpace )
       
  3118         {
       
  3119         RUBY_TRAP_IGNORE( SetFullResyncCrFlagL( ETrue ) );
       
  3120         RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace NOT enough disk space available" );
       
  3121         return ETrue;
       
  3122         }
       
  3123     else
       
  3124         {
       
  3125         RUBY_DEBUG0( "CNssContactHandlerImplementation::NoDiskSpace There is enough disk space" );
       
  3126         return EFalse;
       
  3127         }
       
  3128     }
       
  3129 
       
  3130 // ---------------------------------------------------------
       
  3131 // CNssContactHandlerImplementation::TrimName
       
  3132 // Substitutes separator characters in descriptor with
       
  3133 // white spaces. Removes extra withspaces. 
       
  3134 // ---------------------------------------------------------
       
  3135 //    
       
  3136 void CNssContactHandlerImplementation::TrimName( HBufC* aBuf )
       
  3137     {
       
  3138     TPtr ptr = aBuf->Des();
       
  3139    
       
  3140     for ( TInt findIndex = 0; findIndex < aBuf->Des().Length(); findIndex++ )
       
  3141         {
       
  3142         if ( ptr[findIndex] == iSeparator )
       
  3143             {
       
  3144             ptr[findIndex] = ' ';
       
  3145             }
       
  3146         }
       
  3147        
       
  3148     ptr.TrimAll();
       
  3149     }
       
  3150 
       
  3151 // ---------------------------------------------------------
       
  3152 // CNssContactHandlerImplementation::AppendName
       
  3153 // Appends name to given buffer
       
  3154 // ---------------------------------------------------------
       
  3155 //    
       
  3156 void CNssContactHandlerImplementation::AppendName( HBufC* aBuf, HBufC* aName )
       
  3157     {
       
  3158     if ( aName->Length() != 0 )
       
  3159         {     
       
  3160         aBuf->Des().Append( iSeparator );
       
  3161         aBuf->Des().Append( KNameTrainingIndex );
       
  3162         aBuf->Des().Append( aName->Des() );
       
  3163         }
       
  3164     }
       
  3165 
       
  3166 // ---------------------------------------------------------
       
  3167 // CNssContactHandlerImplementation::AppendExtensionMarker
       
  3168 // Appends marker for the extensions
       
  3169 // Parameters should be in format "%U text message"
       
  3170 // In which case output is "%U_2text message"
       
  3171 // ---------------------------------------------------------
       
  3172 //    
       
  3173 void CNssContactHandlerImplementation::AppendExtensionMarker( TDes& aDes )
       
  3174     {
       
  3175     if ( aDes.Length() > 0 )
       
  3176         {
       
  3177         TInt insertPosition( 0 );
       
  3178         if ( aDes.Find( KExtensionFormatString ) == 0 )
       
  3179             {
       
  3180             // Find the first space and insert marker to that position
       
  3181             TInt firstSpace( 0 );
       
  3182             firstSpace = aDes.Find( _L(" ") );
       
  3183             if ( firstSpace == 2 )         // Next character after KExtensionFormatString
       
  3184                 {
       
  3185                 aDes.Delete( firstSpace, 1 );
       
  3186                 }
       
  3187             insertPosition = 2;
       
  3188             }
       
  3189         // Insert marker
       
  3190         aDes.Insert( insertPosition, KExtensionTrainingIndex );
       
  3191         aDes.Insert( insertPosition, KNameSeparator );
       
  3192         }
       
  3193     }
       
  3194 
       
  3195 /**
       
  3196 * Establishes the connection to the contact engine and 
       
  3197 * starts listening to it
       
  3198 */ 
       
  3199 void CNssContactHandlerImplementation::ConnectToPhonebookL()
       
  3200 	{
       
  3201 	RUBY_ASSERT_DEBUG( (!iPbkHandler), User::Leave( KErrNotReady ) );
       
  3202 	iPbkHandler = CVasVPbkHandler::NewL();
       
  3203 	iPbkHandler->InitializeL();
       
  3204 	iPbkHandler->CreateContactObserverL( this );
       
  3205 	}
       
  3206 
       
  3207 /** 
       
  3208 * Clears the connection to the contact engine
       
  3209 */
       
  3210 void CNssContactHandlerImplementation::DisconnectFromPhonebook()
       
  3211 	{
       
  3212 	delete iPbkHandler;
       
  3213 	iPbkHandler = NULL;
       
  3214 	}
       
  3215     
       
  3216 #ifdef __SIND_EXTENSIONS	
       
  3217 
       
  3218 // ---------------------------------------------------------
       
  3219 // CNssContactHandlerImplementation::ReadExtensionsL
       
  3220 // Reads the extension resource file
       
  3221 // ---------------------------------------------------------
       
  3222 //           
       
  3223 void CNssContactHandlerImplementation::ReadExtensionsL()
       
  3224     {
       
  3225     // using StringLoader should be used, but there is no 
       
  3226     // access to CCoeEnv
       
  3227     
       
  3228 
       
  3229     // letters for drives in search order
       
  3230     const TBuf<1> KResourceDrivers = _L("z"); 
       
  3231     _LIT( KResourceFileName, "nssvascontacthandler.rsc" );
       
  3232     
       
  3233     // number of extension commands in the resource file
       
  3234     const TInt KExtensionCommandCount = 8;
       
  3235    
       
  3236     // load resources
       
  3237     RResourceFile resourceFile;
       
  3238     RFs fs;
       
  3239     CleanupClosePushL( fs );
       
  3240     TBool found( EFalse );
       
  3241     User::LeaveIfError( fs.Connect() );
       
  3242    
       
  3243         
       
  3244     TFileName name;
       
  3245     TInt i( 0 );
       
  3246     // use the first drive
       
  3247     name.Append( KResourceDrivers[i] );
       
  3248     name.Append(':');
       
  3249     name.Append( KDC_RESOURCE_FILES_DIR );
       
  3250     name.Append( KResourceFileName );
       
  3251 
       
  3252     while ( !found && i < KResourceDrivers.Length() )
       
  3253         {
       
  3254         name[0] = KResourceDrivers[i++];
       
  3255 
       
  3256         BaflUtils::NearestLanguageFile( fs, name );
       
  3257        
       
  3258         if ( BaflUtils::FileExists(fs, name) )
       
  3259             {
       
  3260             // open resource
       
  3261             resourceFile.OpenL( fs, name );
       
  3262             CleanupClosePushL( resourceFile );
       
  3263             resourceFile.ConfirmSignatureL();
       
  3264             found = ETrue;
       
  3265             }
       
  3266         }
       
  3267 
       
  3268     if ( !found )
       
  3269         {
       
  3270         User::Leave( KErrNotFound );
       
  3271         }
       
  3272     
       
  3273     for ( TInt extensionIndex( 0 ); extensionIndex < KExtensionCommandCount; extensionIndex++ )
       
  3274         {
       
  3275         TExtension extension;
       
  3276         TResourceReader reader;
       
  3277         TBool extentionSupported( ETrue );
       
  3278         
       
  3279         switch ( extensionIndex )
       
  3280             {
       
  3281             
       
  3282             case 0:
       
  3283             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_MOBILE ) );
       
  3284             extension.iId = EPbkFieldIdPhoneNumberMobile;     
       
  3285             extension.iAction = EDial;
       
  3286             extension.iCommand = EMobileCommand;
       
  3287             break;
       
  3288             
       
  3289             case 1:
       
  3290             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_MESSAGE ) );
       
  3291             extension.iId = EPbkFieldIdPhoneNumberMobile;     
       
  3292             extension.iAction = ENewMessage;     
       
  3293             extension.iCommand = EMessageCommand;
       
  3294             break;
       
  3295             
       
  3296             case 2:
       
  3297             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_GENERAL ) );
       
  3298             extension.iId = EPbkFieldIdPhoneNumberGeneral;     
       
  3299             extension.iAction = EDial;
       
  3300             extension.iCommand = EGeneralCommand;          
       
  3301             break;
       
  3302             
       
  3303             case 3:
       
  3304             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_WORK ) );
       
  3305             extension.iId = EPbkFieldIdPhoneNumberWork;     
       
  3306             extension.iAction = EDial;
       
  3307             extension.iCommand = EWorkCommand; 
       
  3308             break;
       
  3309             
       
  3310             case 4:
       
  3311             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_HOME ) );
       
  3312             extension.iId = EPbkFieldIdPhoneNumberHome;     
       
  3313             extension.iAction = EDial;
       
  3314             extension.iCommand = EHomeCommand;          
       
  3315             break;
       
  3316             
       
  3317             case 5:
       
  3318             if ( iVideoCallFeatureSupported )
       
  3319                 {  
       
  3320                 reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_VIDEO ) );
       
  3321                 extension.iId = EPbkFieldIdPhoneNumberVideo;     
       
  3322                 extension.iAction = EDial;
       
  3323                 extension.iCommand = EVideoCommand;                
       
  3324                 }
       
  3325             else
       
  3326                 { 
       
  3327                 extentionSupported = EFalse;
       
  3328                 }
       
  3329             break; 
       
  3330                                                                        
       
  3331             case 6:
       
  3332             reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_EMAIL ) );
       
  3333             extension.iId =EPbkFieldIdEmailAddress ;     
       
  3334             extension.iAction = ENewEmail;  
       
  3335             extension.iCommand = EEmailCommand;
       
  3336             break;
       
  3337             
       
  3338             case 7:
       
  3339             if ( iVoIPFeatureSupported )
       
  3340                 {                
       
  3341                 reader.SetBuffer( resourceFile.AllocReadLC( R_SIND_EXTENSION_VOIP ) );
       
  3342                 extension.iId = EPbkFieldIdVOIP;     
       
  3343                 extension.iAction = EDial;
       
  3344                 extension.iCommand = EVoipCommand; 
       
  3345                 }
       
  3346             else
       
  3347                 {
       
  3348                 extentionSupported = EFalse;
       
  3349                 }
       
  3350             break; 
       
  3351             
       
  3352             default:
       
  3353             User::Leave( KErrGeneral );  // !!! @todo: PANIC                               
       
  3354             }
       
  3355         
       
  3356         if ( extentionSupported )
       
  3357             {           
       
  3358             extension.iText = reader.ReadHBufCL();
       
  3359             CleanupStack::PushL( extension.iText );    
       
  3360             User::LeaveIfError( iExtensionList.Append( extension ) );
       
  3361             CleanupStack::Pop( extension.iText );
       
  3362             CleanupStack::PopAndDestroy(); // AllocReadLC
       
  3363             }
       
  3364         }
       
  3365 
       
  3366     CleanupStack::PopAndDestroy( &resourceFile );    
       
  3367     CleanupStack::PopAndDestroy( &fs );
       
  3368 
       
  3369     }
       
  3370 	
       
  3371 // ---------------------------------------------------------
       
  3372 // CNssContactHandlerImplementation::FindExtensionField
       
  3373 // Finds the extension field based on priority lists
       
  3374 // ---------------------------------------------------------
       
  3375 //        	
       
  3376 TInt CNssContactHandlerImplementation::FindExtensionField( TVasExtensionAction aAction, 
       
  3377                                                            TPbkFieldId aDefaultFieldId )
       
  3378     {  
       
  3379     TInt found = KErrNotFound;
       
  3380     
       
  3381     switch ( aDefaultFieldId )
       
  3382         {
       
  3383         case EPbkFieldIdPhoneNumberVideo:
       
  3384             {
       
  3385             // Use defaults for video extension
       
  3386             found = ExtensionFieldFindLoop( KVideoExtensionFields, KVideoExtensionFieldsCount );
       
  3387             break;
       
  3388             }
       
  3389         
       
  3390         case EPbkFieldIdPhoneNumberMobile:
       
  3391             {
       
  3392             if ( aAction == ENewMessage )
       
  3393                 {
       
  3394                 // Use defaults for message extension
       
  3395                 found = ExtensionFieldFindLoop( KMessageExtensionFields, KMessageExtensionFieldsCount );  
       
  3396                 }
       
  3397             else
       
  3398                 {
       
  3399                 TRAP( found, iPbkHandler->FindFieldL( aDefaultFieldId ) );
       
  3400                 }
       
  3401                 
       
  3402             break;
       
  3403             }
       
  3404             
       
  3405         case EPbkFieldIdVOIP:
       
  3406             {
       
  3407             // Use defaults for VOIP extension
       
  3408             found = ExtensionFieldFindLoop( KVOIPExtensionFields, KVOIPExtensionFieldsCount );  
       
  3409                 
       
  3410             break;
       
  3411             }
       
  3412         
       
  3413         default:
       
  3414             {
       
  3415             TRAP( found, iPbkHandler->FindFieldL( aDefaultFieldId ) );
       
  3416             break;
       
  3417             }
       
  3418         }
       
  3419     return found;
       
  3420     }
       
  3421 
       
  3422 // ---------------------------------------------------------
       
  3423 // CNssContactHandlerImplementation::ExtensionFieldFindLoop
       
  3424 // Finds the extension from the prioroty list arrays
       
  3425 // ---------------------------------------------------------
       
  3426 //        	
       
  3427 TInt CNssContactHandlerImplementation::ExtensionFieldFindLoop( const TPbkFieldId* const aArray, 
       
  3428                                                                TInt aCount )
       
  3429     {
       
  3430     TInt found = KErrNotFound;
       
  3431        
       
  3432     for ( TInt iCounter = 0; iCounter < aCount; iCounter++ )
       
  3433         {
       
  3434         TRAP( found, iPbkHandler->FindFieldL( aArray[iCounter] ) );
       
  3435         if ( found == KErrNone )
       
  3436             {
       
  3437             break;
       
  3438             }
       
  3439         }
       
  3440     return found;
       
  3441     }
       
  3442 
       
  3443 #endif // __SIND_EXTENSIONS
       
  3444     	
       
  3445 //  End of File