brandingserver/bsserver/cbssession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:31:29 +0300
branchRCL_3
changeset 42 cfd5c2994f10
parent 25 cfe5eb8bb9ca
child 43 113b91e0a2ad
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  CBSSession.cpp
*
*/



//  INCLUDE FILES
#include <e32base.h>
#include <apgcli.h>

#include "cbssession.h"
#include "cbsserver.h"
#include "DebugTrace.h"
#include "cbsbrandhandler.h"
#include "cbsstoragemanager.h"
#include "cbsstorage.h"
#include "cbsbitmap.h"
//#include "cbselement.h"
#include "rbsobjowningptrarray.h"
#include "bselementfactory.h"
#include "bsimportconstants.h"
#include <badesca.h>
#include <s32buf.h>
#include <s32mem.h>
#include <utf.h>
#include <e32property.h>

// ==============================================================
// ======================== SESSION =============================
// ==============================================================

// Two-phased constructor.
CBSSession* CBSSession::NewL()
    {
    TRACE( T_LIT("CBSSession::NewL begin") );
    CBSSession* self = new( ELeave ) CBSSession();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    TRACE( T_LIT("CBSSession::NewL end") );
    return self;
    }

// Symbian OS default constructor can leave.
void CBSSession::ConstructL()
	{
	}


// destructor
CBSSession::~CBSSession()
    {
    TRACE( T_LIT("CBSSession[%d]::~CBSSession()"), this );

    if( Server() )
        {
        Server()->SessionDied( this );
        }
	delete iText;
	delete iBuffer;
	delete iBranding;
	delete iSeveralData;
	
#ifdef __WINSCW__
	if( iStorageManager )
		{
		iStorageManager->WriteIbyFiles();
		}
#endif
	delete iStorageManager;
    delete iSessionInfo;

    }


// C++ default constructor can NOT contain any code, that
// might leave.
//
CBSSession::CBSSession()
    {
    }

// ---------------------------------------------------------
// CBSSession::CreateL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::CreateL()
    {
    TRACE( T_LIT("CBSSession[%d]::CreateL()"), this );
    Server()->SessionCreatedL( this );
    }

// ---------------------------------------------------------
// CBSSession::ServiceL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::ServiceL( const RMessage2 &aMessage )
    {

    /*if( !iSessionInfo )
        {
        TRAPD( err, ExtractInfoL( aMessage ) );
        TRACE( T_LIT("CBSSession::ServiceL() ExtractInfoL returned with [%d]"), err );
        }
	*/
    if( DispatchMessageL( aMessage ) )
        {
        if( !iMessageCompleted )
        	{
        	aMessage.Complete( KErrNone );
        	}
        }
    }

// ---------------------------------------------------------
// CBSSession::ServiceError
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::ServiceError( const RMessage2& aMessage,
                                      TInt aError )
    {
    aMessage.Complete( aError );
    }

// ---------------------------------------------------------
// CBSSession::HandleBackupStateL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::HandleBackupStateL( TBackupState aState )
    {
	iIsBackup = ETrue ;	
    switch( aState )
        {
        case EBackupNotActive: // backup is complete
            {
            // release session lock
            iBackupActive = EFalse;
            if( iStorageManager )
                {
                iStorageManager->ReleaseLockL();
                }
                
			// Sending backup active state change event after unlocking it
			if( iObserverActive )
				{
				iObserverMessage.Complete( KErrNone );
				iObserverActive = EFalse;
				}

            break;
            }
        case EBackupActive: // backup activated
            {

            // Lock session. Branding data is not available until
            // backup is completed.
            iBackupActive = ETrue;

			// Sending backup active state change event before locking it
			if( iObserverActive )
				{
				iObserverMessage.Complete( KErrNone );
				iObserverActive = EFalse;
				}

            if( iStorageManager )
                {
                iStorageManager->LockStorage();
                }
            break;
            }
        default:
            {
            // unknown state
            }
        }

        
    }

