menucontentsrv/srvsrc/menusrvsession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:54:17 +0200
changeset 0 79c6a41cd166
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2009 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:
*
*/
#include "menusrvsession.h"
#include "menusrvstream.h"
#include "menusrvoperation.h"
#include "menusrvobjectfilter.h"
#include "mcsmenunotifier.h" // for the notifier events
#include "menusrvnotifier.h"
#include "menusrvbuf.h"
#include "menumsg.h"
#include "menusrvdef.h"
#include "mcsmenuitem.h"
#include "mcsmenufilter.h"
#include "menuutil.h"
#include "menueng.h"
#include "menusrveng.h"
#include "menuengobject.h"
#include <s32buf.h>
#include <s32strm.h>


const TInt KParamIndAttrName = 1;
const TInt KParamIndAttrEx = 2;
const TInt KParamIndAttrVal = 3;
const TInt KParamIndBuf = 2;
const TInt KParamIndStream = 3;
const TInt KParamIndOp = 3;
const TInt KParamIndNotif = 3;

const TInt KGetListDescriptorPos = 0;
const TInt KGetListReturnPos = 1;

//const TInt KIconSize = 74;


// ================= MEMBER FUNCTIONS =======================

// ---------------------------------------------------------
// CMenuSrvSession::~CMenuSrvSession
// ---------------------------------------------------------
//
CMenuSrvSession::~CMenuSrvSession()
    {
    delete iNotifierIx;
    delete iStreamIx;
    delete iOperationIx;
    iMenuSrv.RemoveContainer( iObjectCon );
    if ( iSharedEng )
        {
        iSharedEng->RemoveSession( this ); // Ownership release.
        }
    }

// ---------------------------------------------------------
// CMenuSrvSession::NewL
// ---------------------------------------------------------
//
CMenuSrvSession* CMenuSrvSession::NewL( CMenuSrv& aMenuSrv )
    {
    CMenuSrvSession* sess = new (ELeave) CMenuSrvSession( aMenuSrv );
    CleanupStack::PushL( sess );
    sess->ConstructL();
    CleanupStack::Pop( sess );
    return sess;
    }

// ---------------------------------------------------------
// CMenuSrvSession::CMenuSrvSession
// ---------------------------------------------------------
//
CMenuSrvSession::CMenuSrvSession( CMenuSrv& aMenuSrv )
: iMenuSrv( aMenuSrv )
    {
    }

// ---------------------------------------------------------
// CMenuSrvSession::ConstructL
// ---------------------------------------------------------
//
void CMenuSrvSession::ConstructL()
    {
    iObjectCon = iMenuSrv.NewContainerL();
    iNotifierIx = CObjectIx::NewL();
    iStreamIx = CObjectIx::NewL();
    iOperationIx = CObjectIx::NewL();
    }

// ---------------------------------------------------------
// CMenuSrvSession::CountResources
// ---------------------------------------------------------
//
TInt CMenuSrvSession::CountResources()
    {
    return iObjectCon->Count();
    }

// ---------------------------------------------------------
// CMenuSrvSession::ServiceL
// ---------------------------------------------------------
//
void CMenuSrvSession::ServiceL( const RMessage2& aMessage )
    {
    if( !ServiceCapabilityTestL( aMessage ) )
    	{
        // The rest of the functions does not work with a dead engine.
        if ( iEngineDead )
            {
            User::Leave( KErrDisconnected );
            }
        
        if( !ServiceCapReadL( aMessage ) )
        	{
        	if( !ServiceCapWriteL( aMessage) )
        		{
    			//Function was not serviced
        		aMessage.Complete( KErrNotSupported ); // Sync request -> complete it now.
        		}
        	}
    	}
    }

// ---------------------------------------------------------
// CMenuSrvSession::ServiceCapabilityTestL
// Handles functions with test capability
// ---------------------------------------------------------
//
TBool CMenuSrvSession::ServiceCapabilityTestL( const RMessage2& aMessage )
	{
	// These debug functions work even with a dead engine.
	TBool serviced = ETrue;
	switch( aMessage.Function() )
	    {
	    case EMenuResourceMarkStart:
	        {
	        ResourceCountMarkStart();
	        aMessage.Complete( KErrNone );
	        break;
	        }
	
	    case EMenuResourceMarkEnd:
	        {
	        ResourceCountMarkEnd( aMessage );
	        aMessage.Complete( KErrNone );
	        break;
	        }
	
	    case EMenuResourceCount:
	        {
	        aMessage.Complete( CountResources() );
	        break;
	        }
	
	    case EMenuSetHeapFailure:
	        {
	        User::__DbgSetAllocFail
	            (
	            RAllocator::EUser,
	            STATIC_CAST( RAllocator::TAllocFail, aMessage.Int0() ),
	            aMessage.Int1()
	            );
	        aMessage.Complete( KErrNone );
	        break;
	        }
	
	    default:
	        {
	        // Not a debug function.
	        serviced = EFalse;
	        break;
	        }
	    }
	return serviced;
	}

