/*
* 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 "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:  Message store session implementation.
*
*/



// ========
// INCLUDES
// ========

#include "msgstoretypes.h"
#include "msgstorepropertykeys.h"

#include "MessageStoreSession.h"
#include "MessageStoreServer.h"
#include "ContainerStore.h"
#include "PropertiesSerializer.h"
#include "ContainerStoreMRUAddressTable.h"
#include "bufferedmessagecreator.h"


// =========
// CONSTANTS
// =========

// The maximum number of observer events that will be queued up for a single session.
const TInt KMsgStoreMaximumEventQueueDepth = 100;
const TInt KInitialAddressBufSize          = 256;
const TInt KSortedArrayGranularity         = 100;

const TUint KValThree = 3;
const TUint KGranularity25 = 25;
const TUint KGranularity15 = 15;

// ======================
// CLASS CSearchResult
// ======================
// ==========================================================================
// FUNCTION: NewL
// ==========================================================================
CSearchResult* CSearchResult::NewL( TContainerId aMessageId, TContainerId aFolderId, const TDesC8& aPropertyBuf )
    {
    CSearchResult* self = new(ELeave) CSearchResult( aMessageId, aFolderId );
    CleanupStack::PushL( self );
    self->ConstructL( aPropertyBuf );
    CleanupStack::Pop( self );
    return self;
    }

CSearchResult* CSearchResult::SearchCompleteResultL()
    {
    return NewL( KContainerInvalidId, KContainerInvalidId, KNullDesC8 );
    }

// ==========================================================================
// FUNCTION: Constructor
// ==========================================================================
CSearchResult::CSearchResult( TContainerId aMessageId, TContainerId aFolderId )
    : iMessageId( aMessageId ), iFolderId( aFolderId )
    {
    }

// ==========================================================================
// FUNCTION: ConstructL
// ==========================================================================
void CSearchResult::ConstructL( const TDesC8& aPropertyBuf )
    {
    iPropertyBuf.Create( aPropertyBuf );
    }

// ==========================================================================
// FUNCTION: Destructor
// ==========================================================================
CSearchResult::~CSearchResult()
    {
    iPropertyBuf.Close();
    }
        

// ==========================
// CLASS CMessageStoreSession
// ==========================
// ==========================================================================
// FUNCTION: Constructor
// ==========================================================================
CMessageStoreSession::CMessageStoreSession(CMessageStoreServer& aMessageStoreServer) : 
	iServer(aMessageStoreServer),
	iIds( KGranularity25 ),
	iEventQueue( KGranularity15 ),
    iSearchHandler( NULL )
    {
  	__LOG_CONSTRUCT( "msg", "CMessageStoreSession" )
  	}

// ==========================================================================
// FUNCTION: CreateL
// ==========================================================================
void CMessageStoreSession::CreateL()
    {
    __LOG_ENTER( "CreateL" )
    
    iServer.AddSession( this );

    // This could leave if a session is created while the store is unavailable.
    TRAP_IGNORE( iServer.MessageStoreL().ObserveL( this ) );
    
    __LOG_EXIT
    } // end CreateL

// ==========================================================================
// FUNCTION: Destructor
// ==========================================================================
CMessageStoreSession::~CMessageStoreSession()	
	{
    delete iBufferedMessageCreator;
    
	iIds.Reset();
	
    iMruAddressArray.ResetAndDestroy();
    
	iPropertyNames.ResetAndDestroy();
    
	iMatchMessages.ResetAndDestroy();
    
    iSearchStrings.ResetAndDestroy();
	
	delete iSearchHandler;
	
	TRAP_IGNORE( iServer.MessageStoreL().StopObserving( this ) );
	
	//close all the sort iterators when the client exits/crashes
	for ( TInt i = 0 ; i < iSortSessionIds.Count(); i++  )
	    {
	    TRAP_IGNORE( iServer.MessageStoreL().EndSortingL( iSortSessionIds[i] ) );
	    }
	iSortSessionIds.Close();

	iEventQueue.Close();

	if( !iObserverMessage.IsNull() )
		{
		iObserverMessage.Complete( KErrCancel );
		} // end if

	if( !iGetMatchesMessage.IsNull() )
		{
		iGetMatchesMessage.Complete( KErrCancel );
		} // end if

	iServer.DropSession( this );

	__LOG_DESTRUCT
	} // end destructor

// ==========================================================================
// FUNCTION:ServiceL
// ==========================================================================
void CMessageStoreSession::ServiceL(const RMessage2& aMessage)
  {
  __LOG_ENTER_SUPPRESS( "ServiceL" )
  __LOG_WRITE8_FORMAT1_INFO( "%d", aMessage.Function() )

  // Call the appropriate message handler function, based on the message function ID.
  switch( aMessage.Function() )
    {
	case EMsgStoreCmdAuthenticated:
		DoAuthenticatedL( aMessage );
		break;
        
	case EMsgStoreCmdAuthenticate:
		DoAuthenticateL( aMessage );
		break;
        
	case EMsgStoreCmdClearAuthentication:
		DoClearAuthenticationL( aMessage );
		break;
        
	case EMsgStoreCmdHasPassword:
		DoHasPasswordL( aMessage );
		break;
        
	case EMsgStoreCmdSetPassword:
		DoSetPasswordL( aMessage );
		break;
        
	case EMsgStoreCmdChangePassword:
		DoChangePasswordL( aMessage );
		break;
        
    case EMsgStoreCmdEnableEncryption:
        DoEnableEncryptionL( aMessage );
        break;
        
    case EMsgStoreCmdDisableEncryption:
        DoDisableEncryptionL( aMessage );
        break;
        
	case EMsgStoreCmdWipeEverything:
		DoWipeEverythingL( aMessage );
		break;
        
    case EMsgStoreCmdStartObserving:
		DoStartObserving( aMessage );
		break;
        
    case EMsgStoreCmdGetEvents:
		DoGetEventsL( aMessage );
		break;
        
    case EMsgStoreCmdStopObserving:	
		DoStopObserving( aMessage );
		break;
		
    case EMsgStoreCmdCreateAccount:	
    	DoCreateAccountL( aMessage );
    	break;
    	
    case EMsgStoreCmdOpenAccount:	
		DoOpenAccountL( aMessage );
		break;
		
    case EMsgStoreCmdDeleteAccount:	
		DoDeleteAccountL( aMessage );
		break;
		
    case EMsgStoreCmdRenameAccount:	
		DoRenameAccountL( aMessage );
		break;
		
    case EMsgStoreCmdListAccounts:	
		DoListAccountsL( aMessage );
		break;
    
    case EMsgStoreCmdCreateContainer:
		DoCreateContainerL( aMessage );
		break;
        
    case EMsgStoreCmdCommitContainer:
		DoCommitContainerL( aMessage );
		break;
        
    case EMsgStoreCmdAbandonContainer:
		DoAbandonContainerL( aMessage );
		break;
        
    case EMsgStoreCmdMoveContainer:
		DoMoveContainerL( aMessage );
		break;
        
    case EMsgStoreCmdCopyContainer:
		DoCopyContainerL( aMessage );
		break;
        
	case EMsgStoreCmdDeleteContainer:
		DoDeleteContainerL( aMessage );
		break;
        
	case EMsgStoreCmdChildrenCounts:
		DoChildrenCountsL( aMessage );
		break;
        
	case EMsgStoreCmdTotalCounts:
		DoTotalCountsL( aMessage );
		break;
        
    case EMsgStoreCmdChildrenIds:
		DoChildrenIdsL( aMessage );
		break;
        
    case EMsgStoreCmdPropertiesList:
		DoPropertiesListL( aMessage );
		break;
        
	case EMsgStoreCmdFetchProperties:
		DoFetchPropertiesL( aMessage );
		break;
        
	case EMsgStoreCmdUpdateProperties:
		DoUpdatePropertiesL( aMessage );
		break;
        
	case EMsgStoreCmdUpdateProperty:
		DoUpdatePropertyL( aMessage );
		break;
        
    case EMsgStoreCmdContentLength:
		DoContentLengthL( aMessage );
		break;
        
    case EMsgStoreCmdFetchContentToBuffer:
		DoFetchContentToBufferL( aMessage );
		break;
        
    case EMsgStoreCmdFetchContentToFile:
		DoFetchContentToFileL( aMessage );
		break;
        
    case EMsgStoreCmdReplaceContentWithBuffer:
		DoReplaceContentWithBufferL( aMessage );
		break;
        
    case EMsgStoreCmdReplaceContentWithFile:
		DoReplaceContentWithFileL( aMessage );
		break;
        
    case EMsgStoreCmdAppendToContent:
        DoAppendToContentL( aMessage );
		break;
        
    case EMsgStoreCmdPrependToContent:
        DoPrependToContentL( aMessage );
        break;

    case EMsgStoreCmdRemoveContent:
		DoRemoveContentL( aMessage );
		break;
        
    case EMsgStoreCmdOpenContentFile:
        DoOpenContentFileL( aMessage );
        break;
        
    case EMsgStoreCmdPrepareSearch:
		DoPrepareSearchL( aMessage );
		break;
        
    case EMsgStoreCmdGetMatches:
		DoGetMatches( aMessage );
		break;
        
    case EMsgStoreCmdCancelSearch:
		DoCancelSearch( aMessage );
		break;
        
    case EMsgStoreCmdClearSearchResultCache:
        DoClearSearchResultCache( aMessage );
        break;
        
    case EMsgStoreCmdStartSorting:
        DoStartSortingL( aMessage );
        break;
        
    case EMsgStoreCmdEndSorting:
        DoEndSortingL( aMessage );
        break;
        
    case EMsgStoreCmdGetSortedRows:
        DoGetSortedRowsL( aMessage );
        break;
        
    case EMsgStoreCmdGetIteratorGroupCount:
        DoGetIteratorGroupCountL( aMessage );
        break;

    case EMsgStoreCmdGetIteratorIdsAndFlags:
        DoGetSortedIdsAndFlagsL( aMessage );
        break;
    
    case EMsgStoreCmdSortedIndexOf:
        DoGetSortedIndexOfL( aMessage );
        break;

    case EMsgStoreCmdGetIteratorIds:
        DoGetSortedIdsL( aMessage );
        break;
        
    case EMsgStoreCmdGetIteratorIdsAndGroupCount:
        DoGetSortedIdsAndGroupCountL( aMessage );
        break;
        
    case EMsgStoreCmdSetMaxMruAddressCount:
        DoSetMaxMruAdressCountL( aMessage );
        break;
        
    case EMsgStoreCmdSetMruAddressList:
        DoSetMruAddressListL( aMessage );
        break;
        
    case EMsgStoreCmdGetMruAddressList:
        DoGetMruAddressListL( aMessage );
        break;
        
    case EMsgStoreCmdBeginBatchInsert:
        DoBeginBatchInsertL( aMessage );
        break;

    case EMsgStoreCmdFinishBatchInsert:
        DoFinishBatchInsertL( aMessage );
        break;

#ifdef _DEBUG
        
    case EMsgStoreCmdInjectBackupRestoreEvent:
        DoInjectBackupRestoreEventL( aMessage );
        break;
    case EMsgStoreCmdInjectPointSecEvent:
        DoInjectPointSecEvent( aMessage );
        break;
    case EMsgStoreCmdSimulateLowDiskSpace:
        DoSimulateLowDiskSpaceL( aMessage );
        break;
    case EMsgStoreCmdGetEncryptionState:
        DoGetEncryptionStateL( aMessage );
        break;
    case EMsgStoreCmdShutdownServer:
        DoShutdownServer( aMessage );
        break;
    
#endif  
        
    default:
      __LOG_WRITE_ERROR( "Illegal function!" )
      PanicClient( aMessage, EPanicIllegalFunction );
      break;
    } // end switch
       
  __LOG_EXIT    
  } // end ServiceL