// ---------------------------------------------------------
// CBSSession::DispatchMessageL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CBSSession::DispatchMessageL( const RMessage2& aMessage )
    {
    TRACE( T_LIT("CBrandingSession[%d]::DispatchMessageL() %d"),
                  this, aMessage.Function() );
	iMessageCompleted = EFalse;
    TBool msgNeedsToBeCompleted = ETrue;
    
    if( iBackupActive )
        {
        // if backup is active, we don't take requests.
        // We could take some requests which do not require disk
        // operations. This is not a good solution and a better one should be
        // investigated. I'm running out of time.
        TInt msg = aMessage.Function() ; 
        if( msg == EBSObserveGetChange ||
        	msg == EBSObserveGetBackupState ||
        	msg == EBSObserveBrand)
        	{
        	//allow to do the operation	
        	}
        else
    	    {
	       	User::Leave( KErrNotReady );	
        	}
        
        }
    
    switch( aMessage.Function() )
        {
        case EBSInitInstall:
        	{
        	InitUpdateL( aMessage, EBSTxInstall );
        	break;
        	}
        case EBSInitUninstall:
        	{
        	InitUpdateL( aMessage, EBSTxUninstall );
        	break;
        	}
        case EBSInitAppend:
        	{
        	InitUpdateL( aMessage, EBSTxAppend );
        	break;
        	}
        case EBSInitReplace:
        	{
        	InitUpdateL( aMessage, EBSTxReplace );
        	break;
        	}
        case EBSInitAccess:
        	{
        	InitAccessL( aMessage );
        	break;
        	}
        case EBSPrepareText:
            {
			GetTextL( aMessage );
            break;
            }
        case EBSGetText:
            {
            if( iText )
            	{
            	aMessage.WriteL( 2, *iText );	
            	}
			else
				{
				aMessage.WriteL( 2, KNullDesC() );
				}
            break;
            }

		case EBSIsBrandUpdateRequired:
			isBrandUpdateRequiredL (aMessage);
			break;

        case EBSGetInt:
            {
			GetIntL( aMessage );
            break;
            }

        case EBSPrepareBuffer:
            {
			GetBufferL( aMessage );
            break;
            }
            
        case EBSGetBuffer:
            {
            if( iBuffer )
            	{
            	aMessage.WriteL( 2, *iBuffer );	
            	}
			else
				{
				aMessage.WriteL( 2, KNullDesC8() );
				}
            break;
            }
            
        case EBSGetFile:
            {
 			GetFileL( aMessage );
            break;
            }

        case EBSPrepareSeveral:
        	{
			PrepareSeveralL( aMessage );
        	break;
        	}

        case EBSGetSeveral:
        	{
			GetSeveralL( aMessage );
        	break;
        	}

        case EBSPrepareStructure:
        	{
			PrepareStructureL( aMessage );
        	break;
        	}

        case EBSGetStructure:
    		{
			GetStructureL( aMessage );
    		break;
    		}

        case EBSStartTransaction:
        	{
			StartTransactionL( aMessage );
        	break;
        	}
        	
        case EBSStopTransaction:
        	{
        	StopTransactionL( aMessage );
        	break;
        	}
        case EBSCancelTransaction:
        	{
        	CancelTransactionL( aMessage );
        	break;
        	}

        case EBSInstall:
        	{
        	InstallL( aMessage );
        	break;
        	}

        case EBSReplace:
        	{
        	ReplaceL( aMessage );
        	break;
        	}

        case EBSAppend:
        	{
        	AppendL( aMessage );
        	break;
        	}

        case EBSRemoveBrand:
        	{
        	RemoveBrandL( aMessage );
        	break;
        	}
        case EBSRemoveApplication:
        	{
        	RemoveApplicationL( aMessage );
        	break;
        	}
        	
        case EBSObserveBrand:
        	{
        	if( iObserverActive )
        		{
        		// complete the old observer request with KErrCancel
        		iObserverMessage.Complete( KErrCancel );
        		}
        	iObserverMessage = aMessage;
        	iObserverActive = ETrue;
        	msgNeedsToBeCompleted = EFalse;
        	break;
        	}

        case EBSObserveGetNewVersion:
        	{
        	TInt newVersion = GetNewVersionL();
			TPckgC<TInt> pack( newVersion );
			aMessage.WriteL( 0, pack );
        	break;
        	}
        	
		// Get what change happen        	
        case EBSObserveGetChange:
        	{
			TPckgC<TInt> pack( iIsBackup );
			aMessage.WriteL( 0, pack );
        	break ;
        	}
        	
        // Get the backup state
        case EBSObserveGetBackupState:
        	{
			TPckgC<TInt> pack( iBackupActive );
			aMessage.WriteL( 0, pack );
        	break ;	
        	}
        	
        default:
            {
            User::Leave( KErrNotSupported );
            break;
            }
        }

    return msgNeedsToBeCompleted;
    }