// ---------------------------------------------------------
// CMenuSrvSession::ServiceCapReadWriteL
// Handles functions with read device data capability
// ---------------------------------------------------------
//
TBool CMenuSrvSession::ServiceCapReadL( const RMessage2& aMessage )
	{
	TBool serviced = ETrue;
	switch( aMessage.Function() )
        {
		case EMenuConstructSession:
            {
            __ASSERT_ALWAYS( !iSharedEng, PanicClientL( aMessage ) );
            RBuf name;
            name.CreateL( aMessage.GetDesLengthL( 0 ) );
            CleanupClosePushL( name );
            aMessage.ReadL( 0, name );
            // Get the shared engine and open it.
            CMenuSrvEng* sharedEng = iMenuSrv.GetEngineL( name );
            CleanupClosePushL( *sharedEng );
            sharedEng->AddSessionL( this ); // Ownership transfer.
            // No leaving after this point.
            CleanupStack::Pop( sharedEng );
            iSharedEng = sharedEng;
            CleanupStack::PopAndDestroy( &name );
            break;
            };

        case EMenuRootFolder:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TPckgBuf<TInt> root;
            TInt id;
            iSharedEng->Engine().RootFolderL( id );
            root() = id;
            aMessage.WriteL( 0, root );
            break;
            }

        case EMenuStreamClose:
            {
            TInt handle = aMessage.Int3();
            StreamL( handle ); // Check that handle is valid.
            iStreamIx->Remove( handle );
            break;
            };

        case EMenuStreamOpen:
            {
            NewStreamL( *(HMenuSrvBuf::NewL()), aMessage );
            break;
            }

        case EMenuStreamRead:
            {
            TInt handle = aMessage.Int3();
            TInt len;
            StreamL( handle ).ReadL( aMessage, len );
            break;
            }

        case EMenuStreamWrite:
            {
            TInt handle = aMessage.Int3();
            StreamL( handle ).WriteL( aMessage );
            break;
            }

        case EMenuGetHdr:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt id = aMessage.Int0();
            TPckgBuf<TMenuItem> hdr;
            iSharedEng->Engine().GetItemL( id, hdr() );
            aMessage.WriteL( 1, hdr );
            break;
            }

        case EMenuGetItems:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            HMenuSrvBuf* streamBuf = HMenuSrvBuf::NewLC();
            RWriteStream stream( streamBuf );
            TInt folder = aMessage.Int0();
            TBool recursive = aMessage.Int1();
            RArray<TMenuItem> items;
            CleanupClosePushL( items );
            iSharedEng->Engine().GetItemsL( items, folder, NULL, recursive );
            MenuUtil::ExternalizeL( items, stream );
            stream.CommitL();
            CleanupStack::PopAndDestroy( &items );
            CleanupStack::Pop( streamBuf );
            NewStreamL( *(stream.Sink()), aMessage );
            break;
            }

        case EMenuGetRunningApps:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            HMenuSrvBuf* streamBuf = HMenuSrvBuf::NewLC();
            RWriteStream stream( streamBuf );
            RArray<TUid> items;
            CleanupClosePushL( items );
            iSharedEng->GetRunningAppsL( items );
            MenuUtil::ExternalizeL( items, stream );
            stream.CommitL();
            CleanupStack::PopAndDestroy( &items );
            CleanupStack::Pop( streamBuf );
            NewStreamL( *(stream.Sink()), aMessage );
            break;
            }            
            
        case EMenuGetItemsFiltered:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt folder = aMessage.Int0();
            TBool recursive = aMessage.Int1();
            TInt bufHandle = aMessage.Int2();
            RArray<TMenuItem> items;
            CleanupClosePushL( items );
            MStreamBuf& buf = StreamL( bufHandle ).Host();
            RReadStream rs( &buf );
            CMenuFilter* filter = CMenuFilter::NewLC();
            filter->InternalizeL( rs );
            TMenuSrvObjectFilter engFilter( *filter );
            iSharedEng->Engine().GetItemsL
                ( items, folder, &engFilter, recursive );
            CleanupStack::PopAndDestroy( filter );
            RWriteStream stream( &buf );
            MenuUtil::ExternalizeL( items, stream );
            stream.CommitL();
            CleanupStack::PopAndDestroy( &items );
            break;
            }
            
        case EMenuGetListSize:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt deslen = aMessage.GetDesLength( KGetListDescriptorPos );
            HBufC8* buffer = HBufC8::NewLC( deslen );
            TPtr8 tempDes = buffer->Des( );
            aMessage.Read( KGetListDescriptorPos, tempDes );
            TInt size = iSharedEng->GetListSizeL( *buffer );
            TPckg<TInt> sizeDes( size );
            aMessage.WriteL( KGetListReturnPos, sizeDes );
            CleanupStack::PopAndDestroy( buffer );
            break;
            }   

        case EMenuGetListData:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            aMessage.WriteL( KGetListDescriptorPos, 
            		iSharedEng->GetListDataL() );
            iSharedEng->CloseOutputBuffer();
            break;
            }              
                        
            
        case EMenuItemGetAttribute:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt id = aMessage.Int0();
            RBuf name;
            name.CreateL( aMessage.GetDesLengthL( KParamIndAttrName ) );
            CleanupClosePushL( name );
            aMessage.ReadL( KParamIndAttrName, name );
            TPckgBuf<TBool> attrExistsBuf;
            TBool attrExists(EFalse);
        	RBuf attrVal;
        	attrVal.CleanupClosePushL();
        	attrVal.CreateL(KMenuMaxAttrValueLen);
        	iSharedEng->GetAttributeL( id, name, attrExists, attrVal);
            attrExistsBuf() = attrExists;
            aMessage.WriteL( KParamIndAttrEx, attrExistsBuf );
            
            if ( attrExists )
                {
                aMessage.WriteL( KParamIndAttrVal, attrVal );
                }
        	CleanupStack::PopAndDestroy( &attrVal );
            CleanupStack::PopAndDestroy( &name );
            break;
            }
            
        case EMenuItemGetAttributeList:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt id = aMessage.Int0();
            TInt bufHandle = aMessage.Int2();
            HMenuSrvBuf* streamBuf = HMenuSrvBuf::NewLC();
            RWriteStream ws( streamBuf );
            RArray<TPtrC> attributeList;
        	CleanupClosePushL(attributeList);
            
            iSharedEng->GetAttributeListL( id, attributeList );

            for ( TInt ndx = 0; ndx < attributeList.Count(); ndx++ )
                {
                TPtrC name;
                name.Set( attributeList[ndx] );
                ws.WriteInt32L( name.Length() );
                ws.WriteL( name );
                }
            ws.WriteInt32L( 0 );
            ws.CommitL();

        	CleanupStack::PopAndDestroy(&attributeList);
            CleanupStack::Pop( streamBuf );
            NewStreamL( *(ws.Sink()), aMessage );

            break;
            }

        case EMenuNotifierClose:
            {
            TInt handle = aMessage.Int3();
            NotifierL( handle ); // Check that handle is valid.
            iNotifierIx->Remove( handle );
            break;
            };

        case EMenuNotifierOpen:
            {
            NewNotifierL( aMessage );
            break;
            }

        case EMenuNotifierNotify:
            {
            TInt handle = aMessage.Int3();
            CMenuSrvNotifier& notifier( NotifierL( handle ) );
            notifier.NotifyL( aMessage.Int0(), aMessage.Int1(), aMessage );
            // No leaving after this point!
            return ETrue; // Async request -> the object will complete it.
            }

        case EMenuNotifierNotifyCancel:
            {
            TInt handle = aMessage.Int3();
            NotifierL( handle ).Cancel();
            break;
            }
            
	    default:
	        {
	        serviced = EFalse;
	        break;
	        }
        }
	if( serviced )
		{
		aMessage.Complete( KErrNone );// Sync request -> complete it now.
		}
	return serviced;
	}