// ==========================================================================
// FUNCTION: ServiceError
// ==========================================================================
void CMessageStoreSession::ServiceError(const RMessage2& aMessage, TInt aError)
  {
  __LOG_ENTER_SUPPRESS( "ServiceError" )
  __LOG_WRITE8_FORMAT1_ERROR( "ServiceError %d", aError)
  CSession2::ServiceError( aMessage, aError );
  } // end ServiceError

// ==========================================================================
// FUNCTION: ContainerStoreUnavailable
// ==========================================================================
void CMessageStoreSession::ContainerStoreUnavailable()
	{
    // Cancel any ongoing searches.
    delete iSearchHandler;
    iSearchHandler = NULL;
    iMatchMessages.ResetAndDestroy();    
    
	TRAP_IGNORE( iServer.MessageStoreL().StopObserving( this ) );
	} // end ContainerStoreUnavailable

// ==========================================================================
// FUNCTION: ContainerStoreAvailable
// ==========================================================================
void CMessageStoreSession::ContainerStoreAvailable()
	{
	TRAP_IGNORE( iServer.MessageStoreL().ObserveL( this ) );
	} // end ContainerStoreAvailable

// ----------------------
// OBSERVER FUNCTIONALITY
// ----------------------

// ==========================================================================
// FUNCTION: DoStartObserving
// ==========================================================================
void CMessageStoreSession::DoStartObserving( const RMessage2& aMessage )
	{
	iIsObserving = ETrue;
	
	aMessage.Complete( KErrNone );
	} // end DoStartObserving
	
// ==========================================================================
// FUNCTION: DoStopObserving
// ==========================================================================
void CMessageStoreSession::DoStopObserving( const RMessage2& aMessage )
	{
	iIsObserving = EFalse;
	
	iEventQueue.Reset();
	
	if( !iObserverMessage.IsNull() )
		{
		iObserverMessage.Complete( KErrCancel );
		} // end if
		
	aMessage.Complete( KErrNone );
	} // end DoStopObserving
	
// ==========================================================================
// FUNCTION: DoCreateAccountL
// ==========================================================================
void CMessageStoreSession::DoCreateAccountL( const RMessage2& aMessage )
	{
	TInt32 ownerId = aMessage.Int1();

    RBuf name;    
    CleanupClosePushL( name );
    name.CreateL( aMessage.GetDesLengthL( 2 ) );
    
	aMessage.ReadL( 2, name );
	
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );
	propertiesBuf.CreateL( aMessage.GetDesLengthL( KValThree ) );
	aMessage.ReadL( KValThree, propertiesBuf );
	
	TContainerId mbId = iServer.MessageStoreL().CreateAccountL( ownerId, name, this, propertiesBuf );
	
    TPckg<TContainerId> mbIdPckg( mbId );
	aMessage.WriteL( 0, mbIdPckg );
	
	CleanupStack::PopAndDestroy( &propertiesBuf );
	CleanupStack::PopAndDestroy( &name );
	
    aMessage.Complete( KErrNone );
	}

// ==========================================================================
// FUNCTION: DoOpenAccountL
// ==========================================================================
void CMessageStoreSession::DoOpenAccountL( const RMessage2& aMessage )
	{
	__LOG_ENTER_SUPPRESS("DoOpenAccountL")
	
	//parameter 0 - result
	TUint result;
	TPckg<TUint> resultPckg( result );
	
    //parameter 1 - params
	TMsgStoreOpenAccountCmdParams params;
    TPckg<TMsgStoreOpenAccountCmdParams> paramsPckg( params );
	aMessage.ReadL( 1, paramsPckg );
	
	TInt32 ownerId = params.iOwnerId;
	
	//parameter 2 - account anme
    RBuf name;    
    CleanupClosePushL( name );
    name.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, name );
	
	//parameter 3 - property buf
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );
	
	params.iMailBoxId = iServer.MessageStoreL().OpenAccountL( ownerId, name, propertiesBuf );
	
	if( propertiesBuf.Length() > aMessage.GetDesMaxLengthL( KValThree ) )
	    {
	    // Overflow!
	    __LOG_WRITE8_FORMAT1_ERROR( "property buffer too long (%i)", propertiesBuf.Length() );
	    
	    // Write the required length to the result parameter, to indicate to the client that the
	    // buffer must be increased to the given size.
	    result = propertiesBuf.Length();
	    aMessage.WriteL( 0, resultPckg );	    
	    }
	else
	    {	    	
        result = 0;
	    aMessage.WriteL( 0, resultPckg );
	    
 	    aMessage.WriteL( 1, paramsPckg );

        aMessage.WriteL( KValThree, propertiesBuf );

	    } // end if
	
	CleanupStack::PopAndDestroy( &propertiesBuf );
	CleanupStack::PopAndDestroy( &name );
	
    aMessage.Complete( KErrNone );
	}

// ==========================================================================
// FUNCTION: DoRenameAccountL
// ==========================================================================
void CMessageStoreSession::DoRenameAccountL( const RMessage2& aMessage )
	{
	TInt32 ownerId = aMessage.Int0();

    RBuf oldName;    
    CleanupClosePushL( oldName );
    oldName.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, oldName );
	
    RBuf newName;    
    CleanupClosePushL( newName );
    newName.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, newName );
	
	iServer.MessageStoreL().RenameAccountL( ownerId, oldName, newName, this );
	
	CleanupStack::PopAndDestroy( &newName );
	CleanupStack::PopAndDestroy( &oldName );
	
    aMessage.Complete( KErrNone );
	}

// ==========================================================================
// FUNCTION: DoDeleteAccountL
// ==========================================================================
void CMessageStoreSession::DoDeleteAccountL( const RMessage2& aMessage )
	{
	TInt32 ownerId = aMessage.Int0();

    RBuf name;    
    CleanupClosePushL( name );
    name.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, name );
	
	iServer.MessageStoreL().DeleteAccountL( ownerId, name, this );
	
	CleanupStack::PopAndDestroy( &name );
	
    aMessage.Complete( KErrNone );
	}

// ==========================================================================
// FUNCTION: DoListAccountsL
// ==========================================================================
void CMessageStoreSession::DoListAccountsL( const RMessage2& aMessage )
	{
    RBuf8 resultBuf;
    CleanupClosePushL( resultBuf );
    resultBuf.CreateL( aMessage.GetDesMaxLength(0) );
    
    iServer.MessageStoreL().ListAccountsL( resultBuf );
    
    aMessage.WriteL( 0, resultBuf );
    
	CleanupStack::PopAndDestroy( &resultBuf );
	
    aMessage.Complete( KErrNone );
	}

// ==========================================================================
// FUNCTION: DoGetEventsL
// ==========================================================================
void CMessageStoreSession::DoGetEventsL( const RMessage2& aMessage )
	{
	// If there are any queued events then send them right away, otherwise
	// save the message until events become avaialable.
	if( iEventQueue.Count() > 0 )
		{
        TUint desLength = aMessage.GetDesMaxLengthL( 0 );
        
        TUint position = 0;
        
        while( iEventQueue.Count() > 0 && position < desLength )
            {
            TPckg<TMsgStoreEvent> eventPckg( iEventQueue[0] );
			aMessage.WriteL( 0, eventPckg, position );
            
            position += sizeof( TMsgStoreEvent );
            iEventQueue.Remove( 0 );		
            } // end while
            
        aMessage.Complete( KErrNone );
	    }
	else
	    {
	    iObserverMessage = aMessage;
		} // end if	
		
	} // end DoGetEventsL
	
// ==========================================================================
// FUNCTION: SendEventToObserver
// ==========================================================================
void CMessageStoreSession::SendEventToObserver( TMsgStoreEvent aEvent )
	{
	__LOG_ENTER( "SendEventToObserver" )
	
	// If there is no observer message pending then queue up the message,
	// otherwise send it immediately.
	
	if( iObserverMessage.IsNull() )
		{
		if( iEventQueue.Count() > KMsgStoreMaximumEventQueueDepth )
		    {
		    __LOG_WRITE_ERROR( "EVENT QUEUE OVERFLOW" );
		    iEventQueue.Reset();
		    
        	TMsgStoreEvent event;
        	event.iType        = EObserverEventQueueOverflow;
        	event.iId          = KMsgStoreInvalidId;
        	event.iParentId    = KMsgStoreInvalidId;
        	event.iOtherId     = KMsgStoreInvalidId;
        	event.iFlags       = KMsgStoreFlagsNotFound;

    		iEventQueue.Append( event );		
		    }
		else
		    {
    		__LOG_WRITE_INFO( "event queued" )
    		iEventQueue.Append( aEvent );		
		    } // end if		
		}
	else
		{
		__LOG_WRITE_INFO( "Sending event now" )
		
		TPckg<TMsgStoreEvent> eventPckg( aEvent );
					
		TRAPD( result, iObserverMessage.WriteL( 0, eventPckg ) );			
		
		iObserverMessage.Complete( result );
		} // end if	
		
    __LOG_EXIT		
	} // end SendEventToObserver