// ---------------------------------------------------------
// CBSSession::InitUpdateL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::InitUpdateL( const RMessage2 &aMessage, TTransactionType aType)
	{
    TRACE( T_LIT("CBSSession::InitUpdateL: begin TTransactionType[%d] "),aType );
	
	// get the application id
	TInt bufferSize( aMessage.GetDesLength( 0 ) );

    HBufC8* appId = HBufC8::NewLC( bufferSize );
	TPtr8 appPtr = appId->Des();
	aMessage.ReadL( 0, appPtr );

	HBufC* tmpAppId = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *appId );
	CleanupStack::PopAndDestroy( appId );
	
	delete iApplicationId;
	iApplicationId = tmpAppId;

	// get the brand id
	bufferSize = aMessage.GetDesLength( 1 );
    HBufC8* streamBuf = HBufC8::NewLC( bufferSize );
	TPtr8 streamPtr = streamBuf->Des();
	aMessage.ReadL( 1, streamPtr );

	RDesReadStream stream;
	CleanupClosePushL( stream );
	stream.Open( streamPtr );
	
	TInt descriptorLength = stream.ReadInt16L();
	HBufC8* brandId = HBufC8::NewLC( descriptorLength );
	TPtr8 brandPtr = brandId->Des();
	stream.ReadL( brandPtr, descriptorLength );

	HBufC* tmpBrandId = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *brandId );
	CleanupStack::PopAndDestroy( brandId );
	delete iBrandId;
	iBrandId = tmpBrandId;
	
	descriptorLength = stream.ReadInt16L();
	HBufC8* defaultBrandId = HBufC8::NewLC( descriptorLength );
	TPtr8 defaultPtr = defaultBrandId->Des();
	stream.ReadL( defaultPtr, descriptorLength );
	
	HBufC* tmpDefaultBrandId = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *defaultBrandId );
	CleanupStack::PopAndDestroy( defaultBrandId );
	delete iDefaultBrandId;
	iDefaultBrandId = tmpDefaultBrandId;
	
	CleanupStack::PopAndDestroy( 2, streamBuf ); // stream, streamBuf


	// get the language id
	iLanguageId = (TLanguage)aMessage.Int2();

	// get the version
	iReserved = aMessage.Int3();

	// Check if brand is discarded and client is trying to access/append/replace on that
	// give error message saying brand not found so that client will not use that brand
	if(aType == EBSTxAccess || aType == EBSTxAppend || aType == EBSTxReplace )
	{
		if(!iStorageManager)
		{
			iStorageManager = CBSStorageManager::NewL( this, *iApplicationId );	
		}
		
		TBool brandDiscarded = EFalse ;
		brandDiscarded = iStorageManager->CheckBrandDiscarded(*iApplicationId, *iBrandId) ;
		
		if(brandDiscarded)
		{
			TRACE( T_LIT("CBSSession::InitUpdateL: Brand discarded!->LeaveWith KErrNotFound") );
			///Server()->DisplaySessionInfoL( this, KErrNotFound );
			User::Leave( KErrNotFound );	
		}
	}

	if( aType == EBSTxAppend )
		{
		PrepareAppendL();
		}
	else if( aType == EBSTxReplace )
		{
		PrepareReplaceL();
		}
	else if(aType == EBSTxUninstall)
		{
		if( !iStorageManager )
			{
			iStorageManager = CBSStorageManager::NewL( this, *iApplicationId );
			}
		// if any client is accessing same brand leave with KErrInUse.
		// check if the brand has any active clients
		TBool brandActive = EFalse;
		CBSServer* server = Server();
		if( server )
			{
			brandActive = server->MatchSessionUninstallL( *iApplicationId, *iBrandId,
												 			this);					
			}
			
		if(brandActive)
			{
			TRACE( T_LIT("CBSSession::InitUpdateL: UnInstallation aborted -> LeaveWith KErrInUse") );
			//Server()->DisplaySessionInfoL( this,KErrInUse);
			//when changing this errorcode: please read the note in 
			//UninstallL() ( installer.cpp )
			User::Leave( KErrInUse );
			}
		}
	else if( aType == EBSTxInstall )
		{
		if( !iStorageManager )
			{
			iStorageManager = CBSStorageManager::NewL( this, *iApplicationId );
			}
			
		HBufC* drive = HBufC::NewLC(3);
		TRAPD( err, iStorageManager->GetNewestVersionL( *iApplicationId,
												   	      *iBrandId,
										   		    	  iLanguageId ) );
		if( ( err == KErrNotFound ) || ( err == KErrPathNotFound ) )
			{
			CleanupStack::PopAndDestroy(drive);
			// this brand is not yet there, which is the correct situation here
			// for starting install. We can just ignore this error
			}
			
		else if( !err )
			{
			// there was no error, therefore this brand already exists in the ROM
			// (Z drive).
			// we leave with KErrAlreadyExists
			if( 0 == (drive->Des().Compare(KBSZDrive)) )
				{
				CleanupStack::PopAndDestroy(drive);		
			    User::Leave( KErrAlreadyExists );
				}
			else
				{
				//PopAndDestroy drive as it is not needed any longer.
				CleanupStack::PopAndDestroy(drive);

				// if any client is accessing same brand leave with KErrInUse.
				// check if the brand has any active clients
				TBool brandActive = EFalse;
				CBSServer* server = Server();
				if( server )
					{
					brandActive = server->MatchSessionL( *iApplicationId, *iBrandId,
													 iLanguageId, this, iReserved );					
					}

				if(brandActive == EFalse)
					{	
					TRACE( T_LIT("CBSSession::InitUpdateL: Brand not used -> remove") );
					iStorageManager->RemoveBrandL( *iApplicationId, *iBrandId,
													iLanguageId, iReserved );
					}
				else
					{
					TRACE( T_LIT("CBSSession::InitUpdateL: Installation aborted->LeaveWith KErrInUse") );
					//Server()->DisplaySessionInfoL( this,KErrInUse);
					//when changing this errorcode: please read the note in 
					//UninstallL() ( installer.cpp )
					User::Leave( KErrInUse );
					}
				}
			}
		else
			{
			CleanupStack::PopAndDestroy(drive);	
			// some other error
			TRACE( T_LIT("CBSSession::InitUpdateL: ERROR aType[%d] LeaveWith[%d]"),aType,err );
			User::Leave( err );
			}
		}
		
	
	iInitialized = ETrue;

    TRACE( T_LIT("Server initialized") );
	}



// ---------------------------------------------------------
// CBSSession::PrepareAppendL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::PrepareAppendL()
	{
	if( !iStorageManager )
		{
		iStorageManager = CBSStorageManager::NewL( this, *iApplicationId );
		}
		
	RFile brandHandle;
	iStorageManager->BrandHandleL( *iApplicationId,
								   *iBrandId, iLanguageId, brandHandle, iReserved );
	CleanupClosePushL( brandHandle );
	RFileReadStream oldStream;
	oldStream.Attach( brandHandle );
	CleanupClosePushL( oldStream );
	TInt version = oldStream.ReadInt16L();

	TInt count = oldStream.ReadInt16L();
	
	if( !iStorageManager->Storage() )
		{
		iStorageManager->CreateStorageL();
		}
	for( TInt i = 0; i < count; i++ )
		{
		MBSElement* element = InternalizeElementL( oldStream, ETrue );
		CleanupDeletePushL( element );
		// transfers ownership
		iStorageManager->Storage()->AppendElementsL( element );
		CleanupStack::Pop(); // element
		}

	iStorageManager->Storage()->SetVersion( iReserved );
	iStorageManager->Storage()->SetStorageIdL( *iBrandId );
	iStorageManager->Storage()->SetApplicationIdL( *iApplicationId );
	iStorageManager->Storage()->SetLanguageL( iLanguageId );

	CleanupStack::PopAndDestroy( 2 ); // oldStream, brandHandle
	iAppending = ETrue;
	}
// ---------------------------------------------------------
// CBSSession::PrepareReplaceL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::PrepareReplaceL()
	{
	PrepareAppendL();
	}
	
// ---------------------------------------------------------
// CBSSession::InitAccessL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::InitAccessL( const RMessage2 &aMessage )
	{
	InitUpdateL( aMessage, EBSTxAccess );
	
	iBranding = CBSBrandHandler::NewL( *iApplicationId, *iBrandId, *iDefaultBrandId,
										iLanguageId, this, iReserved );


	iAccessInit = ETrue;
    TRACE( T_LIT("Access initialized") );
	}