// ---------------------------------------------------------
// CMenuSrvSession::ServiceCapWriteL
// Handles functions with write device data capability
// ---------------------------------------------------------
//
TBool CMenuSrvSession::ServiceCapWriteL( const RMessage2& aMessage )
	{
	TBool serviced = ETrue;
	switch( aMessage.Function() )
        {
        case EMenuOperationClose:
            {
            TInt handle = aMessage.Int3();
            OperationL( handle ); // Check that handle is valid.
            iOperationIx->Remove( handle );
            break;
            };

        case EMenuOperationCreateRemove:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            CMenuSrvOperation* op = new (ELeave) CMenuSrvRemoveOperation
                ( iSharedEng->Engine(), aMessage.Int0() );
            AddOperationL( op, aMessage ); // Ownership taken before adding.
            break;
            }

        case EMenuOperationCreateMoveToFolder:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt bufHandle = aMessage.Int0();
            MStreamBuf& buf = StreamL( bufHandle ).Host();
            RReadStream rs( &buf );
            CMenuSrvOperation* op = CMenuSrvMoveToFolderOperation::NewL
                ( iSharedEng->Engine(), rs, aMessage.Int1(), aMessage.Int2() );
            AddOperationL( op, aMessage ); // Ownership taken before adding.
            break;
            }

        case EMenuOperationCreateReorder:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            CMenuSrvOperation* op = new (ELeave) CMenuSrvReorderOperation
                ( iSharedEng->Engine(), aMessage.Int0(), aMessage.Int1() );
            AddOperationL( op, aMessage ); // Ownership taken before adding.
            break;
            }

        case EMenuOperationCreateAdd:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TBuf<KMenuMaxTypeLen> type;
            __ASSERT_ALWAYS( aMessage.GetDesLength( 0 ) <= type.MaxLength(), \
                User::Leave( KErrBadDescriptor ) ); // Panic the client.
            aMessage.ReadL( 0, type );
            TInt bufHandle = aMessage.Int1();
            MStreamBuf& buf = StreamL( bufHandle ).Host();
            RReadStream rs( &buf );
            CMenuSrvAddOperation* op = CMenuSrvAddOperation::NewL
                ( iSharedEng->Engine(), type, rs );
            CleanupStack::PushL( op ); // Leaving calls before AddOperationL.
            // Send the ID back. Object not yet added to engine!
            TPckgBuf<TInt> id;
            id() = op->ObjectId();
            __ASSERT_DEBUG( id(), User::Invariant() ); // We must have the ID already!
            aMessage.WriteL( 2, id );
            CleanupStack::Pop( op );
            AddOperationL( op, aMessage ); // Ownership taken before adding.
            break;
            }

        case EMenuOperationCreateUpdate:
            {
            __ASSERT_ALWAYS( iSharedEng, PanicClientL( aMessage ) );
            TInt bufHandle = aMessage.Int1();
            MStreamBuf& buf = StreamL( bufHandle ).Host();
            RReadStream rs( &buf );
            CMenuSrvOperation* op = CMenuSrvUpdateOperation::NewL
                ( iSharedEng->Engine(), aMessage.Int0(), rs );
            AddOperationL( op, aMessage ); // Ownership taken before adding.
            break;
            }

        case EMenuOperationCancel:
            {
            TInt handle = aMessage.Int3();
            OperationL( handle ).Cancel();
            break;
            }

        case EMenuOperationStart:
            {
            TInt handle = aMessage.Int3();
            OperationL( handle ).StartL( aMessage );
            // No leaving after this point!
            return ETrue; // Async request -> the object will complete it.
            }
        default:
            {
            serviced = EFalse;
            break;
            }
        }
	if( serviced )
		{
		aMessage.Complete( KErrNone );// Sync request -> complete it now.
		}
	return serviced;
	}