// ==========================================================================
// FUNCTION: ContainerModified
// ==========================================================================
void CMessageStoreSession::ContainerModified( 
        TOperation aOperation, 
        const RArray<TContainerId>& aHierarchy, 
        TContainerId aNewParentId, 
        const TDesC8& aQuickProperties )
	{
	// If the children IDs array is not empty then a series of EMsgStoreCmdChildrenProperties
	// messages are in progress, and a modified container could affect the data being streamed.
	
	if( iIds.Count() > 0 )
	    {
        // The following event types could affect the properties that are being streamed to the client.
        // Reset the ID list to indicate that the streaming operation should be restarted.
        	
	    if ( ( iUsingQuery ) && ( aHierarchy.Count() > 1 ) ) 
	        {	        
	        // If this is a query based list then the current change only affects the list if the
	        // query was for all types or if the type match.
	        if( (iQueryParams.iType == KContainerTypeAny) || (iQueryParams.iType == (aHierarchy[0] & KContainerTypeMask )) )
	            {	            
            	switch( aOperation )
            		{
            		case EAdd:
            		case EMove:
             		case EDelete:
            		case EUpdateProperties:
            
                        // The current change only affects the list if the query was recursive or
                        // if the modified container has the same parent as used in the query.
            		    if( iQueryParams.iRecursive || (iQueryParams.iId == aHierarchy[1]) )
            		        {
            		        iIds.Reset();
            		        } // end if
                        break;
                            		        
            		} // end switch
            		
	            } // end if
	        }
	    else
	        {	        
   	        // Only deletes and property updates can affect the provided list of IDs.  Adds and
	        // moves do not affect this operation.
        	switch( aOperation )
        		{
         		case EDelete:
        		case EUpdateProperties:
        		
                    iIds.Reset();
                    break;
                        		        
           		} // end switch
           		
	        } // end if
    		
	    } // end if	    
	
	// If the client session is currently observing then create an observer event.
	
	if( iIsObserving )
	    {	    
    	TMsgStoreEvent event;

    	switch( aOperation )
    		{
    		case EAdd:
    		    event.iType = EMsgStoreAdd;
    			break;
    		case EMove:
    		    event.iType = EMsgStoreMove;
    			break;
    		case EDelete:
    			event.iType = EMsgStoreDelete;
    			break;
    		case EUpdateProperties:
    			event.iType = EMsgStoreUpdateProperties;
    			break;
    		case EUpdateContent:
    			event.iType = EMsgStoreUpdateContent;
    			break;
    		case ERemoveContent:
    			event.iType = EMsgStoreRemoveContent;
    			break;
    		default:
    		    // This shouldn't happen.
    		    event.iType = 0;
    		    break;    		    
    		} // end switch
    		
    	event.iId = aHierarchy[0];
    	
    	if( aHierarchy.Count() > 1 )
    	    {    	    
    	    event.iParentId = aHierarchy[1];
    	    }
    	else
    	    {
    	    event.iParentId = KContainerInvalidId;
    	    } // end if
    	        	
	    if( aNewParentId != KContainerInvalidId )
	        {
	        // Use the new parent Id for the "other" id.
	        event.iOtherId = aNewParentId;	        
	        }
	    else if( aHierarchy.Count() > 2 )
	        {
	        // Use the grandparent ID for the "other" ID.
	        event.iOtherId = aHierarchy[2];
	        }
	    else
	        {
	        event.iOtherId = KContainerInvalidId;
	        } // end if
	    
	    //Get the MailBoxId from the buttom of the Hierarchy
	    if ( aHierarchy.Count() > 1 )
	    	{
	    	event.iMailBoxId = aHierarchy[ aHierarchy.Count() - 2 ];
	    	}
	    else
	    	{
	    	//this should not happen
	    	event.iMailBoxId = KContainerInvalidId;
	    	}
    	        	
        // Find the value of the flags property.

    	event.iFlags = KMsgStoreFlagsNotFound;
        if( aQuickProperties.Length() > 0 )
            {
            TPropertiesDeserializer deserializer( aQuickProperties );
            
            if( deserializer.Find( KMsgStorePropertyFlags ) && deserializer.Type() == EMsgStoreTypeUint32 )
                {
    			TPckgBuf<TUint32> flagsPckg;
    			flagsPckg.Copy( deserializer.Value() );

                event.iFlags = flagsPckg();                    
    			} // end if

            } // end if
        
        //initialize the names which are not used
        event.iAccountName.SetLength( 0 );
        event.iNewAccountName.SetLength( 0 );

    	SendEventToObserver( event );    	
    	
	    } // end if
	    
	} // end ContainerModified
	
// ==========================================================================
// FUNCTION: AuthenticationChanged
// ==========================================================================
void CMessageStoreSession::AuthenticationChanged( TBool aAuthenticated )
    {
    if( iIsObserving )
        {            
    	TMsgStoreEvent event;

    	if( aAuthenticated )
    	    {
    	    event.iType = EMsgStoreAuthenticated;
    	    }
    	else
    	    {
    	    event.iType = EMsgStoreNotAuthenticated;
    	    } // end if

    	event.iMailBoxId   = KMsgStoreInvalidId;
    	event.iId          = KMsgStoreInvalidId;
    	event.iParentId    = KMsgStoreInvalidId;
    	event.iOtherId     = KMsgStoreInvalidId;
    	event.iFlags       = KMsgStoreFlagsNotFound;
    	
        //initialize the names which are not used
        event.iAccountName.SetLength( 0 );
        event.iNewAccountName.SetLength( 0 );
    	
    	SendEventToObserver( event );
        } // end if
        
    } // end AuthenticationChanged

// ==========================================================================
// FUNCTION: AccountModified
// ==========================================================================
void CMessageStoreSession::AccountModified( TOperation aOperation, TInt32 aOwnerId, const TDesC8& aName, const TDesC8& aNewName, TContainerId aMailboxId )
	{
    if( iIsObserving )
        {            
    	TMsgStoreEvent event;
    	
    	switch( aOperation )
		{
		case EAdd:
		    event.iType = EMsgStoreAccountCreated;
			break;
		case EDelete:
			event.iType = EMsgStoreAccountDeleted;
			break;
		case ERenameAccount:
			event.iType = EMsgStoreAccountRenamed;
			break;
		default:
		    // This shouldn't happen.
		    event.iType = 0;
		    break;    		    
		} // end switch

    	event.iMailBoxId   = aMailboxId;
    	event.iId          = aOwnerId;
    	event.iParentId    = KMsgStoreInvalidId;
    	event.iOtherId     = KMsgStoreInvalidId;
    	event.iFlags       = KMsgStoreFlagsNotFound;
    	
        //initialize the names which are not used
        event.iAccountName.Copy( aName );
        event.iNewAccountName.Copy( aNewName );
    	
    	SendEventToObserver( event );
        } // end if
	
	}


// --------------------    	
// SEARCH FUNCTIONALITY
// -------------------- 
    
// ==========================================================================
// FUNCTION: DoPrepareSearchL
// ==========================================================================
void CMessageStoreSession::DoPrepareSearchL( const RMessage2& aMessage )
    {
    //param 0 (search cmd param)
    TMsgStoreSearchCmdParams params;   
    TPckg<TMsgStoreSearchCmdParams> paramsPckg( params );
    aMessage.ReadL( 0, paramsPckg );

    //param 1 (search string)
    ReadString16ArrayL( aMessage, 1, iSearchStrings );
    
    //param 2 (folder IDs)
    ReadIdArrayL( aMessage, 2, iIds );

    //param 3 (property keys)
    // Deserialize the property names list.
    ReadString8ArrayL( aMessage, KValThree, iPropertyNames );
    
	iMatchMessages.ResetAndDestroy();
    
    if ( iSearchHandler )
        {
        if ( iSearchHandler->IsSameSearchCriteriaL( iSearchStrings ) )
            {
            iSearchHandler->RestartL( params, iIds, iPropertyNames );
            }
        else
            {
            delete iSearchHandler;
            iSearchHandler = NULL;
            }
        }
    
    if ( !iSearchHandler )
        {
        // Create an asynchronous search handler and start it.
        iSearchHandler = iServer.MessageStoreL().SearchL( EMsgStoreMessageBits, params, iSearchStrings, iIds, iPropertyNames, *this );        
    	iSearchHandler->StartL();
        }
	
    aMessage.Complete( KErrNone );
    } // end DoPrepareSearchL
    
// ==========================================================================
// FUNCTION: DoGetMatchesL
// ==========================================================================
void CMessageStoreSession::DoGetMatches( const RMessage2& aMessage )
    {
    // TIpcArgs( &aMatchBuffer )
    
    iGetMatchesMessage = aMessage;
    
    // Always send the search results if the search has completed, even if there are not results found.
    // The end of the search is indicated by a null search handler pointer.
    TBool searchInProgress = EFalse;
    if ( iSearchHandler )
        {
        searchInProgress = iSearchHandler->IsSearchInProgress();
        }
    
    SendMatchesToClient( !searchInProgress );        
    }
    
// ==========================================================================
// FUNCTION: DoCancelSearch
// ==========================================================================
void CMessageStoreSession::DoCancelSearch( const RMessage2& aMessage )
    {
    iMatchMessages.ResetAndDestroy();
    
    if( iSearchHandler )
        {     
        //do not delete the search handler
        iSearchHandler->CancelSearch();
        } // end if
        
    if( !iGetMatchesMessage.IsNull() )
        {
        iGetMatchesMessage.Complete( KErrCancel );
        } // end if
    
    iMatchMessages.ResetAndDestroy();
    	
	aMessage.Complete( KErrNone );
    } // end DoCancelSearch

// ==========================================================================
// FUNCTION: DoClearSearchResultCache
// ==========================================================================
void CMessageStoreSession::DoClearSearchResultCache( const RMessage2& aMessage )
    {
    delete iSearchHandler;
    iSearchHandler = NULL;
    
    aMessage.Complete( KErrNone );
    }

// ==========================================================================
// FUNCTION: MatchFound
// ==========================================================================
void CMessageStoreSession::MatchFound( TContainerId aMessageId, TContainerId aFolderId, const TDesC8& aPropertyBuf )
    {
    TRAP_IGNORE( DoMatchFoundL( aMessageId, aFolderId, aPropertyBuf ) );
    } // end MatchFound

// ==========================================================================
// FUNCTION: DoMatchFoundL
// ==========================================================================
void CMessageStoreSession::DoMatchFoundL( TContainerId aMessageId, TContainerId aFolderId, const TDesC8& aPropertyBuf )
    {
    CSearchResult* result = CSearchResult::NewL( aMessageId, aFolderId, aPropertyBuf );
    iMatchMessages.Append( result );

    SendMatchesToClient();
    } // end MatchFound

// ==========================================================================
// FUNCTION: SearchComplete
// ==========================================================================
void CMessageStoreSession::SearchComplete( TInt /*aStatus*/ )
    {
    //do not delete the search handler
    
    // Always send the search results if the search has completed, even if there are not results found.
    SendMatchesToClient( ETrue );
    } // end SearchComplete
    
