diff -r 000000000000 -r 79c6a41cd166 menucontentsrv/srvsrc/menusrvsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/menucontentsrv/srvsrc/menusrvsession.cpp Thu Dec 17 08:54:17 2009 +0200 @@ -0,0 +1,731 @@ +/* +* 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 +#include + + +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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