// ---------------------------------------------------------
// CBSSession::GetTextL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetTextL( const RMessage2 &aMessage )
	{
	if( !iAccessInit )
		{
		User::Leave( KErrNotReady );
		}
	TInt idSize( aMessage.GetDesLength( 0 ) );

    HBufC8* idBuffer = HBufC8::NewLC( idSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 0, ptrId );

    HBufC* temp = iBranding->GetTextL( ptrId );
    delete iText;
    iText = temp;

    CleanupStack::PopAndDestroy( idBuffer );
    TPckgC<TInt> pack( iText->Size() );
    aMessage.WriteL( 1, pack );
    TRACE( T_LIT("aMessage.WriteL( 1, %d );"), iText->Size() );
	}

void CBSSession :: isBrandUpdateRequiredL (const RMessage2 &aMessage)
{
	if( !iAccessInit )
		{
		User::Leave( KErrNotReady );
		}
	TInt updateRequired = iBranding->isBrandUpdateRequiredL ();
//	iValue = updateRequired;
	TPckgC <TInt> pack (updateRequired);
	aMessage.WriteL( 0, pack );
}
// ---------------------------------------------------------
// CBSSession::GetIntL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetIntL( const RMessage2 &aMessage )
	{
	if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
	TInt idSize( aMessage.GetDesLength( 0 ) );

	HBufC8* idBuffer = HBufC8::NewLC( idSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 0, ptrId );

	iValue = iBranding->GetIntL( ptrId );
	TPckgC<TInt> pack( iValue );
	aMessage.WriteL( 1, pack );
	CleanupStack::PopAndDestroy( idBuffer );
	}

// ---------------------------------------------------------
// CBSSession::GetBufferL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetBufferL( const RMessage2 &aMessage )
	{
	if( !iAccessInit )
		{
		User::Leave( KErrNotReady );
		}
	TInt idSize( aMessage.GetDesLength( 0 ) );

    HBufC8* idBuffer = HBufC8::NewLC( idSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 0, ptrId );

    HBufC8* temp = iBranding->GetBufferL( ptrId );
    delete iBuffer;
    iBuffer = temp;

    CleanupStack::PopAndDestroy( idBuffer );
    TPckgC<TInt> pack( iBuffer->Size() );
    aMessage.WriteL( 1, pack );
    TRACE( T_LIT("aMessage.WriteL( 1, %d );"), iBuffer->Size() );
	}


// ---------------------------------------------------------
// CBSSession::GetFileL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetFileL( const RMessage2 &aMessage )
	{
    TRACE( T_LIT("CBSSession::GetFileL begin") );
    if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
	TInt idSize( aMessage.GetDesLength( 2 ) );
	HBufC8* idBuffer = HBufC8::NewLC( idSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 2, ptrId );

	RFile file;
    iBranding->GetFileL( ptrId, file );

	CleanupStack::PopAndDestroy( idBuffer );

	User::LeaveIfError( file.TransferToClient( aMessage, 0 ) );

	iMessageCompleted = ETrue;

	file.Close();
	TRACE( T_LIT("CBSSession::GetFileL end") );
	}


// ---------------------------------------------------------
// CBSSession::InternalizeElementIdsL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::InternalizeElementIdsL( RReadStream& aStream, RBSObjOwningPtrArray<HBufC8>& aArray )
	{
	TInt count = aStream.ReadInt16L();
	
	for(TInt i = 0; i < count; i++ )
		{
		TInt length = aStream.ReadInt16L();
		HBufC8* id = HBufC8::NewLC( length );
		TPtr8 ptrId = id->Des();
		aStream.ReadL( ptrId, length );
		aArray.AppendL( id );
		CleanupStack::Pop( id );
		}
	}

// ---------------------------------------------------------
// CBSSession::PrepareTextL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::PrepareSeveralL( const RMessage2 &aMessage )
	{
	if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
		
	TInt msgSize( aMessage.GetDesLength( 1 ) );

    HBufC8* idBuffer = HBufC8::NewLC( msgSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 1, ptrId );

	RDesReadStream idStream;
	CleanupClosePushL( idStream );
	idStream.Open( ptrId );

	RBSObjOwningPtrArray<HBufC8> idArray;
	CleanupClosePushL( idArray );
	
	InternalizeElementIdsL( idStream, idArray );


	MBSElement* texts = iBranding->GetSeveralL( idArray );

	CleanupStack::PopAndDestroy(); // idArray
	CleanupStack::PopAndDestroy(); // idStream
	CleanupStack::PopAndDestroy();  // idBuffer

	CleanupDeletePushL( texts );

	// FIXME magic number
	CBufFlat* data = CBufFlat::NewL( 2000 );
	CleanupStack::PushL( data );

	RBufWriteStream writeStream;
	CleanupClosePushL( writeStream );
	writeStream.Open( *data );

	texts->ExternalizeL( writeStream );	

	CleanupStack::PopAndDestroy(); // writeStream
	
	delete iSeveralData;
	iSeveralData = data;
	CleanupStack::Pop( data );

	CleanupStack::PopAndDestroy(); // texts

	delete iBuffer;
	iBuffer = NULL;
	iBuffer = iSeveralData->Ptr(0).AllocL();

	delete iSeveralData;
	iSeveralData = NULL;
	TPckgC<TInt> pack( iBuffer->Size() );
	TRACE( T_LIT("DispatchMessageL - EPlatSecPrepareSeveral writing size %d"), iBuffer->Size() );
    aMessage.WriteL( 0, pack );

	}

// ---------------------------------------------------------
// CBSSession::GetSeveralTextL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetSeveralL( const RMessage2 &aMessage )
	{
	if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
	aMessage.WriteL( 0, *iBuffer );

	delete iBuffer;
	iBuffer = NULL;
	}