// ==========================================================================
// FUNCTION: SendMatchesToClientL
// ==========================================================================
void CMessageStoreSession::SendMatchesToClient( TBool aAlwaysSend )
    {
    // If there is a pending GetMatches message and either aAlwaysSend is true or matches were found
    // then build a nuffer of matching IDs and send to the client.
    
    if( !iGetMatchesMessage.IsNull() && (aAlwaysSend || iMatchMessages.Count() > 0 ) )
        {
        TRAPD( result, DoWriteMatchesToMessageL() );
        iGetMatchesMessage.Complete( result );
        } // end if

    } // end SendMatchesToClient
  
  
// ==========================================================================
// FUNCTION: DoWriteMatchesToMessageL
// ==========================================================================
void CMessageStoreSession::DoWriteMatchesToMessageL()
    {
    __LOG_ENTER_SUPPRESS( "DoWriteMatchesToMessageL" )
    
    TUint desLength = iGetMatchesMessage.GetDesMaxLengthL( 0 );        
    TUint offset = 0;
    
    TUint fixedLength = sizeof(TContainerId)*2 + sizeof(TUint);  //fixed size: 2 ids and a length
    
    TInt msgWritten = 0;
    
    while( iMatchMessages.Count() > 0 && offset < desLength )
        {
        CSearchResult* result = iMatchMessages[0];
        TUint length = result->PropertyBuf().Length();
	    TPckgBuf<TUint> lengthPkg( length );
        
        if ( desLength - offset >= fixedLength + length )
            {
            //write the message id
            TPckgBuf<TContainerId> idPkg( result->MessageId() );
            iGetMatchesMessage.WriteL( 0, idPkg, offset );
            offset += sizeof( TContainerId );
            
            //write the folder id
            TPckgBuf<TContainerId> folderIddPkg( result->FolderId() );
            iGetMatchesMessage.WriteL( 0, folderIddPkg, offset );
            offset += sizeof( TContainerId );

            //write the length
            iGetMatchesMessage.WriteL( 0, lengthPkg, offset );
            offset += sizeof( TUint );
            
            if ( length > 0 )
                {
                iGetMatchesMessage.WriteL( 0, result->PropertyBuf(), offset );
                offset += length;
                }
            delete result;
            iMatchMessages.Remove( 0 );
            msgWritten++;
            }
        else
            {
            if ( msgWritten == 0 )
                {
                __LOG_WRITE_ERROR("ERR: Client buffer size too small, not enough for even 1 message")
                User::Leave( KErrOverflow );
                }
            break;
            }
        } // end while
        
    } // end DoWriteMatchesToMessageL

// -------------------------
// MESSAGE HANDLER FUNCTIONS
// -------------------------

// ==========================================================================
// FUNCTION: DoAuthenticatedL
// ==========================================================================
void CMessageStoreSession::DoAuthenticatedL( const RMessage2& aMessage )
    {
    // TIpcArgs( &resultPckg )
    
    TBool authenticated = iServer.MessageStoreL().Authenticated();

    TPckg<TBool> authenticatedPckg( authenticated );
	aMessage.WriteL( 0, authenticatedPckg );
	
	aMessage.Complete( KErrNone );    
    } // end DoAuthenticatedL
    
// ==========================================================================
// FUNCTION: DoAuthenticateL
// ==========================================================================
void CMessageStoreSession::DoAuthenticateL( const RMessage2& aMessage )
    {
    // TIpcArgs( &resultPckg, &aPassword )
    
	RBuf password;
	CleanupClosePushL( password );
	password.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, password );
    
    TBool result = iServer.MessageStoreL().AuthenticateL( password );

    CleanupStack::PopAndDestroy( &password );

    TPckg<TBool> resultPckg( result );
	aMessage.WriteL( 0, resultPckg );

	aMessage.Complete( KErrNone );    
    } // end DoAuthenticateL
    
// ==========================================================================
// FUNCTION: DoClearAuthenticationL
// ==========================================================================
void CMessageStoreSession::DoClearAuthenticationL( const RMessage2& aMessage )
    {
    // No arguments
    
    iServer.MessageStoreL().ClearAuthentication();
    
	aMessage.Complete( KErrNone );    
    } // end DoClearAuthenticationL
    
// ==========================================================================
// FUNCTION: DoHasPasswordL
// ==========================================================================
void CMessageStoreSession::DoHasPasswordL( const RMessage2& aMessage )
    {
    // TIpcArgs( &resultPckg )
    
    TBool result = iServer.MessageStoreL().HasPasswordL();

    TPckg<TBool> resultPckg( result );
	aMessage.WriteL( 0, resultPckg );
	
	aMessage.Complete( KErrNone );    
    } // end DoHasPasswordL
    
// ==========================================================================
// FUNCTION: DoSetPasswordL
// ==========================================================================
void CMessageStoreSession::DoSetPasswordL( const RMessage2& aMessage )
    {
    // TIpcArgs( &aPassword )
    
	RBuf password;
	CleanupClosePushL( password );
	password.CreateL( aMessage.GetDesLengthL( 0 ) );
	aMessage.ReadL( 0, password );
    
    iServer.MessageStoreL().SetPasswordL( password );

    CleanupStack::PopAndDestroy( &password );

	aMessage.Complete( KErrNone );    
    } // end DoSetPasswordL

// ==========================================================================
// FUNCTION: DoChangePasswordL
// ==========================================================================
void CMessageStoreSession::DoChangePasswordL( const RMessage2& aMessage )
    {
    // TIpcArgs( &resultPckg, &aOldPassword, &aNewPassword )
    
	RBuf oldPassword;
	CleanupClosePushL( oldPassword );
	oldPassword.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, oldPassword );
    
	RBuf newPassword;
	CleanupClosePushL( newPassword );
	newPassword.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, newPassword );
    
    TBool result = iServer.MessageStoreL().ChangePasswordL( oldPassword, newPassword );

    CleanupStack::PopAndDestroy( &newPassword );
    CleanupStack::PopAndDestroy( &oldPassword );

    TPckg<TBool> resultPckg( result );
	aMessage.WriteL( 0, resultPckg );

	aMessage.Complete( KErrNone );    
    } // end DoChangePasswordL

// ==========================================================================
// FUNCTION: DoEnableEncryptionL
// ==========================================================================
void CMessageStoreSession::DoEnableEncryptionL( const RMessage2& aMessage )
    {
    iServer.MessageStoreL().EnableEncryptionL();
    
    aMessage.Complete( KErrNone );    
    }  // end DoEnableEncryptionL

// ==========================================================================
// FUNCTION: DoDisableEncryptionL
// ==========================================================================
void CMessageStoreSession::DoDisableEncryptionL( const RMessage2& aMessage )
    {
    iServer.MessageStoreL().DisableEncryptionL();
    
    aMessage.Complete( KErrNone );    
    } // end DoDisableEncryptionL

// ==========================================================================
// FUNCTION: DoWipeEverythingL
// ==========================================================================
void CMessageStoreSession::DoWipeEverythingL( const RMessage2& aMessage )
	{
	iServer.WipeEverythingL();
	
	aMessage.Complete( KErrNone );
	} // end DoWipeEverythingL

	
// ==========================================================================
// FUNCTION: DoCreateContainerL
// ==========================================================================
void CMessageStoreSession::DoCreateContainerL( const RMessage2& aMessage )
	{
	__LOG_ENTER( "DoCreateContainerL" )
	
	TMsgStoreCreateContainerCmdParams params;	
	TPckg<TMsgStoreCreateContainerCmdParams> paramsPckg( params );
	aMessage.ReadL( 0, paramsPckg );
	
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );
	propertiesBuf.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, propertiesBuf );
	
    RFile contentFile;
    CleanupClosePushL( contentFile );
    if( params.iHasContent )
        {        
	    User::LeaveIfError( contentFile.AdoptFromClient( aMessage, 2, KValThree ) );
	    }

    CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    TBool queued = creator.EnqueueL(
        iServer.MessageStoreL(), params, propertiesBuf );
    
    //if the operation is queued then all subsequent and related
    //CreateContainerL calls will be queued until the message container is
    //committed; "related" are any direct or indirect descendants of the message
    //container.
    
    if ( queued )
        {
        if( params.iHasContent )
            {
            TRAPD( err, creator.ReplaceContentL(
                iServer.MessageStoreL(), params.iId, contentFile ) );
            
            if ( KErrNone != err )
                {
                creator.ResetL( iServer.MessageStoreL() );
                User::Leave( err );
                }
            }    
        }
    else
        {
        params.iId = iServer.MessageStoreL().CreateContainerL( params.iType, 
                                                       params.iParentId, 
                                                       params.iGrandparentId, 
                                                       propertiesBuf );
    
        if( params.iHasContent )
            {
            TRAPD( result, iServer.MessageStoreL().ReplaceContentL( params.iId, 
                                                                params.iParentId, 
                                                                contentFile,
                                                                NULL ) );

            // Abandon the entire container if the content could not be written.
            if( result != KErrNone )
                {
                __LOG_WRITE_ERROR( "failed to add content" );
                iServer.MessageStoreL().AbandonContainerL( params.iId );
                User::Leave( result );
                }
            }

        if ( params.iCommitContainer )
            {
            iServer.MessageStoreL().CommitContainerL(
                params.iId, params.iParentId, params.iMailBoxId, this );
            }
        }
   
    CleanupStack::PopAndDestroy( &contentFile );
    // if queued the ownership was transferred to the message creator.
    queued ? CleanupStack::Pop( &propertiesBuf )
        : CleanupStack::PopAndDestroy( &propertiesBuf );
	
	aMessage.WriteL( 0, paramsPckg );
	aMessage.Complete( KErrNone );
	
	__LOG_EXIT
	} // end DoCreateContainerL

// ==========================================================================
// FUNCTION: DoCommitContainerL
// ==========================================================================
void CMessageStoreSession::DoCommitContainerL( const RMessage2& aMessage )
    {
	TMsgStoreId id = aMessage.Int0();
	TMsgStoreId destinationId = aMessage.Int1();
	TMsgStoreId mailBoxId = aMessage.Int2();

	CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
	if ( creator.IsContainerBuffered( id ) )
	    {
        creator.CommitMessageL( iServer.MessageStoreL(), this );
	    }
	else
	    {
        iServer.MessageStoreL().CommitContainerL(
            id, destinationId, mailBoxId, this );
	    }
	
    aMessage.Complete( KErrNone );
    } // end DoCommitContainerL

// ==========================================================================
// FUNCTION: DoAbandonContainerL
// ==========================================================================
void CMessageStoreSession::DoAbandonContainerL( const RMessage2& aMessage )
    {
    // TIpcArgs( aId )    
    
	TMsgStoreId id = aMessage.Int0();

	CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
	if ( creator.IsContainerBuffered( id ) )
        {
        creator.AbandonMessageL( iServer.MessageStoreL(), id );
        }
	else
	    {
        iServer.MessageStoreL().AbandonContainerL( id );
	    }
    
    aMessage.Complete( KErrNone );
    } // end DoAbandonContainerL