// ---------------------------------------------------------
// CMenuSrvSession::ServiceError
// ---------------------------------------------------------
//
void CMenuSrvSession::ServiceError( const RMessage2& aMessage, TInt aError )
    {
    // A bad descriptor / bad handle error implies a badly programmed client,
    // so panic it; otherwise use the default handling (report the error to
    // the client).
    if ( aError == KErrBadDescriptor || aError == KErrBadHandle )
        {
        aMessage.Panic( KMenuSrvName, aError );
        }
    if ( aError == KErrNoMemory )
    	{
    	iSharedEng->CloseOutputBuffer();
    	iSharedEng->CleanAttributeCache();
    	}
    CSession2::ServiceError( aMessage, aError );
    }

// ---------------------------------------------------------
// CMenuSrvSession::EngineEvents
// ---------------------------------------------------------
//
void CMenuSrvSession::EngineEvents( TInt aFolder, TInt aEvents )
    {
    for ( TInt i = 0; i < iNotifierIx->Count(); i++ )
        {
        CMenuSrvNotifier* notif = (CMenuSrvNotifier*)(*iNotifierIx)[i];
        notif->HandleEvents( aFolder, aEvents );
        }
    }

// ---------------------------------------------------------
// CMenuSrvSession::EngineError
// ---------------------------------------------------------
//
void CMenuSrvSession::EngineError( TInt /*aErr*/ )
    {
    // Unrecoverable engine error. The engine is dead and will be deleted.
    // This session has already been removed from the shared engine's list.
    // This session became useless now; it rejects all messages and is
    // waiting to be closed.
    iSharedEng = NULL;
    iEngineDead = ETrue;
    }
