diff -r 9f5ae1728557 -r db3f5fa34ec7 messagingfw/sendas/server/src/csendassession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingfw/sendas/server/src/csendassession.cpp Wed Nov 03 22:41:46 2010 +0530 @@ -0,0 +1,527 @@ +// Copyright (c) 2004-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 "csendassession.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "csendasserver.h" +#include "csendasmtmmanager.h" +#include "csendasmessage.h" +#include "sendasserverdefs.h" +#include "tsendasserverpanic.h" + +CSendAsSession* CSendAsSession::NewL(const TVersion& aVersion, CSendAsServer& aServer) + { + TVersion version(KSendAsServerVersionMajor, KSendAsServerVersionMinor, KSendAsServerVersionBuild); + if( !User::QueryVersionSupported(version, aVersion) ) + { + User::Leave(KErrNotSupported); + } + + CSendAsSession* self = new(ELeave) CSendAsSession(aServer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CSendAsSession::ConstructL() + { + iMessages = CObjectIx::NewL(); + iContainer = iServer.NewContainerL(); + TMsvSelectionOrdering order(KMsvNoGrouping, EMsvSortByDetails, ETrue); + iMsvEntry = CMsvEntry::NewL(GetMsvSessionL(), KMsvRootIndexEntryId, order); + iSendAsAccounts = CSendAsAccounts::NewL(); + + // Prepare available message type list + iAvailableMessageTypes = CSendAsMessageTypes::NewL(); + ResetTypeFilterL(); + } + +CSendAsSession::CSendAsSession(CSendAsServer& aServer) +: iServer(aServer) + { + } + +CSendAsSession::~CSendAsSession() + { + delete iMessages; + // iContainer will be deleted by the server + iServer.SessionClosed(iContainer); + delete iSendAsAccounts; + delete iAvailableMessageTypes; + delete iMsvEntry; + } + +/** Service the incoming message. + +If the message is for the session object, it will be dispatched to +the correct handler. If the message is for the subsession object, +it will be dispatched to the handler located in the subsession. + +This allows all of the subsession logic to be internal to itself. + +If a handler requires an asynchronous response, then this method +should return ETrue. If this method leaves, the trap harness in +the ServiceL method will catch the error and complete the message +with the error code. + +@param aMessage +The IPC message object. +*/ +TBool CSendAsSession::DoServiceL(const RMessage2& aMessage) + { + // session methods + switch (aMessage.Function()) + { + case ESASSetFilter: + DoSetMessageTypeFilterL(aMessage); + break; + case ESASClearFilter: + DoClearMessageTypeFilterL(); + break; + case ESAMDestroySubSession: + // this is a sub session message, which means that the handle is transmitted + // automatically, but we will handle it at the session level so we can + // not only close the subsession, but also delete the object properly. + RemoveMessage(aMessage.Int3()); + break; + case ESASGetMessageTypeListLength: + DoGetMessageTypeListLengthL(aMessage); + break; + case ESASGetMessageTypes: + DoGetMessageTypeListL(aMessage); + break; + case ESASGetAccountListLength: + DoGetAccountListLengthL(aMessage); + break; + case ESASGetAccountList: + DoGetAccountListL(aMessage); + break; + case ESASCreateSubSession: + CreateSubsessionL(aMessage); + break; + default: + { + // must be a subsession method + CSendAsMessage* msg = MessageFromHandle(aMessage.Int3()); + if( msg == NULL ) + { + PanicClient(aMessage, ESendAsClientPanicBadSubSessionHandle); + User::Leave(KErrBadHandle); + } + return msg->DoSubSessionServiceL(aMessage); + } + } + return EFalse; + } + +/** Create a new subsession object to represent a message. + +Each message is represented by a CSendAsMessage object. These objects +are derived from CContainer. This allows us to use the object container +framework to keep track of allocated objects and to ensure that the +object handles are unique. + +The RMessage is required so that the session can pass the new +subsession handle to the client-side RSubSession object. + +@param aMessage +The IPC message object. +*/ +void CSendAsSession::CreateSubsessionL(const RMessage2& aMessage) + { + // new message (subsession) + CSendAsMessage* message = CSendAsMessage::NewL(*this); + CleanupClosePushL(*message); + + // add message class into the container and obtain a handle for it. + iContainer->AddL(message); + TInt id = iMessages->AddL(message); + CleanupStack::Pop(message); + + // write the handle back to the client + TPckg pckg(id); + TInt err = aMessage.Write(3, pckg); + + if( err != KErrNone ) + { + iMessages->Remove(id); + message->Close(); + + User::Leave(err); + } + ++iMessageCount; + } + +/** Find a subsession pointer from its handle. + +A message sent from an RSubSession-derived object will always contain +a handle to the server-side subsession object in parameter 3. + +This method takes that handle and looks it up in the object index to +find the pointer to the correct subsession instance. + +@param aHandle +The handle for the subsession object + +@return +The pointer to the subsesion object referred to by aHandle if it exists, +otherwise NULL is returned. +*/ +CSendAsMessage* CSendAsSession::MessageFromHandle(TUint aHandle) + { + return static_cast(iMessages->At(aHandle)); + } + +void CSendAsSession::RemoveMessage(TUint aHandle) + { + // this operation will delete the subsession. + iMessages->Remove(aHandle); + --iMessageCount; + } + +void CSendAsSession::PanicClient(const RMessage2& aMessage, TSendAsClientPanic aPanic) const + { + _LIT(KSendAsServerSession, "SendAsSession"); + aMessage.Panic(KSendAsServerSession, aPanic); + } + +/** Add a message type filter to the list. + +This removes any non-compliant MTMs from the list of available MTMs. + +This is a cumulative operation, filters are applied as they are received +and the list is shortened each time. + +@param aMessage +The IPC message object. +*/ +void CSendAsSession::DoSetMessageTypeFilterL(const RMessage2& aMessage) + { + // extract filter + TPckgBuf filterBuf; + aMessage.ReadL(0, filterBuf); + + // apply to available mtm list + AddTypeFilterL(filterBuf()); + } + +/** Remove the message type filter. + +In reality, this means that we repopulate the entire list. +*/ +void CSendAsSession::DoClearMessageTypeFilterL() + { + ResetTypeFilterL(); + } + +void CSendAsSession::DoGetMessageTypeListLengthL(const RMessage2& aMessage) + { + // return size of message types data + TPckgBuf buf(iAvailableMessageTypes->Size()); + aMessage.WriteL(0, buf); + } + +void CSendAsSession::DoGetMessageTypeListL(const RMessage2& aMessage) + { + // buffer to hold message types data + HBufC8* buffer = HBufC8::NewLC(iAvailableMessageTypes->Size()); + + // stream + RDesWriteStream strm; + CleanupClosePushL(strm); + TPtr8 ptr(buffer->Des()); + strm.Open(ptr); + + // write to stream + iAvailableMessageTypes->ExternalizeL(strm); + strm.CommitL(); + aMessage.WriteL(0, *buffer); + + // clean up + CleanupStack::PopAndDestroy(2, buffer); // buffer, strm + } + +void CSendAsSession::DoGetAccountListLengthL(const RMessage2& aMessage) + { + // message slot 1 contains the mtm uid + TPckgBuf uidBuf; + aMessage.ReadL(1, uidBuf); + + // reset the account list + iSendAsAccounts->Reset(); + + // get account list for this mtm + TUid acctUid = uidBuf(); + iMsvEntry->SetEntryL(KMsvRootIndexEntryId); + CMsvEntrySelection* selection = iMsvEntry->ChildrenWithMtmL(acctUid); + CleanupStack::PushL(selection); + + // populate account list + TInt count = selection->Count(); + iSendAsAccounts->SetMessageType(acctUid); + for (TInt i=0; iAt(i); + // set context + iMsvEntry->SetEntryL(id); + // add account + iSendAsAccounts->AppendAccountL(iMsvEntry->Entry().iDetails, id); + } + CleanupStack::PopAndDestroy(selection); + + // get size + TPckgBuf buf(iSendAsAccounts->Size()); + aMessage.WriteL(0, buf); + } + +void CSendAsSession::DoGetAccountListL(const RMessage2& aMessage) + { + // buffer to hold accounts data + HBufC8* buffer = HBufC8::NewLC(iSendAsAccounts->Size()); + + // buffer write stream + RDesWriteStream strm; + CleanupClosePushL(strm); + TPtr8 ptr(buffer->Des()); + strm.Open(ptr); + + // write to buffer + iSendAsAccounts->ExternalizeL(strm); + + // commit and return buffer + strm.CommitL(); + aMessage.WriteL(0, *buffer); + + // clean up + CleanupStack::PopAndDestroy(2, buffer); // buffer, strm + } + +CMsvSession& CSendAsSession::GetMsvSessionL() + { + return iServer.GetMsvSessionL(); + } + +CSendAsActiveContainer& CSendAsSession::ActiveContainer() + { + return iServer.ActiveContainer(); + } + +const TUid& CSendAsSession::NotifierUid() const + { + return iServer.NotifierUid(); + } + +const TUid& CSendAsSession::EditUtilsPluginUid() const + { + return iServer.EditUtilsPluginUid(); + } + +/* + * methods from CSession2 + */ + +/** Session ServiceL method. + +This method traps the real serviceL method so that leaves can +be trapped and returned as error completion codes on the message. + +This prevents the session from leaving during the server AO's +RunL and causing a panic. + +@param aMessage +The IPC message object. +*/ +void CSendAsSession::ServiceL(const RMessage2& aMessage) + { + TBool async = EFalse; + TRAPD(err, async = DoServiceL(aMessage)); + + // complete the message if necessary. + if (!async || err != KErrNone) + { + aMessage.Complete(err); + } + } + + +/** Handles session disconnect. + +@param aMessage +The IPC message object. +*/ +void CSendAsSession::Disconnect(const RMessage2& aMessage) + { + // Cancel all sub-session objects. + TInt count = iMessages->Count(); + for( TInt i=0; i((*iMessages)[i]); + message->CancelMessage(); + } + + // Must call the base class implementation - this will delete the object. + CSession2::Disconnect(aMessage); + } + + +/* + * available Client MTM array management and access methods. + */ + +/** Resets the available message type list + +*/ +void CSendAsSession::ResetTypeFilterL() + { + // get unfiltered MTM array + RArray& aMtmUidArray = iServer.GetMtmManager()->GetMtmUidArray(); + + // get client registry + CClientMtmRegistry* aClientRegistry = iServer.GetMtmManager()->GetClientMtmRegistry(); + + // reset filtered MTM array + iAvailableMessageTypes->Reset(); + + // populate filtered MTM array + TInt count = aMtmUidArray.Count(); + for( TInt i=0; iRegisteredMtmDllInfo(mtmUid).HumanReadableName(); + iAvailableMessageTypes->AppendMessageTypeL(name, mtmUid); + } + } + +/** Reduces available message type list according to filter + +@param aFilter +The filter to be applied +*/ +void CSendAsSession::AddTypeFilterL(const TSendAsMessageTypeFilter& aFilter) + { + if( aFilter.iMessageCapability == KUidMtmQueryCanSendMsg ) + { + // the list of mtms available to sendas sessions is created with this + // capability by default by the sendas MTM manager, so no action needed + return; + } + + // locals used in scan loop + CBaseMtm* mtm = NULL; + TInt response; + TInt error; + TBool capable; + + // scan list of mtms and filter out those without the required capabilities + TInt count = iAvailableMessageTypes->Count(); + while( count-- > 0 ) + { + // get mtm by uid + mtm = iServer.GetMtmManager()->FindStoredMtmL(iAvailableMessageTypes->MessageTypeUid(count)); + + // check if capability supported + response = 0; + error = mtm->QueryCapability(aFilter.iMessageCapability, response); + + // if capability supported, check conditions + capable = EFalse; + if( error == KErrNone ) + { + switch (aFilter.iCondition) + { + case RSendAs::ESendAsNoCondition: + capable = ETrue; + break; + case RSendAs::ESendAsEquals: + capable = (response == aFilter.iValue); + break; + case RSendAs::ESendAsNotEquals: + capable = (response != aFilter.iValue); + break; + case RSendAs::ESendAsGreaterThan: + capable = (response > aFilter.iValue); + break; + case RSendAs::ESendAsLessThan: + capable = (response < aFilter.iValue); + break; + case RSendAs::ESendAsBitwiseAnd: + capable = (response & aFilter.iValue); + break; + case RSendAs::ESendAsBitwiseOr: + capable = (response | aFilter.iValue); + break; + case RSendAs::ESendAsBitwiseNand: + capable = !(response & aFilter.iValue); + break; + case RSendAs::ESendAsBitwiseNor: + capable = !(response | aFilter.iValue); + break; + default: + break; + } + } + else if( error != KErrNotSupported ) + { + User::Leave(error); + } + + if( !capable ) + { + // mtm is not capable, so remove it from the available list + iAvailableMessageTypes->RemoveMessageType(count); + } + } + } + +/** Updates the array of available Client MTMs + +*/ +void CSendAsSession::HandleMtmChange() + { + // get unfiltered MTM UID array + RArray& aMtmUidArray = iServer.GetMtmManager()->GetMtmUidArray(); + + // check for removed mtm from filtered lists + TInt count = iAvailableMessageTypes->Count(); + for( TInt i=0; iMessageTypeUid(i)) == KErrNotFound) + { + iAvailableMessageTypes->RemoveMessageType(i); + break; + } + } + } + +/** Returns the client MTM specified by UID + +@param aMtmUid +The UID of the Client MTM +*/ +CBaseMtm* CSendAsSession::GetClientMtmL(TUid aMtmUid) + { + return ( iServer.GetMtmManager()->GetClientMtmL(aMtmUid) ); + }