// ==========================================================================
// FUNCTION: DoMoveContainerL
// ==========================================================================
void CMessageStoreSession::DoMoveContainerL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aSourceId, aDestinationId )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId sourceId = aMessage.Int1();
	
	TMsgStoreId destinationId = aMessage.Int2();

	iServer.MessageStoreL().MoveContainerL( id, sourceId, destinationId, this );
	
	aMessage.Complete( KErrNone );	
	} // end DoMoveContainerL
	
// ==========================================================================
// FUNCTION: DoCopyContainerL
// ==========================================================================
void CMessageStoreSession::DoCopyContainerL( const RMessage2& aMessage )
	{
    // TIpcArgs( &paramsPckg, &idPckg )	

	TMsgStoreCopyContainerCmdParams        params;
	TPckg<TMsgStoreCopyContainerCmdParams> paramsPckg( params );
	aMessage.ReadL( 0, paramsPckg );
	
	TUint newId = iServer.MessageStoreL().CopyContainerL( params.iId,
	                                                      params.iSourceId,
	                                                      params.iSourceParentId,
	                                                      params.iDestinationId,
	                                                      params.iDestinationParentId,
	                                                      params.iMailBoxId,
	                                                      this );

	TPckg<TMsgStoreId> newIdPckg(newId);
	aMessage.WriteL( 1, newIdPckg );
	
	aMessage.Complete( KErrNone );	
	} // end DoCopyContainerL
	
// ==========================================================================
// FUNCTION: DoFetchPropertiesL
// ==========================================================================
void CMessageStoreSession::DoFetchPropertiesL( const RMessage2& aMessage )
	{
	__LOG_ENTER( "DoFetchPropertiesL" )
	
    // TIpcArgs( &params, &parentIdPckg, &aBuffer, &resultPckg );
    
    TMsgStoreFetchPropertiesCmdParams params;
    TPckg<TMsgStoreFetchPropertiesCmdParams> paramsPckg( params );
	aMessage.ReadL( 0, paramsPckg );

	TMsgStoreId parentId;
	TPckg<TMsgStoreId> parentIdPckg( parentId );
	aMessage.ReadL( 1, parentIdPckg );
	
	TUint result;
	TPckg<TUint> resultPckg( result );
	
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );

	iServer.MessageStoreL().FetchPropertiesL( params.iId, parentId, params.iGrandparentId, propertiesBuf, params.iMailboxId );

	if( propertiesBuf.Length() > aMessage.GetDesMaxLengthL( 2 ) )
	    {
	    // Overflow!
	    __LOG_WRITE8_FORMAT1_ERROR( "property buffer too long (%i)", propertiesBuf.Length() );
	    
	    // Write the required length to the result parameter, to indicate to the client that the
	    // buffer must be increased to the given size.
	    result = propertiesBuf.Length();
	    aMessage.WriteL( KValThree, resultPckg );	    
	    }
	else
	    {	    	
 	    aMessage.WriteL( 1, parentIdPckg );

        aMessage.WriteL( 2, propertiesBuf );

        result = 0;
	    aMessage.WriteL( KValThree, resultPckg );
	    } // end if
	    	    
   	CleanupStack::PopAndDestroy( &propertiesBuf );	

	aMessage.Complete( KErrNone );
	
	__LOG_EXIT
	} // end DoFetchPropertiesL

// ==========================================================================
// FUNCTION: DoUpdatePropertiesL
// ==========================================================================
void CMessageStoreSession::DoUpdatePropertiesL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, properties )

	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();
	
	TMsgStoreId mailBoxId = aMessage.Int2();

	TInt propertiesLength = aMessage.GetDesLengthL( KValThree );
	RBuf8 propertiesBuf;
	CleanupClosePushL( propertiesBuf );
	propertiesBuf.CreateL( propertiesLength );
	aMessage.ReadL( KValThree, propertiesBuf );

	iServer.MessageStoreL().UpdatePropertiesL( id, parentId, mailBoxId, propertiesBuf, this );
	
	CleanupStack::PopAndDestroy( &propertiesBuf );
	
	aMessage.Complete( KErrNone );
	} // end DoUpdatePropertiesL

// ==========================================================================
// FUNCTION: DoUpdatePropertyL
// ==========================================================================
void CMessageStoreSession::DoUpdatePropertyL( const RMessage2& aMessage )
	{
    // TIpcArgs( &params, &aName, &aValue )    
    
    TMsgStoreUpdatePropertyCmdParams        params;
    TPckg<TMsgStoreUpdatePropertyCmdParams> paramsPckg( params );
	aMessage.ReadL( 0, paramsPckg );

	RBuf8 nameBuf;
	CleanupClosePushL( nameBuf );
	nameBuf.CreateL( aMessage.GetDesLengthL( 1 ) );
	aMessage.ReadL( 1, nameBuf );

	RBuf8 valueBuf;
	CleanupClosePushL( valueBuf );
	valueBuf.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, valueBuf );

	iServer.MessageStoreL().UpdatePropertyL( params.iId, params.iParentId, params.iMailBoxId, nameBuf, params.iType, valueBuf, this );
	
	CleanupStack::PopAndDestroy( &valueBuf );
	CleanupStack::PopAndDestroy( &nameBuf );
	
	aMessage.Complete( KErrNone );
	} // end DoUpdatePropertyL

// ==========================================================================
// FUNCTION: DoChildrenCountsL
// ==========================================================================
void CMessageStoreSession::DoChildrenCountsL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, &counts )

	TMsgStoreId id = aMessage.Int0();

	RBuf8 countsBuf;
	CleanupClosePushL( countsBuf );
	countsBuf.CreateL( KMsgStoreCountsLength );
	
	iServer.MessageStoreL().ChildrenCountsL( id, countsBuf );
		
	aMessage.WriteL( 1, countsBuf );
	
	CleanupStack::PopAndDestroy( &countsBuf );
	
	aMessage.Complete( KErrNone );
	} // end DoChildrenCountsL

// ==========================================================================
// FUNCTION: DoTotalCountsL
// ==========================================================================
void CMessageStoreSession::DoTotalCountsL( const RMessage2& aMessage )
	{
	// TIpcArgs( &counts )
	
	TMsgStoreId mailBoxId = aMessage.Int0();

	RBuf8 countsBuf;
	CleanupClosePushL( countsBuf );
	countsBuf.CreateL( KMsgStoreCountsLength );
	
	iServer.MessageStoreL().TotalCountsL( mailBoxId, countsBuf );
		
	aMessage.WriteL( 1, countsBuf );
	
	CleanupStack::PopAndDestroy( &countsBuf );
	
	aMessage.Complete( KErrNone );
	} // end DoTotalCountsL

// ==========================================================================
// FUNCTION: DoChildrenIdsL
// ==========================================================================
void CMessageStoreSession::DoChildrenIdsL( const RMessage2& aMessage )	
	{
	// TIpcArgs( aId, aType, &childrenDes, &resultBuf )

	__LOG_ENTER( "DoChildrenIdsL" )
		
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId type = aMessage.Int1();

	RArray<TMsgStoreId> childIds( KGranularity25 );
	CleanupClosePushL( childIds );
	
	TUint result;
	TPckg<TUint> resultPckg( result );
	
	iServer.MessageStoreL().ListChildrenL( childIds, id, KMsgStoreInvalidId, type );

    TUint sizeNeeded = childIds.Count() * sizeof(TMsgStoreId);

    if( sizeNeeded > aMessage.GetDesMaxLengthL( 2 ) )
        {
	    // Overflow!
	    __LOG_WRITE8_FORMAT1_ERROR( "children IDs buffer too long (%i)", sizeNeeded );
	    
	    // Write the required length to the result parameter, to indicate to the client that the
	    // buffer must be increased to the given size.
        result = sizeNeeded;
        aMessage.WriteL( KValThree, resultPckg );        
        }
    else
        {        
    	for( TInt count = 0; count < childIds.Count(); count++ )
    		{
    		TPckg<TMsgStoreId> currentChild( childIds[count] );
    		const TUint KFour = 4;
    		aMessage.WriteL( 2, currentChild, count*KFour );
    		} // end for
    		
        result = 0;
        aMessage.WriteL( KValThree, resultPckg );            		
        } // end if
        
	CleanupStack::PopAndDestroy( &childIds ); 
	
	aMessage.Complete( KErrNone );
	
	__LOG_EXIT	
	} // end DoChildrenIdsL

