ncdengine/provider/server/src/ncdsubscriptionmanagerimpl.cpp
changeset 0 ba25891c3a9e
equal deleted inserted replaced
-1:000000000000 0:ba25891c3a9e
       
     1 /*
       
     2 * Copyright (c) 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:   Implements CNcdSubscriptionManager class
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "ncdsubscriptionmanagerimpl.h"
       
    20 
       
    21 #include <s32mem.h>
       
    22 #include <bamdesca.h> // MDesCArray
       
    23 
       
    24 #include "catalogssession.h"
       
    25 #include "catalogsbasemessage.h"
       
    26 #include "ncdnodefunctionids.h"
       
    27 #include "ncdnodeclassids.h"
       
    28 #include "catalogsconstants.h"
       
    29 #include "ncd_pp_dataentity.h"
       
    30 #include "ncd_pp_subscription.h"
       
    31 #include "ncd_cp_query.h"
       
    32 #include "catalogsutils.h"
       
    33 #include "ncdstoragedataitem.h"
       
    34 #include "ncdsubscriptionssourceidentifier.h"
       
    35 #include "ncdserverpartofsubscription.h"
       
    36 #include "ncdclientssubscriptions.h"
       
    37 #include "ncdsubscriptiongroup.h"
       
    38 #include "catalogscontext.h"
       
    39 #include "ncddatabasestorage.h"
       
    40 #include "ncdstorage.h"
       
    41 #include "ncdproviderdefines.h"
       
    42 #include "ncdstorageitem.h"
       
    43 #include "ncdstoragemanagerimpl.h"
       
    44 #include "ncdpurchaseoptionimpl.h"
       
    45 #include "ncdnodeidentifier.h"
       
    46 #include "ncdnodemanager.h"
       
    47 #include "ncdrootnode.h"
       
    48 #include "ncdsubscriptiongroup.h"
       
    49 #include "ncdutils.h"
       
    50 #include "ncdnodeiconimpl.h"
       
    51 
       
    52 // This is for the contentsourcemap
       
    53 #include "ncdloadrootnodeoperationimpl.h"
       
    54 
       
    55 #include "ncdsubscriptionmanagerobserver.h"
       
    56 #include "ncdsubscriptiondatacompleter.h"
       
    57 
       
    58 #include "catalogsdebug.h"
       
    59 
       
    60 CNcdSubscriptionManager::CNcdSubscriptionManager(
       
    61     CNcdStorageManager& aStorageManager,
       
    62     CNcdNodeManager& aNodeManager )
       
    63     : CCatalogsCommunicable(),
       
    64       iStorageManager( aStorageManager ),
       
    65       iNodeManager( aNodeManager )
       
    66     {
       
    67     DLTRACEIN((""));
       
    68 
       
    69     DLTRACEOUT((""));
       
    70     }
       
    71 
       
    72 void CNcdSubscriptionManager::ConstructL()
       
    73     {
       
    74     }
       
    75 
       
    76 CNcdSubscriptionManager* CNcdSubscriptionManager::NewL(
       
    77     CNcdStorageManager& aStorageManager,
       
    78     CNcdNodeManager& aNodeManager )
       
    79     {
       
    80     CNcdSubscriptionManager* self =
       
    81         CNcdSubscriptionManager::NewLC( aStorageManager, aNodeManager );
       
    82     CleanupStack::Pop( self );
       
    83     return self;        
       
    84     }
       
    85 
       
    86 CNcdSubscriptionManager* CNcdSubscriptionManager::NewLC(
       
    87     CNcdStorageManager& aStorageManager,
       
    88     CNcdNodeManager& aNodeManager )
       
    89     {
       
    90     CNcdSubscriptionManager* self = 
       
    91         new( ELeave ) CNcdSubscriptionManager( aStorageManager, aNodeManager );
       
    92     CleanupClosePushL( *self );
       
    93     self->ConstructL();
       
    94     return self;        
       
    95     }
       
    96 
       
    97 
       
    98 CNcdSubscriptionManager::~CNcdSubscriptionManager()
       
    99     {
       
   100     DLTRACEIN((""));
       
   101 
       
   102     iSubscriptionDataCompleters.ResetAndDestroy();
       
   103 
       
   104     // All subscriptions should be saved into database if they
       
   105     // are new or changed. So there is no need to save all of them
       
   106     // here.
       
   107 
       
   108     const TInt clientsCount( iClientSubscriptions.Count() );
       
   109     TInt indexer( 0 );
       
   110     
       
   111     while( indexer < clientsCount )
       
   112         {
       
   113         delete iClientSubscriptions[indexer];
       
   114         
       
   115         ++indexer;
       
   116         }
       
   117     iClientSubscriptions.Reset();
       
   118     
       
   119     // Complete the pending messages
       
   120     NotifyAllListeners( KErrServerTerminated );
       
   121     iPendingMessages.Close();
       
   122 
       
   123     DLTRACEOUT((""));
       
   124     }        
       
   125 
       
   126 void CNcdSubscriptionManager::SetOperationManager(
       
   127     CNcdOperationManager* aManager )
       
   128     {
       
   129     iOperationManager = aManager;
       
   130     }
       
   131 
       
   132 
       
   133 
       
   134 
       
   135 RPointerArray<CNcdSubscriptionsSourceIdentifier>
       
   136     CNcdSubscriptionManager::SubscriptionsSourcesL( TUid aClientUid ) const
       
   137     {    
       
   138     DLTRACEIN((""));
       
   139     
       
   140     // First read possibly existing subscriptions sources from the
       
   141     // subscriptions database
       
   142     TInt clientIndex( -1 );
       
   143     RPointerArray<CNcdSubscriptionsSourceIdentifier> sources;    
       
   144     TRAP_IGNORE( clientIndex = IsInCacheL( aClientUid ) );
       
   145     if ( clientIndex > -1 )
       
   146         {
       
   147         TRAP_IGNORE( sources = SubscriptionsSourcesL( clientIndex ) );
       
   148         }
       
   149 
       
   150 
       
   151     DLINFO(( "Getting subscriptions sources from the root node." ));
       
   152 
       
   153     // Get content sources from root node.
       
   154     CNcdRootNode& rootNode = 
       
   155         iNodeManager.CreateRootL( aClientUid );
       
   156     CNcdContentSourceMap& csMap = rootNode.ContentSourceMap();
       
   157     DLTRACE(("Content sources: %d", csMap.ContentSourceCount() ));
       
   158     
       
   159 
       
   160     TIdentityRelation<CNcdSubscriptionsSourceIdentifier> match( 
       
   161             &CNcdSubscriptionsSourceIdentifier::CompareIdentifiers );
       
   162     
       
   163     for ( TInt i = 0; i < csMap.ContentSourceCount(); i++ ) 
       
   164         {
       
   165         CNcdContentSource& contentSource = csMap.ContentSource( i );
       
   166         // When we get the source identifier from the root node, we don't know
       
   167         // if it supports subscriptions so that has to be checked when sending
       
   168         // requests -> aRequireCapabilityCheck (last param) is set ETrue
       
   169         CNcdSubscriptionsSourceIdentifier* sourceId =
       
   170             CNcdSubscriptionsSourceIdentifier::NewLC(
       
   171                 contentSource.Uri(), contentSource.NameSpace(), ETrue );
       
   172         
       
   173         // Do not add the source identifier if the same exists already.
       
   174         if ( sources.Find( sourceId, match ) == KErrNotFound )
       
   175             {
       
   176             sources.AppendL( sourceId );
       
   177             DLINFO(( "Subscriptions source appended into the array." ));
       
   178             CleanupStack::Pop( sourceId );
       
   179             }
       
   180         else
       
   181             {
       
   182             DLINFO(( "Subscriptions source already found from the array." ));
       
   183             CleanupStack::PopAndDestroy( sourceId );
       
   184             }
       
   185         
       
   186         DLINFO(( _L( "Source namespace: %S."), &contentSource.NameSpace() ));
       
   187         }
       
   188 
       
   189     // Handle bundle content sources. This actually helps only after the
       
   190     // user has browsed inside a bundle because we won't know the capabilities
       
   191     // of the bundle's servers before that
       
   192     TInt bundleCount = csMap.BundleFolderCount();
       
   193     DLINFO(("Bundle folders: %d", bundleCount ));
       
   194     for ( TInt i = 0; i < bundleCount; i++ ) 
       
   195         {
       
   196         const CNcdNodeIdentifier& bundleId = csMap.BundleFolder( i );
       
   197         TInt folderIndex = csMap.FindFolder( bundleId );
       
   198         CNcdFolderContent& folderContent = csMap.FolderContent( folderIndex );
       
   199         
       
   200         DLTRACE(("Bundle has %d content sources", 
       
   201             folderContent.ContentSourceCount() ));
       
   202             
       
   203         for ( TInt index = 0; index < folderContent.ContentSourceCount(); ++index ) 
       
   204             {            
       
   205             CNcdContentSource& contentSource = folderContent.ContentSource( index );
       
   206             // When we get the source identifier from the root node, we don't know
       
   207             // if it supports subscriptions so that has to be checked when sending
       
   208             // requests -> aRequireCapabilityCheck (last param) is set ETrue
       
   209             CNcdSubscriptionsSourceIdentifier* sourceId =
       
   210                 CNcdSubscriptionsSourceIdentifier::NewLC(
       
   211                     contentSource.Uri(), contentSource.NameSpace(), ETrue );
       
   212             
       
   213             // Do not add the source identifier if the same exists already.
       
   214             if ( sources.Find( sourceId, match ) == KErrNotFound )
       
   215                 {
       
   216                 sources.AppendL( sourceId );
       
   217                 CleanupStack::Pop( sourceId );
       
   218                 }
       
   219             else
       
   220                 {
       
   221                 CleanupStack::PopAndDestroy( sourceId );
       
   222                 }
       
   223             DLINFO(( _L( "Source namespace: %S."), &contentSource.NameSpace() ));
       
   224             }
       
   225         }
       
   226 
       
   227     return sources;    
       
   228     }
       
   229 
       
   230 void CNcdSubscriptionManager::InternalizeSubscriptionsFromServerL(
       
   231     TUid aClientUid,
       
   232     const TDesC& aUri,
       
   233     RPointerArray<MNcdPreminetProtocolSubscription>& aServersSubscriptions,
       
   234     MCatalogsContext* aContext,
       
   235     MNcdSubscriptionManagerObserver* aObserver )
       
   236     {
       
   237     DLTRACEIN((""));
       
   238     
       
   239     // Should do leave handling
       
   240     
       
   241     // First we create objects resembling subscriptions
       
   242     // and mark them as recently created.
       
   243     // This also writes subscriptions to database.
       
   244     InternalizeAndMarkSubscriptionsL( aClientUid,
       
   245                                       aUri,
       
   246                                       aServersSubscriptions );
       
   247     
       
   248     // Get the subscriptions related to given server
       
   249     // Here we should get also the recently created ones
       
   250     RPointerArray<CNcdSubscriptionGroup> serversGroups =
       
   251         ServersGroupsL( aClientUid, aUri );
       
   252         
       
   253     // In the end we remove subscriptions that were
       
   254     // not received in the aServersSubscriptions array and reset
       
   255     // the flags of subscriptions that were received. (Subscriptions that
       
   256     // were not received from the server in the aServersSubscriptions array
       
   257     // and are marked as received from the server (earlier) are removed
       
   258     // from the database, from the cache and from the serversGroups
       
   259     // array.)
       
   260     TRAP_IGNORE( RemoveUnmarkedSubscriptionsL( aClientUid, serversGroups ) );
       
   261 
       
   262     // Check that server's current subscriptions have all needed data and
       
   263     // if not get them from the corresponding nodes. Do also the needed
       
   264     // callback of observer and notifying of subscription manager's listeners
       
   265     // Also database write is done after completion. The earlier write
       
   266     // was done to ensure that some entry is found from the db if this
       
   267     // operation does not end before shutdown or some possible error situation
       
   268     // occurs.
       
   269     TRAP_IGNORE( CompleteSubscriptionsDataL( aClientUid,
       
   270                                              serversGroups,
       
   271                                              aContext,
       
   272                                              aObserver ) );
       
   273 
       
   274     // As the subscriptions are stored in member variable,
       
   275     // they should not be deleted. Just close for the array.
       
   276     serversGroups.Close();    
       
   277     }    
       
   278 
       
   279 
       
   280 void CNcdSubscriptionManager::InternalizeSubscriptionL( 
       
   281     TUid aClientUid,
       
   282     const TDesC& aUri,
       
   283     MNcdPreminetProtocolSubscription& aSubscription,
       
   284     MCatalogsContext* aContext,
       
   285     MNcdSubscriptionManagerObserver* aObserver )
       
   286     {
       
   287     DLTRACEIN((""));
       
   288 
       
   289     // Get or create subscription group
       
   290 
       
   291     CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
       
   292         aClientUid,
       
   293         aSubscription.EntityId(),
       
   294         aSubscription.Namespace(),
       
   295         aUri );
       
   296 
       
   297 
       
   298     groupForSubscription.InternalizeSubscriptionL( aSubscription );
       
   299 
       
   300     DLTRACE(( "Subscription internalized." ));
       
   301 
       
   302     // Database should always have updated info so at this point we have
       
   303     // to write updates there.
       
   304     
       
   305     // Because there is a database for each client the writing has
       
   306     // to be done here where we know which group was updated.
       
   307 
       
   308     SaveGroupIntoDatabaseL( aClientUid,
       
   309                             groupForSubscription );
       
   310 
       
   311     DLTRACE(( "Subscription group saved into database." ));
       
   312 
       
   313 
       
   314     // Check that current subscription (and its group) has all needed
       
   315     // data and if not, get them from the corresponding nodes. Do also
       
   316     // the needed callback of observer and notifying of subscription
       
   317     // manager's listeners. Also database write is done after completion.
       
   318     // The earlier write was done to ensure that some entry is found
       
   319     // from the db if this operation does not end before shutdown or
       
   320     // some possible error situation occurs.
       
   321     RPointerArray<CNcdSubscriptionGroup> groups;
       
   322     groups.AppendL( &groupForSubscription );
       
   323     TRAP_IGNORE( CompleteSubscriptionsDataL( aClientUid,
       
   324                                              groups,
       
   325                                              aContext,
       
   326                                              aObserver ) );
       
   327 
       
   328     // As the subscriptions are stored in member variable,
       
   329     // they should not be deleted. Just close for the array.
       
   330     groups.Close();
       
   331 
       
   332     DLTRACEOUT((""));
       
   333     }
       
   334 
       
   335 
       
   336 void CNcdSubscriptionManager::RemoveSubscriptionL(
       
   337     const CNcdNodeIdentifier& aData,
       
   338     const TDesC& aPurchaseOptionId)
       
   339     {
       
   340     
       
   341     CNcdSubscriptionGroup& group = FindGroupL( aData.ClientUid(),
       
   342                                                aData.NodeId(),
       
   343                                                aData.NodeNameSpace() );
       
   344 
       
   345     group.RemoveSubscriptionL( aPurchaseOptionId );
       
   346     
       
   347     if ( group.SubscriptionCount() == 0 )
       
   348         {
       
   349         TInt index = IsInCacheL( aData.ClientUid() );
       
   350         CNcdClientsSubscriptions* clientsSubscriptions =
       
   351         iClientSubscriptions[index];
       
   352         
       
   353         clientsSubscriptions->RemoveGroup( &group );
       
   354         
       
   355         RemoveGroupFromDatabaseL( aData.ClientUid(),
       
   356                                   group );
       
   357         }    
       
   358     else
       
   359         {
       
   360         SaveGroupIntoDatabaseL( aData.ClientUid(), group );
       
   361         }
       
   362 
       
   363     // As the clientsSubscriptions only exists in the cache,
       
   364     // it is not checked that if groups still exist after this
       
   365     // group removal and whether the clientsSubscriptions
       
   366     // should be removed.    
       
   367 
       
   368     // Notify the listeners.
       
   369     NotifyListeners( aData.ClientUid() );
       
   370     }
       
   371 
       
   372 CNcdSubscription& CNcdSubscriptionManager::SubscriptionL(
       
   373     const TDesC& aNodeId,
       
   374     const TDesC& aNodeNameSpace,
       
   375     const TDesC& aPurchaseOptionId,
       
   376     const TUid& aClientUid ) 
       
   377     {
       
   378     DLTRACEIN((""));
       
   379     
       
   380     TInt index = IsInCacheL( aClientUid );
       
   381     CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
       
   382     RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
       
   383     TInt groupIndex = FindGroupL( groups, aNodeId, aNodeNameSpace );
       
   384     CNcdSubscriptionGroup* group = groups[groupIndex];
       
   385     return group->SubscriptionIfExistsL( aPurchaseOptionId );
       
   386     }
       
   387     
       
   388     
       
   389 void CNcdSubscriptionManager::ClearSubscriptionDbL( const MCatalogsContext& aContext ) 
       
   390     {
       
   391     DLTRACEIN((""));
       
   392     iStorageManager.RemoveStorageL(
       
   393         aContext.FamilyId().Name(), NcdProviderDefines::KSubscriptionNamespace );
       
   394     
       
   395     // Remove from RAM cache too.
       
   396     for ( TInt i = 0; i < iClientSubscriptions.Count(); i++ ) 
       
   397         {
       
   398         if ( iClientSubscriptions[i]->ClientId() == aContext.FamilyId() ) 
       
   399             {
       
   400             delete iClientSubscriptions[i];
       
   401             iClientSubscriptions.Remove( i );
       
   402             break;
       
   403             }
       
   404         }    
       
   405     }
       
   406     
       
   407 
       
   408 void CNcdSubscriptionManager::NotifyListeners( TUid aClientUid ) 
       
   409     {
       
   410     DLTRACEIN((""));
       
   411     for ( TInt i = iPendingMessages.Count() - 1; i >= 0; i-- ) 
       
   412         {
       
   413         if ( iPendingMessages[i]->Session().Context().FamilyId() == 
       
   414              aClientUid ) 
       
   415             {            
       
   416             iPendingMessages[i]->CompleteAndRelease( KErrNone );
       
   417             iPendingMessages.Remove( i );                        
       
   418             }
       
   419         }
       
   420     }
       
   421 
       
   422 void CNcdSubscriptionManager::SubscriptionCompleted(
       
   423         CNcdSubscriptionDataCompleter* aFinishedCompleter )
       
   424     {
       
   425     const TInt KCompleterAmount( iSubscriptionDataCompleters.Count() );
       
   426     TInt completerIndexer( 0 );
       
   427     
       
   428     CNcdSubscriptionDataCompleter* tempCompleter( NULL );
       
   429     while ( completerIndexer < KCompleterAmount )
       
   430         {
       
   431         tempCompleter = iSubscriptionDataCompleters[ completerIndexer ];
       
   432         if ( tempCompleter == aFinishedCompleter )
       
   433             {
       
   434             iSubscriptionDataCompleters.Remove( completerIndexer );
       
   435             delete aFinishedCompleter;
       
   436             return;
       
   437             }        
       
   438         ++completerIndexer;
       
   439         }
       
   440     }
       
   441 
       
   442 void CNcdSubscriptionManager::SaveGroupIntoDatabaseL(
       
   443     TUid aClientUid,
       
   444     CNcdSubscriptionGroup& aGroup )
       
   445     {
       
   446     DLTRACEIN((""));
       
   447     
       
   448     // Databases are created for each client. (for each uid)
       
   449     // As a namespace we use a constant namespace (KSubscriptionNameSpace)
       
   450     // so we know in the future where from to load all data.
       
   451 
       
   452     HBufC* dataId = GenerateGroupDataIdL( aGroup );
       
   453     CleanupStack::PushL( dataId );
       
   454 
       
   455     DLTRACE(( _L("DataId for subscription group database item: %S"),
       
   456               dataId ));
       
   457 
       
   458 
       
   459     SaveDataIntoDatabaseL( aClientUid,
       
   460                            NcdProviderDefines::KSubscriptionNamespace,
       
   461                            *dataId,
       
   462                            aGroup,
       
   463                            NcdNodeClassIds::ENcdSubscriptionsData );
       
   464                            
       
   465     CleanupStack::PopAndDestroy( dataId );
       
   466     
       
   467     DLTRACEOUT((""));
       
   468     }
       
   469 
       
   470 
       
   471 void CNcdSubscriptionManager::ReceiveMessage( 
       
   472     MCatalogsBaseMessage* aMessage,
       
   473     TInt aFunctionNumber )
       
   474     {
       
   475     DLTRACEIN((""));    
       
   476 
       
   477     DASSERT( aMessage );
       
   478 
       
   479     // Now, we can be sure that rest of the time iMessage exists.
       
   480     // This member variable is set for the CounterPartLost function.
       
   481     iMessage = aMessage;
       
   482     
       
   483     TInt trapError( KErrNone );
       
   484     
       
   485     // Check which function is called by the proxy side object.
       
   486     // Function number are located in ncdnodefunctinoids.h file.
       
   487     switch( aFunctionNumber )
       
   488         {
       
   489         case NcdNodeFunctionIds::ENcdSubscriptionGroupIdentifiers:
       
   490             // Subscription group identifiers requested from proxy side.
       
   491             TRAP( trapError, SubscriptionGroupIdentifiersRequestL( *aMessage ) );
       
   492             break;
       
   493             
       
   494         case NcdNodeFunctionIds::ENcdInternalize:
       
   495             // Internalize the proxy side according to the data
       
   496             // of this object.
       
   497             TRAP( trapError, InternalizeRequestL( *aMessage ) );
       
   498             break;
       
   499 
       
   500         case NcdNodeFunctionIds::ENcdRelease:
       
   501             // The proxy does not want to use this object anymore.
       
   502             // So, release the handle from the session.
       
   503             ReleaseRequest( *aMessage );
       
   504             break;
       
   505             
       
   506         case NcdNodeFunctionIds::ENcdListenerEnrollment:
       
   507             // The proxy wants to enroll as listener.
       
   508             TRAP( trapError, ListenerEnrolledL( *aMessage ) );
       
   509             break;
       
   510                     
       
   511         default:
       
   512             break;
       
   513         }
       
   514 
       
   515     if ( trapError != KErrNone )
       
   516         {
       
   517         // Because something went wrong, the complete has not been
       
   518         // yet called for the message.
       
   519         // So, inform the client about the error if the
       
   520         // message is still available.
       
   521         aMessage->CompleteAndRelease( trapError );
       
   522         }
       
   523 
       
   524     // Because the message should not be used after this, set it NULL.
       
   525     // So, CounterPartLost function will know that no messages are
       
   526     // waiting the response at the moment.
       
   527     iMessage = NULL;        
       
   528     
       
   529     DLTRACEOUT((""));
       
   530     }
       
   531 
       
   532 
       
   533 void CNcdSubscriptionManager::CounterPartLost( 
       
   534     const MCatalogsSession& aSession )
       
   535     {
       
   536     // This function may be called whenever -- when the message is waiting
       
   537     // response or when the message does not exist.
       
   538     // iMessage may be NULL here, because in the end of the
       
   539     // ReceiveMessage it is set to NULL. The life time of the message
       
   540     // ends shortly after CompleteAndRelease is called.
       
   541     if ( iMessage != NULL )
       
   542         {
       
   543         iMessage->CounterPartLost( aSession );
       
   544         }
       
   545         
       
   546     for ( TInt i = 0; i < iPendingMessages.Count(); i++ ) 
       
   547         {
       
   548         iPendingMessages[i]->CounterPartLost( aSession );
       
   549         }
       
   550     }
       
   551  
       
   552                     
       
   553 
       
   554 void CNcdSubscriptionManager::ReleaseRequest( 
       
   555     MCatalogsBaseMessage& aMessage )
       
   556     {
       
   557     DLTRACEIN((""));
       
   558 
       
   559     // Decrease the reference count for this object.
       
   560     // When the reference count reaches zero, this object will be destroyed
       
   561     // and removed from the session.
       
   562     MCatalogsSession& requestSession( aMessage.Session() );
       
   563     TInt handle( aMessage.Handle() );
       
   564 
       
   565     DLTRACE(("Calling counterpart lost for messages"));
       
   566     for ( TInt i = 0; i < iPendingMessages.Count(); i++ ) 
       
   567         {
       
   568         iPendingMessages[i]->CounterPartLost( requestSession );
       
   569         }
       
   570 
       
   571 
       
   572     // Send complete information back to proxy.
       
   573     aMessage.CompleteAndRelease( KErrNone );
       
   574         
       
   575     // Remove this object from the session.
       
   576     requestSession.RemoveObject( handle );
       
   577 
       
   578     DLTRACEOUT((""));
       
   579     }
       
   580 
       
   581 
       
   582 
       
   583 
       
   584 void CNcdSubscriptionManager::InternalizeRequestL( 
       
   585     MCatalogsBaseMessage& aMessage )
       
   586     {
       
   587     DLTRACEIN((""));
       
   588     
       
   589     // Parse the input message and create an array containing
       
   590     // subscription group identifiers which are requested.
       
   591     RPointerArray<CNcdKeyValuePair> groupIds;
       
   592     CleanupResetAndDestroyPushL( groupIds );
       
   593     
       
   594     HBufC8* input = HBufC8::NewLC( aMessage.InputLength() );
       
   595     TPtr8 inputPtr = input->Des();
       
   596     aMessage.ReadInput( inputPtr );
       
   597     RDesReadStream inputStream( *input );
       
   598     CleanupClosePushL( inputStream );
       
   599     
       
   600     TInt32 groupCount = inputStream.ReadInt32L();
       
   601     groupIds.ReserveL( groupCount );
       
   602     for ( TInt i = 0; i < groupCount; i++ ) 
       
   603         {
       
   604         CNcdKeyValuePair* pair = CNcdKeyValuePair::NewL( inputStream );
       
   605         groupIds.Append( pair );
       
   606         }
       
   607  
       
   608     CleanupStack::PopAndDestroy( &inputStream );
       
   609     CleanupStack::PopAndDestroy( input );
       
   610            
       
   611            
       
   612     CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
       
   613     CleanupStack::PushL( buf );
       
   614     
       
   615     RBufWriteStream stream( *buf );
       
   616     CleanupClosePushL( stream );
       
   617 
       
   618 
       
   619     // We need session info in the functions for example to
       
   620     // check the client id (there can be several clients)
       
   621     // and to register needed objects to the session.
       
   622     MCatalogsSession& session = aMessage.Session();
       
   623     TUid clientUid = session.Context().FamilyId();
       
   624     
       
   625     ExternalizeClientsSubscriptionsL( session, groupIds, stream );
       
   626     
       
   627     // Commits data to the stream when closing.
       
   628     CleanupStack::PopAndDestroy( &stream );
       
   629 
       
   630 
       
   631     // If this leaves, ReceiveMessage will complete the message.
       
   632     // NOTE: that here we expect that the buffer contains at least
       
   633     // some data. So, make sure that ExternalizeDataForRequestL inserts
       
   634     // something to the buffer.
       
   635     aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );        
       
   636         
       
   637     
       
   638     DLTRACE(("Deleting the buf"));
       
   639     CleanupStack::PopAndDestroy( buf );
       
   640     CleanupStack::PopAndDestroy( &groupIds );
       
   641         
       
   642     DLTRACEOUT((""));
       
   643     }
       
   644     
       
   645     
       
   646 void CNcdSubscriptionManager::SubscriptionGroupIdentifiersRequestL(
       
   647     MCatalogsBaseMessage& aMessage )
       
   648     {
       
   649     DLTRACEIN((""));
       
   650     
       
   651     CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
       
   652     CleanupStack::PushL( buf );
       
   653     
       
   654     RBufWriteStream stream( *buf );
       
   655     CleanupClosePushL( stream );
       
   656     
       
   657     TUid clientUid = aMessage.Session().Context().FamilyId();
       
   658     TInt clientIndex( -1 );
       
   659     TRAPD( err, clientIndex = IsInCacheL( clientUid ) );
       
   660     if ( err == KErrNotFound )
       
   661         {
       
   662         // Check also storage.
       
   663         // Needed for example when the engine has not retrieved
       
   664         // the info from db after last restart.
       
   665         TRAP_IGNORE( LoadClientsInfoFromStorageL( clientUid ) );
       
   666                           
       
   667         TRAP_IGNORE( clientIndex = IsInCacheL( clientUid ) );
       
   668         }
       
   669         
       
   670     if ( clientIndex < 0 ) 
       
   671         {
       
   672         stream.WriteInt32L( 0 );
       
   673         }
       
   674     else 
       
   675         {
       
   676         CNcdClientsSubscriptions* subscriptions =
       
   677             iClientSubscriptions[clientIndex];
       
   678         RPointerArray<CNcdSubscriptionGroup>& groups =
       
   679             subscriptions->Groups();
       
   680         stream.WriteInt32L( groups.Count() );
       
   681         for ( TInt i = 0; i < groups.Count(); i++ ) 
       
   682             {
       
   683             CNcdKeyValuePair* pair = CNcdKeyValuePair::NewLC(
       
   684                 groups[i]->Namespace(), groups[i]->EntityId() );
       
   685             pair->ExternalizeL( stream );
       
   686             CleanupStack::PopAndDestroy( pair );
       
   687             }
       
   688         }
       
   689         
       
   690     CleanupStack::PopAndDestroy( &stream );
       
   691     
       
   692     // If this leaves, ReceiveMessage will complete the message.
       
   693     aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
       
   694     
       
   695     CleanupStack::PopAndDestroy( buf );
       
   696     }
       
   697 
       
   698 
       
   699 void CNcdSubscriptionManager::CompleteSubscriptionsDataL(
       
   700     TUid aClientUid,
       
   701     RPointerArray<CNcdSubscriptionGroup>& aServersGroups,
       
   702     MCatalogsContext* aContext,
       
   703     MNcdSubscriptionManagerObserver* aObserver )
       
   704     {
       
   705     DLTRACEIN((""));
       
   706     // Create array of node identifiers to identify the nodes
       
   707     // (and subscriptions)
       
   708     // and create array of purchase option ids to identify
       
   709     // the subscriptions
       
   710     RPointerArray<CNcdNodeIdentifier> nodeIds;
       
   711     CDesCArrayFlat* purchaseOptionIDs( NULL );
       
   712 
       
   713     CNcdSubscriptionDataCompleter* completer( NULL );
       
   714     TRAPD( error,
       
   715         {
       
   716         purchaseOptionIDs = new (ELeave) CDesCArrayFlat( 5 );
       
   717         IdentifiersForCompletionL( aServersGroups,
       
   718                                    nodeIds,
       
   719                                    *purchaseOptionIDs );
       
   720 
       
   721         // Create data completer object
       
   722         completer =
       
   723             CNcdSubscriptionDataCompleter::NewL( *this,
       
   724                                                  iNodeManager,
       
   725                                                  *iOperationManager );
       
   726         iSubscriptionDataCompleters.AppendL( completer );
       
   727         
       
   728         } );
       
   729     if ( error != KErrNone )
       
   730         {
       
   731         nodeIds.ResetAndDestroy();
       
   732         
       
   733         if ( purchaseOptionIDs )
       
   734             {
       
   735             purchaseOptionIDs->Reset();
       
   736             }
       
   737         User::Leave( error );
       
   738         }
       
   739     
       
   740     // passing ownership of identifiers
       
   741     completer->CompleteSubscriptions( aClientUid,
       
   742                                       nodeIds,
       
   743                                       purchaseOptionIDs,
       
   744                                       aContext,
       
   745                                       aObserver );
       
   746     DLTRACEOUT((""));
       
   747     }
       
   748 
       
   749 void CNcdSubscriptionManager::IdentifiersForCompletionL(
       
   750     RPointerArray<CNcdSubscriptionGroup>& aGroups,
       
   751     RPointerArray<CNcdNodeIdentifier>& aNodeIds,
       
   752     CDesCArrayFlat& aPurchaseOptionIDs )
       
   753     {
       
   754     DLTRACEIN((""));
       
   755     TInt groupIndex( 0 );
       
   756     const TInt KGroupCount( aGroups.Count() );
       
   757     while( groupIndex < KGroupCount )
       
   758         {
       
   759         DLINFO(( "group nro: %d", groupIndex ));
       
   760         aGroups[groupIndex]->AppendIncompleteSubscriptionIDsL(
       
   761                                  aNodeIds,
       
   762                                  aPurchaseOptionIDs );
       
   763 
       
   764         ++groupIndex;
       
   765         }
       
   766     DLTRACEOUT((""));
       
   767     }
       
   768 
       
   769 TInt CNcdSubscriptionManager::IsInCacheL( TUid aUid ) const
       
   770     {
       
   771     DLTRACEIN((""));
       
   772     
       
   773     TInt clientIndex( 0 );
       
   774     const TInt KClientCount( iClientSubscriptions.Count() );
       
   775     while( clientIndex < KClientCount )
       
   776         {
       
   777         if ( iClientSubscriptions[clientIndex]->ClientId() == aUid )
       
   778             {
       
   779             return clientIndex;
       
   780             }
       
   781         ++clientIndex;
       
   782         }
       
   783         
       
   784     User::Leave( KErrNotFound );
       
   785     DLTRACEOUT((""));
       
   786     return KErrNotFound;
       
   787     }
       
   788 
       
   789 
       
   790 TInt CNcdSubscriptionManager::ClientsSubscriptionsL( TUid aClientUid )
       
   791     {
       
   792     DLTRACEIN((""));
       
   793     TInt clientIndex( -1 );
       
   794     TRAPD( searchError, clientIndex = IsInCacheL( aClientUid ) );
       
   795     if ( searchError == KErrNotFound )
       
   796         {
       
   797         // Let's create new ClientsSubscriptions because it was not
       
   798         // found
       
   799         CNcdClientsSubscriptions* clientsSubscriptions =
       
   800             CNcdClientsSubscriptions::NewLC( aClientUid );        
       
   801         iClientSubscriptions.AppendL( clientsSubscriptions );        
       
   802         CleanupStack::Pop( clientsSubscriptions );        
       
   803         
       
   804         // set clientIndex to the appended clients subscriptions
       
   805         clientIndex = iClientSubscriptions.Count() - 1;
       
   806         }
       
   807     else if ( searchError != KErrNone )
       
   808         {
       
   809         // If leave occurs and it is not KErrNotFound, leave.
       
   810         User::Leave( searchError );
       
   811         }
       
   812 
       
   813     return clientIndex;
       
   814     }
       
   815 
       
   816 
       
   817 TInt CNcdSubscriptionManager::FindGroupL(
       
   818     const RPointerArray<CNcdSubscriptionGroup>& aGroups,
       
   819     const TDesC& aEntityId,
       
   820     const TDesC& aNamespace ) const
       
   821     {
       
   822     DLTRACEIN((""));
       
   823     
       
   824     TInt groupIndex( 0 );
       
   825     const TInt KGroupCount( aGroups.Count() );
       
   826     while( groupIndex < KGroupCount )
       
   827         {
       
   828         if ( aGroups[groupIndex]->EntityId() == aEntityId &&
       
   829              aGroups[groupIndex]->Namespace() == aNamespace )
       
   830             {
       
   831             return groupIndex;
       
   832             }
       
   833         ++groupIndex;
       
   834         }
       
   835         
       
   836     User::Leave( KErrNotFound );
       
   837     DLTRACEOUT((""));    
       
   838     return KErrNotFound;
       
   839     }
       
   840 
       
   841 CNcdSubscriptionGroup& CNcdSubscriptionManager::FindGroupL(
       
   842     TUid aClientUid,
       
   843     const TDesC& aEntityId,
       
   844     const TDesC& aNamespace ) const
       
   845     {
       
   846     DLTRACEIN((""));
       
   847     TInt index = IsInCacheL( aClientUid );
       
   848     CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
       
   849     RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
       
   850     TInt groupIndex = FindGroupL( groups, aEntityId, aNamespace );    
       
   851     return *groups[groupIndex];    
       
   852     }
       
   853 
       
   854 CNcdSubscriptionGroup& CNcdSubscriptionManager::ClientsSubscriptionGroupL(
       
   855     const TDesC& aUri,
       
   856     const CNcdPurchaseOptionImpl& aData )
       
   857     {
       
   858     DLTRACEIN((""));
       
   859     
       
   860     const CNcdNodeIdentifier& nodeIdentifier = aData.ParentMetaIdentifier();
       
   861     const TDesC& nameSpace = nodeIdentifier.NodeNameSpace();
       
   862     const TUid& clientUid = nodeIdentifier.ClientUid();
       
   863     const TDesC& entityId = nodeIdentifier.NodeId();
       
   864 
       
   865     CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
       
   866         clientUid,
       
   867         entityId,
       
   868         nameSpace,
       
   869         aUri );
       
   870  
       
   871     // Icon is always set here to be sure that it is set. So it does
       
   872     // not have to be retrieved later on.
       
   873     // Icon for the subscription is at the moment thought to be icon
       
   874     // of the node where from the subscription is bought
       
   875     const CNcdNodeIcon& metaDataIcon = aData.ParentIconL();
       
   876     HBufC8* icon = metaDataIcon.IconDataL();
       
   877     CleanupStack::PushL( icon );
       
   878     groupForSubscription.SetIconL( *icon );
       
   879     CleanupStack::PopAndDestroy( icon );
       
   880 
       
   881     return groupForSubscription;
       
   882     }
       
   883 
       
   884 CNcdSubscriptionGroup& CNcdSubscriptionManager::ClientsSubscriptionGroupL(
       
   885     TUid aClientUid,
       
   886     const TDesC& aEntityId,
       
   887     const TDesC& aNamespace,
       
   888     const TDesC& aUri )
       
   889     {
       
   890     DLTRACEIN((""));
       
   891     // Get or create object for clients subscription info    
       
   892     TInt clientIndex( ClientsSubscriptionsL( aClientUid ) );
       
   893     
       
   894     RPointerArray<CNcdSubscriptionGroup>& groupsOfClient =
       
   895         iClientSubscriptions[clientIndex]->Groups();
       
   896     
       
   897     // Go through groups resembling subscriptions and if a group
       
   898     // is from the same dataentity as the given
       
   899     // protocol-subscription, use it.
       
   900 
       
   901     TInt groupIndex( -1 );    
       
   902     TRAPD( searchError, groupIndex = FindGroupL( groupsOfClient,
       
   903                                                  aEntityId,
       
   904                                                  aNamespace ) );    
       
   905     if ( searchError == KErrNotFound )
       
   906         {
       
   907         // Let's create new group because it was not
       
   908         // found
       
   909         CNcdSubscriptionGroup* group =
       
   910             CNcdSubscriptionGroup::NewLC();
       
   911         groupsOfClient.AppendL( group );        
       
   912         CleanupStack::Pop( group );
       
   913         
       
   914         group->SetEntityInfoL( aEntityId,
       
   915                                aNamespace,
       
   916                                aUri,
       
   917                                aClientUid );
       
   918         
       
   919         // set clientIndex to the appended clients subscriptions
       
   920         groupIndex = groupsOfClient.Count() - 1;
       
   921         }
       
   922     else if ( searchError != KErrNone )
       
   923         {
       
   924         // If leave occurs and it is not KErrNotFound, leave.
       
   925         User::Leave( searchError );
       
   926         }
       
   927     
       
   928     return *(groupsOfClient[groupIndex]);
       
   929     }
       
   930 
       
   931 RPointerArray<CNcdSubscriptionGroup> CNcdSubscriptionManager::ServersGroupsL(
       
   932     TUid aClientUid,
       
   933     const TDesC& aUri ) const
       
   934     {
       
   935     DLTRACEIN((""));
       
   936     // Into this array we gather all groups that are got from the given
       
   937     // server
       
   938     RPointerArray<CNcdSubscriptionGroup> returnArray;
       
   939     CleanupClosePushL( returnArray );
       
   940 
       
   941     TInt index = IsInCacheL( aClientUid );
       
   942     CNcdClientsSubscriptions* subscriptions = iClientSubscriptions[index];
       
   943     // All groups (also groups from other servers)
       
   944     RPointerArray<CNcdSubscriptionGroup>& groups = subscriptions->Groups();
       
   945 
       
   946     // And now, take only groups that are from the given server
       
   947     TInt groupCount( groups.Count() );
       
   948     TInt groupIndex( 0 );
       
   949 
       
   950     while ( groupIndex < groupCount )
       
   951         {
       
   952         if ( aUri == groups[groupIndex]->ServerUri() )
       
   953             {
       
   954             returnArray.AppendL( groups[groupIndex] );
       
   955             }
       
   956         ++groupIndex;
       
   957         }
       
   958 
       
   959     CleanupStack::Pop( &returnArray );
       
   960     return returnArray;
       
   961     }
       
   962 
       
   963 void CNcdSubscriptionManager::InternalizeAndMarkSubscriptionsL(
       
   964     TUid aClientUid,
       
   965     const TDesC& aUri,
       
   966     RPointerArray<MNcdPreminetProtocolSubscription>&
       
   967         aServersSubscriptions )
       
   968     {
       
   969     DLTRACEIN((""));
       
   970     TInt count( aServersSubscriptions.Count() );
       
   971     
       
   972     for ( TInt i = 0; i < count; i++ )
       
   973         {
       
   974         DLINFO(( "index: %d of count: %d", i, count ));
       
   975         // Write all that can be updated. If some are not
       
   976         // successfull, continue to next one.
       
   977         TRAP_IGNORE( InternalizeAndMarkSubscriptionL(
       
   978                          aClientUid,
       
   979                          aUri,
       
   980                          *aServersSubscriptions[i] ) );
       
   981         }
       
   982     }
       
   983 
       
   984 void CNcdSubscriptionManager::InternalizeAndMarkSubscriptionL(
       
   985     TUid aClientUid,
       
   986     const TDesC& aUri,
       
   987     MNcdPreminetProtocolSubscription& aSubscription )
       
   988     {
       
   989     DLTRACEIN((""));
       
   990     // First internalize and write to db
       
   991     InternalizeSubscriptionL( aClientUid,
       
   992                               aUri,
       
   993                               aSubscription );
       
   994     DLINFO((""));
       
   995     // Search for group and then mark it as updated so that
       
   996     // all that were not updated can be removed later on.
       
   997     // If this fails, then this subscription will probably be
       
   998     // removed later on.
       
   999 
       
  1000     CNcdSubscriptionGroup& group = FindGroupL( aClientUid,
       
  1001                                                aSubscription.EntityId(),
       
  1002                                                aSubscription.Namespace() );
       
  1003 
       
  1004     SaveGroupIntoDatabaseL( aClientUid, group );
       
  1005     DLTRACE(( "Subscription group saved into database." ));                                           
       
  1006     
       
  1007     // With this flag we later determine if this subscription was
       
  1008     // received from the server and should not be removed.
       
  1009     group.SetRecentlyUpdatedL( ETrue,
       
  1010                                aSubscription.PurchaseOptionId() );
       
  1011     DLINFO(("subscription set as recently updated"));
       
  1012     DLTRACEOUT((""));
       
  1013     }
       
  1014 
       
  1015 void CNcdSubscriptionManager::InternalizeSubscriptionL( 
       
  1016     TUid aClientUid,
       
  1017     const TDesC& aUri,
       
  1018     MNcdPreminetProtocolSubscription& aSubscription )
       
  1019     {
       
  1020     DLTRACEIN((""));
       
  1021 
       
  1022     // Get or create subscription group
       
  1023 
       
  1024     CNcdSubscriptionGroup& groupForSubscription = ClientsSubscriptionGroupL(
       
  1025         aClientUid,
       
  1026         aSubscription.EntityId(),
       
  1027         aSubscription.Namespace(),
       
  1028         aUri );
       
  1029 
       
  1030 
       
  1031     groupForSubscription.InternalizeSubscriptionL( aSubscription );
       
  1032 
       
  1033     DLTRACE(( "Subscription internalized." ));
       
  1034 
       
  1035     // Database should always have updated info so at this point we have
       
  1036     // to write updates there.
       
  1037     
       
  1038     // Because there is a database for each client the writing has
       
  1039     // to be done here where we know which group was updated.
       
  1040 
       
  1041     SaveGroupIntoDatabaseL( aClientUid,
       
  1042                             groupForSubscription );
       
  1043 
       
  1044     DLTRACE(( "Subscription group saved into database." ));
       
  1045     
       
  1046     DLTRACEOUT((""));
       
  1047     }
       
  1048     
       
  1049 void CNcdSubscriptionManager::RemoveUnmarkedSubscriptionsL(
       
  1050     TUid aClientUid,
       
  1051     RPointerArray<CNcdSubscriptionGroup>& aGroups )
       
  1052     {
       
  1053     DLTRACEIN((""));
       
  1054     // Client reference is only needed if a whole group has to be removed
       
  1055     TInt index = IsInCacheL( aClientUid );
       
  1056     CNcdClientsSubscriptions* clientsSubscriptions =
       
  1057         iClientSubscriptions[index];
       
  1058 
       
  1059 
       
  1060     TInt groupIndex( aGroups.Count() - 1 );
       
  1061     
       
  1062     while ( groupIndex > -1 )
       
  1063         {
       
  1064         TBool changesMade = 
       
  1065             aGroups[groupIndex]->RemoveUnmarkedSubscriptionsAndUnmarkL();
       
  1066         
       
  1067         if ( changesMade )
       
  1068             {
       
  1069             if ( aGroups[groupIndex]->SubscriptionCount() == 0 )
       
  1070                 {
       
  1071                 // No subscriptions left in the group, remove the group
       
  1072                 
       
  1073                 // from cache
       
  1074                 clientsSubscriptions->RemoveGroup( aGroups[groupIndex] );
       
  1075                 // from db
       
  1076                 RemoveGroupFromDatabaseL( aClientUid,
       
  1077                                           *aGroups[groupIndex] );
       
  1078                 
       
  1079                 // Remove the group also from the array given array
       
  1080                 // so the array is up to date and can be used after
       
  1081                 // completion of this function
       
  1082                 aGroups.Remove( groupIndex );
       
  1083                 }
       
  1084             else
       
  1085                 {
       
  1086                 // Subscriptions left in the group, write current
       
  1087                 // status of the group into db
       
  1088                 SaveGroupIntoDatabaseL( aClientUid, *aGroups[groupIndex] );
       
  1089                 }                            
       
  1090             }
       
  1091         --groupIndex;
       
  1092         }
       
  1093 
       
  1094     // As the clientsSubscriptions only exists in the cache,
       
  1095     // it is not checked that if groups still exist after this
       
  1096     // group removal and whether the clientsSubscriptions
       
  1097     // should be removed.
       
  1098     }
       
  1099 
       
  1100 RPointerArray<CNcdSubscriptionsSourceIdentifier> 
       
  1101     CNcdSubscriptionManager::SubscriptionsSourcesL( TInt aClientIndex ) const
       
  1102     {
       
  1103     DLTRACEIN(( "Getting subscriptions sources from subscriptions db." ));
       
  1104     RPointerArray<CNcdSubscriptionGroup>& clientsGroups =
       
  1105         iClientSubscriptions[aClientIndex]->Groups();
       
  1106     
       
  1107     TInt groupCount( clientsGroups.Count() );
       
  1108     if ( groupCount < 1 )
       
  1109         {
       
  1110         User::Leave( KErrNotFound );
       
  1111         }
       
  1112         
       
  1113     RPointerArray<CNcdSubscriptionsSourceIdentifier> returnArray;
       
  1114     CleanupResetAndDestroyPushL( returnArray );
       
  1115     
       
  1116     // Let's take the first subscriptions source info always into
       
  1117     // the array because nothing is yet in the array.
       
  1118     
       
  1119     // Notice that in this function we set all source identifiers not
       
  1120     // to require capability check. This is because we assume that
       
  1121     // if the server has once supported subscriptions, it will support
       
  1122     // them also later.
       
  1123 
       
  1124     TInt groupIndex( 0 );
       
  1125     
       
  1126     CNcdSubscriptionsSourceIdentifier* tmpIdentifier =
       
  1127         CNcdSubscriptionsSourceIdentifier::NewLC(
       
  1128             clientsGroups[groupIndex]->ServerUri(),
       
  1129             clientsGroups[groupIndex]->Namespace(),
       
  1130             EFalse );
       
  1131             
       
  1132     returnArray.AppendL( tmpIdentifier );
       
  1133     CleanupStack::Pop( tmpIdentifier );
       
  1134     tmpIdentifier = NULL;
       
  1135     
       
  1136     ++groupIndex;
       
  1137     
       
  1138     // Then go through others one at a time and check that such info
       
  1139     // is not already found from the array.
       
  1140     
       
  1141     // Notice that only uri and namespace are compared here,
       
  1142     // capability requirement is not checked
       
  1143     TIdentityRelation<CNcdSubscriptionsSourceIdentifier> match( 
       
  1144             &CNcdSubscriptionsSourceIdentifier::CompareIdentifiers );
       
  1145     
       
  1146     while ( groupIndex < groupCount )
       
  1147         {
       
  1148         tmpIdentifier = CNcdSubscriptionsSourceIdentifier::NewLC(
       
  1149             clientsGroups[groupIndex]->ServerUri(),
       
  1150             clientsGroups[groupIndex]->Namespace(),
       
  1151             EFalse );
       
  1152 
       
  1153         if ( returnArray.Find( tmpIdentifier, match ) == KErrNotFound )
       
  1154             {
       
  1155             returnArray.AppendL( tmpIdentifier );
       
  1156             CleanupStack::Pop( tmpIdentifier );
       
  1157             }
       
  1158         else
       
  1159             {
       
  1160             CleanupStack::PopAndDestroy( tmpIdentifier );
       
  1161             }
       
  1162         
       
  1163         tmpIdentifier = NULL;
       
  1164     
       
  1165         ++groupIndex;
       
  1166         }
       
  1167     
       
  1168     CleanupStack::Pop( &returnArray );
       
  1169     
       
  1170     return returnArray;    
       
  1171     }
       
  1172 
       
  1173 
       
  1174 void CNcdSubscriptionManager::ExternalizeClientsSubscriptionsL(
       
  1175     MCatalogsSession& aSession,
       
  1176     const RPointerArray<CNcdKeyValuePair>& aGroupIdentifiers,
       
  1177     RWriteStream& aStream )
       
  1178     {
       
  1179     DLTRACEIN((""));
       
  1180 
       
  1181     if ( aGroupIdentifiers.Count() == 0) 
       
  1182         {
       
  1183         aStream.WriteInt32L( 0 );
       
  1184         return;
       
  1185         }
       
  1186 
       
  1187     // Because one subscription manager serves all clients, we
       
  1188     // check here which client uid the client has and pass it
       
  1189     // forward
       
  1190     MCatalogsContext& context = aSession.Context();
       
  1191     TUid familyId = context.FamilyId();
       
  1192 
       
  1193     // check if clients info is in cache
       
  1194     TInt index( -1 );
       
  1195     index = IsInCacheL( familyId );
       
  1196 
       
  1197     ExternalizeDataForRequestL( index, aSession, aGroupIdentifiers, aStream );
       
  1198     DLTRACEOUT((""));
       
  1199     }
       
  1200 
       
  1201 void CNcdSubscriptionManager::LoadClientsInfoFromStorageL( TUid aUid )
       
  1202     {
       
  1203     DLTRACEIN((""));
       
  1204 
       
  1205     DLTRACE(( "Loading subscription info from storage for client: %d",
       
  1206               aUid.iUid ));
       
  1207 
       
  1208     // Loading from the current client
       
  1209     MNcdStorage& storage = *StorageL( aUid, 
       
  1210         NcdProviderDefines::KSubscriptionNamespace );
       
  1211     
       
  1212     // NOTE: this creates the database if it does not already exist
       
  1213     MNcdDatabaseStorage& database = 
       
  1214         storage.DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
       
  1215     
       
  1216     CNcdClientsSubscriptions* clientsSubscriptions =
       
  1217         CNcdClientsSubscriptions::NewLC( aUid );
       
  1218     
       
  1219     iClientSubscriptions.AppendL( clientsSubscriptions );
       
  1220     
       
  1221     CleanupStack::Pop( clientsSubscriptions );
       
  1222     
       
  1223     
       
  1224     RPointerArray<MNcdStorageItem> items;
       
  1225     CleanupClosePushL( items );
       
  1226     database.StorageItemsL( items );
       
  1227     
       
  1228     const TInt foudItemCount( items.Count() );
       
  1229 
       
  1230     DLTRACE(( "Found %d subscription storage items for client %d.",
       
  1231               foudItemCount,
       
  1232               aUid.iUid ));
       
  1233 
       
  1234     if ( items.Count() < 1 )
       
  1235         {
       
  1236         // Nothing is found for given client, but the
       
  1237         // ClientsSubscriptions-object is created for possible later
       
  1238         // use
       
  1239         CleanupStack::PopAndDestroy( &items );
       
  1240         return;
       
  1241         }    
       
  1242     
       
  1243     TInt itemIndex( 0 );
       
  1244     while( itemIndex < foudItemCount )
       
  1245         {
       
  1246         CNcdSubscriptionGroup* group = CNcdSubscriptionGroup::NewLC();
       
  1247         
       
  1248         clientsSubscriptions->AddGroupL( group );
       
  1249         
       
  1250         CleanupStack::Pop( group );
       
  1251         
       
  1252         // Note: database has the ownership of the item
       
  1253         MNcdStorageItem* item = items[itemIndex];
       
  1254 
       
  1255         // Get data from database by using aDataItem as the target so that 
       
  1256         // internalize will be called for it
       
  1257         item->SetDataItem( group );
       
  1258         
       
  1259         // Read node data -> calls InternalizeL of aDataItem
       
  1260         item->ReadDataL();
       
  1261         
       
  1262         ++itemIndex;
       
  1263         }
       
  1264     CleanupStack::PopAndDestroy( &items );
       
  1265     DLTRACEOUT((""));    
       
  1266     }
       
  1267 
       
  1268 
       
  1269 void CNcdSubscriptionManager::ExternalizeDataForRequestL(
       
  1270     TInt aIndex,
       
  1271     MCatalogsSession& aSession,
       
  1272     const RPointerArray<CNcdKeyValuePair>& aGroupIdentifiers,
       
  1273     RWriteStream& aStream )
       
  1274     {
       
  1275     DLTRACEIN((""));
       
  1276     
       
  1277     if ( aIndex < 0 )
       
  1278         {
       
  1279         // No entries with given client uid. If there was one, then its
       
  1280         // Externalize (which is called later) has to write the amount
       
  1281         // of groups as its first entry. This way we have entry amount
       
  1282         // always as the first entry in the stream.
       
  1283         aStream.WriteInt32L( 0 );
       
  1284         return;
       
  1285         }
       
  1286     
       
  1287     CNcdClientsSubscriptions* clientsSubscriptions = 
       
  1288         iClientSubscriptions[aIndex];
       
  1289 
       
  1290     RPointerArray<CNcdSubscriptionGroup>& groups =
       
  1291         clientsSubscriptions->Groups();
       
  1292     
       
  1293     aStream.WriteInt32L( aGroupIdentifiers.Count() );
       
  1294     for ( TInt i = 0; i < aGroupIdentifiers.Count(); i++ ) 
       
  1295         {
       
  1296         const TDesC& nameSpace = aGroupIdentifiers[i]->Key();
       
  1297         const TDesC& entityId = aGroupIdentifiers[i]->Value();
       
  1298     
       
  1299         TBool found = EFalse;
       
  1300         for ( TInt i = 0; i < groups.Count(); i++ ) 
       
  1301             {
       
  1302             CNcdSubscriptionGroup* group = groups[i];
       
  1303             if ( group->Namespace() == nameSpace &&
       
  1304                  group->EntityId() == entityId ) 
       
  1305                 {
       
  1306                 TInt tmpHandle( aSession.AddObjectL( group ) );
       
  1307                 DLTRACE(( "Sending subscriptiongroup handle: %i",
       
  1308                     tmpHandle ));
       
  1309                 TRAPD( addError, aStream.WriteInt32L( tmpHandle ));
       
  1310                 if ( addError != KErrNone ) 
       
  1311                     {
       
  1312                     // Should all other added objects be removed from
       
  1313                     // the session also?
       
  1314                     aSession.RemoveObject( tmpHandle );
       
  1315                     User::Leave( addError );
       
  1316                     }
       
  1317                 found = ETrue;
       
  1318                 break;
       
  1319                 }
       
  1320             }
       
  1321         if ( !found ) 
       
  1322             {
       
  1323             User::Leave( KErrNotFound );
       
  1324             }
       
  1325         }
       
  1326                 
       
  1327     DLTRACEOUT((""));
       
  1328     }
       
  1329 
       
  1330 
       
  1331 HBufC* CNcdSubscriptionManager::GenerateGroupDataIdL(
       
  1332     CNcdSubscriptionGroup& aGroup )
       
  1333     {
       
  1334     // Items written to database are identified by classtype (integer)
       
  1335     // and dataid (string). Here we use a constant classtype so the
       
  1336     // dataid has to be unique. Because group contains subscriptions
       
  1337     // available from one entity, we use entityid and namespace to
       
  1338     // identify the item. The format is as follows:
       
  1339     // namespace<separator>entityid
       
  1340     // This kind of format does not promise full uniqueness but it is
       
  1341     // hopefully close enough.
       
  1342 
       
  1343     const TDesC& entityNamespace = aGroup.Namespace();
       
  1344     TInt namespaceLength( entityNamespace.Length() );
       
  1345     
       
  1346     const TDesC& entityId = aGroup.EntityId();
       
  1347     TInt entityIdLength( entityId.Length() );
       
  1348     
       
  1349     _LIT( KIdSeparator, "|" );
       
  1350     
       
  1351     HBufC* dataId = HBufC::NewL( namespaceLength + entityIdLength + 1 );
       
  1352     TPtr modifiableDataId = dataId->Des();
       
  1353     
       
  1354     modifiableDataId.Append( entityNamespace );
       
  1355     modifiableDataId.Append( KIdSeparator );
       
  1356     modifiableDataId.Append( entityId );
       
  1357 
       
  1358     return dataId;
       
  1359     }
       
  1360 
       
  1361 void CNcdSubscriptionManager::RemoveGroupFromDatabaseL(
       
  1362     TUid aClientUid,
       
  1363     CNcdSubscriptionGroup& aGroup )
       
  1364     {
       
  1365     DLTRACEIN((""));
       
  1366     
       
  1367     // Databases are created for each client. (for each uid)
       
  1368     // As a namespace we use a constant namespace (KSubscriptionNameSpace)
       
  1369     // so we know in the future where from to load all data.
       
  1370 
       
  1371     HBufC* dataId = GenerateGroupDataIdL( aGroup );
       
  1372     CleanupStack::PushL( dataId );
       
  1373 
       
  1374     DLTRACE(( _L("DataId for subscription group database item: %S"),
       
  1375               dataId ));
       
  1376 
       
  1377 
       
  1378     RemoveDataFromDatabaseL( aClientUid,
       
  1379                              NcdProviderDefines::KSubscriptionNamespace,
       
  1380                              *dataId,
       
  1381                              NcdNodeClassIds::ENcdSubscriptionsData );
       
  1382                            
       
  1383     CleanupStack::PopAndDestroy( dataId );
       
  1384     
       
  1385     DLTRACEOUT((""));
       
  1386     }
       
  1387 
       
  1388 void CNcdSubscriptionManager::RemoveDataFromDatabaseL( 
       
  1389     TUid aUid,
       
  1390     const TDesC& aNamespace,
       
  1391     const TDesC& aDataId,
       
  1392     NcdNodeClassIds::TNcdNodeClassType aClassType )
       
  1393     {
       
  1394     DLTRACEIN(( _L("%S::%S"), &aNamespace, &aDataId ));
       
  1395 
       
  1396     DLTRACE(( _L("Removing database item with dataid: %S and classtype: %d"),
       
  1397               &aDataId,
       
  1398               aClassType ));
       
  1399 
       
  1400     if( aNamespace == KNullDesC || aDataId == KNullDesC )
       
  1401         {
       
  1402         DLTRACE(( _L("Empty namespace or id given for storage removing: %S, %S"),
       
  1403                   &aNamespace, 
       
  1404                   &aDataId ));
       
  1405         User::Leave( KErrArgument );
       
  1406         }
       
  1407     
       
  1408     // Removing from the current client and from the namespace in which
       
  1409     // the metadata is defined
       
  1410     MNcdStorage* storage = StorageL( aUid, aNamespace );
       
  1411         
       
  1412     // NOTE: this creates the database if it does not already exist
       
  1413     MNcdDatabaseStorage& database = 
       
  1414         storage->DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
       
  1415             
       
  1416     // Get/create the storage item which is used in removal
       
  1417     // Note: database has the ownership of the item
       
  1418     MNcdStorageItem* storageItem = 
       
  1419         database.StorageItemL( aDataId, aClassType );    
       
  1420     
       
  1421     // Remove the item from the storage
       
  1422     storageItem->RemoveFromStorageL();
       
  1423 
       
  1424     // Make the removing happen.
       
  1425     database.CommitL();       
       
  1426     
       
  1427     DLTRACEOUT((""));    
       
  1428     }
       
  1429 
       
  1430 void CNcdSubscriptionManager::SaveDataIntoDatabaseL( 
       
  1431     TUid aUid,
       
  1432     const TDesC& aNamespace,
       
  1433     const TDesC& aDataId,
       
  1434     MNcdStorageDataItem& aDataItem,
       
  1435     NcdNodeClassIds::TNcdNodeClassType aClassType )
       
  1436     {
       
  1437     DLTRACEIN(( _L("%S::%S"), &aNamespace, &aDataId ));
       
  1438 
       
  1439     DLTRACE(( _L("Saving to database item with dataid: %S and classtype: %d"),
       
  1440               &aDataId,
       
  1441               aClassType ));
       
  1442 
       
  1443     if( aNamespace == KNullDesC || aDataId == KNullDesC )
       
  1444         {
       
  1445         DLTRACE(( _L("Empty namespace or id given for storage saving: %S, %S"),
       
  1446                   &aNamespace, 
       
  1447                   &aDataId ));
       
  1448         User::Leave( KErrArgument );
       
  1449         }
       
  1450     
       
  1451     // Storing to the current client and to the namespace in which
       
  1452     // the metadata is defined
       
  1453     MNcdStorage* storage = StorageL( aUid, aNamespace );
       
  1454         
       
  1455     // NOTE: this creates the database if it does not already exist
       
  1456     MNcdDatabaseStorage& database = 
       
  1457         storage->DatabaseStorageL( NcdProviderDefines::KDefaultDatabaseUid );
       
  1458             
       
  1459     // Get/create the storage item where the data is saved
       
  1460     // Note: database has the ownership of the item
       
  1461     MNcdStorageItem* storageItem = 
       
  1462         database.StorageItemL( aDataId, aClassType );    
       
  1463     
       
  1464     // Here call the storage functions that will handle 
       
  1465     // the saving of the data
       
  1466     
       
  1467     // Save new item to database
       
  1468     storageItem->SetDataItem( &aDataItem );
       
  1469     storageItem->OpenL();
       
  1470     
       
  1471     // Calls ExternalizeL for data item
       
  1472     storageItem->WriteDataL();
       
  1473     
       
  1474     // Save the data to the database.
       
  1475     // The data object implements MNcdStorageDataItem interface.
       
  1476     // So, the externalize function will insert the data to the stream
       
  1477     // that the database handler will save to the database.
       
  1478     storageItem->SaveL();        
       
  1479     
       
  1480     DLTRACEOUT((""));    
       
  1481     }
       
  1482     
       
  1483     
       
  1484 // ---------------------------------------------------------------------------
       
  1485 // StorageL
       
  1486 // ---------------------------------------------------------------------------
       
  1487 //    
       
  1488 MNcdStorage* CNcdSubscriptionManager::StorageL( 
       
  1489     TUid aUid,
       
  1490     const TDesC& aNamespace ) const
       
  1491     {    
       
  1492     DLTRACEIN((""));
       
  1493     MNcdStorage* storage = NULL;
       
  1494         
       
  1495     DLTRACE(( _L("Subscriptions storage namespace: %S"), &aNamespace ));
       
  1496 
       
  1497     // No need to clean the name anymore
       
  1498     HBufC* uid = aUid.Name().AllocLC();
       
  1499 
       
  1500     TRAPD( err, 
       
  1501         {
       
  1502         storage = &iStorageManager.StorageL( *uid, 
       
  1503                                              aNamespace );
       
  1504         });
       
  1505     
       
  1506     if ( err == KErrNotFound ) 
       
  1507         {
       
  1508         DLTRACE(("Creating subscription storage for the client"));
       
  1509         DLTRACE(( _L("Client identifying uid is %S"), uid ));
       
  1510         storage =
       
  1511             &iStorageManager.CreateStorageL( *uid, 
       
  1512                                              aNamespace );
       
  1513         }
       
  1514     else if ( err != KErrNone )
       
  1515         {
       
  1516         DLTRACE(("Leaving: %i", err));
       
  1517         User::Leave( err );   
       
  1518         }
       
  1519         
       
  1520     CleanupStack::PopAndDestroy( uid );
       
  1521 
       
  1522     DLTRACEOUT((""));
       
  1523     return storage;
       
  1524     }
       
  1525 
       
  1526 void CNcdSubscriptionManager::ListenerEnrolledL(
       
  1527     MCatalogsBaseMessage& aMessage ) 
       
  1528     {
       
  1529     DLTRACEIN((""));
       
  1530     iPendingMessages.AppendL( &aMessage );
       
  1531     }
       
  1532     
       
  1533 void CNcdSubscriptionManager::NotifyAllListeners( TInt aError ) 
       
  1534     {
       
  1535     DLTRACEIN((""));
       
  1536     for ( TInt i = 0; i < iPendingMessages.Count(); i++ ) 
       
  1537         {
       
  1538         iPendingMessages[i]->CompleteAndRelease( aError );
       
  1539         }
       
  1540     iPendingMessages.Reset();
       
  1541     }