cbs/CbsServer/ServerSrc/CCbsDbImpTopicList.cpp
changeset 0 ff3b6d0fd310
child 50 2313cb430f28
equal deleted inserted replaced
-1:000000000000 0:ff3b6d0fd310
       
     1 /*
       
     2 * Copyright (c) 2003 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:  This file contains the implementation of the CCbsDbImpTopicList class
       
    15 *            member functions.
       
    16 *    
       
    17 *                This class represents the topic list contained in the database.
       
    18 *
       
    19 */
       
    20 
       
    21 
       
    22 
       
    23 // INCLUDE FILES
       
    24 #include <e32base.h>
       
    25 #include <e32svr.h>
       
    26 #include <f32file.h>
       
    27 
       
    28 #include <shareddataclient.h>   // RequestFreeDiskSpaceLC
       
    29 
       
    30 #include <barsc.h>              // Resource access
       
    31 #include <barsread.h>           // Resource access
       
    32 
       
    33 #include <CbsServer.rsg>
       
    34 
       
    35 #include "CbsServerPanic.h"
       
    36 #include "CbsStreamHelper.h"
       
    37 #include "CbsDbConstants.h"
       
    38 #include "CbsUtils.h"
       
    39 #include "CCbsDbImpTopicList.h"
       
    40 #include "MCbsDbTopicListObserver.H"
       
    41 #include "CCbsDbImpTopicMessages.h"
       
    42 
       
    43 #include "CbsLogger.h"
       
    44 
       
    45 #include <centralrepository.h>  // for local variation
       
    46 #include "cbsinternalcrkeys.h"  // for local variation
       
    47 #include "cbsvariant.hrh"       // for local variation
       
    48  
       
    49 // CONSTANTS
       
    50 
       
    51 // Initial size for topic cache array
       
    52 const TInt KDefaultTopicListSize = 10;
       
    53 
       
    54 // Size of the topic stream, used in checking against FFS free space limit
       
    55 const TInt KTopicStreamSize = 92;
       
    56 
       
    57 // Size of the topic messages stream, FFS critical level check
       
    58 const TInt KEmptyTopicMessagesStreamSize = 4;
       
    59 
       
    60 // Size of topic list stream, FFS critical level check
       
    61 const TInt KTopicListStreamSize = 85;
       
    62 
       
    63 // Size of topic list stream (root), FFS critical level check
       
    64 const TInt KTopicListRootStreamSize = 2;
       
    65 
       
    66 // Time in microseconds to wait after a critical store exception 
       
    67 // before a recovery attempt is made.
       
    68 const TInt KWaitAfterCriticalStoreException = 2000000;
       
    69 
       
    70 // Used when unsaved message stream ids are deleted from topic messages 
       
    71 // stream
       
    72 const TInt KTypicalNumberOfTopicMessages = 6;
       
    73 
       
    74 // Minimum interval between compacting the stores in minutes
       
    75 const TInt KMinimumCompactInterval = 30;
       
    76 
       
    77 // Number of the index topic
       
    78 const TInt KIndexTopicNumber = 0;
       
    79 
       
    80 // Space for reading messages
       
    81 const TInt KReadMessageSize = 92;
       
    82 
       
    83 const TInt KTopicsGranularity = 1;
       
    84 
       
    85 const TInt KTopicListsGranularity = 1;
       
    86 
       
    87 const TInt KTopicIdsGranularity = 5;
       
    88 
       
    89 // ================= MEMBER FUNCTIONS =======================
       
    90 
       
    91 // -----------------------------------------------------------------------------
       
    92 // CCbsDbImpTopicList::CCbsDbImpTopicList
       
    93 // C++ default constructor can NOT contain any code, that
       
    94 // might leave.
       
    95 // -----------------------------------------------------------------------------
       
    96 //
       
    97 CCbsDbImpTopicList::CCbsDbImpTopicList( 
       
    98     RFs& aFs, 
       
    99     CCbsDbImp& aDatabase )
       
   100     : iDatabase( aDatabase ), 
       
   101     iFs( aFs ),
       
   102     iTopicCount( 0 ),
       
   103     iInitializing( EFalse ),
       
   104     iDeleteAllTopics( EFalse )
       
   105     {
       
   106     }
       
   107 
       
   108 // -----------------------------------------------------------------------------
       
   109 // CCbsDbImpTopicList::ConstructL
       
   110 // Symbian 2nd phase constructor can leave.
       
   111 // -----------------------------------------------------------------------------
       
   112 //
       
   113 void CCbsDbImpTopicList::ConstructL( 
       
   114     const TDesC& aTopicsFile,
       
   115     const TDesC& aUnsavedMessagesFile )
       
   116     {
       
   117     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::ConstructL()");
       
   118     
       
   119     // Create observer array
       
   120     iObservers = new ( ELeave ) CArrayFixFlat< MCbsDbTopicListObserver* >( 
       
   121         KCbsDbObserverArraySize );
       
   122 
       
   123     // Create topic array, additional memory size in new alloc, 1*192 B = 192 B
       
   124     iTopics = new ( ELeave ) CArrayFixFlat< TCbsDbImpTopic >( KTopicsGranularity );
       
   125 
       
   126     // Create the root item table, additional memory size in new alloc, 1*184 B = 184 B
       
   127     iTopicLists = new ( ELeave ) CArrayFixFlat< TCbsDbImpTopicList >( KTopicListsGranularity ); 
       
   128 
       
   129     // Create topic ID array, additional memory size in new alloc, 5*4 B = 20 B
       
   130     iTopicIds = new ( ELeave ) CArrayFixFlat< TStreamId >( KTopicIdsGranularity ); 
       
   131 
       
   132     // Initialize iPreviousCompact to now
       
   133     iPreviousCompact.UniversalTime();
       
   134 
       
   135     // Copy datafile names from parameters
       
   136     iTopicsFilename = aTopicsFile.AllocL();
       
   137     iUnsavedMessagesFilename = aUnsavedMessagesFile.AllocL();
       
   138     
       
   139     // Fetch local variation bits from CenRep    
       
   140     CRepository* repository = CRepository::NewL( KCRUidCbsVariation );    
       
   141     TInt err = repository->Get( KCbsVariationFlags, iLVBits );
       
   142     CBSLOGSTRING2("CBSSERVER: CCbsRecEtel::ConstructL(): CenRep error: %d", err );    
       
   143     if ( err )
       
   144         {
       
   145         iLVBits = 0;
       
   146         }    
       
   147     delete repository;
       
   148 
       
   149     // If aLoadFactorySettings, then the files are recreated and initialized.
       
   150     // If not, then the nonexisting files are created, files opened and
       
   151     // data internalized.
       
   152 
       
   153     TBool unsavedMsgFileExists( CbsUtils::ExistsL( iFs, *iUnsavedMessagesFilename ) );
       
   154 
       
   155     TBool loadFactorySettings( !CbsUtils::ExistsL( iFs, aTopicsFile ) );
       
   156     TRAPD( error, OpenFilesL( loadFactorySettings, EFalse ) );
       
   157     
       
   158     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::ConstructL(): OpenFilesL() error: %d", error );
       
   159     
       
   160     if ( error == KErrDiskFull )
       
   161         {
       
   162         // Delete the store and open is again
       
   163         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ConstructL(): About to delete iTopicStore..." );
       
   164         
       
   165         delete iTopicStore;
       
   166         iTopicStore = NULL;
       
   167         
       
   168         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ConstructL(): iTopicStore deletion finished." );
       
   169 
       
   170         // Try to open the store again   
       
   171         TRAPD( error, iTopicStore = CFileStore::OpenL( iFs, *iTopicsFilename, EFileRead | EFileWrite ) );
       
   172         CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::ConstructL(); iTopicStore OpenL() error: %d", error );
       
   173         if ( error )
       
   174             {
       
   175             InitializeListL( ETrue );
       
   176             }        
       
   177         }
       
   178     else
       
   179         {
       
   180         if ( loadFactorySettings )
       
   181             {
       
   182             // Create a topic list for standard topics
       
   183             if ( iTopicLists->Count() == 0 )
       
   184                 {
       
   185                 CreateStandardTopicListL();
       
   186                 }                
       
   187             }
       
   188 
       
   189         // Only load the topics, if not already loaded when opening the files
       
   190         if ( loadFactorySettings || unsavedMsgFileExists )
       
   191             {
       
   192             // Load the topics
       
   193             LoadDefaultTopicStreamL();
       
   194             }
       
   195         
       
   196         // Compact the topic store
       
   197         TopicStoreL()->CompactL();
       
   198         TopicStoreL()->CommitL();
       
   199         }            
       
   200     
       
   201     // Reset the unread message count to be sure that UI client gets the correct information,
       
   202     // at this point count is always zero.
       
   203     for ( TInt i( 0 ); i < iTopics->Count(); ++i )
       
   204         {
       
   205         iTopics->At( i ).iTopicData.iUnreadMessages = 0;
       
   206         }
       
   207         
       
   208     __TEST_INVARIANT;
       
   209     
       
   210     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::ConstructL()");
       
   211     }
       
   212 
       
   213 // -----------------------------------------------------------------------------
       
   214 // CCbsDbImpTopicList::NewL
       
   215 // Two-phased constructor.
       
   216 // -----------------------------------------------------------------------------
       
   217 //
       
   218 CCbsDbImpTopicList* CCbsDbImpTopicList::NewL( 
       
   219     RFs& aFs, 
       
   220     const TDesC& aTopicsFile, 
       
   221     const TDesC& aUnsavedMessagesFile,
       
   222     CCbsDbImp& aDatabase )
       
   223     {
       
   224     CCbsDbImpTopicList* self = 
       
   225         new ( ELeave ) CCbsDbImpTopicList( aFs, aDatabase );
       
   226     CleanupStack::PushL( self );
       
   227     self->ConstructL( aTopicsFile, aUnsavedMessagesFile );
       
   228     CleanupStack::Pop();
       
   229     return self;
       
   230     }
       
   231 
       
   232 // Destructor
       
   233 CCbsDbImpTopicList::~CCbsDbImpTopicList()
       
   234     {
       
   235     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::~CCbsDbImpTopicList()");
       
   236     delete iTopics;
       
   237     delete iTopicStore;
       
   238     delete iTopicLists;
       
   239     delete iTopicIds;
       
   240     delete iUnsavedMessageStore;
       
   241     delete iObservers;
       
   242     delete iUnsavedMessagesFilename;
       
   243     if ( iTopicsFilename )
       
   244         {
       
   245         delete iTopicsFilename;
       
   246         }
       
   247     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::~CCbsDbImpTopicList()");
       
   248     }
       
   249 
       
   250 #ifndef __SECURE_BACKUP__
       
   251 // -----------------------------------------------------------------------------
       
   252 // CCbsDbImpTopicList::ChangeFileLockL
       
   253 // Closes or reopens the settings file if requested by a backup.
       
   254 // (other items were commented in a header).
       
   255 // -----------------------------------------------------------------------------
       
   256 //
       
   257 void CCbsDbImpTopicList::ChangeFileLockL( 
       
   258     const TDesC& aFileName,
       
   259     TFileLockFlags aFlags )
       
   260     {
       
   261     CBSLOGSTRING2("CBSSERVER: >>> CCbsDbImpTopicList::ChangeFileLockL() (1): flag: %d", aFlags );
       
   262     
       
   263     if ( aFlags == ETakeLock && iTopicStore == NULL )
       
   264         {
       
   265         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (1): Try to open store...");
       
   266         
       
   267         // Try to open the store.
       
   268         iTopicStore = CPermanentFileStore::OpenL( iFs, 
       
   269             aFileName, EFileRead | EFileWrite );
       
   270             
       
   271         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (1): Store opened.");
       
   272         }
       
   273     else if ( aFlags != ETakeLock )
       
   274         {
       
   275         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (1): Deleting iTopicStore...");
       
   276         
       
   277         delete iTopicStore; 
       
   278         iTopicStore = NULL;
       
   279         
       
   280         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (1): iTopicStore deleted.");
       
   281         }
       
   282     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::ChangeFileLockL() (1)");
       
   283     }
       
   284 #else
       
   285 
       
   286 // -----------------------------------------------------------------------------
       
   287 // CCbsDbImpSettings::ChangeFileLockL
       
   288 // Closes or reopens the settings file if requested by backup.
       
   289 // (other items were commented in a header).
       
   290 // -----------------------------------------------------------------------------
       
   291 //    
       
   292 void CCbsDbImpTopicList::ChangeFileLockL( const TCbsBackupRequest& aRequest )
       
   293     {
       
   294     CBSLOGSTRING2("CBSSERVER: >>> CCbsDbImpTopicList::ChangeFileLockL() (2): aRequest: %d", aRequest );
       
   295     
       
   296     // If backing up or restoring, release locks
       
   297     if ( ( aRequest == ECbsBackup || 
       
   298         aRequest == ECbsRestore ) )
       
   299         {
       
   300         delete iTopicStore; 
       
   301         iTopicStore = NULL;
       
   302         
       
   303         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (2): iTopicStore deleted.");
       
   304         }
       
   305     // Else take files into use again
       
   306     else if ( ( aRequest == ECbsNoBackup || 
       
   307         aRequest == ECbsBackupNotDefined ) && 
       
   308         iTopicStore == NULL)
       
   309         {
       
   310         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (2): Calling CPermanentFileStore::OpenL()...");
       
   311         // Try to open the store.
       
   312         iTopicStore = CPermanentFileStore::OpenL( iFs, 
       
   313             iTopicsFilename->Des(), EFileRead | EFileWrite );
       
   314         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::ChangeFileLockL() (2): CPermanentFileStore::OpenL() finished.");
       
   315         }
       
   316     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::ChangeFileLockL() (2)");
       
   317     }
       
   318 
       
   319 #endif
       
   320 
       
   321 // -----------------------------------------------------------------------------
       
   322 // CCbsDbImpTopicList::CheckFileLockL
       
   323 // Check if the server has a file lock.
       
   324 // (other items were commented in a header).
       
   325 // -----------------------------------------------------------------------------
       
   326 //
       
   327 void CCbsDbImpTopicList::CheckFileLockL() const
       
   328     {
       
   329     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::CheckFileLockL()");
       
   330     if ( iTopicStore == NULL )
       
   331         {
       
   332         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::CheckFileLockL(): iTopicStore == NULL, leaving with KErrLocked...");
       
   333         User::Leave( KErrLocked );
       
   334         }
       
   335     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::CheckFileLockL()");
       
   336     }
       
   337 
       
   338 // -----------------------------------------------------------------------------
       
   339 // CCbsDbImpTopicList::CreateNewTopicListL
       
   340 // Creates a new topic list.
       
   341 // (other items were commented in a header).
       
   342 // -----------------------------------------------------------------------------
       
   343 //
       
   344 void CCbsDbImpTopicList::CreateNewTopicListL( const TDesC& aTopicListName )
       
   345     {
       
   346     // FFS critical level check
       
   347     CbsUtils::FFSCriticalLevelCheckL( KTopicListStreamSize + 
       
   348         KCbsDbTopicArraySize, iFs );
       
   349 
       
   350     TInt topicListCount = iTopicLists->Count();
       
   351 
       
   352     // Check if there already is 10 topic lists
       
   353     if ( topicListCount < KCbsRootItemsSize )
       
   354         {                  
       
   355         // Create the stream for this topic list entry
       
   356         RStoreWriteStream outstream;
       
   357         TStreamId topicListStreamId( 
       
   358             outstream.CreateLC( *TopicStoreL() ) ); // on CS        
       
   359 
       
   360         // Set the values for this new topic list and set it as "current".
       
   361         // Reset the topic count of this topic list.
       
   362         iCurrentTopicList.iTopicCount = 0;
       
   363 
       
   364         // Topic list stream id for this list
       
   365         iCurrentTopicList.iTopicListId = topicListStreamId;
       
   366     
       
   367         // List name
       
   368         iCurrentTopicList.iTopicListName = aTopicListName; 
       
   369 
       
   370         // Is this the default list
       
   371         iCurrentTopicList.iIsDefaultTopicList = ETrue;
       
   372 
       
   373         // Number of this list, which is a int value between 0...9
       
   374         iCurrentTopicList.iNumber = iTopicLists->Count();
       
   375 
       
   376         // Add this list to the list array        
       
   377         TKeyArrayFix key( _FOFF( TCbsDbImpTopicList, iNumber ), ECmpTUint16 );
       
   378         iTopicLists->InsertIsqL( iCurrentTopicList, key );
       
   379     
       
   380         // Write the values to this topic list's stream
       
   381         outstream << iCurrentTopicList.iTopicListName;
       
   382         CbsStreamHelper::WriteBoolL( outstream, iCurrentTopicList.iIsDefaultTopicList );
       
   383         outstream.WriteInt16L( iCurrentTopicList.iNumber );
       
   384         outstream.WriteInt16L( iCurrentTopicList.iTopicCount );
       
   385 
       
   386         // Write space for topic stream IDs        
       
   387         for ( TInt i( 0 ); i < KCbsDbTopicArraySize; i++ )
       
   388             {
       
   389             outstream << TStreamId( 0 );
       
   390             }        
       
   391            
       
   392         outstream.CommitL();
       
   393         CleanupStack::PopAndDestroy(); // outstream    
       
   394         
       
   395         // Reset the topic array and add an index topic to this
       
   396         // topic list
       
   397         iTopics->Reset();
       
   398         AddIndexTopicL();
       
   399             
       
   400         // Update the root stream
       
   401         UpdateRootStreamL( EFalse );
       
   402     
       
   403         // Commit file changes
       
   404         CommitFilesL();
       
   405 
       
   406         // Load the topics (count = 1, Index topic only), 
       
   407         // so that the array is up to date
       
   408         LoadTopicsL( iCurrentTopicList.iTopicListId );            
       
   409         } 
       
   410     else
       
   411         {
       
   412         User::Leave( KErrGeneral );
       
   413         }   
       
   414     }
       
   415 
       
   416 // -----------------------------------------------------------------------------
       
   417 // CCbsDbImpTopicList::SetTopicMessages
       
   418 // Sets the topic messages db object for this topic list.
       
   419 // Note that this function does not transfer ownership
       
   420 // of aMessages.
       
   421 // (other items were commented in a header).
       
   422 // -----------------------------------------------------------------------------
       
   423 //
       
   424 void CCbsDbImpTopicList::SetTopicMessages( 
       
   425     CCbsDbImpTopicMessages* aMessages )
       
   426     {
       
   427     __ASSERT_ALWAYS( aMessages != NULL,
       
   428         CbsServerPanic( ECbsTopicMessagesNull ) );
       
   429     iMessages = aMessages;
       
   430     }
       
   431 
       
   432 // -----------------------------------------------------------------------------
       
   433 // CCbsDbImpTopicList::TopicCount
       
   434 // Returns the total amount of topics the list contains.
       
   435 // (other items were commented in a header).
       
   436 // -----------------------------------------------------------------------------
       
   437 //
       
   438 TInt CCbsDbImpTopicList::TopicCount() const
       
   439     {
       
   440     return iTopics->Count();
       
   441     }
       
   442 
       
   443 // -----------------------------------------------------------------------------
       
   444 // CCbsDbImpTopicList::TopicListCount
       
   445 // Get topic list count.
       
   446 // (other items were commented in a header).
       
   447 // -----------------------------------------------------------------------------
       
   448 //
       
   449 TInt CCbsDbImpTopicList::TopicListCount() const
       
   450     {
       
   451     return iTopicLists->Count();
       
   452     }
       
   453 
       
   454 // -----------------------------------------------------------------------------
       
   455 // CCbsDbImpTopicList::TopicStoreL
       
   456 // Returns pointer to the current store which contains topics
       
   457 // of the server (i.e., Topics-file) and saved messages. 
       
   458 // (other items were commented in a header).
       
   459 // -----------------------------------------------------------------------------
       
   460 //
       
   461 CFileStore* CCbsDbImpTopicList::TopicStoreL() const
       
   462     {
       
   463     CheckFileLockL();
       
   464     return iTopicStore;
       
   465     }
       
   466 
       
   467 // ---------------------------------------------------------
       
   468 // TopicFilename() 
       
   469 //
       
   470 // ---------------------------------------------------------
       
   471 const TDesC& CCbsDbImpTopicList::TopicFilename() const
       
   472     {
       
   473     return *iTopicsFilename;
       
   474     }
       
   475 
       
   476 // -----------------------------------------------------------------------------
       
   477 // CCbsDbImpTopicList::UnsavedMessagesStore
       
   478 // Returns a pointer to the store, which contains unsaved
       
   479 // messages of the server (Unsaved Messages-file, "cbs4.dat").
       
   480 // (other items were commented in a header).
       
   481 // -----------------------------------------------------------------------------
       
   482 //
       
   483 CFileStore* CCbsDbImpTopicList::UnsavedMessagesStore() const
       
   484     {
       
   485     return iUnsavedMessageStore;
       
   486     }
       
   487 
       
   488 // -----------------------------------------------------------------------------
       
   489 // CCbsDbImpTopicList::UnsavedMessagesFilename
       
   490 // Returns a reference to the name of the file, which contains unsaved
       
   491 // messages of the server (Unsaved Messages-file, "cbs4.dat").
       
   492 // (other items were commented in a header).
       
   493 // -----------------------------------------------------------------------------
       
   494 //
       
   495 const TDesC& CCbsDbImpTopicList::UnsavedMessagesFilename() const
       
   496     {
       
   497     return *iUnsavedMessagesFilename;
       
   498     }
       
   499 
       
   500 // -----------------------------------------------------------------------------
       
   501 // CCbsDbImpTopicList::ExtractTopicNumber
       
   502 // Extracts topic handle from message handle.
       
   503 // Note that the method does not check that the message exists.
       
   504 // (other items were commented in a header).
       
   505 // -----------------------------------------------------------------------------
       
   506 //
       
   507 TCbsDbTopicNumber CCbsDbImpTopicList::ExtractTopicNumber( 
       
   508     const TCbsDbMessageHandle& aHandle ) const
       
   509     {    
       
   510     return TCbsDbTopicNumber( aHandle >> 16 );
       
   511     }
       
   512 
       
   513 // -----------------------------------------------------------------------------
       
   514 // CCbsDbImpTopicList::GetTopicMessagesIdL
       
   515 // Returns the topic messages stream id by topic handle.
       
   516 // (other items were commented in a header).
       
   517 // -----------------------------------------------------------------------------
       
   518 //
       
   519 void CCbsDbImpTopicList::GetTopicMessagesIdL( 
       
   520     TCbsDbTopicNumber aNumber, TStreamId& aId ) const
       
   521     {
       
   522     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::GetTopicMessagesIdL()");
       
   523 
       
   524     // Find the topic.
       
   525     TInt index( TopicIndexInList( aNumber ) );
       
   526     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::GetTopicMessagesIdL(): Leaving if index != 0. Index: %d.", index );
       
   527     User::LeaveIfError( index );
       
   528 
       
   529     // Return the topic message stream id.
       
   530     aId = iTopics->At( index ).iTopicMessagesId;
       
   531     
       
   532     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::GetTopicMessagesIdL()");
       
   533     }
       
   534 
       
   535 // -----------------------------------------------------------------------------
       
   536 // CCbsDbImpTopicList::UpdateTopicMessagesIdL
       
   537 // Updates the topic messages stream id by topic handle. 
       
   538 // The new identifier is expected not to be a null id.
       
   539 // Note that the method will not commit changes to the store. 
       
   540 // It also changes the internal state and thus if the method leaves, 
       
   541 // it is good to reload the whole root stream.
       
   542 // The method will delete the old topic messages stream.
       
   543 // (other items were commented in a header).
       
   544 // -----------------------------------------------------------------------------
       
   545 //
       
   546 void CCbsDbImpTopicList::UpdateTopicMessagesIdL( 
       
   547     TCbsDbTopicNumber aNumber, 
       
   548     const TStreamId& aNewId )
       
   549     {
       
   550     __TEST_INVARIANT;
       
   551     // Find position.
       
   552     TInt index( TopicIndexInList( aNumber ) );
       
   553     User::LeaveIfError( index );
       
   554 
       
   555     // Get the old id.
       
   556     TStreamId oldId( iTopics->At( index ).iTopicMessagesId );
       
   557 
       
   558     // Get the topic information.
       
   559     TCbsDbTopic topic;
       
   560     GetTopicL( index, topic );
       
   561 
       
   562     // Write information to the stream.
       
   563     RStoreWriteStream outstream;
       
   564     outstream.OpenLC( *TopicStoreL(), iTopics->At( index ).iTopicId ); // on CS
       
   565     WriteTopicInformationL( outstream, topic, aNewId );
       
   566     outstream.CommitL();
       
   567     CleanupStack::PopAndDestroy();
       
   568 
       
   569     // Delete the old stream.
       
   570     TopicStoreL()->DeleteL( oldId );
       
   571 
       
   572     // Update the topic messages id.
       
   573     iTopics->At( index ).iTopicMessagesId = aNewId;
       
   574     __TEST_INVARIANT;
       
   575     }
       
   576 
       
   577 // -----------------------------------------------------------------------------
       
   578 // CCbsDbImpTopicList::GenerateMessageHandle
       
   579 // Generates a new message handle using the topic 
       
   580 // handle of the message and a given random value.
       
   581 // Note that it must be checked that the message handle is unique 
       
   582 // in that topic.
       
   583 // (other items were commented in a header).
       
   584 // -----------------------------------------------------------------------------
       
   585 //
       
   586 TCbsDbMessageHandle CCbsDbImpTopicList::GenerateMessageHandle( 
       
   587     const TCbsDbTopicNumber aNumber, 
       
   588     TUint16 aRandom ) const
       
   589     {
       
   590     return ( aNumber << 16 ) + aRandom;
       
   591     }
       
   592 
       
   593 // -----------------------------------------------------------------------------
       
   594 // CCbsDbImpTopicList::ReloadRootStreamL
       
   595 // Reloads the root stream to the memory.
       
   596 // (other items were commented in a header).
       
   597 // -----------------------------------------------------------------------------
       
   598 //
       
   599 void CCbsDbImpTopicList::ReloadRootStreamL()
       
   600     {
       
   601     LoadRootStreamL();
       
   602     __TEST_INVARIANT;
       
   603     }
       
   604 
       
   605 // -----------------------------------------------------------------------------
       
   606 // CCbsDbImpTopicList::InformNewMessageReceivedL
       
   607 // Informs that a new message has been received in a topic.
       
   608 // This method is called by CCbsDbImpTopicMessages. After internal 
       
   609 // records are changed, the observers are informed of this event.
       
   610 // Note: leaves changes in stores uncommited.
       
   611 // (other items were commented in a header).
       
   612 // -----------------------------------------------------------------------------
       
   613 //
       
   614 void CCbsDbImpTopicList::InformNewMessageReceivedL( 
       
   615     const TCbsDbMessageHandle& aMessageHandle )
       
   616     {
       
   617     __TEST_INVARIANT;
       
   618     // Find topic by handle.
       
   619     TCbsDbTopicNumber number( ExtractTopicNumber( aMessageHandle ) );
       
   620 
       
   621     TCbsDbTopic topic;
       
   622     FindTopicByNumberL( number, topic );
       
   623 
       
   624     topic.iUnreadMessages++;
       
   625 
       
   626     // Increase the counter in cache
       
   627     TInt position = TopicIndexInList( topic.iNumber );
       
   628     iTopics->At( position ).iTopicData.iUnreadMessages++;
       
   629 
       
   630     // Write topic information to topic stream but leave changes uncommited.
       
   631     UpdateTopicCountersL( topic, EFalse );    
       
   632 
       
   633     if ( topic.iHotmarked )
       
   634         {
       
   635         SetHotmarkedMessage( aMessageHandle );
       
   636         }
       
   637 
       
   638     __TEST_INVARIANT;
       
   639     }
       
   640 
       
   641 // -----------------------------------------------------------------------------
       
   642 // CCbsDbImpTopicList::InformMessageSavedL
       
   643 // Informs that a message has been set as saved.
       
   644 // Updates the saved messages counters
       
   645 // for the topic of the message and the whole system.
       
   646 // Called by CCbsDbTopicMessages.
       
   647 // (other items were commented in a header).
       
   648 // -----------------------------------------------------------------------------
       
   649 //
       
   650 void CCbsDbImpTopicList::InformMessageSavedL( 
       
   651     const TCbsDbMessageHandle& aMessageHandle )
       
   652     {
       
   653     __TEST_INVARIANT;
       
   654     // Find topic by handle.
       
   655     TCbsDbTopicNumber number( ExtractTopicNumber( aMessageHandle ) );
       
   656 
       
   657     TCbsDbTopic topic;
       
   658     FindTopicByNumberL( number, topic );
       
   659 
       
   660     topic.iSavedMessages++;
       
   661 
       
   662     // Increase the counter in cache
       
   663     TInt position = TopicIndexInList( topic.iNumber );
       
   664     iTopics->At( position ).iTopicData.iSavedMessages++;
       
   665 
       
   666     // Write topic information to topic stream but leave changes uncommited.
       
   667     UpdateTopicCountersL( topic, EFalse );
       
   668 
       
   669     __TEST_INVARIANT;
       
   670     }
       
   671 
       
   672 // -----------------------------------------------------------------------------
       
   673 // CCbsDbImpTopicList::InformUnreadMessageReadL
       
   674 // Informs that an unread message has been read.
       
   675 // Updates the counters when a message is read by the client. 
       
   676 // Note: leaves changes in stores uncommited.
       
   677 // (other items were commented in a header).
       
   678 // -----------------------------------------------------------------------------
       
   679 //
       
   680 void CCbsDbImpTopicList::InformUnreadMessageReadL( 
       
   681     const TCbsDbMessageHandle& aMessageHandle )
       
   682     {
       
   683     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::InformUnreadMessageReadL()");
       
   684     
       
   685     __TEST_INVARIANT;
       
   686 
       
   687     // Check for file lock
       
   688     CheckFileLockL();
       
   689 
       
   690     // Check disk space
       
   691     TRAPD( error, CbsUtils::FFSCriticalLevelCheckL( KReadMessageSize, iFs ) );
       
   692     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::InformUnreadMessageReadL(): FFSCriticalLevelCheckL returned: %d", error );
       
   693     if ( error == KErrDiskFull )
       
   694         {
       
   695         return;
       
   696         }
       
   697 
       
   698     // Find topic by number.
       
   699     TCbsDbTopicNumber number( ExtractTopicNumber( aMessageHandle ) );
       
   700 
       
   701     TCbsDbTopic topic;
       
   702     FindTopicByNumberL( number, topic );
       
   703 
       
   704     // Decrease the counter
       
   705     topic.iUnreadMessages--;
       
   706 
       
   707     // Decrease the counter in cache
       
   708     TInt position = TopicIndexInList( topic.iNumber );
       
   709     iTopics->At( position ).iTopicData.iUnreadMessages--;
       
   710 
       
   711     // Write topic information to topic stream but leave changes uncommited.
       
   712     UpdateTopicCountersL( topic, EFalse );
       
   713 
       
   714     __TEST_INVARIANT;
       
   715     
       
   716    CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::InformUnreadMessageReadL()");
       
   717     }
       
   718 
       
   719 // -----------------------------------------------------------------------------
       
   720 // CCbsDbImpTopicList::InformMessageDeletedL
       
   721 // Informs that an unread message has been deleted.
       
   722 // Updates the counters when a message is deleted. 
       
   723 // Note: leaves changes in stores uncommited.
       
   724 // (other items were commented in a header).
       
   725 // -----------------------------------------------------------------------------
       
   726 //
       
   727 void CCbsDbImpTopicList::InformMessageDeletedL( 
       
   728     const TCbsDbMessageHandle& aMessageHandle,
       
   729     TBool aPermanent, 
       
   730     TBool aRead )
       
   731     {
       
   732     // Find topic by handle.
       
   733     TCbsDbTopicNumber number( ExtractTopicNumber( aMessageHandle ) );
       
   734 
       
   735     TCbsDbTopic topic;
       
   736     FindTopicByNumberL( number, topic );
       
   737 
       
   738     TInt position = TopicIndexInList( topic.iNumber );    
       
   739 
       
   740     if ( aPermanent )
       
   741         {
       
   742         topic.iSavedMessages--;
       
   743         iTopics->At( position ).iTopicData.iSavedMessages--;
       
   744         }
       
   745     
       
   746     if ( !aRead )
       
   747         {        
       
   748         topic.iUnreadMessages--;
       
   749         iTopics->At( position ).iTopicData.iUnreadMessages--;
       
   750         }
       
   751 
       
   752     // Write topic information to topic stream but leave changes uncommited.
       
   753     UpdateTopicCountersL( topic, ETrue );
       
   754     }
       
   755 
       
   756 // -----------------------------------------------------------------------------
       
   757 // CCbsDbImpTopicList::TotalSavedMessages
       
   758 // Returns the number of saved messages in the current topic list.
       
   759 // (other items were commented in a header).
       
   760 // -----------------------------------------------------------------------------
       
   761 //
       
   762 TInt CCbsDbImpTopicList::TotalSavedMessages() const
       
   763     {
       
   764     // Return the total amount of saved messages.
       
   765     TInt count( 0 );
       
   766     for ( TInt i( 0 ); i < iTopics->Count(); i++ )
       
   767         {
       
   768         count += iTopics->At( i ).iTopicData.iSavedMessages;
       
   769         }
       
   770 
       
   771     return count;
       
   772     }
       
   773 
       
   774 // -----------------------------------------------------------------------------
       
   775 // CCbsDbImpTopicList::GetTopicCount
       
   776 // Returns the number of topic stored in this topic list.
       
   777 // (other items were commented in a header).
       
   778 // -----------------------------------------------------------------------------
       
   779 //
       
   780 void CCbsDbImpTopicList::GetTopicCount( 
       
   781     TInt& aCount ) const
       
   782     {
       
   783     // Return the total amount of topics.
       
   784     aCount = TopicCount();
       
   785     }
       
   786 
       
   787 // -----------------------------------------------------------------------------
       
   788 // CCbsDbImpTopicList::InitializeListL
       
   789 // Initializes the whole topic list. 
       
   790 // Creates and opens the topic list file, 
       
   791 // invalidates the cache and informs the observers.
       
   792 // (other items were commented in a header).
       
   793 // -----------------------------------------------------------------------------
       
   794 //
       
   795 void CCbsDbImpTopicList::InitializeListL( const TBool aFileOpenFailed )
       
   796     {
       
   797     __TEST_INVARIANT;
       
   798 
       
   799     if ( !aFileOpenFailed )
       
   800         {
       
   801         // Check for file lock
       
   802         CheckFileLockL();
       
   803         }    
       
   804 
       
   805     // About to write to FFS: make critical level check
       
   806     CbsUtils::FFSCriticalLevelCheckL( 0, iFs );
       
   807 
       
   808     if ( iMessages != NULL && iMessages->IsLockedMessages() )
       
   809         {
       
   810         User::Leave( KErrAccessDenied );
       
   811         }    
       
   812 
       
   813     // If only one topic list exists, just delete and recreate the whole file
       
   814     if ( iTopicLists->Count() == 1 || aFileOpenFailed == 1 )
       
   815         {
       
   816         delete iTopicStore; 
       
   817         iTopicStore = NULL;
       
   818         delete iUnsavedMessageStore; 
       
   819         iUnsavedMessageStore = NULL;
       
   820         CbsUtils::DeleteFileL( iFs, *iTopicsFilename  );
       
   821         CbsUtils::DeleteFileL( iFs, *iUnsavedMessagesFilename );
       
   822 
       
   823         iTopicLists->Reset();
       
   824        
       
   825         // Create new files.
       
   826         OpenFilesL( EFalse, ETrue );
       
   827         }
       
   828     
       
   829     iIsHotmarkedMessage = EFalse;
       
   830     iLastTopicNumber = 0;
       
   831     iMessageHandle = 0;
       
   832 
       
   833     // Inform the message manager.
       
   834     if ( iMessages )
       
   835         {
       
   836         iMessages->InvalidateCache();
       
   837         }
       
   838 
       
   839     // Notify everyone.
       
   840     NotifyTopicListInitializedL();
       
   841 
       
   842     __TEST_INVARIANT;
       
   843     }
       
   844 
       
   845 // -----------------------------------------------------------------------------
       
   846 // CCbsDbImpTopicList::GetTopicL
       
   847 // Returns a topic matching the given index.
       
   848 // (other items were commented in a header).
       
   849 // -----------------------------------------------------------------------------
       
   850 //
       
   851 void CCbsDbImpTopicList::GetTopicL( 
       
   852     TInt aIndex, 
       
   853     TCbsDbTopic& aTopic )
       
   854     {
       
   855     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::GetTopicL()");
       
   856 
       
   857     __TEST_INVARIANT;
       
   858     
       
   859     // Check that aIndex is in proper range.
       
   860     if ( ( aIndex < 0 ) || ( aIndex >= iTopics->Count() ) )
       
   861         {
       
   862         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::GetTopicL(): Leaving with KErrArgument...");
       
   863         User::Leave( KErrArgument );
       
   864         }
       
   865 
       
   866     // And then get the information from the array.
       
   867     aTopic = iTopics->At( aIndex ).iTopicData;
       
   868 
       
   869     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::GetTopicL()");
       
   870     
       
   871     __TEST_INVARIANT;
       
   872     }
       
   873 
       
   874 // -----------------------------------------------------------------------------
       
   875 // CCbsDbImpTopicList::FindTopicByNumberL
       
   876 // Returns a topic matching the given topic number 
       
   877 // (in GSM Specs this is called the Message Identifier)
       
   878 // (other items were commented in a header).
       
   879 // -----------------------------------------------------------------------------
       
   880 //
       
   881 void CCbsDbImpTopicList::FindTopicByNumberL( 
       
   882     TCbsDbTopicNumber aNumber, 
       
   883     TCbsDbTopic& aTopic )
       
   884     {
       
   885     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::FindTopicByNumberL()");
       
   886     
       
   887     __TEST_INVARIANT;
       
   888 
       
   889     TInt topicIndex( TopicIndexInList( aNumber ) );
       
   890     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::FindTopicByNumberL(): Leaving if topicIndex < 0: topicIndex: %d.", topicIndex );
       
   891     User::LeaveIfError( topicIndex );
       
   892 
       
   893     GetTopicL( topicIndex, aTopic );
       
   894 
       
   895     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::FindTopicByNumberL()");
       
   896     
       
   897     __TEST_INVARIANT;
       
   898     }
       
   899 
       
   900 // -----------------------------------------------------------------------------
       
   901 // CCbsDbImpTopicList::AddTopicL
       
   902 // Adds a new topic to the list.
       
   903 // (other items were commented in a header).
       
   904 // -----------------------------------------------------------------------------
       
   905 //
       
   906 void CCbsDbImpTopicList::AddTopicL( 
       
   907     TCbsDbTopic& aTopic, const TBool aDetected )
       
   908     {
       
   909     __TEST_INVARIANT;
       
   910 
       
   911     // Check for file lock
       
   912     CheckFileLockL();
       
   913     
       
   914     // Check that topic number is in proper range
       
   915     if ( !CheckTopicNumber( aTopic.iNumber ) )
       
   916         {
       
   917         User::Leave( KErrArgument );
       
   918         }    
       
   919 
       
   920     // Check if there is a topic with the 
       
   921     // same topic number in current topic list.
       
   922     if ( TopicIndexInList( aTopic.iNumber ) != KErrNotFound )
       
   923         {
       
   924         User::Leave( KErrAlreadyExists );
       
   925         } 
       
   926 
       
   927     // There should not be any saved or unread messages
       
   928     aTopic.iSavedMessages = 0;
       
   929     aTopic.iUnreadMessages = 0;
       
   930 
       
   931     // Variated feature. Also, only topics that were not detected automatically
       
   932     // are subscribed by default.
       
   933     if ( iLVBits & KCbsLVFlagTopicSubscription && !aDetected )
       
   934         {
       
   935         aTopic.iSubscribed = ETrue;
       
   936         }
       
   937     else
       
   938         {
       
   939         aTopic.iSubscribed = EFalse;        
       
   940         }
       
   941         
       
   942     // Now we have the handle, so let's add the topic.
       
   943     TRAPD( error, DoAddTopicL( aTopic ) );
       
   944     if ( error != KErrNone )
       
   945         {
       
   946         RevertFilesL();
       
   947         __TEST_INVARIANT;
       
   948         User::Leave( error );
       
   949         }
       
   950     else
       
   951         {        
       
   952         iLastTopicNumber = aTopic.iNumber;
       
   953         NotifyTopicAddedL( aTopic.iNumber );        
       
   954         }        
       
   955     
       
   956     __TEST_INVARIANT;
       
   957     }
       
   958 
       
   959 // -----------------------------------------------------------------------------
       
   960 // CCbsDbImpTopicList::UpdateTopicNameAndNumberL
       
   961 // Updates the name and the topic number of a topic 
       
   962 // matching the given handle to the database.
       
   963 // (other items were commented in a header).
       
   964 // -----------------------------------------------------------------------------
       
   965 //
       
   966 void CCbsDbImpTopicList::UpdateTopicNameAndNumberL( 
       
   967     TCbsDbTopicNumber aOldNumber,
       
   968     TCbsDbTopicNumber aNewNumber, 
       
   969     const TCbsDbTopicName& aName )
       
   970     {
       
   971     // Check for file lock
       
   972     CheckFileLockL();
       
   973 
       
   974     // First, check that the new number is ok.
       
   975     if ( !CheckTopicNumber( aNewNumber ) )
       
   976         {
       
   977         User::Leave( KErrArgument );
       
   978         }
       
   979 
       
   980     // First find and then update.
       
   981     TCbsDbTopic topic;
       
   982     FindTopicByNumberL( aOldNumber, topic );
       
   983 
       
   984     // If no changes to topic, no need to update
       
   985     if ( !( aOldNumber == aNewNumber && topic.iName == aName ) )
       
   986         {        
       
   987         if ( topic.iProtected )
       
   988             {
       
   989             User::Leave( KErrAccessDenied );
       
   990             }
       
   991 
       
   992         topic.iName = aName;
       
   993         topic.iNumber = aNewNumber;
       
   994 
       
   995         UpdateTopicL( aOldNumber, topic );        
       
   996         }    
       
   997     }
       
   998 
       
   999 // -----------------------------------------------------------------------------
       
  1000 // CCbsDbImpTopicList::UpdateTopicSubscriptionStatusL
       
  1001 // Updates the new topic subscription status to the database.
       
  1002 // (other items were commented in a header).
       
  1003 // -----------------------------------------------------------------------------
       
  1004 //
       
  1005 void CCbsDbImpTopicList::UpdateTopicSubscriptionStatusL( 
       
  1006     TCbsDbTopicNumber aNumber, 
       
  1007     TBool aStatus )
       
  1008     {
       
  1009     __TEST_INVARIANT;
       
  1010 
       
  1011     // Update topic subsciption status.
       
  1012     TCbsDbTopic topic;
       
  1013     FindTopicByNumberL( aNumber, topic );
       
  1014 
       
  1015     topic.iSubscribed = aStatus;
       
  1016     UpdateTopicL( aNumber, topic );
       
  1017     __TEST_INVARIANT;
       
  1018 
       
  1019     }
       
  1020 
       
  1021 // -----------------------------------------------------------------------------
       
  1022 // CCbsDbImpTopicList::UpdateTopicHotmarkStatusL
       
  1023 // Updates the new topic hotmarking status to the database.
       
  1024 // (other items were commented in a header).
       
  1025 // -----------------------------------------------------------------------------
       
  1026 //
       
  1027 void CCbsDbImpTopicList::UpdateTopicHotmarkStatusL( 
       
  1028     TCbsDbTopicNumber aNumber, 
       
  1029     TBool aStatus )
       
  1030     {
       
  1031     __TEST_INVARIANT;
       
  1032 
       
  1033     // Check for file lock
       
  1034     CheckFileLockL();
       
  1035 
       
  1036     // Update topic hotmark status.
       
  1037     TCbsDbTopic topic;
       
  1038     FindTopicByNumberL( aNumber, topic );
       
  1039 
       
  1040     topic.iHotmarked = aStatus;
       
  1041     UpdateTopicL( aNumber, topic );
       
  1042     __TEST_INVARIANT;
       
  1043     }
       
  1044 
       
  1045 // -----------------------------------------------------------------------------
       
  1046 // CCbsDbImpTopicList::DeleteTopicL
       
  1047 // Deletes an existing topic and all its messages.
       
  1048 // (other items were commented in a header).
       
  1049 // -----------------------------------------------------------------------------
       
  1050 //
       
  1051 void CCbsDbImpTopicList::DeleteTopicL( 
       
  1052     TCbsDbTopicNumber aNumber )
       
  1053     {
       
  1054     __TEST_INVARIANT;
       
  1055 
       
  1056     // Try to find the position. If it is not found, leave.
       
  1057     TInt position( TopicIndexInList( aNumber ) );
       
  1058     User::LeaveIfError( position );
       
  1059 
       
  1060     // Check that there are no locked messages in the topic.
       
  1061     if ( iMessages->IsLockedMessagesInTopic( aNumber ) )
       
  1062         {
       
  1063         User::Leave( KErrAccessDenied );
       
  1064         }
       
  1065 
       
  1066     // Topic only in one topic list, not an index topic, so delete the topic.
       
  1067     if ( aNumber != 0 )
       
  1068         {
       
  1069         // Just try to delete
       
  1070         TRAPD( error, DoDeleteTopicL( position ) );
       
  1071         if ( error != KErrNone )
       
  1072             {
       
  1073             // It failed, so we must revert.
       
  1074             RevertFilesL();
       
  1075 
       
  1076             // Inform the topic messages.
       
  1077             iMessages->InvalidateCacheIfTopic( aNumber );
       
  1078 
       
  1079             __TEST_INVARIANT;
       
  1080             User::Leave( error );
       
  1081             }
       
  1082         else
       
  1083             {               
       
  1084             // Notify the observers
       
  1085             NotifyTopicDeletedL( aNumber );
       
  1086             }
       
  1087         }
       
  1088     __TEST_INVARIANT;
       
  1089     }
       
  1090 
       
  1091 // -----------------------------------------------------------------------------
       
  1092 // CCbsDbImpTopicList::GetUnreadMessageCount
       
  1093 // Gets the total amount of unread messages.
       
  1094 // (other items were commented in a header).
       
  1095 // -----------------------------------------------------------------------------
       
  1096 //
       
  1097 void CCbsDbImpTopicList::GetUnreadMessageCount( 
       
  1098     TInt& aCount ) const
       
  1099     {
       
  1100     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::GetUnreadMessageCount()");
       
  1101     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::GetUnreadMessageCount(): Topic count: %d", iTopics->Count() );
       
  1102     
       
  1103     // Return the total amount of unread messages.
       
  1104     TInt count( 0 );
       
  1105     for ( TInt i( 0 ); i < iTopics->Count(); i++ )
       
  1106         {
       
  1107         count += iTopics->At( i ).iTopicData.iUnreadMessages;
       
  1108         }
       
  1109 
       
  1110     aCount = count;
       
  1111     
       
  1112     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::GetUnreadMessageCount(): Unread msgs found: %d", count );
       
  1113     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::GetUnreadMessageCount()");
       
  1114     }
       
  1115 
       
  1116 // -----------------------------------------------------------------------------
       
  1117 // CCbsDbImpTopicList::GetHotmarkedMessageHandleL
       
  1118 // Returns the handle to the latest hotmarked message.      
       
  1119 // (other items were commented in a header).
       
  1120 // -----------------------------------------------------------------------------
       
  1121 //
       
  1122 void CCbsDbImpTopicList::GetHotmarkedMessageHandleL( 
       
  1123     TCbsDbMessageHandle& aMessage )
       
  1124     {
       
  1125     __TEST_INVARIANT;
       
  1126     
       
  1127     // Check if there is a hotmarked message.
       
  1128     if ( iIsHotmarkedMessage )
       
  1129         {
       
  1130         // If there is, then return it.
       
  1131         aMessage = iMessageHandle;
       
  1132         iIsHotmarkedMessage = EFalse;
       
  1133         }
       
  1134     else
       
  1135         {
       
  1136         // Otherwise leave.
       
  1137         __TEST_INVARIANT;
       
  1138         User::Leave( KErrNotFound );
       
  1139         }
       
  1140     __TEST_INVARIANT;
       
  1141     }
       
  1142 
       
  1143 // -----------------------------------------------------------------------------
       
  1144 // CCbsDbImpTopicList::UnreadHotmarkedMessageCount
       
  1145 // Returns the handle to the latest hotmarked message.      
       
  1146 // (other items were commented in a header).
       
  1147 // -----------------------------------------------------------------------------
       
  1148 //
       
  1149 TInt CCbsDbImpTopicList::UnreadHotmarkedMessageCount() const
       
  1150     {
       
  1151     // Return the total amount of unread messages in hotmarked topics.
       
  1152     TInt count( 0 );
       
  1153     for ( TInt i( 0 ); i < iTopics->Count(); i++ )
       
  1154         {
       
  1155         TCbsDbTopic& topic = iTopics->At( i ).iTopicData;
       
  1156         if ( topic.iHotmarked )
       
  1157             {
       
  1158             count += topic.iUnreadMessages;
       
  1159             }
       
  1160         }
       
  1161     return count;
       
  1162     }
       
  1163 
       
  1164 // -----------------------------------------------------------------------------
       
  1165 // CCbsDbImpTopicList::AddObserverL
       
  1166 // Adds a topic list observer. 
       
  1167 // After an observer is added to the topic list, 
       
  1168 // it will be notified whenever an event occurs.      
       
  1169 // (other items were commented in a header).
       
  1170 // -----------------------------------------------------------------------------
       
  1171 //
       
  1172 void CCbsDbImpTopicList::AddObserverL(
       
  1173     MCbsDbTopicListObserver* aObserver )
       
  1174     {
       
  1175     __ASSERT_DEBUG( aObserver != 0, CbsServerPanic( ECbsObserverNull ) );
       
  1176     iObservers->AppendL( aObserver );
       
  1177     }
       
  1178 
       
  1179 // -----------------------------------------------------------------------------
       
  1180 // CCbsDbImpTopicList::RemoveObserver
       
  1181 // Removes a topic list observer. 
       
  1182 // If aObserver is not in the list, the method will panic.  
       
  1183 // (other items were commented in a header).
       
  1184 // -----------------------------------------------------------------------------
       
  1185 //
       
  1186 void CCbsDbImpTopicList::RemoveObserver( 
       
  1187     const MCbsDbTopicListObserver* aObserver )
       
  1188     {
       
  1189     __TEST_INVARIANT;
       
  1190     __ASSERT_DEBUG( aObserver != 0, CbsServerPanic( ECbsObserverNull ) );
       
  1191     
       
  1192     TBool observerFound( EFalse );
       
  1193     TInt amountOfObservers( iObservers->Count() );
       
  1194 
       
  1195     // Check if the observer exists and 
       
  1196     // find its possible location index in the array.
       
  1197     for ( TInt index( 0 ); ( index < amountOfObservers ) && !observerFound; index++ )
       
  1198         {
       
  1199         if ( aObserver == iObservers->At( index ) )
       
  1200             {
       
  1201             iObservers->Delete( index );
       
  1202             observerFound = ETrue;
       
  1203             }
       
  1204         }
       
  1205 
       
  1206     __TEST_INVARIANT;
       
  1207 
       
  1208 #ifdef _DEBUG
       
  1209     if ( !observerFound )
       
  1210         {
       
  1211         CbsServerPanic( ECbsObserverNotFound );
       
  1212         }
       
  1213 #endif
       
  1214 
       
  1215     }
       
  1216 
       
  1217 // -----------------------------------------------------------------------------
       
  1218 // CCbsDbImpTopicList::TopicIndexInList
       
  1219 // Finds the index of the topic matching the given topic number
       
  1220 // in the topic list.
       
  1221 // (other items were commented in a header).
       
  1222 // -----------------------------------------------------------------------------
       
  1223 //
       
  1224 TInt CCbsDbImpTopicList::TopicIndexInList( 
       
  1225     TCbsDbTopicNumber aNumber ) const
       
  1226     {
       
  1227     // Create a TCbsDbImpTopic to compare against and use a binary search.
       
  1228     TKeyArrayFix key( _FOFF( TCbsDbImpTopic, iTopicData.iNumber ), ECmpTUint16 );
       
  1229     TCbsDbImpTopic dummy;
       
  1230     TInt position;
       
  1231 
       
  1232     dummy.iTopicData.iNumber = aNumber;
       
  1233     TInt result( iTopics->FindIsq( dummy, key, position ) );
       
  1234     
       
  1235     if ( result != KErrNone )
       
  1236         {
       
  1237         position = KErrNotFound;
       
  1238         }
       
  1239 
       
  1240     return position;
       
  1241     }
       
  1242 
       
  1243 // -----------------------------------------------------------------------------
       
  1244 // CCbsDbImpTopicList::GetNextAndPrevTopicNumberL
       
  1245 // Retrieves numbers of topics that precede and succeed the topic
       
  1246 // with number aCurrentTopic.
       
  1247 // (other items were commented in a header).
       
  1248 // -----------------------------------------------------------------------------
       
  1249 //
       
  1250 void CCbsDbImpTopicList::GetNextAndPrevTopicNumberL( 
       
  1251     const TCbsTopicNumber& aCurrentTopic,
       
  1252     TCbsTopicNumber& aNextTopic, 
       
  1253     TCbsTopicNumber& aPrevTopic,
       
  1254     TInt& aPosition )
       
  1255     {
       
  1256     // Determine position of requested topic in topic list.
       
  1257     TInt index( TopicIndexInList( aCurrentTopic ) );
       
  1258     User::LeaveIfError( index );    // if KErrNotFound
       
  1259     
       
  1260     // Determine position indications
       
  1261     aPosition = 0;
       
  1262     if ( index == 0 )
       
  1263         {
       
  1264         aPosition |= ECbsHead;
       
  1265         }
       
  1266     else
       
  1267         {
       
  1268         aPrevTopic = iTopics->At( index-1 ).iTopicData.iNumber;
       
  1269         }
       
  1270 
       
  1271     if ( index == iTopics->Count()-1 )
       
  1272         {
       
  1273         aPosition |= ECbsTail;
       
  1274         }
       
  1275     else
       
  1276         {
       
  1277         aNextTopic = iTopics->At( index+1 ).iTopicData.iNumber;
       
  1278         }
       
  1279     }
       
  1280 
       
  1281 // -----------------------------------------------------------------------------
       
  1282 // CCbsDbImpTopicList::NotifyNewMessageArrivedL
       
  1283 // Notifies each observer that a new message has arrived to a topic.
       
  1284 // (other items were commented in a header).
       
  1285 // -----------------------------------------------------------------------------
       
  1286 //
       
  1287 void CCbsDbImpTopicList::NotifyNewMessageArrivedL(
       
  1288     const TCbsDbMessageHandle& aHandle )
       
  1289     {
       
  1290     // Notify each observer.
       
  1291     TInt count( iObservers->Count() );
       
  1292     for ( TInt index( 0 ); index < count; index++ )
       
  1293         {
       
  1294         iObservers->At( index )->TopicNewMessageReceivedIndL( aHandle );
       
  1295         }
       
  1296     }
       
  1297 
       
  1298 // -----------------------------------------------------------------------------
       
  1299 // CCbsDbImpTopicList::AppendSubscribedTopicsL
       
  1300 // Adds numbers of subscribed topics to the given array.
       
  1301 // (other items were commented in a header).
       
  1302 // -----------------------------------------------------------------------------
       
  1303 //
       
  1304 void CCbsDbImpTopicList::AppendSubscribedTopicsL( 
       
  1305     CArrayFixFlat<TUint16>& aSubscriptions ) const
       
  1306     {
       
  1307     TInt count( iTopics->Count() );
       
  1308     for ( TInt i( 0 ); i < count; i++ ) 
       
  1309         {
       
  1310         TCbsDbImpTopic& topic = iTopics->At( i );
       
  1311         if ( topic.iTopicData.iSubscribed )
       
  1312             {
       
  1313             aSubscriptions.AppendL( topic.iTopicData.iNumber );
       
  1314             }
       
  1315         }
       
  1316     }
       
  1317 
       
  1318 // -----------------------------------------------------------------------------
       
  1319 // CCbsDbImpTopicList::LoadRootStreamL
       
  1320 // Loads the root stream to the memory.
       
  1321 // (other items were commented in a header).
       
  1322 // -----------------------------------------------------------------------------
       
  1323 //
       
  1324 void CCbsDbImpTopicList::LoadRootStreamL()
       
  1325     {
       
  1326     __ASSERT_DEBUG( iTopicLists != NULL, 
       
  1327         CbsServerPanic( ECbsTopicListArrayNull ) );
       
  1328 
       
  1329     // Get the root stream and open it.
       
  1330     TStreamId id( TopicStoreL()->Root() );
       
  1331     RStoreReadStream instream;
       
  1332     instream.OpenLC( *TopicStoreL(), id ); // on CS
       
  1333 
       
  1334     // Load the topic list count
       
  1335     TInt topicListCount( instream.ReadInt16L() );
       
  1336 
       
  1337     // Sanity check
       
  1338     if ( topicListCount < 0 )
       
  1339         {
       
  1340         User::Leave( KErrCorrupt );
       
  1341         }
       
  1342 
       
  1343     // Reset the topic list array
       
  1344     iTopicLists->Reset();    
       
  1345 
       
  1346     // Load the topic list information
       
  1347     TCbsDbImpTopicList item; 
       
  1348     instream >> item.iTopicListId;
       
  1349     ReadTopicListInformationL( item.iTopicListId, item );
       
  1350     iTopicLists->AppendL( item );
       
  1351         
       
  1352     // Destroy the stream.
       
  1353     CleanupStack::PopAndDestroy(); // instream
       
  1354     }
       
  1355 
       
  1356 // -----------------------------------------------------------------------------
       
  1357 // CCbsDbImpTopicList::LoadDefaultTopicStreamL
       
  1358 // Loads the default topic list to the memory.
       
  1359 // (other items were commented in a header).
       
  1360 // -----------------------------------------------------------------------------
       
  1361 //
       
  1362 void CCbsDbImpTopicList::LoadDefaultTopicStreamL()
       
  1363     {
       
  1364     __ASSERT_DEBUG( iTopics != NULL, 
       
  1365         CbsServerPanic( ECbsTopicListArrayNull ) );
       
  1366 
       
  1367     // Read root item count
       
  1368     TInt topicListCount = iTopicLists->Count();
       
  1369 
       
  1370     // If there isn't any, create a topic list for standard topics here
       
  1371     if ( topicListCount == 0 )
       
  1372         {
       
  1373         CreateStandardTopicListL();
       
  1374         topicListCount = iTopicLists->Count();
       
  1375         }
       
  1376 
       
  1377     TStreamId defaultTopicListId( 0 );
       
  1378     TBool quitSearch( EFalse );
       
  1379 
       
  1380     TInt i;
       
  1381     // Find the default topic list      
       
  1382     for ( i = 0; ( i < topicListCount ) && !quitSearch; ++i )
       
  1383         {
       
  1384         if ( iTopicLists->At( i ).iIsDefaultTopicList )
       
  1385             {            
       
  1386             defaultTopicListId = iTopicLists->At( i ).iTopicListId;
       
  1387             quitSearch = ETrue;
       
  1388             }        
       
  1389         }
       
  1390         
       
  1391     CArrayFixFlat< TStreamId >* topicIds = 
       
  1392         new ( ELeave ) CArrayFixFlat< TStreamId >( KTopicIdsGranularity );
       
  1393 
       
  1394     // Open the default topic list stream
       
  1395     RStoreReadStream instream;
       
  1396     instream.OpenLC( *TopicStoreL(), defaultTopicListId ); // on CS
       
  1397 
       
  1398     // Set the ID
       
  1399     iCurrentTopicList.iTopicListId = defaultTopicListId;
       
  1400     
       
  1401     // Set the name
       
  1402     HBufC* topicListName = HBufC::NewL( instream, KCbsDbTopicNameLength );
       
  1403     iCurrentTopicList.iTopicListName.Copy( topicListName->Des() );
       
  1404     delete topicListName;
       
  1405     topicListName = NULL;
       
  1406 
       
  1407     // Skip default list status, since it is always true in default topic list
       
  1408     CbsStreamHelper::ReadBoolL( instream );
       
  1409     iCurrentTopicList.iIsDefaultTopicList = ETrue;
       
  1410 
       
  1411     // Set the topic list number
       
  1412     iCurrentTopicList.iNumber = instream.ReadInt16L();
       
  1413     
       
  1414     // Read the amount of topics
       
  1415     TInt topicCount = instream.ReadInt16L();
       
  1416     iCurrentTopicList.iTopicCount = topicCount;
       
  1417 
       
  1418     // Clear the topic array.
       
  1419     iTopics->ResizeL( 0 );
       
  1420 
       
  1421     TStreamId id( 0 );
       
  1422 
       
  1423     // Load the topic IDs       
       
  1424     for ( i = 0; i < topicCount; i++ )
       
  1425         {
       
  1426         instream >> id;
       
  1427         topicIds->AppendL( id );
       
  1428         }   
       
  1429     
       
  1430     // Destroy the stream.
       
  1431     CleanupStack::PopAndDestroy();
       
  1432        
       
  1433     // Load necessary information for each topic
       
  1434     TInt count = topicIds->Count();
       
  1435     TCbsDbImpTopic topic;
       
  1436     for ( i = 0; i < count; i++ )
       
  1437         {
       
  1438         ReadTopicInformationL( topicIds->At( i ), topic );
       
  1439 
       
  1440         if ( topic.iTopicData.iNumber == KIndexTopicNumber )
       
  1441             {
       
  1442             HBufC* indexName = ReadIndexTopicNameLC(); // on CS
       
  1443             topic.iTopicData.iName.Copy( *indexName );
       
  1444             CleanupStack::PopAndDestroy(); // indexName
       
  1445             }
       
  1446 
       
  1447         iTopics->AppendL( topic );
       
  1448         }
       
  1449     delete topicIds;
       
  1450     topicIds = NULL;
       
  1451     }
       
  1452 
       
  1453 // -----------------------------------------------------------------------------
       
  1454 // CCbsDbImpTopicList::ReadTopicListInformationL
       
  1455 // Reads topic list information from stream.
       
  1456 // (other items were commented in a header).
       
  1457 // -----------------------------------------------------------------------------
       
  1458 //
       
  1459 void CCbsDbImpTopicList::ReadTopicListInformationL( 
       
  1460     const TStreamId& aId, 
       
  1461     TCbsDbImpTopicList& aTopicList ) const
       
  1462     {
       
  1463     RStoreReadStream instream;
       
  1464     instream.OpenLC( *TopicStoreL(), aId ); // on CS
       
  1465 
       
  1466     // Topic List name
       
  1467     HBufC* topicListName = HBufC::NewL( instream, KCbsDbTopicNameLength );
       
  1468     aTopicList.iTopicListName.Copy( topicListName->Des() );
       
  1469     delete topicListName;
       
  1470     topicListName = NULL;
       
  1471 
       
  1472     // Default list status
       
  1473     aTopicList.iIsDefaultTopicList = CbsStreamHelper::ReadBoolL( instream );
       
  1474 
       
  1475     // Topic List number
       
  1476     aTopicList.iNumber = instream.ReadInt16L();
       
  1477 
       
  1478     // Topic count of this topic list
       
  1479     aTopicList.iTopicCount = instream.ReadInt16L();   
       
  1480 
       
  1481     CleanupStack::PopAndDestroy(); // instream
       
  1482     }
       
  1483 
       
  1484 // -----------------------------------------------------------------------------
       
  1485 // CCbsDbImpTopicList::ReadTopicInformationL
       
  1486 // Reads all information on topic found in stream aId
       
  1487 // into aTopic.
       
  1488 // (other items were commented in a header).
       
  1489 // -----------------------------------------------------------------------------
       
  1490 //
       
  1491 void CCbsDbImpTopicList::ReadTopicInformationL( 
       
  1492     const TStreamId& aId, 
       
  1493     TCbsDbImpTopic& aTopic ) const
       
  1494     {
       
  1495     RStoreReadStream instream;
       
  1496     instream.OpenLC( *TopicStoreL(), aId ); // on CS
       
  1497 
       
  1498     // Topic ID
       
  1499     aTopic.iTopicId = aId;
       
  1500 
       
  1501     // Read saved messages.
       
  1502     aTopic.iTopicData.iSavedMessages = instream.ReadInt16L();
       
  1503 
       
  1504     // Read name.
       
  1505     instream >> aTopic.iTopicData.iName;
       
  1506     
       
  1507     // Read topic number (message identifier)
       
  1508     aTopic.iTopicData.iNumber = instream.ReadInt16L();
       
  1509 
       
  1510     // Read statuses
       
  1511     aTopic.iTopicData.iProtected = CbsStreamHelper::ReadBoolL( instream ); // Protected
       
  1512     aTopic.iTopicData.iSubscribed = CbsStreamHelper::ReadBoolL( instream );// Subscribed
       
  1513     aTopic.iTopicData.iHotmarked = CbsStreamHelper::ReadBoolL( instream ); // Hotmarked
       
  1514     
       
  1515     // Read unread messages count
       
  1516     aTopic.iTopicData.iUnreadMessages = instream.ReadInt16L();
       
  1517 
       
  1518     // Topic messages' stream ID
       
  1519     instream >> aTopic.iTopicMessagesId;
       
  1520 
       
  1521     // Sanity check
       
  1522     if ( aTopic.iTopicData.iSavedMessages > KCbsDbMaxSavedMessages
       
  1523         || aTopic.iTopicData.iNumber > KCbsMaxValidTopicNumber
       
  1524         || aTopic.iTopicData.iUnreadMessages > KCbsDbMaxReceivedMessages )
       
  1525         {
       
  1526         User::Leave( KErrCorrupt );
       
  1527         }
       
  1528 
       
  1529     CleanupStack::PopAndDestroy(); // instream
       
  1530     }
       
  1531 
       
  1532 // -----------------------------------------------------------------------------
       
  1533 // CCbsDbImpTopicList::DoAddTopicL
       
  1534 // Adds a topic into the database.
       
  1535 // Assumes aTopic is not a duplicate.
       
  1536 // (other items were commented in a header).
       
  1537 // -----------------------------------------------------------------------------
       
  1538 //
       
  1539 void CCbsDbImpTopicList::DoAddTopicL( 
       
  1540     const TCbsDbTopic& aTopic )
       
  1541     {
       
  1542     // About to write to FFS: make critical level check
       
  1543     CbsUtils::FFSCriticalLevelCheckL( KTopicStreamSize + 
       
  1544         KEmptyTopicMessagesStreamSize, iFs );  
       
  1545 
       
  1546     // Generate general information about topic.
       
  1547     TCbsDbImpTopic topic;
       
  1548     topic.iTopicData = aTopic;
       
  1549     
       
  1550     // Write stream for messages.
       
  1551     topic.iTopicMessagesId = 
       
  1552         CCbsDbImpTopicMessages::CreateDefaultTopicMessagesStreamL( 
       
  1553             *TopicStoreL() );
       
  1554 
       
  1555     // Create stream for topic information.
       
  1556     RStoreWriteStream outstream;
       
  1557     topic.iTopicId = outstream.CreateLC( *TopicStoreL() ); // on CS
       
  1558     
       
  1559     WriteTopicInformationL( outstream, aTopic, topic.iTopicMessagesId );
       
  1560 
       
  1561     outstream.CommitL();
       
  1562     CleanupStack::PopAndDestroy(); // outstream
       
  1563 
       
  1564     // Now, insert the new topic information to the array
       
  1565     TKeyArrayFix key( _FOFF( TCbsDbImpTopic, iTopicData.iNumber ), ECmpTUint16 );
       
  1566     iTopics->InsertIsqL( topic, key );    
       
  1567 
       
  1568     // Update the topic list stream
       
  1569     UpdateTopicListStreamL( iCurrentTopicList, EFalse );
       
  1570   
       
  1571     // We have modified only iTopicStore, so if CommitFilesL() leaves,
       
  1572     // we either get all committed or nothing committed.
       
  1573     CommitFilesL();
       
  1574     }
       
  1575 
       
  1576 // -----------------------------------------------------------------------------
       
  1577 // CCbsDbImpTopicList::DoUpdateTopicL
       
  1578 // Updates the data for a topic into the database.
       
  1579 // The position of the topic in the list is
       
  1580 // changed if necessary. 
       
  1581 // If the position has to be changed, the handles of messages
       
  1582 // contained in the topic have to be changed as well because
       
  1583 // the high word of the handle identifies the topic by it's
       
  1584 // number.
       
  1585 // Please note that standard EPOC DoSomethingL protocol
       
  1586 // is not followed here as this function does NOT commit
       
  1587 // changes made to the store. Instead, the caller must ensure
       
  1588 // use of proper commit/revert operations.
       
  1589 // (other items were commented in a header).
       
  1590 // -----------------------------------------------------------------------------
       
  1591 //
       
  1592 void CCbsDbImpTopicList::DoUpdateTopicL( 
       
  1593     const TCbsDbTopic& aTopic, 
       
  1594     TBool aNeedToChange, 
       
  1595     TInt aOldPosition,
       
  1596     TBool aDeleting )
       
  1597     {
       
  1598     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::DoUpdateTopicL()");
       
  1599     
       
  1600     RSharedDataClient sharedData;
       
  1601     // About to write to FFS: make critical level check
       
  1602     if ( aDeleting )
       
  1603         {
       
  1604         User::LeaveIfError( sharedData.Connect() );
       
  1605         sharedData.RequestFreeDiskSpaceLC( KTopicStreamSize ); // on CS
       
  1606         }
       
  1607     else
       
  1608         {
       
  1609         CbsUtils::FFSCriticalLevelCheckL( KTopicStreamSize, iFs );
       
  1610         }
       
  1611 
       
  1612     TInt newPosition( aOldPosition );
       
  1613 
       
  1614     // If there is need to change position, change it.
       
  1615     if ( aNeedToChange )
       
  1616         {
       
  1617         TCbsDbImpTopic topic( iTopics->At( aOldPosition ) );
       
  1618 
       
  1619         // Adjust handles of topic messages to match the changed topic number.
       
  1620         iMessages->UpdateHandlesOfTopicMessagesL( 
       
  1621             topic.iTopicData.iNumber, aTopic.iNumber );
       
  1622             
       
  1623         // Delete topic from the array.
       
  1624         iTopics->Delete( aOldPosition );        
       
  1625 
       
  1626         // Set the number and reinsert into array
       
  1627         topic.iTopicData.iNumber = aTopic.iNumber;
       
  1628         TKeyArrayFix key( _FOFF( TCbsDbImpTopic, iTopicData.iNumber ), ECmpTUint16 );
       
  1629         newPosition = iTopics->InsertIsqL( topic, key );
       
  1630         }
       
  1631 
       
  1632     iTopics->At( newPosition ).iTopicData.iSubscribed = aTopic.iSubscribed;
       
  1633     iTopics->At( newPosition ).iTopicData.iHotmarked = aTopic.iHotmarked;
       
  1634     iTopics->At( newPosition ).iTopicData.iName = aTopic.iName;
       
  1635     iTopics->At( newPosition ).iTopicData.iSavedMessages = aTopic.iSavedMessages;
       
  1636     iTopics->At( newPosition ).iTopicData.iUnreadMessages = aTopic.iUnreadMessages;
       
  1637     
       
  1638     // Replace existing stream.
       
  1639     RStoreWriteStream outstream;
       
  1640     outstream.ReplaceLC( *TopicStoreL(), 
       
  1641         iTopics->At( newPosition ).iTopicId ); // on CS
       
  1642     WriteTopicInformationL( outstream, aTopic, 
       
  1643         iTopics->At( newPosition ).iTopicMessagesId );
       
  1644 
       
  1645     outstream.CommitL();
       
  1646     CleanupStack::PopAndDestroy(); // outstream
       
  1647 
       
  1648     // Free the reserved space
       
  1649     if ( aDeleting )
       
  1650         {
       
  1651         CleanupStack::PopAndDestroy(); // disk space
       
  1652         sharedData.Close();
       
  1653         }
       
  1654     
       
  1655     // Update topic list stream, if necessary.
       
  1656     if ( aNeedToChange )
       
  1657         {
       
  1658         UpdateTopicListStreamL( iCurrentTopicList, EFalse );
       
  1659         }
       
  1660     
       
  1661     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::DoUpdateTopicL()");
       
  1662     }
       
  1663 
       
  1664 // -----------------------------------------------------------------------------
       
  1665 // CCbsDbImpTopicList::DoDeleteTopicL
       
  1666 // Deletes a topic from the given position in the database.
       
  1667 // (other items were commented in a header).
       
  1668 // -----------------------------------------------------------------------------
       
  1669 //
       
  1670 void CCbsDbImpTopicList::DoDeleteTopicL( 
       
  1671     TInt aPosition )
       
  1672     {
       
  1673     // Check that the topic is not protected.
       
  1674     TCbsDbTopic topic;
       
  1675     GetTopicL( aPosition, topic );
       
  1676 
       
  1677     // It is not allowed to delete a topic that is protected. It must
       
  1678     // first be updated to be not protected.
       
  1679     if ( topic.iProtected )
       
  1680         {
       
  1681         User::Leave( KErrAccessDenied );
       
  1682         }
       
  1683 
       
  1684     // First delete all messages the topic contains.
       
  1685     RStoreReadStream instream;    
       
  1686     instream.OpenLC( *TopicStoreL(), 
       
  1687         iTopics->At( aPosition ).iTopicMessagesId ); // on CS
       
  1688     CCbsDbImpTopicMessages::DeleteAllTopicMessagesL( *TopicStoreL(), 
       
  1689         *iUnsavedMessageStore, instream );
       
  1690     iMessages->InvalidateCache();
       
  1691     CleanupStack::PopAndDestroy(); // instream
       
  1692 
       
  1693     // Delete topic and topic messages streams.
       
  1694     TopicStoreL()->DeleteL( iTopics->At( aPosition ).iTopicMessagesId );
       
  1695     TopicStoreL()->DeleteL( iTopics->At( aPosition ).iTopicId );    
       
  1696 
       
  1697     // Remove from the internal cache.
       
  1698     iTopics->Delete( aPosition );
       
  1699 
       
  1700     iCurrentTopicList.iTopicCount--;                
       
  1701     UpdateTopicListStreamL( iCurrentTopicList, ETrue );
       
  1702     CommitFilesL();
       
  1703     }
       
  1704 
       
  1705 // -----------------------------------------------------------------------------
       
  1706 // CCbsDbImpTopicList::UpdateRootStreamL
       
  1707 // Updates the root stream. 
       
  1708 // (other items were commented in a header).
       
  1709 // -----------------------------------------------------------------------------
       
  1710 //
       
  1711 void CCbsDbImpTopicList::UpdateRootStreamL(
       
  1712     TBool aDeleting )
       
  1713     {      
       
  1714     // Check the free space
       
  1715     TInt neededSpace( KTopicListRootStreamSize + iTopicLists->Count() * 2 );        
       
  1716 
       
  1717     RSharedDataClient sharedData;
       
  1718     // About to write to FFS: make critical level check
       
  1719     if ( aDeleting )
       
  1720         {
       
  1721         User::LeaveIfError( sharedData.Connect() );
       
  1722         sharedData.RequestFreeDiskSpaceLC( neededSpace ); // on CS
       
  1723         }
       
  1724     else
       
  1725         {
       
  1726         CbsUtils::FFSCriticalLevelCheckL( neededSpace, iFs );
       
  1727         }
       
  1728 
       
  1729     // Now there is room for all topics. So we can just replace.
       
  1730     RStoreWriteStream outstream;
       
  1731     outstream.ReplaceLC( *TopicStoreL(), TopicStoreL()->Root() ); // on CS        
       
  1732 
       
  1733     // Write root stream
       
  1734     WriteRootStreamL( outstream );
       
  1735     CleanupStack::PopAndDestroy(); // outstream
       
  1736 
       
  1737     // Free the reserved space
       
  1738     if ( aDeleting )
       
  1739         {
       
  1740         CleanupStack::PopAndDestroy(); // disk space
       
  1741         sharedData.Close();
       
  1742         }
       
  1743     }
       
  1744 
       
  1745 // -----------------------------------------------------------------------------
       
  1746 // CCbsDbImpTopicList::UpdateTopicListStreamL
       
  1747 // Updates topic list stream. 
       
  1748 // (other items were commented in a header).
       
  1749 // -----------------------------------------------------------------------------
       
  1750 //
       
  1751 void CCbsDbImpTopicList::UpdateTopicListStreamL( 
       
  1752     TCbsDbImpTopicList& aTopicList,
       
  1753     TBool aDeleting )
       
  1754     {        
       
  1755     TInt neededSpace( KTopicListStreamSize + iTopics->Count() * 2 );
       
  1756     
       
  1757     RSharedDataClient sharedData;
       
  1758     // About to write to FFS: make critical level check
       
  1759     if ( aDeleting )
       
  1760         {
       
  1761         User::LeaveIfError( sharedData.Connect() );
       
  1762         sharedData.RequestFreeDiskSpaceLC( neededSpace ); // on CS
       
  1763         }
       
  1764     else
       
  1765         {
       
  1766         CbsUtils::FFSCriticalLevelCheckL( neededSpace, iFs );
       
  1767         }
       
  1768     
       
  1769     // Replace the stream
       
  1770     RStoreWriteStream outstream;
       
  1771     outstream.ReplaceLC( *TopicStoreL(), aTopicList.iTopicListId ); // on CS
       
  1772     
       
  1773     // Write root stream
       
  1774     WriteTopicListStreamL( outstream, aTopicList );
       
  1775     CleanupStack::PopAndDestroy(); // outstream
       
  1776     
       
  1777     // Free the reserved space
       
  1778     if ( aDeleting )
       
  1779         {
       
  1780         CleanupStack::PopAndDestroy(); // disk space
       
  1781         sharedData.Close();
       
  1782         }
       
  1783     }
       
  1784 
       
  1785 // -----------------------------------------------------------------------------
       
  1786 // CCbsDbImpTopicList::UpdateTopicL
       
  1787 // Updates the information for a topic already existing 
       
  1788 // in the database.
       
  1789 // (other items were commented in a header).
       
  1790 // -----------------------------------------------------------------------------
       
  1791 //
       
  1792 void CCbsDbImpTopicList::UpdateTopicL( 
       
  1793     TCbsDbTopicNumber aTopicNumber, 
       
  1794     TCbsDbTopic& aTopic )
       
  1795     {
       
  1796     // Check that the new topic number is unique.
       
  1797     TBool needToChangePosition( ETrue );
       
  1798 
       
  1799     // Try to find the topic and leave if it was not found.
       
  1800     TInt oldPosition( TopicIndexInList( aTopicNumber ) );
       
  1801     User::LeaveIfError( oldPosition );
       
  1802 
       
  1803     // Check if we have to change the position of the topic in the 
       
  1804     // internal array
       
  1805     if ( aTopic.iNumber == aTopicNumber )
       
  1806         {
       
  1807         needToChangePosition = EFalse;
       
  1808         }
       
  1809     else
       
  1810         {
       
  1811         TInt topicWithTheNewNumber( TopicIndexInList( aTopic.iNumber ) );
       
  1812         if ( topicWithTheNewNumber != KErrNotFound && 
       
  1813              topicWithTheNewNumber != oldPosition )
       
  1814             {
       
  1815             User::Leave( KErrAlreadyExists );
       
  1816             }
       
  1817         }
       
  1818 
       
  1819     // Write data to store.
       
  1820     // Deviation from EPOC standards: DoUpdateTopicL does NOT commit 
       
  1821     // the store.
       
  1822     TRAPD( result, DoUpdateTopicL( aTopic, needToChangePosition, 
       
  1823         oldPosition, EFalse ) );
       
  1824 
       
  1825     // Commit both topic and unsaved msgs store
       
  1826     if ( result == KErrNone )
       
  1827         {
       
  1828         TRAP( result, CommitFilesL() );
       
  1829         }
       
  1830 
       
  1831     // If either DoUpdateTopicL or CommitFilesL fails => revert.
       
  1832     if ( result != KErrNone )
       
  1833         {
       
  1834         TopicStoreL()->Revert();
       
  1835         ReloadRootStreamL();
       
  1836         User::Leave( result );
       
  1837         }    
       
  1838     else
       
  1839         {
       
  1840         // Notify the observers.
       
  1841         NotifyTopicModifiedL( aTopicNumber );
       
  1842         }
       
  1843     }
       
  1844 
       
  1845 // -----------------------------------------------------------------------------
       
  1846 // CCbsDbImpTopicList::CheckTopicNumber
       
  1847 // Checks if a topic number is valid.
       
  1848 // The valid topic number range in this implementation is 
       
  1849 // 000..999, with 000 indicating an index message.
       
  1850 // (other items were commented in a header).
       
  1851 // -----------------------------------------------------------------------------
       
  1852 //
       
  1853 TBool CCbsDbImpTopicList::CheckTopicNumber( 
       
  1854     TCbsDbTopicNumber aNumber ) const
       
  1855     {
       
  1856     // Check that the number is in proper range
       
  1857     return aNumber <= KCbsMaxValidTopicNumber;        
       
  1858     }
       
  1859 
       
  1860 // -----------------------------------------------------------------------------
       
  1861 // CCbsDbImpTopicList::WriteRootStreamL
       
  1862 // Write the root stream.
       
  1863 // (other items were commented in a header).
       
  1864 // -----------------------------------------------------------------------------
       
  1865 //
       
  1866 void CCbsDbImpTopicList::WriteRootStreamL( 
       
  1867     RWriteStream& aOut ) const
       
  1868     {
       
  1869     // Write the total amount of topic lists 
       
  1870     TInt topicListCount( iTopicLists->Count() );
       
  1871     aOut.WriteInt16L( topicListCount );
       
  1872     
       
  1873     // Write space for topic list stream ids
       
  1874     TInt index;
       
  1875     for ( index = 0; index < topicListCount; index++ )
       
  1876         {
       
  1877         aOut << iTopicLists->At( index ).iTopicListId;
       
  1878         }
       
  1879     
       
  1880     // Write null stream ids
       
  1881     for ( ; index < KCbsRootItemsSize; index++ )
       
  1882         {
       
  1883         aOut << TStreamId( 0 );
       
  1884         }
       
  1885     
       
  1886     aOut.CommitL();
       
  1887     }
       
  1888 
       
  1889 // -----------------------------------------------------------------------------
       
  1890 // CCbsDbImpTopicList::WriteTopicListStreamL
       
  1891 // Writes topic list information to specified stream.
       
  1892 // (other items were commented in a header).
       
  1893 // -----------------------------------------------------------------------------
       
  1894 //
       
  1895 void CCbsDbImpTopicList::WriteTopicListStreamL( 
       
  1896     RWriteStream& aOut, 
       
  1897     TCbsDbImpTopicList& aTopicList ) const
       
  1898     {
       
  1899     // Write the values to this topic list's stream
       
  1900 
       
  1901     // Topic List name
       
  1902     aOut << aTopicList.iTopicListName;
       
  1903 
       
  1904     // Is this the default list
       
  1905     CbsStreamHelper::WriteBoolL( aOut, aTopicList.iIsDefaultTopicList );
       
  1906 
       
  1907     // Topic List number
       
  1908     aOut.WriteInt16L( aTopicList.iNumber );
       
  1909 
       
  1910     // NUmber of topics in this list
       
  1911     aOut.WriteInt16L( iTopics->Count() );
       
  1912 
       
  1913     // Write the stream IDs of the topics belonging to this list    
       
  1914     TInt i;
       
  1915     for ( i = 0; i < iTopics->Count(); i++ )
       
  1916         {
       
  1917         aOut << iTopics->At( i ).iTopicId;
       
  1918         }
       
  1919 
       
  1920     // Write space for the rest topic stream IDs    
       
  1921     for ( ; i < KCbsDbTopicArraySize; i++ )
       
  1922         {
       
  1923         aOut << TStreamId( 0 );
       
  1924         }        
       
  1925            
       
  1926     aOut.CommitL();
       
  1927     }
       
  1928 
       
  1929 // -----------------------------------------------------------------------------
       
  1930 // CCbsDbImpTopicList::NotifyTopicListInitializedL
       
  1931 // Notifies each observer that the topic list has been initialized.
       
  1932 // (other items were commented in a header).
       
  1933 // -----------------------------------------------------------------------------
       
  1934 //
       
  1935 void CCbsDbImpTopicList::NotifyTopicListInitializedL()
       
  1936     {
       
  1937     // Notify each observer.
       
  1938     TInt count( iObservers->Count() );
       
  1939     for( TInt index( 0 ); index < count; index++ )
       
  1940         {
       
  1941         iObservers->At( index )->TopicListInitializedIndL();
       
  1942         }
       
  1943     }
       
  1944 
       
  1945 // -----------------------------------------------------------------------------
       
  1946 // CCbsDbImpTopicList::NotifyTopicAddedL
       
  1947 // Notifies each observer that a topic has been added.
       
  1948 // (other items were commented in a header).
       
  1949 // -----------------------------------------------------------------------------
       
  1950 //
       
  1951 void CCbsDbImpTopicList::NotifyTopicAddedL( 
       
  1952     TCbsDbTopicNumber aNumber )
       
  1953     {
       
  1954     // Notify each observer.
       
  1955     TInt count( iObservers->Count() );
       
  1956     for ( TInt index( 0 ); index < count; index++ )
       
  1957         {
       
  1958         iObservers->At( index )->TopicAddedIndL( aNumber );
       
  1959         }
       
  1960     }
       
  1961 
       
  1962 // -----------------------------------------------------------------------------
       
  1963 // CCbsDbImpTopicList::NotifyTopicModifiedL
       
  1964 // Notifies each observer that a topic has been modified.
       
  1965 // (other items were commented in a header).
       
  1966 // -----------------------------------------------------------------------------
       
  1967 //
       
  1968 void CCbsDbImpTopicList::NotifyTopicModifiedL( 
       
  1969     TCbsDbTopicNumber aNumber )
       
  1970     {
       
  1971     // Notify each observer.
       
  1972     TInt count( iObservers->Count() );
       
  1973     for( TInt index( 0 ); index < count; index++ )
       
  1974         {
       
  1975         iObservers->At( index )->TopicModifiedIndL( aNumber );
       
  1976         }
       
  1977     }
       
  1978 
       
  1979 // -----------------------------------------------------------------------------
       
  1980 // CCbsDbImpTopicList::NotifyTopicDeletedL
       
  1981 // Notifies each observer that a topic has been deleted.
       
  1982 // (other items were commented in a header).
       
  1983 // -----------------------------------------------------------------------------
       
  1984 //
       
  1985 void CCbsDbImpTopicList::NotifyTopicDeletedL( 
       
  1986     TCbsDbTopicNumber aNumber )
       
  1987     {
       
  1988     // Notify each observer.
       
  1989     TInt count( iObservers->Count() );
       
  1990     for( TInt index( 0 ); index < count; index++ )
       
  1991         {
       
  1992         iObservers->At( index )->TopicDeletedIndL( aNumber );
       
  1993         }
       
  1994     }
       
  1995 
       
  1996 // -----------------------------------------------------------------------------
       
  1997 // CCbsDbImpTopicList::SetHotmarkedMessage
       
  1998 // Sets the hotmarked message handle.
       
  1999 // (other items were commented in a header).
       
  2000 // -----------------------------------------------------------------------------
       
  2001 //
       
  2002 void CCbsDbImpTopicList::SetHotmarkedMessage( 
       
  2003     const TCbsDbMessageHandle& aMessageHandle )
       
  2004     {
       
  2005     // Set the hotmarked message.
       
  2006     iIsHotmarkedMessage = ETrue;
       
  2007     iMessageHandle = aMessageHandle;
       
  2008     }
       
  2009 
       
  2010 // -----------------------------------------------------------------------------
       
  2011 // CCbsDbImpTopicList::CreateDefaultRootStreamL
       
  2012 // Creates a root stream and writes default values into it. 
       
  2013 // (other items were commented in a header).
       
  2014 // -----------------------------------------------------------------------------
       
  2015 //
       
  2016 TStreamId CCbsDbImpTopicList::CreateDefaultRootStreamL( 
       
  2017     CStreamStore& aStore ) const
       
  2018     {
       
  2019     // Create the stream
       
  2020     RStoreWriteStream outstream;
       
  2021     TStreamId id( outstream.CreateLC( aStore ) ); // on CS
       
  2022 
       
  2023     // Write the amount of topic lists
       
  2024     outstream.WriteInt16L( 0 );
       
  2025 
       
  2026     // Write space for topic list stream ids
       
  2027     for ( TInt index( 0 ); index < KCbsRootItemsSize; index++ )
       
  2028         {
       
  2029         outstream << TStreamId( 0 );
       
  2030         } 
       
  2031 
       
  2032     outstream.CommitL();
       
  2033     CleanupStack::PopAndDestroy(); // aStore
       
  2034 
       
  2035     // Return the stream id.
       
  2036     return id;
       
  2037     }
       
  2038 
       
  2039 // -----------------------------------------------------------------------------
       
  2040 // CCbsDbImpTopicList::WriteTopicInformationL
       
  2041 // Writes topic data into a stream.
       
  2042 // This includes number of saved messages, 
       
  2043 // number of unread messages, topic handle, 
       
  2044 // topic name, topic number, protection status, 
       
  2045 // subscription status and hotmark status.
       
  2046 // (other items were commented in a header).
       
  2047 // -----------------------------------------------------------------------------
       
  2048 //
       
  2049 void CCbsDbImpTopicList::WriteTopicInformationL( 
       
  2050     RWriteStream& aOut, 
       
  2051     const TCbsDbTopic& aTopic, 
       
  2052     const TStreamId& aTopicMessagesId ) const
       
  2053     {
       
  2054     // Write saved messages.
       
  2055     aOut.WriteInt16L( aTopic.iSavedMessages );
       
  2056 
       
  2057     // Write name.
       
  2058     aOut << aTopic.iName;
       
  2059     
       
  2060     // Write topic number (message identifier)
       
  2061     aOut.WriteInt16L( aTopic.iNumber );
       
  2062 
       
  2063     // Write statuses
       
  2064     CbsStreamHelper::WriteBoolL( aOut, aTopic.iProtected ); // Protected
       
  2065     CbsStreamHelper::WriteBoolL( aOut, aTopic.iSubscribed ); // Subscribed
       
  2066     CbsStreamHelper::WriteBoolL( aOut, aTopic.iHotmarked ); // Hotmarked
       
  2067     
       
  2068     // Write unread messages count
       
  2069     aOut.WriteInt16L( aTopic.iUnreadMessages );
       
  2070 
       
  2071     // And then write the topic messages stream id.
       
  2072     aOut << aTopicMessagesId;
       
  2073     }
       
  2074 
       
  2075 
       
  2076 // -----------------------------------------------------------------------------
       
  2077 // CCbsDbImpTopicList::RevertFilesL
       
  2078 // Reverts all changes made to three datafiles handled by this class.
       
  2079 // (other items were commented in a header).
       
  2080 // -----------------------------------------------------------------------------
       
  2081 //
       
  2082 void CCbsDbImpTopicList::RevertFilesL()
       
  2083     {
       
  2084 
       
  2085     // Check for file lock
       
  2086     CheckFileLockL();
       
  2087 
       
  2088     iTopicStore->Revert();   
       
  2089     iUnsavedMessageStore->Revert();
       
  2090     ReloadRootStreamL();
       
  2091     }
       
  2092 
       
  2093 // -----------------------------------------------------------------------------
       
  2094 // CCbsDbImpTopicList::CommitFilesL
       
  2095 // Commits all changes made to two datafiles handled by this class.
       
  2096 // (other items were commented in a header).
       
  2097 // -----------------------------------------------------------------------------
       
  2098 //
       
  2099 void CCbsDbImpTopicList::CommitFilesL()
       
  2100     {
       
  2101     TopicStoreL()->CommitL();
       
  2102     TInt errorCode( iUnsavedMessageStore->Commit() );
       
  2103 
       
  2104     // If committing of the unsaved msg store fails, remove all
       
  2105     // messages in the store and rebuild the topic list
       
  2106     if ( errorCode != KErrNone )
       
  2107         {
       
  2108         TRAPD( errorCode2, RebuildUnsavedMessageStoreL() );
       
  2109         if ( errorCode2 != KErrNone )
       
  2110             {
       
  2111             CActiveScheduler::Stop();
       
  2112             User::Leave( KErrServerTerminated );
       
  2113             }
       
  2114 
       
  2115         // Tell the caller that something went wrong
       
  2116         User::Leave( errorCode );
       
  2117         }
       
  2118 
       
  2119     // Check if we should compact
       
  2120     TTime now;
       
  2121     TTimeIntervalMinutes interval;
       
  2122     now.UniversalTime();
       
  2123     now.MinutesFrom( iPreviousCompact, interval );
       
  2124     if ( interval.Int() >= KMinimumCompactInterval )
       
  2125         {
       
  2126         TopicStoreL()->CompactL();
       
  2127         iUnsavedMessageStore->CompactL();
       
  2128         iPreviousCompact = now;
       
  2129         }
       
  2130 
       
  2131     }
       
  2132 
       
  2133 // -----------------------------------------------------------------------------
       
  2134 // CCbsDbImpTopicList::RebuildUnsavedMessageStoreL
       
  2135 // Deletes the unsaved messages' store and rebuilds it.
       
  2136 // (other items were commented in a header).
       
  2137 // -----------------------------------------------------------------------------
       
  2138 //
       
  2139 void CCbsDbImpTopicList::RebuildUnsavedMessageStoreL() 
       
  2140     {
       
  2141     // Close the stores and delete the unsaved store
       
  2142     delete iUnsavedMessageStore; iUnsavedMessageStore = NULL;
       
  2143     delete iTopicStore; iTopicStore = NULL;
       
  2144     CbsUtils::DeleteFileL( iFs, *iUnsavedMessagesFilename );
       
  2145 
       
  2146     // Re-create the store
       
  2147     DoCreateStoreL( *iUnsavedMessagesFilename );
       
  2148     TryToOpenFilesL( ETrue, EFalse );
       
  2149 
       
  2150     // Remove the stream ids to unsaved messages, because
       
  2151     // they were all just deleted.
       
  2152     HandleDeletionOfUnsavedMessagesFileL();
       
  2153 
       
  2154     // Compact the topic list
       
  2155     TopicStoreL()->CommitL();
       
  2156     TopicStoreL()->CompactL();
       
  2157     }
       
  2158 
       
  2159 // -----------------------------------------------------------------------------
       
  2160 // CCbsDbImpTopicList::RebuildTopicAndUnsavedStoresL
       
  2161 // Deletes and rebuilds topic/topic list and unsaved message stores.
       
  2162 // Loads Standard Topic List into memory.
       
  2163 // (other items were commented in a header).
       
  2164 // -----------------------------------------------------------------------------
       
  2165 //
       
  2166 void CCbsDbImpTopicList::RebuildTopicAndUnsavedStoresL()
       
  2167     {
       
  2168     __TEST_INVARIANT;
       
  2169 
       
  2170     // Check for file lock
       
  2171     CheckFileLockL();
       
  2172 
       
  2173     // About to write to FFS: make critical level check
       
  2174     CbsUtils::FFSCriticalLevelCheckL( KTopicListRootStreamSize + 
       
  2175         KDefaultTopicListSize * 2, iFs );
       
  2176     
       
  2177     if ( iMessages != NULL && iMessages->IsLockedMessages() )
       
  2178         {
       
  2179         User::Leave( KErrAccessDenied );
       
  2180         }
       
  2181 
       
  2182     delete iTopicStore; 
       
  2183     iTopicStore = NULL;
       
  2184     delete iUnsavedMessageStore; 
       
  2185     iUnsavedMessageStore = NULL;
       
  2186     CbsUtils::DeleteFileL( iFs, *iTopicsFilename  );
       
  2187     CbsUtils::DeleteFileL( iFs, *iUnsavedMessagesFilename );
       
  2188 
       
  2189     // Create new files.
       
  2190     OpenFilesL( ETrue, EFalse );
       
  2191 
       
  2192     // Add standard index topic.
       
  2193     AddIndexTopicL();
       
  2194     
       
  2195     // Load the Standard Topic list
       
  2196     LoadDefaultTopicStreamL();
       
  2197 
       
  2198     iIsHotmarkedMessage = EFalse;
       
  2199     iLastTopicNumber = 0;
       
  2200     iMessageHandle = 0;
       
  2201 
       
  2202     // Inform the message manager.
       
  2203     if ( iMessages )
       
  2204         {
       
  2205         iMessages->InvalidateCache();
       
  2206         }
       
  2207 
       
  2208     // Notify everyone.
       
  2209     NotifyTopicListInitializedL();
       
  2210 
       
  2211     __TEST_INVARIANT;
       
  2212     }
       
  2213 
       
  2214 // -----------------------------------------------------------------------------
       
  2215 // CCbsDbImpTopicList::GetLatestTopicNumber
       
  2216 // Returns the number of the topic that was added last
       
  2217 // to the database by topic detection feature.
       
  2218 // (other items were commented in a header).
       
  2219 // -----------------------------------------------------------------------------
       
  2220 //
       
  2221 TInt CCbsDbImpTopicList::GetLatestTopicNumber( 
       
  2222     TCbsTopicNumber& aNumber ) const
       
  2223     {
       
  2224     TInt result( KErrNone );
       
  2225     if ( iLastTopicNumber == 0 )
       
  2226         {
       
  2227         result = KErrNotFound;
       
  2228         }
       
  2229     aNumber = iLastTopicNumber;
       
  2230     return result;
       
  2231     }
       
  2232 
       
  2233 // -----------------------------------------------------------------------------
       
  2234 // CCbsDbImpTopicList::OpenFilesL
       
  2235 // After a call to this function, the file stores can be assumed
       
  2236 // to be open and initialized.
       
  2237 // (other items were commented in a header).
       
  2238 // -----------------------------------------------------------------------------
       
  2239 //
       
  2240 void CCbsDbImpTopicList::OpenFilesL( 
       
  2241     TBool aDeleteExistingFiles,
       
  2242     TBool aCreateNewTopicList )
       
  2243     {
       
  2244     __ASSERT_DEBUG( iTopicsFilename->Length() > 0, 
       
  2245         CbsServerPanic( ECbsInvalidFilenameDescriptor ) );
       
  2246     __ASSERT_DEBUG( iUnsavedMessagesFilename->Length() > 0, 
       
  2247         CbsServerPanic( ECbsInvalidFilenameDescriptor ) );
       
  2248 
       
  2249     // if LFS, delete files, create files, open files, write root stream
       
  2250     // if not LFS, create file if it doesn't exist, open files
       
  2251 
       
  2252     // Close file stores.
       
  2253     delete iTopicStore; 
       
  2254     iTopicStore = NULL;
       
  2255     delete iUnsavedMessageStore; 
       
  2256     iUnsavedMessageStore = NULL;
       
  2257 
       
  2258     // If any of files doesn't exist, create the file. Also writes the root 
       
  2259     // stream of the topic file, if necessary.
       
  2260     // It is possible that this operation fails because FFS is full.
       
  2261     // In this case the server will take a break and retry. If the second
       
  2262     // attempt fails, the server is shut down.
       
  2263     TBool unsavedMsgFileExists( EFalse );
       
  2264     TRAPD( result, CreateFilesIfNecessaryL( unsavedMsgFileExists ) );
       
  2265     if ( result != KErrNone )
       
  2266         {
       
  2267         // Critical exception: wait for a while and retry.
       
  2268         User::After( KWaitAfterCriticalStoreException );
       
  2269         TBool ignoreThis( EFalse ); // value of unsavedMsgFileExists preserved
       
  2270         TRAP( result, CreateFilesIfNecessaryL( ignoreThis ) );
       
  2271         if ( result != KErrNone )
       
  2272             {
       
  2273             __DEBUGGER();
       
  2274             // Recovery is not possible: shut the server down.
       
  2275             CActiveScheduler::Stop();
       
  2276             User::Leave( KErrServerTerminated );
       
  2277             }
       
  2278         }
       
  2279 
       
  2280     // Open the files for use. Also reads the topic file root stream.
       
  2281     TryToOpenFilesL( unsavedMsgFileExists == EFalse && 
       
  2282                      aDeleteExistingFiles == EFalse, 
       
  2283                      aCreateNewTopicList );
       
  2284 
       
  2285     }
       
  2286 
       
  2287 // -----------------------------------------------------------------------------
       
  2288 // CCbsDbImpTopicList::CreateFilesIfNecessaryL
       
  2289 // Creates CBS files, if appropriate.
       
  2290 // (other items were commented in a header).
       
  2291 // -----------------------------------------------------------------------------
       
  2292 //
       
  2293 void CCbsDbImpTopicList::CreateFilesIfNecessaryL( 
       
  2294     TBool& aUnsavedMsgFileExisted )
       
  2295     {    
       
  2296     if ( CbsUtils::ExistsL( iFs, *iTopicsFilename ) == EFalse )
       
  2297         {
       
  2298         CbsUtils::FFSCriticalLevelCheckL( KTopicListRootStreamSize + 
       
  2299             KDefaultTopicListSize * 2, iFs );
       
  2300    
       
  2301         CPermanentFileStore* store = CPermanentFileStore::CreateLC( iFs,
       
  2302             *iTopicsFilename, EFileWrite ); // on CS
       
  2303     
       
  2304         store->SetTypeL( store->Layout() );
       
  2305         TStreamId id( CreateDefaultRootStreamL( *store ) );
       
  2306         store->SetRootL( id );
       
  2307         store->CommitL();
       
  2308         CleanupStack::PopAndDestroy(); // store
       
  2309         }    
       
  2310 
       
  2311     aUnsavedMsgFileExisted = CbsUtils::ExistsL( iFs, 
       
  2312         *iUnsavedMessagesFilename );
       
  2313     if ( aUnsavedMsgFileExisted == EFalse )
       
  2314         {
       
  2315         // No critical level check, because unsaved msgs reside on ramdisk
       
  2316         DoCreateStoreL( *iUnsavedMessagesFilename );
       
  2317         }
       
  2318     }
       
  2319 
       
  2320 // -----------------------------------------------------------------------------
       
  2321 // CCbsDbImpTopicList::DoCreateStoreL
       
  2322 // Creates an empty file store with the given filename.
       
  2323 // (other items were commented in a header).
       
  2324 // -----------------------------------------------------------------------------
       
  2325 //
       
  2326 void CCbsDbImpTopicList::DoCreateStoreL( 
       
  2327     const TDesC& aFilename )
       
  2328     {
       
  2329     CFileStore* store = CPermanentFileStore::CreateLC( iFs, 
       
  2330         aFilename, EFileWrite ); // on CS
       
  2331     store->SetTypeL( store->Layout() );
       
  2332     store->CommitL();
       
  2333     CleanupStack::PopAndDestroy();
       
  2334     }
       
  2335 
       
  2336 // -----------------------------------------------------------------------------
       
  2337 // CCbsDbImpTopicList::TryToOpenFilesL
       
  2338 // Tries to open topic and unsaved messages files.
       
  2339 // (other items were commented in a header).
       
  2340 // -----------------------------------------------------------------------------
       
  2341 //
       
  2342 void CCbsDbImpTopicList::TryToOpenFilesL( 
       
  2343     TBool aDeleteUnsavedMsgStreamIds,
       
  2344     TBool aCreateNewTopicList )
       
  2345     {
       
  2346     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::TryToOpenFilesL()" );
       
  2347     
       
  2348     if ( !iTopicStore )
       
  2349         {
       
  2350         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::TryToOpenFilesL(): *** NO iTopicStore (1) ***" );    
       
  2351         }
       
  2352     
       
  2353     // Try to open the store    
       
  2354     TRAPD( error, iTopicStore = CFileStore::OpenL( iFs, *iTopicsFilename, EFileRead | EFileWrite ) );
       
  2355     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::TryToOpenFilesL(); iTopicStore OpenL() error: %d", error );
       
  2356     
       
  2357     TRAPD( error2, iUnsavedMessageStore = CFileStore::OpenL( iFs, *iUnsavedMessagesFilename, EFileRead | EFileWrite ) );
       
  2358     CBSLOGSTRING2("CBSSERVER: CCbsDbImpTopicList::TryToOpenFilesL(); iUnsavedMessageStore OpenL() error: %d", error2 );
       
  2359        
       
  2360     if ( error || error2 )
       
  2361         {
       
  2362         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::TryToOpenFilesL(): Calling InitializeListL( ETrue )..." );
       
  2363         
       
  2364         InitializeListL( ETrue );
       
  2365         
       
  2366         CBSLOGSTRING("CBSSERVER: CCbsDbImpTopicList::TryToOpenFilesL(): Calling InitializeListL( ETrue ) finished." );
       
  2367         }
       
  2368     else
       
  2369         {
       
  2370         if ( iTopicLists->Count() == 0 && 
       
  2371             aDeleteUnsavedMsgStreamIds && 
       
  2372             aCreateNewTopicList )
       
  2373             {
       
  2374             // Create first topic list, since it was deleted with the file
       
  2375             CreateStandardTopicListL();
       
  2376             }
       
  2377                                                
       
  2378         // Load the root stream for topic store.
       
  2379         LoadRootStreamL();
       
  2380 
       
  2381         if ( aDeleteUnsavedMsgStreamIds )
       
  2382             {
       
  2383             // Load the topics and repair the topic file 
       
  2384             // since unsaved msg file has been deleted
       
  2385             LoadDefaultTopicStreamL();
       
  2386             HandleDeletionOfUnsavedMessagesFileL();
       
  2387             }
       
  2388         }
       
  2389     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::TryToOpenFilesL()" );
       
  2390     }
       
  2391 
       
  2392 // ---------------------------------------------------------
       
  2393 // CCbsDbImpTopicList::ReadIndexTopicNameLC()
       
  2394 // Reads the localized index topic name
       
  2395 // (other items were commented in a header).
       
  2396 // ---------------------------------------------------------
       
  2397 HBufC* CCbsDbImpTopicList::ReadIndexTopicNameLC()
       
  2398     {
       
  2399     // Open localized resource file.
       
  2400     RResourceFile resourceFile;
       
  2401 
       
  2402     CbsUtils::FindAndOpenDefaultResourceFileLC( iFs, resourceFile ); // on CS
       
  2403     // Read "Index"-string.
       
  2404     TResourceReader reader;
       
  2405     reader.SetBuffer( resourceFile.AllocReadLC( R_TEXT_INDEX_TOPIC ) );//on CS
       
  2406     HBufC* text = reader.ReadHBufCL();
       
  2407     CleanupStack::PopAndDestroy(2); // readerBuf, resourceFile
       
  2408     CleanupStack::PushL( text );
       
  2409 
       
  2410     return text;
       
  2411     }
       
  2412 
       
  2413 // -----------------------------------------------------------------------------
       
  2414 // CCbsDbImpTopicList::AddIndexTopicL
       
  2415 // Adds index topic to topic list.
       
  2416 // (other items were commented in a header).
       
  2417 // -----------------------------------------------------------------------------
       
  2418 //
       
  2419 void CCbsDbImpTopicList::AddIndexTopicL()
       
  2420     {
       
  2421     // Open localized resource file.
       
  2422     HBufC* text = ReadIndexTopicNameLC();
       
  2423 
       
  2424     TCbsDbTopic topic;
       
  2425     topic.iName.Copy( *text );
       
  2426     topic.iNumber = 0;
       
  2427     topic.iHotmarked = EFalse;
       
  2428     topic.iProtected = ETrue;
       
  2429     topic.iSubscribed = ETrue;
       
  2430     topic.iSavedMessages = 0;
       
  2431     topic.iUnreadMessages = 0;
       
  2432 
       
  2433     // Add the topic without notifying anybody.
       
  2434     TRAPD( error, DoAddTopicL( topic ) );
       
  2435     if ( error != KErrNone )
       
  2436         {
       
  2437         RevertFilesL();
       
  2438         __TEST_INVARIANT;
       
  2439         User::Leave( error );
       
  2440         }
       
  2441 
       
  2442     CleanupStack::PopAndDestroy();  // text
       
  2443     }
       
  2444 
       
  2445 // -----------------------------------------------------------------------------
       
  2446 // CCbsDbImpTopicList::HandleDeletionOfUnsavedMessagesFileL
       
  2447 // Called to repair the database when Unsaved messages -file
       
  2448 // has been deleted, but Topics-file still contains information
       
  2449 // on unsaved messages.
       
  2450 //  
       
  2451 // Things to do here: 
       
  2452 //      - Reset unread message counters, because a saved message
       
  2453 //        is always also read.
       
  2454 //      - Remove stream ids to unsaved messages from 
       
  2455 //        Topic messages -streams.
       
  2456 // (other items were commented in a header).
       
  2457 // -----------------------------------------------------------------------------
       
  2458 //
       
  2459 void CCbsDbImpTopicList::HandleDeletionOfUnsavedMessagesFileL()
       
  2460     {
       
  2461     TRAPD( result, DoHandleDeletionOfUnsavedMessagesFileL() );
       
  2462     if ( result != KErrNone )
       
  2463         {
       
  2464         // Recovery impossible -> reset the database.
       
  2465         // Note that this function is not called when the database
       
  2466         // is initialized.
       
  2467         RebuildTopicAndUnsavedStoresL();
       
  2468         }
       
  2469     }
       
  2470 
       
  2471 // -----------------------------------------------------------------------------
       
  2472 // CCbsDbImpTopicList::DoHandleDeletionOfUnsavedMessagesFileL
       
  2473 // Does the work for HandleDeletionOfUnsavedMessagesFileL().
       
  2474 // (other items were commented in a header).
       
  2475 // -----------------------------------------------------------------------------
       
  2476 //
       
  2477 void CCbsDbImpTopicList::DoHandleDeletionOfUnsavedMessagesFileL()
       
  2478     {
       
  2479     // Reset the unread counter of each topic and delete stream ids of 
       
  2480     // unsaved messages.
       
  2481     TInt numberOfTopics( iTopics->Count() );
       
  2482     for ( TInt i( 0 ); i < numberOfTopics; i++ )
       
  2483         {
       
  2484         TCbsDbTopic topic;
       
  2485         FindTopicByNumberL( iTopics->At( i ).iTopicData.iNumber, topic );
       
  2486         topic.iUnreadMessages = 0;
       
  2487         DoUpdateTopicL( topic, EFalse, i, EFalse );
       
  2488         DeleteUnsavedMessageStreamIdsL( iTopics->At( i ).iTopicMessagesId );
       
  2489         }
       
  2490 
       
  2491     UpdateTopicListStreamL( iCurrentTopicList, ETrue );
       
  2492     TopicStoreL()->CommitL();
       
  2493     }
       
  2494 
       
  2495 // -----------------------------------------------------------------------------
       
  2496 // CCbsDbImpTopicList::DeleteUnsavedMessageStreamIdsL
       
  2497 // This function is called when the unsaved messages file has
       
  2498 // been deleted but the Topic messages -stream still contains
       
  2499 // stream ids to deleted message streams.
       
  2500 // All stream ids found in the given topic messages -stream 
       
  2501 // pointing to the unsaved messages file are removed.
       
  2502 // (other items were commented in a header).
       
  2503 // -----------------------------------------------------------------------------
       
  2504 //
       
  2505 void CCbsDbImpTopicList::DeleteUnsavedMessageStreamIdsL( 
       
  2506     const TStreamId& aMsgStreamId ) const
       
  2507     {
       
  2508     CArrayFixFlat< TStreamId >* streamIds = 
       
  2509         new ( ELeave ) CArrayFixFlat< TStreamId >( KTypicalNumberOfTopicMessages );
       
  2510     CleanupStack::PushL( streamIds );
       
  2511 
       
  2512     RStoreReadStream instream;
       
  2513     instream.OpenLC( *TopicStoreL(), aMsgStreamId ); // on CS
       
  2514 
       
  2515     // Read msg count
       
  2516     TInt numberOfMsgs( instream.ReadInt16L() );
       
  2517 
       
  2518     // Read max msg count
       
  2519     TInt maxNumberOfMsgs( instream.ReadInt16L() );
       
  2520 
       
  2521     TInt index( 0 );
       
  2522 
       
  2523     for ( ; index < numberOfMsgs; index++ )
       
  2524         {
       
  2525         TBool saved( CbsStreamHelper::ReadBoolL( instream ) );
       
  2526         TStreamId id( 0 );
       
  2527         instream >> id;
       
  2528         if ( saved )
       
  2529             {
       
  2530             streamIds->AppendL( id );
       
  2531             }
       
  2532         }
       
  2533 
       
  2534     CleanupStack::PopAndDestroy();  // instream
       
  2535 
       
  2536     // Write stream ids of saved messages into the new topic message stream
       
  2537     // which replaces the stream identified with aMsgStreamId.
       
  2538     RStoreWriteStream outstream;    
       
  2539     outstream.ReplaceLC( *TopicStoreL(), aMsgStreamId ); // on CS
       
  2540 
       
  2541     TInt numberOfSavedmessages( streamIds->Count() ); 
       
  2542 
       
  2543     // Number of messages = number of saved messages
       
  2544     outstream.WriteInt16L( numberOfSavedmessages );
       
  2545 
       
  2546     // Number of saved messages <= number of messages <= maxNumberOfMsgs
       
  2547     outstream.WriteInt16L( maxNumberOfMsgs );
       
  2548 
       
  2549     for ( index = 0; index < numberOfSavedmessages; index++ )
       
  2550         {
       
  2551         // All messages are saved (i.e., permanent)
       
  2552         CbsStreamHelper::WriteBoolL( outstream, ETrue );
       
  2553         outstream << streamIds->At( index );
       
  2554         }
       
  2555 
       
  2556     for ( ; index < maxNumberOfMsgs; index ++ )
       
  2557         {
       
  2558         CbsStreamHelper::WriteBoolL( outstream, EFalse );
       
  2559         outstream << TStreamId( 0 );
       
  2560         }
       
  2561 
       
  2562     outstream.CommitL();
       
  2563     CleanupStack::PopAndDestroy(2);  // outstream, streamIds
       
  2564     
       
  2565     }
       
  2566 
       
  2567 // -----------------------------------------------------------------------------
       
  2568 // CCbsDbImpTopicList::UpdateTopicCountersL
       
  2569 // Resolves the topic position in topic list and uses this information
       
  2570 // to call DoUpdateTopicL.       
       
  2571 // Changes to stores are NOT commited.
       
  2572 // Call to DoUpdateTopicL is not trapped.
       
  2573 // (other items were commented in a header).
       
  2574 // -----------------------------------------------------------------------------
       
  2575 //
       
  2576 void CCbsDbImpTopicList::UpdateTopicCountersL( 
       
  2577     const TCbsDbTopic& aTopic,
       
  2578     const TBool aDeleting )
       
  2579     {
       
  2580     CBSLOGSTRING("CBSSERVER: >>> CCbsDbImpTopicList::UpdateTopicCountersL()");
       
  2581     
       
  2582     // Find out the position of the topic in topic list.    
       
  2583     TInt index( TopicIndexInList( aTopic.iNumber ) );
       
  2584     if ( index == KErrNotFound )
       
  2585         {
       
  2586         User::Leave( KErrNotFound );
       
  2587         }   
       
  2588 
       
  2589     // DoUpdateTopicL leaves changes uncommited. EFalse for not having to
       
  2590     // change topic position in topic list.
       
  2591     DoUpdateTopicL( aTopic, EFalse, index, aDeleting );
       
  2592     
       
  2593     CBSLOGSTRING("CBSSERVER: <<< CCbsDbImpTopicList::UpdateTopicCountersL()");
       
  2594     }
       
  2595 
       
  2596 // -----------------------------------------------------------------------------
       
  2597 // CCbsDbImpTopicList::CreateStandardTopicListL
       
  2598 // Creates the Standard topic list (topic list no. 0)
       
  2599 // (other items were commented in a header).
       
  2600 // -----------------------------------------------------------------------------
       
  2601 //
       
  2602 void CCbsDbImpTopicList::CreateStandardTopicListL()
       
  2603     {
       
  2604     // Read standard topic list name from the resource file
       
  2605     RResourceFile resourceFile;
       
  2606     CbsUtils::FindAndOpenDefaultResourceFileLC( iFs, resourceFile ); // on CS
       
  2607 
       
  2608     TResourceReader reader;
       
  2609     reader.SetBuffer( resourceFile.AllocReadLC( R_TEXT_STANDARD_TOPIC_LIST ) ); // on CS
       
  2610     HBufC* standardTopicListName = reader.ReadHBufCL();
       
  2611     CleanupStack::PushL( standardTopicListName );
       
  2612 
       
  2613     // Create a new topic list
       
  2614     CreateNewTopicListL( standardTopicListName->Des() );
       
  2615 
       
  2616     CleanupStack::PopAndDestroy( 3 ); // resourceFile, reader, standardTopicListName
       
  2617     }
       
  2618 
       
  2619 // -----------------------------------------------------------------------------
       
  2620 // CCbsDbImpTopicList::LoadTopicsIdsL
       
  2621 // Reads topic IDs of a topic list from the stream.
       
  2622 // (other items were commented in a header).
       
  2623 // -----------------------------------------------------------------------------
       
  2624 //
       
  2625 void CCbsDbImpTopicList::LoadTopicsIdsL( 
       
  2626     const TStreamId& aTopicListStreamId )
       
  2627     {
       
  2628     // Open the topic list stream
       
  2629     RStoreReadStream instream;
       
  2630     instream.OpenLC( *TopicStoreL(), aTopicListStreamId ); // on CS
       
  2631 
       
  2632     // Skip topic list name
       
  2633     delete HBufC::NewL( instream, KCbsDbTopicNameLength );
       
  2634 
       
  2635     // Skip default list status
       
  2636     CbsStreamHelper::ReadBoolL( instream );
       
  2637 
       
  2638     // Skip Topic List number
       
  2639     instream.ReadInt16L();
       
  2640     
       
  2641     // Skip the amount of topics
       
  2642     TInt topicCount = instream.ReadInt16L();
       
  2643 
       
  2644     // Clear the array
       
  2645     iTopicIds->ResizeL( 0 );
       
  2646 
       
  2647     TStreamId id( 0 );
       
  2648 
       
  2649     // Load the topic IDs       
       
  2650     for ( TInt i = 0; i < topicCount; i++ )
       
  2651         {
       
  2652         instream >> id;
       
  2653         iTopicIds->AppendL( id );
       
  2654         }   
       
  2655     
       
  2656     CleanupStack::PopAndDestroy(); // instream
       
  2657     }
       
  2658 
       
  2659 // -----------------------------------------------------------------------------
       
  2660 // CCbsDbImpTopicList::LoadTopicsL
       
  2661 // Loads topics of a specified topic list.
       
  2662 // (other items were commented in a header).
       
  2663 // -----------------------------------------------------------------------------
       
  2664 //
       
  2665 void CCbsDbImpTopicList::LoadTopicsL( 
       
  2666     const TStreamId& aTopicListStreamId )
       
  2667     {
       
  2668     // Open the topic list stream
       
  2669     RStoreReadStream instream;
       
  2670     instream.OpenLC( *TopicStoreL(), aTopicListStreamId ); // on CS
       
  2671 
       
  2672     // Skip topic list name
       
  2673     delete HBufC::NewL( instream, KCbsDbTopicNameLength );
       
  2674 
       
  2675     // Skip default list status
       
  2676     CbsStreamHelper::ReadBoolL( instream );
       
  2677 
       
  2678     // Skip Topic List number
       
  2679     instream.ReadInt16L();
       
  2680     
       
  2681     // Skip the amount of topics
       
  2682     TInt topicCount = instream.ReadInt16L();
       
  2683 
       
  2684     // Clear the arrays
       
  2685     iTopics->ResizeL( 0 );
       
  2686     iTopicIds->ResizeL( 0 );
       
  2687 
       
  2688     TStreamId id( 0 );
       
  2689 
       
  2690     // Load the topic IDs 
       
  2691     TInt i;
       
  2692     for ( i = 0; i < topicCount; i++ )
       
  2693         {
       
  2694         instream >> id;
       
  2695         iTopicIds->AppendL( id );
       
  2696         }   
       
  2697     
       
  2698     CleanupStack::PopAndDestroy(); // instream
       
  2699    
       
  2700     // Load necessary information for each topic
       
  2701     TInt count = iTopicIds->Count();
       
  2702     TCbsDbImpTopic topic;
       
  2703     for ( i = 0; i < count; i++ )
       
  2704         {
       
  2705         ReadTopicInformationL( iTopicIds->At( i ), topic );
       
  2706 
       
  2707         if ( topic.iTopicData.iNumber == KIndexTopicNumber )
       
  2708             {
       
  2709             HBufC* indexName = ReadIndexTopicNameLC(); // on CS
       
  2710             topic.iTopicData.iName.Copy( *indexName );
       
  2711             CleanupStack::PopAndDestroy(); // indexName
       
  2712             }
       
  2713         iTopics->AppendL( topic );
       
  2714         }    
       
  2715     }
       
  2716 
       
  2717 // -----------------------------------------------------------------------------
       
  2718 // CCbsDbImpTopicList::UpdateTopicStreamIdsL
       
  2719 // Updates the topic stream IDs.
       
  2720 // (other items were commented in a header).
       
  2721 // -----------------------------------------------------------------------------
       
  2722 //
       
  2723 void CCbsDbImpTopicList::UpdateTopicStreamIdsL( 
       
  2724     const TCbsDbTopicNumber aTopicNumber )
       
  2725     {
       
  2726     // Try to find the topic from current topic list
       
  2727     TInt position( TopicIndexInList( aTopicNumber ) );
       
  2728     if ( position >= 0 )
       
  2729         {
       
  2730         // Remove from the internal cache of this topic list
       
  2731         iTopics->Delete( position );
       
  2732 
       
  2733         iCurrentTopicList.iTopicCount--;
       
  2734 
       
  2735         // Update the stream
       
  2736         UpdateTopicListStreamL( iCurrentTopicList, EFalse );
       
  2737         CommitFilesL();
       
  2738         }
       
  2739     }
       
  2740 
       
  2741 // -----------------------------------------------------------------------------
       
  2742 // CCbsDbImpTopicList::__DbgTestInvariant
       
  2743 // Checks that the object is in a valid state, and panics if it is not.
       
  2744 // (other items were commented in a header).
       
  2745 // -----------------------------------------------------------------------------
       
  2746 //
       
  2747 void CCbsDbImpTopicList::__DbgTestInvariant() const
       
  2748     {
       
  2749     /*
       
  2750 #if defined(_DEBUG)
       
  2751 #endif
       
  2752     */
       
  2753     }
       
  2754 
       
  2755 // ========================== OTHER EXPORTED FUNCTIONS =========================
       
  2756 
       
  2757 //  End of File