// ==========================================================================
// FUNCTION: DoPropertiesListL
// ==========================================================================
void CMessageStoreSession::DoPropertiesListL( const RMessage2& aMessage )
	{	
    // TIpcArgs( &paramsPckg, &idList, &paramNames, &serializedBuf )	
    
    __LOG_ENTER( "DoPropertiesList" )
    
	TMsgStorePropertiesListCmdParams params;
	TPckg<TMsgStorePropertiesListCmdParams> paramsPckg( params );
	aMessage.ReadL( 0, paramsPckg );	

	TInt position = 0;

   	TMsgStoreId id;
	TPckg<TMsgStoreId> idPckg( id );

   	TMsgStoreId parentId;
	TPckg<TMsgStoreId> parentIdPckg( parentId );
    
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    TUint32 length32;
    TPckg<TUint32> length32Pckg( length32 );    

	CContainerStore& messageStore = iServer.MessageStoreL();

	// Suspend compaction here, to avoid suspension and resumption of compaction for each
	// fetch properties operation.	
	messageStore.SuspendCompactionLC();

	// Populate the ids and property names lists, if needed.
	
	// params.iStartOver means that the client wants to reset the list
	// iIds.Count == 0 means that the container store has been modified
	if( params.iStartOver || iIds.Count() == 0 )
		{
		__LOG_WRITE_INFO( "Starting over" )
		
		iIds.Reset();
		iPropertyNames.ResetAndDestroy();

		// Indicate to the client that any existing data should be cleared.		
	    params.iClearExisting = ETrue;

        iUsingQuery = params.iUseQuery;
        
        if( iUsingQuery )
            {
            __LOG_WRITE_INFO( "querying for children" )

            TPckg<TMsgStorePropertiesListQueryParams> queryParamsPckg( iQueryParams );    
    
       		aMessage.ReadL( 1, queryParamsPckg );		
            
            // Get the list of children IDs whose properties are to be retrieved.        		              		
    		messageStore.ListChildrenL( iIds,
    		                            iQueryParams.iId,
    		                            iQueryParams.iParentId,
    		                            iQueryParams.iType,
    		                            iQueryParams.iRecursive );
            } 
        else            
            {
            __LOG_WRITE_INFO( "deserializing ID list" )

    		// Deserialize the ID list from the message.
            ReadIdArrayL( aMessage, 1, iIds );
            } // end if
            
        __LOG_WRITE_INFO( "deserializing property names" )
            
		// Deserialize the property names list.
        ReadString8ArrayL( aMessage, 2, iPropertyNames );
		}            
    else
        {
        // The client should not clear any properties that have already been received.
        params.iClearExisting = EFalse; 
		} // end if

    __LOG_WRITE8_FORMAT1_INFO( "iIds.Count=%i", iIds.Count() )
    		    
    RBuf8 propertiesBuf;
    CleanupClosePushL( propertiesBuf );

    const TUint overhead  = idPckg.Length() + parentIdPckg.Length() + length32Pckg.Length();
	const TUint maxLength = aMessage.GetDesMaxLengthL( 3 );

 	TInt  result;
    TBool bufferFull = EFalse;
    
    position = 0;    
	
    // Continue adding properties to the buffer until there are no more properties or the buffer is full.
	while( iIds.Count() > 0 && !bufferFull )
		{
		propertiesBuf.SetLength( 0 );
		id       = iIds[0];
		parentId = KMsgStoreInvalidId;
		if( params.iUseQuery )
		    {
    		// Use the fast fetch because the ContainerModified callback will cause the query to be
    		// reissued if a potential change to a query item has been made.
            TRAP( result, messageStore.FastFetchPropertiesL( id, 
                                                             params.iQuickProperties, 
                                                             parentId, 
                                                             propertiesBuf ) );
		    }
		else
		    {
            // Don't want to return properties for deleted items, so don't use the fast fetch.		    
            TRAP( result, messageStore.FetchPropertiesL( id, 
                                                         parentId,
                                                         KMsgStoreInvalidId, 
                                                         propertiesBuf ) );
		    } // end if
                               
        if( result == KErrNone )
            {            
            // Filter the properties, if needed.
            if( iPropertyNames.Count() > 0 )
                {
                // Remove the properties that are not needed.
                TPropertiesSerializer serializer( propertiesBuf );        
                TBool moreProperties = serializer.First();        
                while( moreProperties )        
                    {
                    TBool found = EFalse;            
                    for( TInt i = 0; !found && (i < iPropertyNames.Count()); i++ )
                        {
                        found = (iPropertyNames[i]->Compare( serializer.Name() ) == 0);
                        } // end for                               
                    if( found )
                        {
                        moreProperties = serializer.Next();
                        }
                    else
                        {
                        moreProperties = serializer.RemovePropertyL();
                        } // end if                
                    } // end while   
                } // end if
                    
            if( position + propertiesBuf.Length() + overhead > maxLength )
                {
                // Insufficient room in the IPC buffer for the current set of properties.
                bufferFull = ETrue;
                }
            else
                {
                // Write the current set of properties into the IPC buffer.
        		aMessage.WriteL( KValThree, idPckg, position );		
        		position += idPckg.Length();
        		
    		    aMessage.WriteL( KValThree, parentIdPckg, position );
        		position += parentIdPckg.Length();		    

        		length32 = propertiesBuf.Length();
        		aMessage.WriteL( KValThree, length32Pckg, position );
        		position += length32Pckg.Length();

        		aMessage.WriteL( KValThree, propertiesBuf, position );        		
        		position += length32;
    		
    		    iIds.Remove( 0 );

                } // end if
            }
        else                            
            {
    	    __LOG_WRITE8_FORMAT1_ERROR( "failure during DoPropertiesListL %i", result );
    	    
    	    // This entry couldn't be read for some reason.  Skip past it.
   		    iIds.Remove( 0 );
    		    
            } // end if            
		    
		} // end for

    // If the current set of properties is larger than the transfer buffer then indicate to the client
    // that a larger transfer buffer is needed.
    params.iNewBufferSize = propertiesBuf.Length() + overhead;
	if( params.iNewBufferSize <= maxLength )
	    {	    
        __LOG_WRITE_INFO( "larger buffer needed" )
	    params.iNewBufferSize = 0;	    
	    } // end if
	    
	if( iIds.Count() > 0 )
	    {
        __LOG_WRITE_INFO( "more properties" )
        
	    // Indicate that there are more properties to stream.
	    params.iMoreProperties = ETrue;
	    }
	else
	    {
        __LOG_WRITE_INFO( "no more properties" )
        
	    // Indicate that there are no more properties to stream.
	    params.iMoreProperties = EFalse;
	    
	    // free the memory
	    iIds.Reset();  
	    iPropertyNames.ResetAndDestroy();
		} // end if

    CleanupStack::PopAndDestroy( &propertiesBuf );

	messageStore.ResumeCompaction();
	    		
	// Write the more flag.
	aMessage.WriteL( 0, paramsPckg );
	
	aMessage.Complete( KErrNone );

    __LOG_EXIT	
	} // end DoPropertiesListL

// ==========================================================================
// FUNCTION: DoContentLengthL
// ==========================================================================
void CMessageStoreSession::DoContentLengthL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, &lengthPckg )
	
	TMsgStoreId id = aMessage.Int0();
	
	TMsgStoreId parentId = aMessage.Int1();

	TUint length = iServer.MessageStoreL().ContentLengthL( id, parentId );
	
	TPckg<TUint> lengthPckg( length );
	aMessage.WriteL( 2, lengthPckg );
	
	aMessage.Complete( KErrNone );
	} // end DoContentLengthL
	
// ==========================================================================
// FUNCTION: DoFetchContentToBufferL
// ==========================================================================
void CMessageStoreSession::DoFetchContentToBufferL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, &aBuffer, aStartOffset )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

	RBuf8 contentBuf;
	CleanupClosePushL( contentBuf );
	contentBuf.CreateL( aMessage.GetDesMaxLengthL( 2 ) );

	TMsgStoreId startOffset = aMessage.Int3();
		
	iServer.MessageStoreL().FetchContentL( id, parentId, contentBuf, startOffset );

	aMessage.WriteL( 2, contentBuf );

	CleanupStack::PopAndDestroy( &contentBuf );
	
	aMessage.Complete( KErrNone );
	} // end DoFetchContentToBufferL
	
// ==========================================================================
// FUNCTION: DoFetchContentToFileL
// ==========================================================================
void CMessageStoreSession::DoFetchContentToFileL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, fs, file )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

	RFile file;	
	User::LeaveIfError( file.AdoptFromClient( aMessage, 2, KValThree ) );
	CleanupClosePushL( file );
	
	iServer.MessageStoreL().FetchContentL( id, parentId, file );

	CleanupStack::PopAndDestroy( &file );

	aMessage.Complete( KErrNone );
	} // end DoFetchContentToFileL
	
// ==========================================================================
// FUNCTION: DoReplaceContentWithBufferL
// ==========================================================================
void CMessageStoreSession::DoReplaceContentWithBufferL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, &aBuffer )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

	RBuf8 contentBuf;
	CleanupClosePushL( contentBuf );
	contentBuf.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, contentBuf );

	CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    if ( creator.IsContainerBuffered( id ) )
        {
        creator.ReplaceContentL(
            iServer.MessageStoreL(), id, contentBuf );
        }
    else
        {
        iServer.MessageStoreL().ReplaceContentL(
            id, parentId, contentBuf, this );
        }
    
	CleanupStack::PopAndDestroy( &contentBuf );

	aMessage.Complete( KErrNone );
	} // end DoReplaceContentWithBufferL
	
// ==========================================================================
// FUNCTION: DoReplaceContentWithFileL
// ==========================================================================
void CMessageStoreSession::DoReplaceContentWithFileL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, fs, file )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

    RFile file;    
    User::LeaveIfError( file.AdoptFromClient( aMessage, 2, KValThree ) );
    CleanupClosePushL( file );
    	
    CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    if ( creator.IsContainerBuffered( id ) )
        {
        creator.ReplaceContentL(
            iServer.MessageStoreL(), id, file );
        }
    else
        {
        iServer.MessageStoreL().ReplaceContentL( id, parentId, file, this );
        }

	CleanupStack::PopAndDestroy( &file );

	aMessage.Complete( KErrNone );
	} // end DoReplaceContentWithFileL
	
// ==========================================================================
// FUNCTION: DoAppendToContentL
// ==========================================================================
void CMessageStoreSession::DoAppendToContentL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, &aContent )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

	RBuf8 contentBuf;
	CleanupClosePushL( contentBuf );
	contentBuf.CreateL( aMessage.GetDesLengthL( 2 ) );
	aMessage.ReadL( 2, contentBuf );

	CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    if ( creator.IsContainerBuffered( id ) )
        {
        creator.AppendContentL(
            iServer.MessageStoreL(), id, contentBuf );
        }
    else
        {
        iServer.MessageStoreL().AppendContentL( id, parentId, contentBuf, this );
        }
	
	CleanupStack::PopAndDestroy( &contentBuf );

	aMessage.Complete( KErrNone );
	} // end DoAppendToContentL
	
// ==========================================================================
// FUNCTION: DoPrependToContentL
// ==========================================================================
void CMessageStoreSession::DoPrependToContentL( const RMessage2& aMessage )
    {
    TMsgStoreId id = aMessage.Int0();
    TMsgStoreId parentId = aMessage.Int1();

    RBuf8 contentBuf;
    CleanupClosePushL( contentBuf );
    contentBuf.CreateL( aMessage.GetDesLengthL( 2 ) );
    aMessage.ReadL( 2, contentBuf );
    
    CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    if ( creator.IsContainerBuffered( id ) )
        {
        creator.PrependContentL(
            iServer.MessageStoreL(), id, contentBuf );
        }
    else
        {
        iServer.MessageStoreL().PrependContentL(
            id, parentId, contentBuf, this );
        }
    
    CleanupStack::PopAndDestroy( &contentBuf );
    aMessage.Complete( KErrNone );
    }

// ==========================================================================
// FUNCTION: DoRemoveContentL
// ==========================================================================
void CMessageStoreSession::DoRemoveContentL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId )
	
	TMsgStoreId id = aMessage.Int0();

	TMsgStoreId parentId = aMessage.Int1();

	iServer.MessageStoreL().RemoveContentL( id, parentId, this );	

	aMessage.Complete( KErrNone );
	} // end DoRemoveContentL


