cbs/CbsServer/ServerSrc/Ccbsreccollector.cpp
changeset 0 ff3b6d0fd310
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 module contains the implementation of CCbsRecDecoder class 
       
    15 *                member functions.
       
    16 *    
       
    17 *                This class represents a collector, which stores pages of multipaged 
       
    18 *                messages. Complete messages are assembled and returned back to 
       
    19 *                the caller of CollectL() method.
       
    20 *  
       
    21 *                CCbsRecCollector stores message pages in a number of dynamic arrays.
       
    22 *                If all but one page of a message are present in collector, and
       
    23 *                the remaining page is received, the pages will be assembled and
       
    24 *                the corresponding message chain deleted.
       
    25 * 
       
    26 *                The maximum number of incomplete messages stored in collector at once
       
    27 *                is fixed and determined by KMaxCollectorMessages in CCbsRecCollector.cpp.
       
    28 * 
       
    29 *                CCbsRecCollector implements a circular list to contain message.
       
    30 *                Each incomplete message occupies a slot in this list. If the list already
       
    31 *                contains KMaxCollectorMessages messages, the next received multipaged
       
    32 *                message will delete all received pages of the oldest message in list.
       
    33 * 
       
    34 *                On receival of a message page, the collector compares network information
       
    35 *                (PLMN, LAC, CellId) of both messages to decide whether pages are of
       
    36 *                the same message. In short, for pages to be of the same message
       
    37 *                their network information have to meet the requirements set by the 
       
    38 *                geographical scope of the already collected page.
       
    39 *                See ETSI GSM 03.41 for a detailed description. 
       
    40 *
       
    41 */
       
    42 
       
    43 
       
    44 // INCLUDE FILES
       
    45 #include "CbsServerPanic.h"
       
    46 #include "CCbsRecCollector.h"
       
    47 #include "CCbsRecMessage.h"
       
    48 #include "CCbsMessageFactory.h"
       
    49 #include "CCbsMessageCleanUpTimer.h"
       
    50 #include "CbsLogger.h"
       
    51 
       
    52 // CONSTANTS
       
    53 
       
    54 // Maximum number of pages in a single CB message.
       
    55 const TInt KMaxMessagePages = 15;
       
    56 
       
    57 // Maximum number of partial messages contained in the collector list.
       
    58 const TInt KMaxCollectorMessages = 10;
       
    59 
       
    60 // ================= MEMBER FUNCTIONS =======================
       
    61 
       
    62 // -----------------------------------------------------------------------------
       
    63 // CCbsRecCollector::CCbsRecCollector
       
    64 // C++ default constructor can NOT contain any code, that
       
    65 // might leave.
       
    66 // -----------------------------------------------------------------------------
       
    67 //
       
    68 CCbsRecCollector::CCbsRecCollector( CCbsMessageFactory& aFactory )
       
    69     : iRootNodeIterator( 0 ),
       
    70     iFactory( aFactory )
       
    71     {
       
    72     }
       
    73 
       
    74 // -----------------------------------------------------------------------------
       
    75 // CCbsRecCollector::ConstructL
       
    76 // Symbian 2nd phase constructor can leave.
       
    77 // -----------------------------------------------------------------------------
       
    78 //
       
    79 void CCbsRecCollector::ConstructL()
       
    80     {
       
    81     CBSLOGSTRING("CBSSERVER: >>> CCbsRecCollector::ConstructL()");
       
    82 
       
    83     // initialize the root node array
       
    84     iRootNodeArray = new ( ELeave ) CArrayPtrFlat< CMessageBuffer >
       
    85         ( KMaxCollectorMessages );
       
    86     iRootNodeArray->SetReserveL( KMaxCollectorMessages );
       
    87     iMessageCleanupTimerArray = new ( ELeave ) CArrayPtrFlat< CCbsMessageCleanupTimer >
       
    88         ( KMaxCollectorMessages );
       
    89 
       
    90     for ( TInt i( 0 ); i < KMaxCollectorMessages; i++)
       
    91         {
       
    92         CMessageBuffer* array = new ( ELeave )
       
    93             CMessageBuffer( KMaxMessagePages );
       
    94         CleanupStack::PushL( array );
       
    95         iRootNodeArray->AppendL( array );
       
    96 
       
    97 		CCbsMessageCleanupTimer* messageCleanUpTimer = CCbsMessageCleanupTimer::NewL( *this, *array );
       
    98 		iMessageCleanupTimerArray->AppendL( messageCleanUpTimer );
       
    99         
       
   100         CleanupStack::Pop(); // array
       
   101         }
       
   102     CBSLOGSTRING("CBSSERVER: <<< CCbsRecCollector::ConstructL()");
       
   103     }
       
   104 
       
   105 
       
   106 // -----------------------------------------------------------------------------
       
   107 // CCbsRecCollector::NewL
       
   108 // Two-phased constructor.
       
   109 // -----------------------------------------------------------------------------
       
   110 //
       
   111  CCbsRecCollector* CCbsRecCollector::NewL( CCbsMessageFactory& aFactory )
       
   112     {
       
   113     CBSLOGSTRING("CBSSERVER: >>> CCbsRecCollector::NewL()");
       
   114 
       
   115     CCbsRecCollector* self = new ( ELeave ) CCbsRecCollector( aFactory );
       
   116     CleanupStack::PushL( self );
       
   117     self->ConstructL();
       
   118     CleanupStack::Pop();
       
   119 
       
   120     CBSLOGSTRING("CBSSERVER: <<< CCbsRecCollector::NewL()");
       
   121     return self;
       
   122     }
       
   123     
       
   124 // Destructor
       
   125 CCbsRecCollector::~CCbsRecCollector()
       
   126     {
       
   127     CBSLOGSTRING("CBSSERVER: >>> CCbsRecCollector::~CCbsRecCollector()");
       
   128 
       
   129     if ( iRootNodeArray )
       
   130         {
       
   131         TInt rootArrayLength( iRootNodeArray->Count() );
       
   132         for ( TInt i( 0 ); i < rootArrayLength; i++ )
       
   133             {
       
   134             iRootNodeArray->At( i )->ResetAndDestroy();
       
   135             }
       
   136         iRootNodeArray->ResetAndDestroy();
       
   137         delete iRootNodeArray;
       
   138         }
       
   139 
       
   140     if ( iMessageCleanupTimerArray )
       
   141         {
       
   142         iMessageCleanupTimerArray->ResetAndDestroy();
       
   143         delete iMessageCleanupTimerArray;
       
   144         }
       
   145 
       
   146     CBSLOGSTRING("CBSSERVER: <<< CCbsRecCollector::~CCbsRecCollector()");
       
   147     }
       
   148 
       
   149 // -----------------------------------------------------------------------------
       
   150 // CCbsRecCollector::CollectL
       
   151 // Adds a message to the location pointed by iRootNodeIterator.
       
   152 //   
       
   153 // Checks if all pages of message are present. If all pages
       
   154 // are present, sets aCompleted to ECbsMessageComplete,
       
   155 // combines message pages into a single message, destroys
       
   156 // pages from the list and returns the complete message
       
   157 // to caller in aMessage.
       
   158 
       
   159 // Algorithm:
       
   160 //   1.  Check if other pages of this message exist in list.
       
   161 //       (serial number and message identifier match)
       
   162 //   2.  True: Check if the other messages in chain need
       
   163 //       to be deleted. This is based on geographical scope
       
   164 //       and network information.
       
   165 //       Add this message to the correct message chain.
       
   166 //       False: Add this message to the chain pointed
       
   167 //       by the iRootNodeIterator.
       
   168 //   3.  Seek out the position in the chosed message chain so that
       
   169 //       the page number sequence remains ordered (1, 2, .., n)
       
   170 //   4.  Add the page to the correct position in chain.
       
   171 //   5.  Check if all pages of this message exist (number count).
       
   172 //   6.  True: Combine message pages into a single message
       
   173 //       and return this page to the caller. Set aCompleted
       
   174 //       to ECbsMessageComplete.
       
   175 //       False: Set aCompleted to ECbsMessageIncomplete.
       
   176 //
       
   177 // Note: Ownership of aMessage assumed. aMessage assumed to be
       
   178 // on cleanup stack.
       
   179 // (other items were commented in a header).
       
   180 // -----------------------------------------------------------------------------
       
   181 //  
       
   182 CCbsMessage* CCbsRecCollector::CollectL( 
       
   183     CCbsMessage* aMessage, TInt aMessageType )  
       
   184     {
       
   185 	CBSLOGSTRING("CBSSERVER: >>> CCbsRecCollector::CollectL()");
       
   186 
       
   187     // 1.
       
   188     CMessageBuffer* array = FindChainContainingPage( *aMessage );
       
   189     CCbsMessage* mergedMessage = NULL;
       
   190 
       
   191     if ( array  ) 
       
   192         {		
       
   193         CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): array != NULL");
       
   194 
       
   195         // 2. (True), 3.
       
   196         __ASSERT_DEBUG( array->Count() > 0, 
       
   197             CbsServerPanic( ECbsCollectorArrayEmpty ) );
       
   198 
       
   199         // Check geographical scope and network info to decide whether
       
   200         // existing pages in this chain should be deleted.
       
   201         TBool preserveExistingPages( 
       
   202             CheckPageAreaInfoMatch( *aMessage, *array->At( 0 ) ) );
       
   203 		
       
   204         CBSLOGSTRING2("CBSSERVER: CCbsRecCollector::CollectL(): preserveExistingPages: %d", preserveExistingPages );
       
   205 
       
   206         if ( preserveExistingPages ) 
       
   207             {			
       
   208             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Adding msg to chain...");
       
   209             // aMessage is deleted, if it is a duplicate.
       
   210             AddMessageToChainL( aMessage, *array );			
       
   211             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Adding msg to chain OK.");
       
   212             }
       
   213         else 
       
   214             {			
       
   215             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Deleting chain...");
       
   216             DeleteChainL( *array );			
       
   217             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Deleting chain OK.");
       
   218             array->InsertL( 0, aMessage );			
       
   219             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Msg added to array.");
       
   220             }
       
   221         // aMessage, ownership transferred to msg chain or
       
   222         // aMessage has been deleted by AddMessageToChainL
       
   223         CleanupStack::Pop(); 
       
   224 
       
   225         // 5. Check if this chain contains all pages of the message.
       
   226         if ( AllPagesPresent( *array ) )
       
   227             {			
       
   228             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): All pages present, merging...");
       
   229 
       
   230             // 6. merge creates a new copy of this message
       
   231             // leaves a pointer to msg to cleanup stack
       
   232             mergedMessage = MergePagesLC( *array ); // on CS			
       
   233             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Merging OK.");
       
   234 
       
   235 			// we stop timer if its livecast message
       
   236 			if ( aMessageType == ECbsMessageLivecast )
       
   237 				{				
       
   238                 CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Msg type == ECbsMessageLivecast, stopping timer.");
       
   239 
       
   240 				TKeyArrayFix key(0, ECmpTUint16);
       
   241 				TInt index;
       
   242 				iRootNodeArray->Find( array, key, index);
       
   243 				iMessageCleanupTimerArray->At( index )->StopTimer();
       
   244                 
       
   245                 CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Timer stopped.");
       
   246 				}
       
   247 
       
   248 			CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Deleting chain...");
       
   249             DeleteChainL( *array );
       
   250 			CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Deleting chain OK.");
       
   251 
       
   252             CleanupStack::Pop(); // mergedMessage
       
   253             }
       
   254         }
       
   255     else
       
   256         {		
       
   257         CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): array == NULL");
       
   258 
       
   259 		// if message pagenumber does not start from 1, its not inserted to chain.
       
   260 		if ( aMessage->ThisPage () == 1 ) 
       
   261 			{			
       
   262             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): aMessage->ThisPage () == 1");
       
   263 
       
   264 			// 2. (False)
       
   265 			// add this page as the first node in chain pointed by 
       
   266 			// iRootNodeIterator. Delete any pages contained in the chain
       
   267 			// occuping this location first.
       
   268 			array = iRootNodeArray->At( iRootNodeIterator );
       
   269 			DeleteChainL( *array );
       
   270 			array->InsertL( 0, aMessage );
       
   271 			CleanupStack::Pop(); // aMessage, ownership transferred to msg chain.
       
   272 			iRootNodeIterator++;
       
   273 			// Return to the first message, if passed the
       
   274 			// maximum messages.
       
   275 			iRootNodeIterator %= KMaxCollectorMessages;
       
   276 
       
   277 			if ( aMessageType == ECbsMessageLivecast )
       
   278 				{				
       
   279                 CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): aMessageType == ECbsMessageLivecast");
       
   280 
       
   281 				// start timeout timer for livecast message
       
   282 				TKeyArrayFix key(0, ECmpTUint16);
       
   283 				TInt index;
       
   284 				iRootNodeArray->Find( array, key, index);
       
   285 				iMessageCleanupTimerArray->At( index )->StartTimer();
       
   286 				
       
   287                 CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): Timer started.");
       
   288 				}
       
   289 			}
       
   290 		else
       
   291 			{			
       
   292             CBSLOGSTRING("CBSSERVER: CCbsRecCollector::CollectL(): CleanupStack::Pop()");
       
   293 			CleanupStack::Pop();
       
   294 			}
       
   295         }
       
   296     // mergedMessage == NULL if msg not completed,
       
   297     // otherwise return the complete message
       
   298 	CBSLOGSTRING("CBSSERVER: <<< CCbsRecCollector::CollectL(), returning mergedMessage.");
       
   299 
       
   300     return mergedMessage;
       
   301     }
       
   302 
       
   303 // -----------------------------------------------------------------------------
       
   304 // CCbsRecCollector::DeleteChainL
       
   305 // Deletes all message pages contained in aArray.
       
   306 // (other items were commented in a header).
       
   307 // -----------------------------------------------------------------------------
       
   308 //  
       
   309 void CCbsRecCollector::DeleteChainL( 
       
   310     CMessageBuffer& aArray ) const
       
   311     {
       
   312     aArray.ResetAndDestroy();
       
   313     }
       
   314 
       
   315 // -----------------------------------------------------------------------------
       
   316 // CCbsRecCollector::AllPagesPresent
       
   317 // Returns ETrue if all pages of the message of aArray are present.
       
   318 // Counts pages in message chain aArray and compares the result
       
   319 // against the total number of pages in the message.
       
   320 // (other items were commented in a header).
       
   321 // -----------------------------------------------------------------------------
       
   322 // 
       
   323 TBool CCbsRecCollector::AllPagesPresent( 
       
   324     const CMessageBuffer& aArray ) const
       
   325     {
       
   326     TBool result( ETrue );
       
   327     if ( TUint( aArray.Count() ) < aArray.At( 0 )->TotalPages() )
       
   328         {
       
   329         result = EFalse;        
       
   330         }
       
   331     
       
   332     return result;
       
   333     }
       
   334 
       
   335 // -----------------------------------------------------------------------------
       
   336 // CCbsRecCollector::MergePagesLC
       
   337 // Returns a complete message in aMessage.
       
   338 // Merges all pages in message chain aArray and returns
       
   339 // a pointer to the resulting assembled message. The pointer
       
   340 // is also left on the cleanup stack.
       
   341 // (other items were commented in a header).
       
   342 // -----------------------------------------------------------------------------
       
   343 //
       
   344 CCbsMessage* CCbsRecCollector::MergePagesLC( 
       
   345     CMessageBuffer& aArray ) const
       
   346     {
       
   347     if ( aArray.Count() <= 0 )
       
   348         {
       
   349         User::Leave( KErrNotFound );
       
   350         }
       
   351     // Create a new message based on first message page in the chain.
       
   352     CCbsMessage* message = iFactory.CreateMessageL( *aArray.At( 0 ) );
       
   353 
       
   354     CleanupStack::PushL( message ); // left on cleanup stack
       
   355 
       
   356     // Traverse through the chain and merge contents.
       
   357     TInt length( 0 );
       
   358     TInt count( aArray.Count() );
       
   359 
       
   360     // If this is a Livecast message, use the 8-bit representation
       
   361     // (message not decoded).
       
   362     if ( message->IsLivecastMessage() )
       
   363         {
       
   364         for ( TInt j( 0 ); j < count; j++ )
       
   365             {
       
   366             length += aArray.At( j )->Contents8().Length();
       
   367             }
       
   368         
       
   369         __ASSERT_DEBUG( length >= 0, CbsServerPanic( ECbsCollectorMergeFailed ) );
       
   370 
       
   371         message->ReserveContentSize8L( length );
       
   372         count = aArray.Count();
       
   373         
       
   374         for ( TInt i( 1 ); i < count; i++ ) 
       
   375             {
       
   376             message->AppendContent8( aArray.At( i )->Contents8() );
       
   377             }
       
   378         }
       
   379     // Else use the 16-bit representation (message already decoded)
       
   380     else
       
   381         {
       
   382         for ( TInt j( 0 ); j < count; j++ )
       
   383             {
       
   384             length += aArray.At( j )->Contents().Length();
       
   385             }
       
   386     
       
   387 	    __ASSERT_DEBUG( length >= 0, CbsServerPanic( ECbsCollectorMergeFailed ) );
       
   388 
       
   389 	    message->ReserveContentSizeL( length );
       
   390 	    count = aArray.Count();
       
   391 
       
   392     // Append the rest of the pages (first page handled earlier)
       
   393 	    for ( TInt i( 1 ); i < count; i++ ) 
       
   394 	        {
       
   395 	        message->AppendContent( aArray.At( i )->Contents() );
       
   396 	        }
       
   397         }
       
   398     return message;
       
   399     }
       
   400 
       
   401 // -----------------------------------------------------------------------------
       
   402 // CCbsRecCollector::FindChainContainingPage
       
   403 // Returns the buffer containing pages of same message.
       
   404 // Finds and returns a message chain which already contains pages
       
   405 // of aMessage's message. If none is found, NULL is returned.
       
   406 // (other items were commented in a header).
       
   407 // -----------------------------------------------------------------------------
       
   408 //
       
   409 CMessageBuffer* CCbsRecCollector::FindChainContainingPage( 
       
   410     const CCbsMessage& aMessage ) const
       
   411     {
       
   412     TBool quitSeek( EFalse );
       
   413     TInt seekIterator( 0 );
       
   414     TCbsDbMessageKey key( aMessage.Key() );
       
   415     TCbsDbTopicNumber topicNumber( aMessage.TopicNumber() );
       
   416     CMessageBuffer* array = NULL;
       
   417     
       
   418     // find out if the root array contains pages of this message
       
   419     while ( ( seekIterator < KMaxCollectorMessages ) && !quitSeek  )
       
   420         {
       
   421         array = iRootNodeArray->At( seekIterator );
       
   422         if ( array->Count() > 0 ) 
       
   423             {
       
   424             CCbsMessage* msg = array->At( 0 );
       
   425             if ( key == msg->Key() && topicNumber == msg->TopicNumber() )
       
   426                 {
       
   427                 quitSeek = ETrue;
       
   428                 }
       
   429             }
       
   430         seekIterator++;
       
   431         }
       
   432 
       
   433     if ( !quitSeek )
       
   434         {
       
   435         array = NULL;
       
   436         }
       
   437     
       
   438     return array;
       
   439     }
       
   440 
       
   441 // -----------------------------------------------------------------------------
       
   442 // CCbsRecCollector::AddMessageToChainL
       
   443 // Adds message page aMessage to the correct position in message chain aArray
       
   444 //        
       
   445 // Message chains are ordered in ascending page number order.
       
   446 // Duplicate pages are not accepted.
       
   447 //
       
   448 // Ownership of aMessage is transferred to aArray, if the given page
       
   449 // hasn't been already collected. The given page will be deleted,
       
   450 // if it already exists in the chain.
       
   451 // (other items were commented in a header).
       
   452 // -----------------------------------------------------------------------------
       
   453 //
       
   454 void CCbsRecCollector::AddMessageToChainL( 
       
   455     CCbsMessage* aMessage, 
       
   456     CMessageBuffer& aArray ) const
       
   457     {
       
   458     // Find out a position for this page in the chain.
       
   459     TInt chainLength( aArray.Count() );    
       
   460     TInt insertPosition( -1 );
       
   461     TBool duplicate( EFalse );
       
   462 
       
   463     for ( TInt i( 0 ); ( i < chainLength ) && !duplicate; i++ )
       
   464         {
       
   465         CCbsMessage* msg = aArray.At( i );
       
   466         if ( insertPosition == -1 && msg->ThisPage() > aMessage->ThisPage() )
       
   467             {
       
   468             insertPosition = i;
       
   469             }
       
   470         else if ( msg->ThisPage() == aMessage->ThisPage() )
       
   471             {
       
   472             duplicate = ETrue; // This page has been already collected
       
   473             delete aMessage;
       
   474             }
       
   475         }
       
   476 
       
   477     // If this message was not a duplicate, add it to the chain
       
   478     if ( !duplicate )
       
   479         {
       
   480         if ( insertPosition == -1 )
       
   481             {
       
   482             aArray.AppendL( aMessage );
       
   483             }
       
   484         else
       
   485             {
       
   486             aArray.InsertL( insertPosition, aMessage );
       
   487             }
       
   488         }    
       
   489     }
       
   490 
       
   491 // -----------------------------------------------------------------------------
       
   492 // CCbsRecCollector::CheckPageAreaInfoMatch
       
   493 // Checks if these pages can be merged. Returns ETrue, if merging is acceptable.
       
   494 //   
       
   495 // Decision is based network information and geographical scope of 
       
   496 // pages. Network information consists of cell id, location area code
       
   497 // and operator id.
       
   498 // 
       
   499 // Assumption: aPage1 and aPage have identical message
       
   500 // identifiers and serial numbers. 
       
   501 // Returns ETrue if the pages are of same message.
       
   502 // On EFalse previous pages should be deleted.
       
   503 // (other items were commented in a header).
       
   504 // -----------------------------------------------------------------------------
       
   505 //
       
   506 TBool CCbsRecCollector::CheckPageAreaInfoMatch( 
       
   507     const CCbsMessage& aPage1, 
       
   508     const CCbsMessage& aPage2 ) const
       
   509     {   
       
   510     RMobilePhone::TMobilePhoneNetworkInfoV1 info1;
       
   511     RMobilePhone::TMobilePhoneNetworkInfoV1 info2;
       
   512 
       
   513     aPage1.GetPLMN( info1 );
       
   514     aPage2.GetPLMN( info2 );
       
   515 
       
   516     TBool result( EFalse );
       
   517 
       
   518     if ( info1.iCountryCode == KRecMessageNoNetworkInfo || 
       
   519         info2.iCountryCode == KRecMessageNoNetworkInfo )
       
   520         {
       
   521         // Network info is unavailable; we must assume that the aPage1
       
   522         // is of the same page area as aPage2, so we return ETrue
       
   523         // unconditionally.
       
   524         result = ETrue;
       
   525         }
       
   526 
       
   527     if ( info1.iCountryCode == info2.iCountryCode && 
       
   528         info1.iNetworkId == info2.iNetworkId )
       
   529         // PLMN match
       
   530         {
       
   531         if ( aPage1.LAC() == aPage2.LAC() )
       
   532             // LAC match
       
   533             {
       
   534             if ( aPage1.CellId() == aPage2.CellId() )
       
   535                 // Cell match
       
   536                 {
       
   537                 // Full network information match
       
   538                 result = ETrue;
       
   539                 }
       
   540             else
       
   541                 {
       
   542                 // Cell mismatch
       
   543                 if ( aPage1.GeographicalScope() == 
       
   544                     ECbsRecGeographicalScopeCell )
       
   545                     // Cell id mismatch and scoped cell wide.
       
   546                     {
       
   547                     result = EFalse;
       
   548                     }
       
   549                 else
       
   550                     // Cell id mismatch, not scoped cell wide.
       
   551                     {
       
   552                     result = ETrue;
       
   553                     }
       
   554                 }
       
   555             }            
       
   556         else
       
   557             // LAC mismatch
       
   558             {
       
   559             if ( aPage1.GeographicalScope() == 
       
   560                 ECbsRecGeographicalScopePLMN )
       
   561                 {
       
   562                 // LAC mismatch but scoped operator-wide
       
   563                 result = ETrue;
       
   564                 }
       
   565             else
       
   566                 {
       
   567                 // LAC mismatch and not scoped operator-wide
       
   568                 result = EFalse;
       
   569                 }
       
   570             }
       
   571         }
       
   572     else
       
   573         // PLMN mismatch
       
   574         {
       
   575         result = EFalse; // operator mismatch
       
   576         }
       
   577 
       
   578     return result;    
       
   579     }
       
   580 
       
   581 
       
   582 // ================= OTHER EXPORTED FUNCTIONS ==============
       
   583 
       
   584 //  End of File