// ---------------------------------------------------------
// CBSSession::PrepareStructureL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::PrepareStructureL( const RMessage2 &aMessage )
	{
	if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
	TInt idSize( aMessage.GetDesLength( 1 ) );

	RBSObjOwningPtrArray<MBSElement> valueArray;
	CleanupClosePushL( valueArray );

    HBufC8* idBuffer = HBufC8::NewLC( idSize );
	TPtr8 ptrId = idBuffer->Des();
	aMessage.ReadL( 1, ptrId );


	MBSElement* extElement = iBranding->GetStructureL( ptrId );
	CleanupDeletePushL( extElement );
	// FIXME magic number
	CBufFlat* data = CBufFlat::NewL( 2000 );
	CleanupStack::PushL( data );

	RBufWriteStream writeStream;
	CleanupClosePushL( writeStream );
	writeStream.Open( *data );

	extElement->ExternalizeL( writeStream );

	CleanupStack::PopAndDestroy(); // writeStream

	delete iSeveralData;
	iSeveralData = data;
	CleanupStack::Pop( data );

	CleanupStack::PopAndDestroy( extElement );

	delete iBuffer;
	iBuffer = NULL;
	iBuffer = iSeveralData->Ptr(0).AllocL();

	delete iSeveralData;
	iSeveralData = NULL;
	TPckgC<TInt> pack( iBuffer->Size() );
	TRACE( T_LIT("DispatchMessageL - EPlatSecPrepareSeveral writing size %d"), iBuffer->Size() );
    aMessage.WriteL( 0, pack );


	CleanupStack::PopAndDestroy(idBuffer);

	CleanupStack::PopAndDestroy(); // valueArray

	}

// ---------------------------------------------------------
// CBSSession::GetStructureL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::GetStructureL( const RMessage2 &aMessage )
	{
	if( !iInitialized )
		{
		User::Leave( KErrNotReady );
		}
	aMessage.WriteL( 0, *iBuffer );

	delete iBuffer;
	iBuffer = NULL;
	}



// ---------------------------------------------------------
// CBSSession::InstallL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::InstallL( const RMessage2 &aMessage )
	{
	TRACE( T_LIT( "CBSSession::InstallL begin") );
	if( !iInitialized || !iStorageManager )
		{
		User::Leave( KErrNotReady );
		}

	if( !iStorageManager->Storage() )
		{
		iStorageManager->CreateStorageL();
		}
	
	iStorageManager->ConnectTransactionL( *iApplicationId,
										  *iBrandId, iLanguageId, EFalse, iReserved );

	TInt msgSize( aMessage.GetDesLength( 0 ) );

    HBufC8* buffer = HBufC8::NewLC( msgSize );
	TPtr8 ptr = buffer->Des();
	aMessage.ReadL( 0, ptr );

	RDesReadStream stream;
	CleanupClosePushL( stream );
	stream.Open( ptr );

	MBSElement* element = InternalizeElementL( stream );
	CleanupDeletePushL( element );

	iStorageManager->Storage()->SetVersion( iReserved );
	iStorageManager->Storage()->SetStorageIdL( *iBrandId );
	iStorageManager->Storage()->SetApplicationIdL( *iApplicationId );
	iStorageManager->Storage()->SetLanguageL( iLanguageId );
	// transfers ownership
	iStorageManager->Storage()->AppendElementsL( element );

	CleanupStack::Pop(); // element 
	CleanupStack::PopAndDestroy( 2, buffer );
	iWriteNeeded = ETrue;
	TRACE( T_LIT( "CBSSession::InstallL end") );
	}

// ---------------------------------------------------------
// CBSSession::ReplaceL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::ReplaceL( const RMessage2 &aMessage )
	{
	TRACE( T_LIT( "CBSSession::ReplaceL begin") );
	if( !iInitialized || !iStorageManager )
		{
		User::Leave( KErrNotReady );
		}
		
	iStorageManager->ConnectTransactionL( *iApplicationId,
										  *iBrandId, iLanguageId, EFalse, iReserved );

	TInt msgSize( aMessage.GetDesLength( 0 ) );

    HBufC8* buffer = HBufC8::NewLC( msgSize );
	TPtr8 ptr = buffer->Des();
	aMessage.ReadL( 0, ptr );

	RDesReadStream stream;
	CleanupClosePushL( stream );
	stream.Open( ptr );

	MBSElement* element = InternalizeElementL( stream );
	CleanupDeletePushL( element );

	// transfers ownership
	iStorageManager->Storage()->ReplaceElementL( element );

	CleanupStack::Pop(); // element 
	CleanupStack::PopAndDestroy( 2, buffer );
	iWriteNeeded = ETrue;
	TRACE( T_LIT( "CBSSession::ReplaceL end") );
	}


// ---------------------------------------------------------
// CBSSession::AppendL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::AppendL( const RMessage2 &aMessage )
	{
	TRACE( T_LIT( "CBSSession::AppendL begin") );
	if( !iInitialized || !iStorageManager )
		{
		User::Leave( KErrNotReady );
		}
	
	iStorageManager->ConnectTransactionL( *iApplicationId,
										  *iBrandId, iLanguageId, EFalse, iReserved );

	TInt msgSize( aMessage.GetDesLength( 0 ) );

    HBufC8* buffer = HBufC8::NewLC( msgSize );
	TPtr8 ptr = buffer->Des();
	aMessage.ReadL( 0, ptr );

	RDesReadStream stream;
	CleanupClosePushL( stream );
	stream.Open( ptr );

	MBSElement* element = InternalizeElementL( stream );
	CleanupDeletePushL( element );

	iStorageManager->Storage()->SetVersion( iReserved );
	iStorageManager->Storage()->SetStorageIdL( *iBrandId );
	iStorageManager->Storage()->SetApplicationIdL( *iApplicationId );
	iStorageManager->Storage()->SetLanguageL( iLanguageId );
	// transfers ownership
	iStorageManager->Storage()->AppendElementsL( element );

	CleanupStack::Pop(); // element 
	CleanupStack::PopAndDestroy( 2, buffer );
	iWriteNeeded = ETrue;
    TRACE( T_LIT( "CBSSession::AppendL end") );
	}