// ==========================================================================
// FUNCTION: DoOpenContentFile
// ==========================================================================
void CMessageStoreSession::DoOpenContentFileL( const RMessage2& aMessage )
    {
    TMsgStoreId id = aMessage.Int0();
    TMsgStoreId parentId = aMessage.Int1();
    
    RFs fs;
    User::LeaveIfError(fs.Connect());
    CleanupClosePushL(fs);                                 //+fs

    User::LeaveIfError(fs.ShareProtected());

    RFile file;
    CleanupClosePushL( file );                             //+file
    
    iServer.MessageStoreL().OpenContentFileL( id, parentId, fs, file );
    
    // transfer to client: store the RFile handle into the package buffer in slot 2 
    // and complete the message with the RFs handle
    // This assumes that if TransferToClient() return an error, then
    // the standard CServer2::RunError() will complete the message
    User::LeaveIfError( file.TransferToClient(aMessage, 2) );
    
    CleanupStack::PopAndDestroy( &file );
    CleanupStack::PopAndDestroy( &fs );
    }

// ==========================================================================
// FUNCTION: DoDeleteContainerL
// ==========================================================================
void CMessageStoreSession::DoDeleteContainerL( const RMessage2& aMessage )
	{
	// TIpcArgs( aId, aParentId, aGrandparentId )
	
	TMsgStoreId id = aMessage.Int0();
	
	TMsgStoreId parentId = aMessage.Int1();

	TMsgStoreId grandparentId = aMessage.Int2();
	
	TMsgStoreId mailBoxId = aMessage.Int3();
	
	iServer.MessageStoreL().DeleteContainerL( id, parentId, grandparentId, mailBoxId, this );
	
	aMessage.Complete( KErrNone );
	} // end DoDeleteContainerL