// ---------------------------------------------------------
// CMenuSrvSession::NewStreamL
// ---------------------------------------------------------
//
void CMenuSrvSession::NewStreamL
( MStreamBuf& aHost, const RMessage2& aMessage )
    {
    aHost.PushL();
    TInt len = Min( aHost.SizeL(), KMenuStreamBufSize );
    if ( len )
        {
        // We already have some data; send it.
        TPckgBuf<TMenuBuf> buf;
        aHost.ReadL( buf().iData, len );
        buf().iLen = len;
        aMessage.WriteL( KParamIndBuf, buf );
        }
    // Create the stream, it takes ownership of aHost.
    CMenuSrvStream* obj = new (ELeave) CMenuSrvStream( aHost );
    CleanupStack::Pop( &aHost );
    CleanupStack::PushL( obj );
    iObjectCon->AddL( obj );
    TInt handle = iStreamIx->AddL( obj );
    CleanupStack::Pop( obj ); // Now we manage the stream by handle.
    TPckgC<TInt> handlePckg( handle );
    TInt err = aMessage.Write( KParamIndStream, handlePckg );
    if ( err )
        {
        iStreamIx->Remove( handle );
        User::Leave( err );
        }
    }

// ---------------------------------------------------------
// CMenuSrvSession::StreamL
// ---------------------------------------------------------
//
CMenuSrvStream& CMenuSrvSession::StreamL( TInt aHandle )
    {
    CMenuSrvStream* obj = (CMenuSrvStream*)iStreamIx->AtL( aHandle );
    if ( !obj )
        {
        User::Leave( KErrBadHandle );
        }
    return *obj;
    }

// ---------------------------------------------------------
// CMenuSrvSession::AddOperationL
// ---------------------------------------------------------
//
void CMenuSrvSession::AddOperationL
( CMenuSrvOperation* aOperation, const RMessage2& aMessage )
    {
    CleanupStack::PushL( aOperation );
    iObjectCon->AddL( aOperation );
    TInt handle = iOperationIx->AddL( aOperation );
    CleanupStack::Pop( aOperation ); // Now we manage the operation by handle.
    TPckgC<TInt> handlePckg( handle );
    TInt err = aMessage.Write( KParamIndOp, handlePckg );
    if ( err )
        {
        iOperationIx->Remove( handle ); // Deletes the operation.
        User::Leave( err );
        }
    }

// ---------------------------------------------------------
// CMenuSrvSession::OperationL
// ---------------------------------------------------------
//
CMenuSrvOperation& CMenuSrvSession::OperationL( TInt aHandle )
    {
    CMenuSrvOperation* obj = (CMenuSrvOperation*)iOperationIx->AtL( aHandle );
    if ( !obj )
        {
        User::Leave( KErrBadHandle );
        }
    return *obj;
    }

// ---------------------------------------------------------
// CMenuSrvSession::NewNotifierL
// ---------------------------------------------------------
//
void CMenuSrvSession::NewNotifierL( const RMessage2& aMessage )
    {
    CMenuSrvNotifier* obj = new (ELeave) CMenuSrvNotifier;
    CleanupStack::PushL( obj );
    iObjectCon->AddL( obj );
    TInt handle = iNotifierIx->AddL( obj );
    CleanupStack::Pop( obj ); // Now we manage the notifier by handle.
    TPckgC<TInt> handlePckg( handle );
    TInt err = aMessage.Write( KParamIndNotif, handlePckg );
    if ( err )
        {
        iNotifierIx->Remove( handle );
        User::Leave( err );
        }
    }

// ---------------------------------------------------------
// CMenuSrvSession::NotifierL
// ---------------------------------------------------------
//
CMenuSrvNotifier& CMenuSrvSession::NotifierL( TInt aHandle )
    {
    CMenuSrvNotifier* obj = (CMenuSrvNotifier*)iNotifierIx->AtL( aHandle );
    if ( !obj )
        {
        User::Leave( KErrBadHandle );
        }
    return *obj;
    }

// ---------------------------------------------------------
// CMenuSrvSession::PanicClientL
// ---------------------------------------------------------
//
void CMenuSrvSession::PanicClientL( const RMessage2& aMessage )
    {
    // Client error. Panic client and leave.
    // Use an error code (KErrGeneral) which does not cause ServiceError
    // to panic the client again!
    aMessage.Panic( KMenuSrvName, KErrGeneral );
    User::Leave( KErrGeneral );
    }

//  End of File