// ---------------------------------------------------------
// CBSSession::StartTransactionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::StartTransactionL( const RMessage2& /*aMessage*/ )
	{
	if( !iStorageManager )
		{
		iStorageManager = CBSStorageManager::NewL( this, *iApplicationId );
		}
	// if we are appending or replacing, we don't need to 
	// create storage
	if( !iAppending )
		{
		iStorageManager->CreateStorageL();	
		}
	}


// ---------------------------------------------------------
// CBSSession::CancelTransactionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::CancelTransactionL( const RMessage2 &aMessage )
	{
	// get the application id
	TInt bufferSize( aMessage.GetDesLength( 0 ) );

    HBufC8* appId = HBufC8::NewLC( bufferSize );
	TPtr8 appPtr = appId->Des();
	aMessage.ReadL( 0, appPtr );


	// get the brand id
	bufferSize = aMessage.GetDesLength( 1 );
    HBufC8* brandId = HBufC8::NewLC( bufferSize );
	TPtr8 brandPtr = brandId->Des();
	aMessage.ReadL( 1, brandPtr );

	// get the language id
	TLanguage language = (TLanguage)aMessage.Int2();

	// get the version
	TInt version = aMessage.Int3();
	
	
	HBufC* tmpBrandId = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *brandId );
	CleanupStack::PopAndDestroy( brandId );
	CleanupStack::PushL( tmpBrandId );
	HBufC* tmpAppId = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *appId );
	CleanupStack::PushL( tmpAppId );
	
	// check if the transaction is correct	
	iStorageManager->ConnectTransactionL( *tmpAppId,
										  *tmpBrandId, iLanguageId,
										  EFalse, iReserved );

	CleanupStack::PopAndDestroy( 2, tmpBrandId ); // tmpBrandId, tmpAppId
	CleanupStack::PopAndDestroy( appId );
	// cancel the transaction
	iStorageManager->CancelTransactionL();
	iWriteNeeded = EFalse;
	}

// ---------------------------------------------------------
// CBSSession::StopTransactionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::StopTransactionL( const RMessage2 &aMessage )
	{
	if( !iStorageManager )
		{
		// transaction not found
		User::Leave( KErrNotFound );
		}
	if( iAppending )
		{
		// find next available version number
		TInt nextVersion = iStorageManager->NextAvailableVersionL();
		iStorageManager->SetVersion( nextVersion );
		iStorageManager->Storage()->SetVersion( nextVersion );
		}
		
	if( iWriteNeeded )
		{
		iReserved = iStorageManager->WriteStorageFilesL();	
		iWriteNeeded = EFalse;
		}
	
	delete iStorageManager;
	iStorageManager = NULL;
	
	TPckgC<TInt> pack( iReserved );
	aMessage.WriteL( 0, pack );
	
	}


// ---------------------------------------------------------
// CBSSession::InternalizeElementL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
MBSElement* CBSSession::InternalizeElementL( RReadStream& aStream, TBool aAppending /*= EFalse*/ )
	{
	MBSElement* returnValue = NULL;

	TBSElementType type = (TBSElementType)aStream.ReadInt16L();
	TInt idSize = aStream.ReadInt16L();
	HBufC8* elementId = HBufC8::NewLC( idSize );
	TPtr8 elementIdPtr = elementId->Des();
	aStream.ReadL( elementIdPtr, idSize );


	switch( type )
		{
		case EBSInt:
			{
			TInt intData = aStream.ReadInt16L();
			returnValue = BSElementFactory::CreateBSElementL( *elementId,
															   EBSInt,
															   intData );
			break;
			}
		case EBSText:
			{
			TInt textSize = aStream.ReadInt16L();
			HBufC* textData = HBufC::NewLC( textSize );

			TPtr textPtr = textData->Des();
			aStream.ReadL( textPtr, textSize );

			returnValue = BSElementFactory::CreateBSElementL( *elementId,
															   type,
															   *textData );

			CleanupStack::Pop( textData );
			break;
			}

		case EBSFile: 
			{
			TInt nameSize = aStream.ReadInt16L();
			HBufC* fileName = HBufC::NewLC( nameSize );

			TPtr filePtr = fileName->Des();
			aStream.ReadL( filePtr, nameSize );
			
			if( !aAppending )
				{
				// we are installing, so the filename is pointing to a file
				// that has to be installed
				// Install file and get the filename without path
				HBufC* strippedName = iStorageManager->InstallFileLC( *fileName );
				returnValue = BSElementFactory::CreateBSElementL( *elementId,
																   type,
																   *strippedName );
				CleanupStack::Pop( strippedName );
				CleanupStack::PopAndDestroy( fileName );
				}
			else
				{
				// we are appending, so this is really the filename
				returnValue = BSElementFactory::CreateBSElementL( *elementId,
																   type,
																   *fileName );
				CleanupStack::Pop( fileName );
				}
			break;
			}
			
		case EBSList:
			{
			RBSObjOwningPtrArray<MBSElement> listData;
			CleanupClosePushL( listData );
			TInt listCount = aStream.ReadInt16L();
			for( TInt i = 0; i < listCount; i++ )
				{
				MBSElement* listElement = InternalizeElementL( aStream );
				CleanupDeletePushL( listElement );
				listData.AppendL( listElement );
				CleanupStack::Pop(); // listElement
				}

			returnValue = BSElementFactory::CreateBSElementL( *elementId,
															   EBSList,
															   listData );
			CleanupStack::Pop(); //  listData
			break;
			}
		case EBSBuffer:
			{
			TInt bufferSize = aStream.ReadInt16L();
			HBufC8* buffer = HBufC8::NewLC( bufferSize );

			TPtr8 buffPtr = buffer->Des();
			aStream.ReadL( buffPtr, bufferSize );

			returnValue = BSElementFactory::CreateBSElementL( *elementId,
															   EBSBuffer,
															   *buffer );

			CleanupStack::Pop( buffer );
			break;
			}
		case EBSBitmap:
			{
			TInt length = aStream.ReadInt16L();
			HBufC8* fileId = HBufC8::NewLC( length );
			
			TPtr8 fileIdPtr = fileId->Des();
			aStream.ReadL( fileIdPtr, length );
			
			TInt bitmapId = aStream.ReadInt16L();
			TInt maskId = aStream.ReadInt16L();
			TInt skinId = aStream.ReadInt16L();
			TInt skinMaskId = aStream.ReadInt16L();


			CBSBitmap* bitmap = CBSBitmap::NewLC( bitmapId,
												  maskId,
												  skinId,
												  skinMaskId,
												  fileIdPtr );
													  
			returnValue = BSElementFactory::CreateBSElementL( *elementId, 
															  EBSBitmap,
															  bitmap );
			CleanupStack::Pop( bitmap ); 
			CleanupStack::PopAndDestroy( fileId );
			break;
			}

		default:
			{
			User::Leave( KErrArgument );
			break;
			}
		}

	CleanupStack::PopAndDestroy( elementId );

	return returnValue;
	}