// -------------------------
// SORTING HANDLER FUNCTIONS
// -------------------------
// ==========================================================================
// FUNCTION: DoStartSortingL
// ==========================================================================
void CMessageStoreSession::DoStartSortingL( const RMessage2& aMessage )
    {
    __LOG_ENTER( "DoStartSortingL" )
    
    TMsgStoreSortCriteria sortCriteria;
    TPckg<TMsgStoreSortCriteria> paramsPckg( sortCriteria );
    aMessage.ReadL( 1, paramsPckg );
    
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    // Deserialize the property names list.
    ReadString8ArrayL( aMessage, 2, iPropertyNames );
    
    //parameter 3
    TBool inMemorySort = aMessage.Int3();

    TContainerId sessionId = iServer.MessageStoreL().StartSortingL( sortCriteria, iPropertyNames, inMemorySort );
    iSortSessionIds.Append( sessionId );
    
    TPckg<TContainerId> sessionIdPckg( sessionId );
    aMessage.WriteL( 0, sessionIdPckg );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoEndSortingL
// ==========================================================================
void CMessageStoreSession::DoEndSortingL( const RMessage2& aMessage )
    {
    __LOG_ENTER( "DoEndSortingL" )
    
    TMsgStoreId sessionId = aMessage.Int0();
    
    iServer.MessageStoreL().EndSortingL( sessionId );
    
    TInt index = iSortSessionIds.Find( sessionId );
    if ( index != KErrNotFound )
        {
        iSortSessionIds.Remove( index );
        }
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: GetSortedRowsL
// ==========================================================================
void CMessageStoreSession::DoGetSortedRowsL( const RMessage2& aMessage )
    {
    __LOG_ENTER( "DoGetSortedRowsL" )
    
    //param 0   
    TUint result;
    TPckg<TUint> resultPckg( result );
    
    //param 1
    TMsgStoreGetSortedRowsCmdParams params;
    TPckg<TMsgStoreGetSortedRowsCmdParams> paramsPckg( params );
    aMessage.ReadL( 1, paramsPckg );
    
    //param 2
    RBuf8 propertiesBuf;
    CleanupClosePushL( propertiesBuf );
    
    //param 3
    TBool hasMore;
    if ( params.iHasStartWith )
        {
        RBuf startWith;
        CleanupClosePushL( startWith );
        
        startWith.CreateL( aMessage.GetDesLengthL( KValThree ) );
        aMessage.ReadL( KValThree, startWith );
        
        hasMore = iServer.MessageStoreL().GetSortedRowsL( params, propertiesBuf, startWith );
        CleanupStack::PopAndDestroy( &startWith );
        }
    else
        {
        hasMore = iServer.MessageStoreL().GetSortedRowsL( params, propertiesBuf );
        }
    params.iHasMoreRows = hasMore;
    
    if( propertiesBuf.Length() > aMessage.GetDesMaxLengthL( 2 ) )
        {
        // Overflow!
        __LOG_WRITE8_FORMAT1_ERROR( "property buffer too long (%i)", propertiesBuf.Length() );
        
        // Write the required length to the result parameter, to indicate to the client that the
        // buffer must be increased to the given size.
        result = propertiesBuf.Length();
        aMessage.WriteL( 0, resultPckg );       
        }
    else
        {           
        result = 0;
        aMessage.WriteL( 0, resultPckg );
        aMessage.WriteL( 1, paramsPckg );
        aMessage.WriteL( 2, propertiesBuf );
        } // end if
    
    CleanupStack::PopAndDestroy( &propertiesBuf );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoGetIteratorGroupCountL
// ==========================================================================
void CMessageStoreSession::DoGetIteratorGroupCountL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoGetIteratorGroupCountL")
    
    //param 0
    TMsgStoreId sessionId = aMessage.Int0();
    
    //param 1
    TInt count;
    TPckg<TInt> resultPckg( count );
    
    RArray<TUint> itemsInGroup;
    CleanupClosePushL( itemsInGroup );
    
    count = iServer.MessageStoreL().IteratorGroupCountL( sessionId, itemsInGroup );
    aMessage.WriteL( 1, resultPckg );
    
    TUint items;
    TPckg<TUint> itemsPkg( items );
    TInt position = 0;
    
    for ( TInt i = 0; i < count; i++ )
        {
        items = itemsInGroup[i];
        aMessage.WriteL( 2, itemsPkg, position );     
        position += itemsPkg.Length();
        }
    
    CleanupStack::PopAndDestroy( &itemsInGroup );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoGetSortedIdsAndFlagsL
// ==========================================================================
void CMessageStoreSession::DoGetSortedIdsAndFlagsL( const RMessage2& aMessage )
	{
    __LOG_ENTER("DoGetSortedIdsAndFlags")
    
    //param 0
    TMsgStoreId sessionId = aMessage.Int0();
    
    //param 1
    TInt count;
    TPckg<TInt> countPckg( count );
    
    RArray<TContainerId> idArray( KSortedArrayGranularity );
    CleanupClosePushL( idArray );
    
    RArray<TUint32> flagArray ( KSortedArrayGranularity );
    CleanupClosePushL( flagArray );
    
    iServer.MessageStoreL().SortedIdsAndFlagsL( sessionId, idArray, flagArray );
    if ( idArray.Count() != flagArray.Count() )
    	{
    	User::Leave( KErrCorrupt );
    	}
    count = idArray.Count();
    aMessage.WriteL( 1, countPckg );
    
    TContainerId id;
    TPckg<TContainerId> idPkg( id );
    
    TUint32 flag;
    TPckg<TUint32> flagPkg( flag );
    
    TInt position = 0;
    
    for ( TInt i = 0; i < count; i++ )
        {
        id = idArray[i];
        aMessage.WriteL( 2, idPkg, position );     
        position += idPkg.Length();
        
        flag = flagArray[i];
        aMessage.WriteL( 2, flagPkg, position );     
        position += flagPkg.Length();
        }
    
    CleanupStack::PopAndDestroy( &flagArray );
    CleanupStack::PopAndDestroy( &idArray );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
	}


// ==========================================================================
// FUNCTION: DoGetSortedIndexOfL
// ==========================================================================
void CMessageStoreSession::DoGetSortedIndexOfL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoGetSortedIndexOfL")
    
    //param 0
    TContainerId sessionId = aMessage.Int0();
    
    //param 1
    TContainerId messageId = aMessage.Int1();
    
    //param 2
    TInt index;
    TPckg<TInt> indexPckg( index );
    
    index = iServer.MessageStoreL().SortedIndexOfL( sessionId, messageId );
    
    aMessage.WriteL( 2, indexPckg );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoGetSortedIdsL
// ==========================================================================
void CMessageStoreSession::DoGetSortedIdsL( const RMessage2& aMessage )
	{
    __LOG_ENTER("DoGetSortedIdsL")
    
    //param 0
    TMsgStoreId sessionId = aMessage.Int0();
    
    //param 1
    TInt count;
    TPckg<TInt> countPckg( count );
    
    RArray<TContainerId> idArray( KSortedArrayGranularity );
    CleanupClosePushL( idArray );
    
    iServer.MessageStoreL().SortedIdsL( sessionId, idArray );
    count = idArray.Count();
    aMessage.WriteL( 1, countPckg );
    
    TContainerId id;
    TPckg<TContainerId> idPkg( id );
    
    TInt position = 0;
    
    for ( TInt i = 0; i < count; i++ )
        {
        id = idArray[i];
        aMessage.WriteL( 2, idPkg, position );     
        position += idPkg.Length();
        }
    
    CleanupStack::PopAndDestroy( &idArray );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
	}


// ==========================================================================
// FUNCTION: DoGetSortedIdsAndGroupCountL
// ==========================================================================
void CMessageStoreSession::DoGetSortedIdsAndGroupCountL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoGetSortedIdsAndGroupCountL")
    
    //param 0
    TMsgStoreId sessionId = aMessage.Int0();
    
    //param 1
    TInt idCount;
    TPckg<TInt> idCountPckg( idCount );
    
    //param 2
    TInt groupCount;
    TPckg<TInt> groupCountPckg( groupCount );
    
    RArray<TContainerId> idArray( KSortedArrayGranularity );
    CleanupClosePushL( idArray );
    
    RArray<TUint> itemsInGroup;
    CleanupClosePushL( itemsInGroup );
    
    iServer.MessageStoreL().SortedIdsAndGroupCountL( sessionId, idArray, itemsInGroup );
    
    idCount = idArray.Count();
    aMessage.WriteL( 1, idCountPckg );
    
    groupCount = itemsInGroup.Count();
    aMessage.WriteL( 2, groupCountPckg );
    
    TContainerId id;
    TPckg<TContainerId> idPkg( id );
    
    TInt position = 0;
    
    for ( TInt i = 0; i < idCount; i++ )
        {
        id = idArray[i];
        aMessage.WriteL( KValThree, idPkg, position );     
        position += idPkg.Length();
        }
    
    TUint items;
    TPckg<TUint> itemsPkg( items );
    
    for ( TInt i = 0 ; i < groupCount ; i++ )
        {
        items = itemsInGroup[i];
        aMessage.WriteL( KValThree, itemsPkg, position );     
        position += itemsPkg.Length();
        }
    
    CleanupStack::PopAndDestroy( &itemsInGroup );
    CleanupStack::PopAndDestroy( &idArray );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoSetMaxMruAdressCountL
// ==========================================================================
void CMessageStoreSession::DoSetMaxMruAdressCountL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoSetMaxMruAdressCountL")
    
    TInt maxCount = aMessage.Int0();
    
    iServer.MessageStoreL().SetMaxMruCountL( maxCount );
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoSetMruAddressListL
// ==========================================================================
void CMessageStoreSession::DoSetMruAddressListL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoSetMruAddressListL")
    
    TMsgStoreId mailboxId = aMessage.Int0();
    
    iMruAddressArray.ResetAndDestroy();
    
    //read the address array
    TInt bufSize = aMessage.GetDesLengthL( 1 );
    
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    RBuf8 addressBuf;
    CleanupClosePushL( addressBuf );
    addressBuf.Create( KInitialAddressBufSize );
    
    RBuf8 dispNameBuf;
    CleanupClosePushL( dispNameBuf );
    dispNameBuf.Create( KInitialAddressBufSize );
    
    TInt position = 0;
    while( position < bufSize )
        {
        //read the email address
        aMessage.ReadL( 1, length16Pckg, position ); 
        position += length16Pckg.Length();
        
        if ( addressBuf.MaxLength() < length16 )
            {
            addressBuf.ReAlloc( length16 );
            }
        aMessage.ReadL( 1, addressBuf, position );
        
        //now read convert the 8 bit descriptor to 16 descriptor
        const TUint16* addressPtr = reinterpret_cast<const TUint16*>( addressBuf.Ptr() );
        TPtrC addressDes( addressPtr, length16 / 2 );  
        
        position += length16;

        //read the display name
        aMessage.ReadL( 1, length16Pckg, position ); 
        position += length16Pckg.Length();
        
        if ( dispNameBuf.MaxLength() < length16 )
            {
            dispNameBuf.ReAlloc( length16 );
            }
        aMessage.ReadL( 1, dispNameBuf, position );
        
        //now read convert the 8 bit descriptor to 16 descriptor
        const TUint16* dispNamePtr = reinterpret_cast<const TUint16*>( dispNameBuf.Ptr() );
        TPtrC dispNameDes( dispNamePtr, length16 / 2 );  
        
        position += length16;
        
        CMruAddress* mruAddress = CMruAddress::NewL(0, addressDes, dispNameDes );
        
        iMruAddressArray.Append( mruAddress );
        
        } // end while
    
    iServer.MessageStoreL().SetMruAddressListL( mailboxId, iMruAddressArray );
    
    CleanupStack::PopAndDestroy( &dispNameBuf );
    CleanupStack::PopAndDestroy( &addressBuf );
    
    iMruAddressArray.ResetAndDestroy();
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

// ==========================================================================
// FUNCTION: DoGetMruAddressListL
// ==========================================================================
void CMessageStoreSession::DoGetMruAddressListL( const RMessage2& aMessage )
    {
    __LOG_ENTER("DoGetMruAddressListL")
    
    TUint result;
    TPckg<TUint> resultPckg( result );
    
    TMsgStoreId mailboxId = aMessage.Int0();
    
    const RPointerArray<CMruAddress> addressArray = iServer.MessageStoreL().MruAddressListL( mailboxId );
    
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    //Find out the size
    TInt totalSize = 0;
    TInt count = addressArray.Count();
    TInt sizeOfLengthFields = sizeof( TUint16 ) * 2;  //two lengths
    for ( TInt i = 0 ; i < count ; i++ )
        {
        totalSize += sizeOfLengthFields;
        CMruAddress* address = addressArray[i];
        totalSize += (address->EmailAddress().Length() * 2);
        totalSize += (address->DisplayName().Length() * 2);
        }
    
    //now check if the client buffer is big enough
    if ( totalSize > aMessage.GetDesMaxLengthL( 2 ) )
        {
        // Overflow!
        __LOG_WRITE8_FORMAT1_ERROR( "Mru buffer too long (%i)", totalSize );
        
        // Write the required length to the result parameter, to indicate to the client that the
        // buffer must be increased to the given size.
        result = static_cast<TUint>(totalSize);
        aMessage.WriteL( 1, resultPckg );       
        }
    else
        {
        //now serialize it to the buffer
        TUint position = 0;
        
        for ( TInt i = 0 ; i < count ; i++ )
            {
            CMruAddress* address = addressArray[i];
            
            //write the email address
            //write the length and update the cursor
            length16 = address->EmailAddress().Length() * 2 ;
            aMessage.Write( 2, length16Pckg, position );
            position += length16Pckg.Length();
            
            //convert the 16 bit descriptor to 8 bit descriptor
            const TUint8* addressPtr = reinterpret_cast<const TUint8*>( address->EmailAddress().Ptr() );
            TPtrC8 addressDes( addressPtr, length16 );  

            //write it and update the cursor
            aMessage.Write( 2, addressDes, position );
            position += length16;
            
            //write the displayName
            //write the length and update the cursor
            length16 = address->DisplayName().Length() * 2 ;
            aMessage.Write( 2, length16Pckg, position );
            position += length16Pckg.Length();
            
            //convert the 16 bit descriptor to 8 bit descriptor
            const TUint8* namePtr = reinterpret_cast<const TUint8*>( address->DisplayName().Ptr() );
            TPtrC8 nameDes( namePtr, length16 );  
            
            //write it and update the cursor
            aMessage.Write( 2, nameDes, position );
            position += length16;
            }
        
        result = 0;
        aMessage.WriteL( 1, resultPckg );       
        }    
    
    aMessage.Complete( KErrNone );
    
    __LOG_EXIT
    }

/**
 * 
 */
void CMessageStoreSession::DoBeginBatchInsertL( const RMessage2& aMessage )
    {
    CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    creator.BeginBatchInsertL( iServer.MessageStoreL() );
    
    aMessage.Complete( KErrNone );
    }

/**
 * 
 */
void CMessageStoreSession::DoFinishBatchInsertL( const RMessage2& aMessage )
    {
    CBufferedMessageCreator& creator = GetBufferedMessageCreatorL();
    creator.FinishBatchInsertL( iServer.MessageStoreL(), this );
    
    aMessage.Complete( KErrNone );
    }

// ==========================================================================
// FUNCTION: ReadString8ArrayL
// ==========================================================================
void CMessageStoreSession::ReadString8ArrayL(  const RMessage2& aMessage, TInt aIndex, RPointerArray<HBufC8>& aArray )
    {
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    // Deserialize the property names list.
    aArray.ResetAndDestroy();
    
    TInt position = 0;
    while( position < aMessage.GetDesLengthL( aIndex ) )
        {
        aMessage.ReadL( aIndex, length16Pckg, position );        
        position += length16Pckg.Length();
        
        HBufC8* buf8 = HBufC8::NewL( length16 );            
        aArray.Append( buf8 );
        TPtr8 buf8Ptr( buf8->Des() );
        aMessage.ReadL( aIndex, buf8Ptr, position );
        buf8->Des().SetLength( length16 ); 
        position += length16;
        } // end while
    }

// ==========================================================================
// FUNCTION: ReadString16ArrayL
// ==========================================================================
void CMessageStoreSession::ReadString16ArrayL(  const RMessage2& aMessage, TInt aIndex, RPointerArray<HBufC>& aArray )
    {
    TUint16 length16;
    TPckg<TUint16> length16Pckg( length16 );
    
    // Deserialize the property names list.
    aArray.ResetAndDestroy();
    
    RBuf8 readBuf;
    CleanupClosePushL( readBuf );
    
    TInt position = 0;
    while( position < aMessage.GetDesLengthL( aIndex ) )
        {
        aMessage.ReadL( aIndex, length16Pckg, position );        
        position += length16Pckg.Length();
        
        if ( readBuf.MaxLength() < length16 )
            {
            readBuf.ReAlloc( length16 );
            }
        aMessage.ReadL( aIndex, readBuf, position );
        
        //now read convert the 8 bit descriptor to 16 descriptor
        const TUint16* valuePtr = reinterpret_cast<const TUint16*>( readBuf.Ptr() );
        TPtrC valueDes( valuePtr, length16 / 2 );  
        
        aArray.Append( valueDes.AllocL() );
        
        position += length16;
        } // end while
    
    CleanupStack::PopAndDestroy( &readBuf );
    }

// ==========================================================================
// FUNCTION: ReadIdArrayL
// ==========================================================================
void CMessageStoreSession::ReadIdArrayL( const RMessage2& aMessage, TInt aIndex, RArray<TContainerId>& aArray )
    {
    TMsgStoreId id;
    TPckg<TMsgStoreId> idPckg( id );
    TInt position = 0;

    aArray.Reset();
    for( position = 0; position < aMessage.GetDesLengthL( aIndex ); position += idPckg.Length() )
        {
        aMessage.ReadL( aIndex, idPckg, position );      
        aArray.Append( id );
        } // end for
    }

/**
 * 
 */
/*private*/
CBufferedMessageCreator& CMessageStoreSession::GetBufferedMessageCreatorL()
    {
    if ( NULL == iBufferedMessageCreator )
        {
        iBufferedMessageCreator = CBufferedMessageCreator::NewL(
            iServer.MessageStoreL() );
        }
    
    return *iBufferedMessageCreator;
    }

// FUNCTIONS TO SUPPORT AUTOMATED UNIT TESTING
#ifdef _DEBUG

void CMessageStoreSession::DoInjectBackupRestoreEventL( const RMessage2& aMessage )
    {
    // parameter 1 contains the event to inject
	TUint event = aMessage.Int0();
    iServer.InjectBackupRestoreEventL( event );
    aMessage.Complete( KErrNone );
    }

void CMessageStoreSession::DoInjectPointSecEvent( const RMessage2& aMessage )
    {
    // parameter 1 contains the event to inject
    TUint event = aMessage.Int0();
    iServer.InjectPointSecEvent( event );
    aMessage.Complete( KErrNone );
    }
	
void CMessageStoreSession::DoSimulateLowDiskSpaceL( const RMessage2& aMessage )
    {    
    // parameter 1 contains the number of calls to delay before indicating low disk space.
	TUint latency = aMessage.Int0();
    iServer.MessageStoreL().SimulateLowDiskSpace( latency );
    aMessage.Complete( KErrNone );
    }

void CMessageStoreSession::DoGetEncryptionStateL( const RMessage2& aMessage )
    {
    TInt state = iServer.MessageStoreL().GetEncryptionStateL();
    
    TPckg<TInt> statePckg( state );
    aMessage.WriteL( 0, statePckg );
    
    aMessage.Complete( KErrNone );
    }

void CMessageStoreSession::DoShutdownServer( const RMessage2& aMessage )
    {
    aMessage.Complete( KErrNone );
    iServer.Shutdown();
    }

#endif
