menucontentsrv/src/menu.cpp
changeset 0 79c6a41cd166
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menucontentsrv/src/menu.cpp	Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,416 @@
+/*
+* 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 "mcsdef.h"
+
+#include "mcsmenu.h"
+#include "menusrvdef.h"
+#include "menumsg.h"
+#include "menubuf.h"
+#include "menuutil.h"
+#include "menuclientoperation.h"
+#include "menuhandlereng.h"
+#include "mcsmenufilter.h"
+
+#include <s32strm.h>
+#include <e32debug.h>
+
+// ================= LOCAL FUNCTIONS =======================
+
+/**
+* Start the server executable.
+* @return Error code.
+*/
+LOCAL_C TInt StartServer()
+    {
+    TInt err( KErrNone );
+    RProcess server;
+    err = server.Create( KMenuSrvExe, KNullDesC, EOwnerThread );
+    if ( !err )
+        {
+        TRequestStatus status;
+        server.Rendezvous( status );
+        if ( status != KRequestPending )
+            {
+            server.Kill( 0 ); // Abort startup.
+            }
+        else
+            {
+            server.Resume(); // Logon OK - start the server.
+            }
+        User::WaitForRequest( status ); // Wait for start or death.
+        // We can't use the 'exit reason' if the server panicked as this
+        // is the panic 'reason' and may be '0' which cannot be distinguished
+        // from KErrNone.
+        err = (server.ExitType() == EExitPanic) ? KErrGeneral : status.Int();
+        server.Close();
+        }
+    return err;
+    }
+
+// ================= MEMBER FUNCTIONS =======================
+
+NONSHARABLE_CLASS( RMenu::TData )
+    {
+public:
+    // Transfer buffer. Size must be big enough to accomodate any object that
+    // will go through it: attribute, TMenuItem
+    TUint16 iBuf[KMenuMaxAttrValueLen];
+    // Handler engine.
+    CMenuHandlerEng* iHandler;
+    };
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// RMenu::Close
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::Close()
+    {
+    RSessionBase::Close();
+    if ( iData )
+        {
+        delete iData->iHandler; iData->iHandler = NULL;
+        delete iData; iData = NULL;
+        }
+    }
+
+// ---------------------------------------------------------
+// RMenu::OpenL
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::OpenL( const TDesC& aName )
+    {
+    __ASSERT_DEBUG( !iData, User::Invariant() );
+    User::LeaveIfError( ConnectSession() );
+    CleanupClosePushL( *this ); // Atomcic connect + local data + construct.
+    iData = new (ELeave) RMenu::TData();
+    iData->iHandler = NULL;
+    // We have a connected blank session, now construct it.
+    // It would be good to have a CreateSession which leaves us at least one
+    // IpcArg, so the name could be sent to session creation directly.
+    // Since having a fully constructed session needs this extra IPC, the
+    // server side session had to be cluttered with ASSERTS. (Almost all
+    // messages need to check that the session is fully constructed.)
+    //
+    // The reason for this is a design issue (we use the session as an object,
+    // and not just as a communication channel. But normally there is only one
+    // object used, so why complicate things for the client?
+    User::LeaveIfError
+        ( SendReceive( EMenuConstructSession, TIpcArgs( &aName ) ) );
+    CleanupStack::Pop( this );
+    }
+
+// ---------------------------------------------------------
+// RMenu::RootFolderL
+// ---------------------------------------------------------
+//
+EXPORT_C TInt RMenu::RootFolderL()
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    TPckgBuf<TInt> pckg;
+    User::LeaveIfError( SendReceive( EMenuRootFolder, TIpcArgs( &pckg ) ) );
+    return pckg();
+    }
+
+// ---------------------------------------------------------
+// RMenu::GetItemsL
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::GetItemsL(
+        RArray<TMenuItem>& aItemArray,
+        TInt aFolder,
+        const CMenuFilter* aFilter /*=NULL*/,
+        TBool aRecursive /*=EFalse*/ )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    if ( aFilter )
+        {
+        // Filtered query, 2+ more IPC.
+        // The buffer is opened empty, used to send the filter
+        // then the result is received into it.
+        RMenuBuf buf;
+        User::LeaveIfError( buf.Open( *this ) );
+        CleanupClosePushL( buf );
+        RWriteStream stream( &buf );
+        aFilter->ExternalizeL( stream );
+        stream.CommitL();
+        TIpcArgs args( aFolder, aRecursive, buf.SubSessionHandle() );
+        User::LeaveIfError( SendReceive( EMenuGetItemsFiltered, args ) );
+        RReadStream rs( &buf );
+        MenuUtil::InternalizeL( aItemArray, rs );
+        CleanupStack::PopAndDestroy( &buf );
+        }
+    else
+        {
+        // Unfiltered query.
+        // The buffer already contains the query result when Open() returns.
+        RMenuBuf buf;
+        TIpcArgs args( aFolder, aRecursive );
+        User::LeaveIfError( buf.Open( *this, EMenuGetItems, args ) );
+        CleanupClosePushL( buf );
+        RReadStream stream( &buf );
+        MenuUtil::InternalizeL( aItemArray, stream );
+        CleanupStack::PopAndDestroy( &buf );
+        }
+    }
+
+// ---------------------------------------------------------
+// RMenu::GetRunningAppsL
+// ---------------------------------------------------------
+//
+EXPORT_C  void RMenu::GetRunningAppsL( RArray<TUid>& aArray )
+	{
+    RMenuBuf buf;
+    TIpcArgs args( 0 );
+    User::LeaveIfError( buf.Open( *this, EMenuGetRunningApps, args ) );
+    CleanupClosePushL( buf );
+    RReadStream stream( &buf );
+    MenuUtil::InternalizeL( aArray, stream );
+    CleanupStack::PopAndDestroy( &buf );
+	}
+    
+
+// ---------------------------------------------------------
+// RMenu::RemoveL
+// ---------------------------------------------------------
+//
+EXPORT_C CMenuOperation* RMenu::RemoveL( TInt aId, TRequestStatus& aStatus )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
+        ( *this, CActive::EPriorityStandard, aStatus );
+    CleanupStack::PushL( op );
+    op->RemoveL( aId );
+    CleanupStack::Pop( op );
+    return op;
+    }
+
+// ---------------------------------------------------------
+// RMenu::MoveToFolderL
+// ---------------------------------------------------------
+//
+EXPORT_C CMenuOperation* RMenu::MoveToFolderL(
+        const RArray<TInt>& aItems,
+        TInt aFolder,
+        TInt aMoveBefore,
+        TRequestStatus& aStatus )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    RMenuBuf buf;
+    User::LeaveIfError( buf.Open( *this ) );
+    CleanupClosePushL( buf );
+    RWriteStream stream( &buf );
+    MenuUtil::ExternalizeL( aItems, stream );
+    stream.CommitL();
+    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
+        ( *this, CActive::EPriorityStandard, aStatus );
+    CleanupStack::PushL( op );
+    op->MoveToFolderL( buf, aFolder, aMoveBefore );
+    CleanupStack::Pop( op );
+    CleanupStack::PopAndDestroy( &buf );
+    return op;
+    }
+
+// ---------------------------------------------------------
+// RMenu::ReorderL
+// ---------------------------------------------------------
+//
+EXPORT_C CMenuOperation* RMenu::ReorderL
+( TInt aId, TInt aMoveBefore, TRequestStatus& aStatus )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    CMenuClientOperation* op = new (ELeave) CMenuClientOperation
+        ( *this, CActive::EPriorityStandard, aStatus );
+    CleanupStack::PushL( op );
+    op->ReorderL( aId, aMoveBefore );
+    CleanupStack::Pop( op );
+    return op;
+    }
+
+// ---------------------------------------------------------
+// RMenu::ResourceMark
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::ResourceMark()
+    {
+    SendReceive( EMenuResourceMarkStart );
+    }
+
+// ---------------------------------------------------------
+// RMenu::ResourceCheck
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::ResourceCheck()
+    {
+    SendReceive( EMenuResourceMarkEnd );
+    }
+
+// ---------------------------------------------------------
+// RMenu::ResourceCount
+// ---------------------------------------------------------
+//
+EXPORT_C TInt RMenu::ResourceCount()
+    {
+    return SendReceive( EMenuResourceCount );
+    }
+
+#ifdef _DEBUG
+
+// ---------------------------------------------------------
+// RMenu::__DbgSetAllocFail
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::__DbgSetAllocFail
+( RAllocator::TAllocFail aType, TInt aRate )
+    {
+    TInt type = STATIC_CAST( TInt, aType );
+    SendReceive( EMenuSetHeapFailure, TIpcArgs( type, aRate ) );
+    }
+
+#else /* not _DEBUG */
+
+// ---------------------------------------------------------
+// RMenu::__DbgSetAllocFail
+// ---------------------------------------------------------
+//
+EXPORT_C void RMenu::__DbgSetAllocFail
+( RAllocator::TAllocFail /*aType*/, TInt /*aRate*/ )
+    {
+    }
+
+#endif /* def _DEBUG */
+
+// ---------------------------------------------------------
+// RMenu::HandleCommandL
+// ---------------------------------------------------------
+//
+CMenuOperation* RMenu::HandleCommandL(
+        CMenuItem& aItem,
+        const TDesC8& aCommand,
+        const TDesC8& aParams,
+        TRequestStatus& aStatus )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    if ( !iData->iHandler )
+        {
+        // Create handler engine on demand - handlers not loaded unless needed.
+        iData->iHandler = CMenuHandlerEng::NewL( *this );
+        }
+    return iData->iHandler->HandleCommandL
+        ( aItem, aCommand, aParams, aStatus );
+    }
+
+// ---------------------------------------------------------
+// RMenu::ConnectSession
+// ---------------------------------------------------------
+//
+TInt RMenu::ConnectSession()
+    {
+    TVersion version( KMenuMajorVersion, KMenuMinorVersion, KMenuBuild );
+    TInt err = CreateSession( KMenuSrvName, version );
+    if ( KErrNotFound == err )
+        {
+        err = StartServer();
+        if ( !err || KErrAlreadyExists == err ) // Deal with race conditions.
+            {
+            err = CreateSession( KMenuSrvName, version );
+            }
+        }
+    return err;
+    }
+
+// ---------------------------------------------------------
+// RMenu::GetAttributeL
+// ---------------------------------------------------------
+//
+HBufC* RMenu::GetAttributeL( TInt aId, const TDesC& aAttrName )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= 2 * KMenuMaxAttrValueLen, \
+        User::Invariant() ); // Must fit into the transfer buffer.
+    
+    RBuf ptr;
+    ptr.CleanupClosePushL();
+    ptr.CreateL(KMenuMaxAttrValueLen);
+    TPckgBuf<TBool> attrExists( EFalse );
+    TIpcArgs args( aId, &aAttrName, &attrExists, &ptr );
+    User::LeaveIfError( SendReceive( EMenuItemGetAttribute, args ) );
+    
+    if( attrExists() )
+    	{
+    	HBufC* ret = ptr.AllocL();
+    	CleanupStack::PopAndDestroy( &ptr );
+    	return ret;
+    	}
+    else
+    	{
+    	CleanupStack::PopAndDestroy( &ptr );
+    	return NULL;
+    	}
+    }
+    
+
+
+// ---------------------------------------------------------
+// RMenu::GetAttributeL
+// ---------------------------------------------------------
+void RMenu::GetAttributeListL( TInt aId, RArray<TAttributeName>& aList )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= 2 * KMenuMaxAttrValueLen, \
+        User::Invariant() ); // Must fit into the transfer buffer.
+
+    RMenuBuf buf;
+    TIpcArgs args( aId );
+    User::LeaveIfError( buf.Open( *this, EMenuItemGetAttributeList, args ) );
+    CleanupClosePushL( buf );
+    RReadStream rs( &buf );
+    
+    TInt len;
+    TAttributeName name;
+    while ( ETrue )
+        {
+
+        len = rs.ReadInt32L();
+
+        if ( len == 0 )
+            {
+            break;
+            }
+
+        rs.ReadL( name, len );
+        aList.AppendL( name );
+        }
+
+    CleanupStack::PopAndDestroy( &buf );
+    }
+
+// ---------------------------------------------------------
+// RMenu::GetHdrL
+// ---------------------------------------------------------
+//
+const TMenuItem& RMenu::GetHdrL( TInt aId )
+    {
+    __ASSERT_DEBUG( iData, User::Invariant() );
+    __ASSERT_DEBUG( sizeof( iData->iBuf ) >= sizeof( TMenuItem ), \
+        User::Invariant() ); // Header must fit into the transfer buffer.
+    TPckg<TMenuItem> pckg( (TMenuItem&)iData->iBuf );
+    TIpcArgs args( aId, &pckg );
+    User::LeaveIfError( SendReceive( EMenuGetHdr, args ) );
+    return pckg(); // Returned object is in the transfer buffer.
+    }