// ---------------------------------------------------------
// CBSSession::MatchSessionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CBSSession::MatchSessionL( const TDesC& aApplicationId,
								 const TDesC& aBrandId,
								 TLanguage aLanguageId,
							 	 TInt aReserved )
	{
	TBool returnValue = EFalse;
	if( iApplicationId && iBrandId )
		{
		if( ( 0 == iApplicationId->Compare( aApplicationId ) ) &&
		   ( 0 == iBrandId->Compare( aBrandId ) ) &&
		   ( iLanguageId == aLanguageId ) && 
		   ( iReserved == aReserved ))
			{
			returnValue = ETrue;
			}
		}
	
	return returnValue;
	}

// ---------------------------------------------------------
// CBSSession::MatchSessionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CBSSession::MatchSessionUninstallL( const TDesC& aApplicationId,
								 const TDesC& aBrandId)
	{
	TBool returnValue = EFalse;
	if( iApplicationId && iBrandId )
		{
		if( ( 0 == iApplicationId->Compare( aApplicationId ) ) &&
		   ( 0 == iBrandId->Compare( aBrandId ) ) )
			{
			returnValue = ETrue;
			}
		}
	
	return returnValue;
	}
// ---------------------------------------------------------
// CBSSession::BrandUpdatedL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::BrandUpdatedL( const TDesC& aApplicationId,
								 const TDesC& aBrandId,
								 TLanguage aLanguageId,
							 	 TInt /*aReserved*/ )
	{
	TRACE( T_LIT( "CBSSession::BrandUpdatedL begin aAppId[%S] aBrandId[%S]"), &aApplicationId, &aBrandId );
	iIsBackup = EFalse ; 
	if( iApplicationId && iBrandId )
		{
		if( ( 0 == iApplicationId->Compare( aApplicationId ) ) &&
		   ( 0 == iBrandId->Compare( aBrandId ) ) &&
		   ( iLanguageId == aLanguageId ) )
			{
			// this event is for us 
			// complete the observer request from client
			if( iObserverActive )
				{
				iObserverMessage.Complete( KErrNone );
				iObserverActive = EFalse;
				}
			}
		}
	TRACE( T_LIT( "CBSSession::BrandUpdatedL end") );
	}


// ---------------------------------------------------------
// CBSSession::RemoveBrandL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::RemoveBrandL( const RMessage2& /*aMessage*/ )
	{
	TRACE( T_LIT( "CBSSession::RemoveBrandL begin") );
	if( !iInitialized || !iStorageManager )
		{
		User::Leave( KErrNotReady );
		}

	iStorageManager->RemoveBrandL( *iApplicationId, *iBrandId,
								   iLanguageId, iReserved );
	
	
	
	TRACE( T_LIT( "CBSSession::RemoveBrandL end") );
	}

// ---------------------------------------------------------
// CBSSession::RemoveApplicationL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CBSSession::RemoveApplicationL( const RMessage2& /*aMessage*/ )
	{
	TRACE( T_LIT( "CBSSession::RemoveApplicationL begin") );
	if( !iInitialized || !iStorageManager )
		{
		User::Leave( KErrNotReady );
		}
	iStorageManager->RemoveApplicationL( *iApplicationId );
	TRACE( T_LIT( "CBSSession::RemoveApplicationL end") );
	}
	
// ---------------------------------------------------------
// CBSSession::GetNewVersionL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//	
TInt CBSSession::GetNewVersionL()
	{
	if( !iStorageManager )
		{
		iStorageManager = CBSStorageManager::NewL( this, KNullDesC );
		}

	return iStorageManager->GetNewestVersionL( *iApplicationId, *iBrandId, iLanguageId );
	}
	

// CBSSessionInfo
CBSSession::CBSSessionInfo* CBSSession::CBSSessionInfo::NewL( const TDesC& aFileName, 
	    		                                              const TDesC& aCaption,
	    		                                              TThreadId aThreadId, 
	    		                                              TProcessId aProcessId )
	{
	CBSSessionInfo* self = new( ELeave ) CBSSessionInfo( aThreadId, aProcessId );
	CleanupStack::PushL( self );
	self->ConstructL( aFileName, aCaption );
	CleanupStack::Pop( self );
	return self;
	}
void CBSSession::CBSSessionInfo::ConstructL( const TDesC& aFileName, const TDesC& aCaption )
	{	
	iFileName = aFileName.AllocL();
	iCaption = aCaption.AllocL();
	}
CBSSession::CBSSessionInfo::CBSSessionInfo( TThreadId aThreadId, TProcessId aProcessId  )
: iThreadId( aThreadId ),
  iProcessId( aProcessId )
	{
	}
CBSSession::CBSSessionInfo::~CBSSessionInfo()
	{
	delete iFileName;
	delete iCaption;
	}

const TDesC& CBSSession::CBSSessionInfo::FileName()
	{
	return *iFileName;
	}
const TDesC& CBSSession::CBSSessionInfo::Caption()
	{
	return *iCaption;
	}

TThreadId CBSSession::CBSSessionInfo::ThreadId()
	{
	return iThreadId;
	}
TProcessId CBSSession::CBSSessionInfo::ProcessId()
	{
	return iProcessId;
	}


// ---------------------------------------------------------------------------
// CBSSession::ExtractInfoL
// Extracts some information from the specified RMessage2 and saves it.
// ---------------------------------------------------------------------------
//
void CBSSession::ExtractInfoL( const RMessage2& aMessage )
    {
	TRACE( T_LIT( "CBSSession::ExtractInfoL begin") );
	//Collect all necessary data
	RThread thread;
	TInt getProcessErr,getClientThreadErr;
	getClientThreadErr = aMessage.Client( thread );
	CleanupClosePushL( thread );
    
	if ( KErrNone == getClientThreadErr )
	    {
	    TRACE( T_LIT( "CBSSession::ExtractInfoL Client retrieved OK") );
	    TThreadId threadId = thread.Id();
	    RProcess process;
	    getProcessErr = thread.Process( process );
	    CleanupClosePushL( process );
	    if ( getProcessErr == KErrNone )
	        {
	        TRACE( T_LIT( "CBSSession::ExtractInfoL Processfilename retrieved OK") );
	        TFileName fileName = process.FileName();	        
	        TParsePtrC parser( fileName );	        
	        TPtrC processFileNameAndExt( parser.NameAndExt() );
	        
	        RApaLsSession session;
	        TInt connectErr = session.Connect();
	        User :: LeaveIfError (connectErr);
	        session.GetAllApps();	        
	        CleanupClosePushL( session );
	        
	        TApaAppInfo info;	        
	        TPtrC captionPtr( KNullDesC );
	        TPtrC printCaptionPtr( KNullDesC );
	        TPtrC fullName( KNullDesC );
	        while ( KErrNone == session.GetNextApp( info ) )
	            {
	            fullName.Set( info.iFullName );
	            printCaptionPtr.Set( info.iCaption );	            
	            if( KErrNotFound != fullName.Find( processFileNameAndExt ) )
	                {	                
	                captionPtr.Set( info.iCaption );
	                TRACE( T_LIT( "CBSSession::ExtractInfoL caption saved: %S"),&captionPtr );
	                break;
	                }	            
	            }	        
	        
	        CBSSessionInfo* temp = 
	            CBSSessionInfo::NewL( processFileNameAndExt,
	                                  captionPtr,
	                                  threadId, 
	                                  process.Id() );
	        TRACE( T_LIT( "CBSSession::ExtractInfoL SessionInfo object creation OK") );
	        delete iSessionInfo;
	        iSessionInfo = NULL;
	        iSessionInfo = temp;	        
	        CleanupStack::PopAndDestroy( &session );
	        }
	    CleanupStack::PopAndDestroy( &process );
	    }    
    CleanupStack::PopAndDestroy( &thread );    
    TRACE( T_LIT( "CBSSession::ExtractInfoL end") );
    }


// ---------------------------------------------------------------------------
// CBSSession::FileName
// ---------------------------------------------------------------------------
//
const TDesC& CBSSession::FileName()
	{
	TRACE( T_LIT( "CBSSession::FileName begin") );
	if ( iSessionInfo )
	    {
	    TRACE( T_LIT( "CBSSession::FileName SessionInfo exists") );
	    return iSessionInfo->FileName();
	    }
	else
	    {
	    TRACE( T_LIT( "CBSSession::FileName SessionInfo does not exist") );
	    return KNullDesC;
	    }
	}

// ---------------------------------------------------------------------------
// CBSSession::Caption
// ---------------------------------------------------------------------------
//	
const TDesC& CBSSession::Caption()
	{
	TRACE( T_LIT( "CBSSession::Caption begin") );
	if ( iSessionInfo )
	    {
	    TRACE( T_LIT( "CBSSession::Caption SessionInfo exists") );
	    return iSessionInfo->Caption();
	    }
	else
	    {
	    TRACE( T_LIT( "CBSSession::Caption SessionInfo does not exist") );
	    return KNullDesC;
	    }
	}	


// ---------------------------------------------------------------------------
// CBSSession::ThreadId
// ---------------------------------------------------------------------------
//		
TInt CBSSession::ThreadId( TThreadId& aThreadId )
	{
	TRACE( T_LIT( "CBSSession::ThreadId begin") );
	TInt err( KErrNotFound );
	if ( iSessionInfo )
	    {	    
	    TRACE( T_LIT( "CBSSession::ThreadId SessionInfo exists") );
	    aThreadId = iSessionInfo->ThreadId();
	    err = KErrNone;
	    }
	return err;
	}


// ---------------------------------------------------------------------------
// CBSSession::ProcessId
// ---------------------------------------------------------------------------
//	
TInt CBSSession::ProcessId( TProcessId& aProcessId )
	{
	TRACE( T_LIT( "CBSSession::ProcessId begin") );
	TInt err( KErrNotFound );
	if ( iSessionInfo )
	    {	    
	    TRACE( T_LIT( "CBSSession::ProcessId SessionInfo exists") );
	    aProcessId = iSessionInfo->ProcessId();
	    err = KErrNone;
	    }
	return err;
	}


// ---------------------------------------------------------------------------
// CBSSession::InfoAvailable
// ---------------------------------------------------------------------------
//	
TBool CBSSession::InfoAvailable()
    {
    return iSessionInfo ? ETrue : EFalse;
    }

// END OF FILE