diff -r 000000000000 -r 876b1a06bc25 plugins/contacts/symbian/contactsmodel/cntsrv/src/ccntitemmsghandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/contacts/symbian/contactsmodel/cntsrv/src/ccntitemmsghandler.cpp Wed Aug 25 15:49:42 2010 +0300 @@ -0,0 +1,691 @@ +/* +* Copyright (c) 2007-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: +* +*/ + + +/** + @file + @internalComponent +*/ + +#include "ccntmsghandler.h" +#include "ccntmsghandlerfptr.h" +#include "ccntitemmsghandler.h" + +#include "ccntipccodes.h" +#include "ccntrequest.h" +#include "ccntdbmanager.h" +#include "ccntstatemachine.h" +#include "ccntdbmanagercontroller.h" +#include "ccntbackuprestoreagent.h" +#include "ccntpackager.h" +#include "cntspeeddials.h" + +const TInt KCntItemIpcCodes[] = + { + ECntItemCreate, + ECntItemUpdate, + ECntItemDelete, + ECntItemRead, + ECntItemCommit, + ECntItemOpen, + ECntItemClose, + ECntConnectionId, + ECntGetCurrentItem, + ECntRemoveCurrentItem, + ECntSetCurrentItem, + ECntGetCurrentDb, + ECntSetCurrentDb, + ECntGetSpeedDialContactIdAndPhoneNumber, + ECntSetSpeedDialIdForPosition, + ECntSetOwnCard, + ECntGetOwnCard, + ECntGetCollection, + ECntSetSortPrefs, + ECntGetSortPrefs, + ECntSetDbViewContactType, + ECntGetDbViewContactType, + ECntDbContactCount, + ECntFindAsync, + ECntFindAsyncInit, + ECntFindAsyncTextDefInit, + ECntFind, + ECntFilterDatabase, + ECntSetAsyncActivity, + ECntResourceCount, + ECntSetHeapFailure, + ECntSeekContactInCollection + }; + +CCntItemMsgHandler* CCntItemMsgHandler::NewLC(CCntSession& aSession) + { + CCntItemMsgHandler* CntItemMsgHandler = new (ELeave) CCntItemMsgHandler(aSession); + CleanupStack::PushL(CntItemMsgHandler); + return CntItemMsgHandler; + } + +CCntItemMsgHandler::CCntItemMsgHandler(CCntSession& aSession) +:CCntMsgHandler(aSession) + { + } + +CCntItemMsgHandler::~CCntItemMsgHandler() + { + } + +/** +Delegates the incoming op code to a message handling method. + +First checks if this class services the op code, it then uses the lookup table and finds +function pointer(to message handling method) mapped to the incoming message function (op code) +and finally delegates the message to handling method. + +It returns KErrNotFound if op code not handled. +*/ +TInt CCntItemMsgHandler::HandleMessageL(const RMessage2& aMessage) + { + MsgHandlerFptr func_ptr = LookupHandlerMethodL(aMessage.Function(), KCntItemIpcCodes, sizeof(KCntItemIpcCodes)/sizeof(TInt)); + + if(func_ptr) + { + ItemMsgHandlerFptr mem_func_ptr = static_cast(func_ptr); + (this->*mem_func_ptr)(aMessage); + return (KErrNone); + } + + return (KErrNotFound); + } + +/** +Message handling methods. + +N.B.: Some operations use aMessage.Complete() to return the a contact ID. This +is not convention but saves on IPC overhead. Only one parameter is returned as +opposed to two (error code and contact ID). + +@param aMessage The message typically containing the Contact Item. +*/ +void CCntItemMsgHandler::ItemCreateL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqCreateCnt* request = CReqCreateCnt::NewLC(iSessionId, aMessage, iTimeOut, iPackager); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemUpdateL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqUpdateCnt* request = CReqUpdateCnt::NewLC(iSessionId, aMessage, iTimeOut, iPackager); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemDeleteL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqDeleteCnt* request = CReqDeleteCnt::NewLC(iSessionId, aMessage, iTimeOut); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemReadL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqReadCnt* request = CReqReadCnt::NewLC(iSessionId, aMessage, iTimeOut, iPackager, iView->ItemDef()); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemCommitL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqCommitCnt* request = CReqCommitCnt::NewLC(iSessionId, aMessage, iTimeOut, iPackager); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemOpenL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqOpenCnt* request = CReqOpenCnt::NewLC(iSessionId, aMessage, iTimeOut, iPackager, iView->ItemDef()); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ItemCloseL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqCloseCnt* request = CReqCloseCnt::NewLC(iSessionId, aMessage, iTimeOut); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ConnectionId(const RMessage2& aMessage) + { + // Complete the request with the session ID. + aMessage.Complete(iSessionId); + } + +void CCntItemMsgHandler::GetCurrentItemL(const RMessage2& aMessage) + { + CheckForManagerL(); + TContactItemId currentItem(iManager->CurrentItem()); + // Complete the request with the contact ID of the current item. + aMessage.Complete(currentItem); + } + +void CCntItemMsgHandler::RemoveCurrentItemL(const RMessage2& aMessage) + { + CheckForManagerL(); + iManager->RemoveCurrentItemL(iSessionId); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::SetCurrentItemL(const RMessage2& aMessage) + { + CheckForManagerL(); + TContactItemId newCurrentItem = aMessage.Int0(); + iManager->SetCurrentItemL(newCurrentItem, iSessionId); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::GetCurrentDb(const RMessage2& aMessage) + { + WriteL(aMessage, KSlot0, Server().Controller().CurrentDb()); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::SetCurrentDbL(const RMessage2& aMessage) + { + CheckForManagerL(); + // Slot 0 in aMessage contains the new current database. + TFileName newCurrentDb; + ReadL(aMessage, KSlot0, newCurrentDb); + // Is this database already open for this session? We make it a + // pre-condition that you cannot set the current database to be one + // that isn't already open by this client. This prevents errors + // whereby a client updates the current database, but then fails to + // open it. + if (newCurrentDb.CompareF(iManager->CntFile()) == 0) + { + Server().Controller().SetCurrentDbL(newCurrentDb, iSessionId); + } + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::GetSpeedDialContactIdAndPhoneNumberL(const RMessage2& aMessage) + { + CheckForManagerL(); + const TInt speedDialIndex = aMessage.Int0(); + TSpeedDialPhoneNumber phoneNumber; + TContactItemId contactId; + iManager->GetSpeedDialContactIdAndPhoneNumberL(speedDialIndex, phoneNumber, contactId); + aMessage.WriteL(KSlot1, phoneNumber); + aMessage.Complete(contactId); + } + +void CCntItemMsgHandler::SetSpeedDialIdForPositionL(const RMessage2& aMessage) + { + CheckForManagerL(); + // fetch the old contacts ID + const CCntServerSpeedDialTable& table = iManager->IniFileManager().SpeedDialManager().TableL(iManager->CntFile()); + CReqSetSpeedDial* request = CReqSetSpeedDial::NewLC(iSessionId, + aMessage, + iTimeOut, + iView->ItemDef(), + iManager->IniFileManager().SpeedDialManager(), + table, + *iManager); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::SetOwnCardL(const RMessage2& aMessage) + { + CheckForManagerL(); + CReqSetOwnCard* request = CReqSetOwnCard::NewLC(iSessionId, + aMessage, + iTimeOut, + iPackager, + iView->ItemDef(), + *iManager); + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::GetOwnCardL(const RMessage2& aMessage) + { + CheckForManagerL(); + aMessage.Complete(iManager->GetPersistenceLayer().ContactProperties().OwnCardIdL()); + } + +void CCntItemMsgHandler::GetCollectionL(const RMessage2& aMessage) + { + CheckForManagerL(); + + // If backup or restore is in progress then database cannot be accessed. + CCntBackupRestoreAgent& burAgent = iManager->BackupRestoreAgent(); + if(burAgent.BackupInProgress() || burAgent.RestoreInProgress()) + { + User::Leave(KErrLocked); + } + + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + MLplCollection::TLplViewType type = static_cast(aMessage.Int1()); + CContactIdArray* idArray = NULL; + + switch(type) + { + case MLplCollection::EChangedSince : + { + TTime time(0); + TPckgBuf buf(time); + aMessage.ReadL(2,buf); + time = buf(); + idArray = collection.CollectionL(type,time,KNullDesC); + } + break; + + case MLplCollection::EFindGuid : + { + TTime time(0); + TBuf<64> buf; + aMessage.ReadL(2,buf); + idArray = collection.CollectionL(type,time,buf); + } + break; + + // Maps to RCntModel::MatchPhoneNumberL(). + case MLplCollection::EMatchPhoneNos: + { + const TInt receivingBufLen = aMessage.GetDesLengthL(2); + HBufC* buf = HBufC::NewLC(receivingBufLen); // digits in the number + TPtr ptr(const_cast(buf->Ptr()), receivingBufLen); + aMessage.ReadL(2, ptr); + idArray = collection.MatchPhoneNumberL(ptr, aMessage.Int3()); + CleanupStack::PopAndDestroy(buf); + } + break; + + default : + { + idArray = collection.CollectionL(type); + } + break; + } + + CleanupStack::PushL(idArray); + TPtr8 ptr = iPackager.PackL(*idArray); + TInt length = ptr.Length(); + + if(aMessage.GetDesMaxLength(0) >= length) + { + aMessage.WriteL(0,ptr); + aMessage.Complete(KErrNone); + } + else + { + aMessage.Complete(length); + } + + CleanupStack::PopAndDestroy(idArray); + } + +void CCntItemMsgHandler::SetSortPrefsL(const RMessage2& aMessage) + { + CheckForManagerL(); + iPackager.SetBufferFromMessageL(aMessage); + CArrayFix* prefs = iPackager.UnpackCArrayFixLC(); + iManager->GetPersistenceLayer().ContactProperties().SetSortPrefsL(prefs); + CleanupStack::Pop(prefs); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::GetSortPrefsL(const RMessage2& aMessage) + { + CheckForManagerL(); + const CArrayFix& prefs = iManager->GetPersistenceLayer().ContactProperties().SortPrefsL(); + TPtr8 ptr = iPackager.PackL(prefs); + TInt length = ptr.Length(); + if(aMessage.GetDesMaxLength(0) >= length) + { + aMessage.WriteL(0,ptr); + aMessage.Complete(KErrNone); + } + else + { + aMessage.Complete(length); + } + } + +void CCntItemMsgHandler::SetDbViewContactTypeL(const RMessage2& aMessage) + { + CheckForManagerL(); + iManager->GetPersistenceLayer().ContactProperties().SetDbViewContactType(TUid::Uid(aMessage.Int0())); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::GetDbViewContactTypeL(const RMessage2& aMessage) + { + CheckForManagerL(); + TPckg dbViewContactType(iManager->GetPersistenceLayer().ContactProperties().GetDbViewContactType()); + aMessage.WriteL(0,dbViewContactType); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::DbContactCountL(const RMessage2& aMessage) + { + CheckForManagerL(); + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + aMessage.Complete(collection.ContactCountL()); + } + +void CCntItemMsgHandler::FindAsyncL(const RMessage2& aMessage) + { + /* Maps to client side AsyncFindL(). Can and will be called iteratively by the + client. One of the two intitialisations below (i.e. ECntFindAsyncInit or + ECntFindAsyncTextDefInit will have been called prior to this call. + **/ + + CheckForManagerL(); + + TBool moreToGo(EFalse); + + // Call Persistence Layer to do the work. moreToGo will be set to + // ETrue if client should call again. CContactIdArray and TBool are + // return parameters to the client. + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + CContactIdArray* idArray = collection.FindAsyncL(moreToGo, iSessionId); + CleanupStack::PushL(idArray); + + TPckg morePckg(moreToGo); + aMessage.WriteL(1,morePckg); + + TPtr8 ptr8 = iPackager.PackL(*idArray); + // Iterative calls rely on packager having large enough buffer. + // Client expands it to 4k before calling. + // Write back to client + aMessage.WriteL(0,ptr8); + + CleanupStack::PopAndDestroy(idArray); + aMessage.Complete(KErrNone); + } + +// +void CCntItemMsgHandler::FindAsyncInitL(const RMessage2& aMessage) + { + /* Asynchronous find can use 2 types of initialisation which map to the + two construction types in the old Contacts Model. One uses a CContactTextDef + and CDesCArray and the other a CContactItemFieldDef and text descriptor. + Once initialisation is complete the client-side CIdleFinder::doFindL() method + calls AsyncFind(). + + Initialisation for asynchronous find using CContactItemFileldDef and TDesC. + **/ + + CheckForManagerL(); + + // Read descriptor into HBuf. + HBufC* text = HBufC::NewLC(aMessage.GetDesLengthL(0)); + TPtr ptr(text->Des()); + aMessage.ReadL(0,ptr); + + CContactItemFieldDef* fieldDef = NULL; + if(aMessage.GetDesLengthL(1) > 0) + { + // Use packager to unpack CContactItemFieldDef. + iPackager.SetBufferFromMessageL(aMessage,1); + fieldDef = static_cast (iPackager.UnpackTUidArrayLC()); + CleanupStack::Pop(fieldDef); + } + + // Persistence Layer does the actual initialisation and also takes + // ownership of fielDef. + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + collection.FindAsyncInitL(text->Des(),fieldDef); + + CleanupStack::PopAndDestroy(text); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::FindAsyncTextDefInitL(const RMessage2& aMessage) + { + /* Initialisation for asynchronous find using CContactTextDef and array of + "find words" constructed on the client-side and required on the server-side + for matching. + **/ + + CheckForManagerL(); + + // CContactTextDef can be NULL in which case the client will have + // passed an empty descriptor. + CContactTextDef* textDef = NULL; + // Assuming that a KNullDesC parameter results in max length of 0. + if(aMessage.GetDesLengthL(1) > 0) + { + // Use packager to unpack CContactTextDef. + iPackager.SetBufferFromMessageL(aMessage,1); + textDef = iPackager.UnpackCntTextDefLC(); + CleanupStack::Pop(textDef); + } + + // Unpack the CDesCArray manually as the packager does not package + // both. + CBufFlat* bufFlat = CBufFlat::NewL(1 << 8); + CleanupStack::PushL(bufFlat); + bufFlat->ExpandL(0,aMessage.GetDesLengthL(0)); + TPtr8 ptr8(bufFlat->Ptr(0)); + aMessage.ReadL(0,ptr8); + RBufReadStream readStream; + readStream.Open(*bufFlat); + TInt count = readStream.ReadInt32L(); + CDesCArray* unpacked = new (ELeave) CDesCArrayFlat(8); + CleanupStack::PushL(unpacked); + for(TInt i=0;i buf; + TInt length = readStream.ReadInt32L(); + readStream.ReadL(buf,length); + unpacked->AppendL(buf); + } + readStream.Close(); + + // Persistence Layer does the actual initialisation and also takes + // ownership of textDef. + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + collection.FindAsyncTextDefInitL(*unpacked,textDef); + + CleanupStack::PopAndDestroy(unpacked); + CleanupStack::PopAndDestroy(bufFlat); + aMessage.Complete(KErrNone); + } + +void CCntItemMsgHandler::SeekContactL(const RMessage2& aMessage) + { + CheckForManagerL(); + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + + TContactItemId actualId; + TUid contactType; + TBool deleted(EFalse); + // SeekContactL returns the Deleted Flag, the Contact ID and the + // contact type. + TBool seekRet = collection.SeekContactL(aMessage.Int0(),actualId,contactType,deleted); + + if(seekRet) + { + TPckg idPckg(actualId); + aMessage.WriteL(1,idPckg); + TPckg typePckg(contactType); + aMessage.WriteL(2,typePckg); + TPckg deletePckg(deleted); + aMessage.WriteL(3,deletePckg); + } + + aMessage.Complete(seekRet); + } + +void CCntItemMsgHandler::FindL(const RMessage2& aMessage) + { + // Maps to RCntModel::FindL() method. + + CheckForManagerL(); + + // CContactItemFieldDef can be NULL in which case the client will + // have passed an empty descriptor. + CContactItemFieldDef* fieldDef = NULL; + // Assuming that a KNullDesC parameter results in max length of 0. + if(aMessage.GetDesLengthL(1) != 0) + { + // Slot 1 contains a serialized CArrayFixFlat. Since + // CContactItemFieldDef derives from it we can use the packager + // to unpack it. + iPackager.SetBufferFromMessageL(aMessage,1); + fieldDef = static_cast (iPackager.UnpackTUidArrayLC()); + } + + // Get the search text from slot 2 + HBufC* text = HBufC::NewLC(aMessage.GetDesLengthL(2)); + TPtr ptr(text->Des()); + aMessage.ReadL(2,ptr); + + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + collection.Reset(); + + // Call the Persistence Layer to perform the find. + CContactIdArray* idArray = collection.FindL(ptr,fieldDef, iSessionId); + CleanupStack::PopAndDestroy(text); + + // Package the contact ID array for return. + CleanupStack::PushL(idArray); + TPtr8 ptr8 = iPackager.PackL(*idArray); + TInt length = ptr8.Length(); + + // Check the descriptor from the client is large enough. + if(aMessage.GetDesMaxLength(0) >= length) + { + // Write back to client. + aMessage.WriteL(0,ptr8); + aMessage.Complete(KErrNone); + } + else + { + // Return required size of buffer to the client. + aMessage.Complete(length); + } + CleanupStack::PopAndDestroy(idArray); + if(fieldDef) + { + CleanupStack::PopAndDestroy(fieldDef); + } + } + +void CCntItemMsgHandler::FilterDatabaseL(const RMessage2& aMessage) + { + CheckForManagerL(); + iPackager.SetBufferFromMessageL(aMessage); + CCntFilter* filter = iPackager.UnpackCntFilterLC(); + MLplCollection& collection = iManager->GetPersistenceLayer().FactoryL().GetCollectorL(); + CContactIdArray* idArray = collection.FilterDatabaseL(*filter); + CleanupStack::PopAndDestroy(filter); + CleanupStack::PushL(idArray); + TPtr8 ptr8 = iPackager.PackL(*idArray); + TInt length = ptr8.Length(); + // Check the descriptor from the client is large enough. + if(aMessage.GetDesMaxLength(0) >= length) + { + // Write back to client. + aMessage.WriteL(0,ptr8); + aMessage.Complete(KErrNone); + } + else + { + // Return required size of buffer to the client. + aMessage.Complete(length); + } + CleanupStack::PopAndDestroy(idArray); + } + +void CCntItemMsgHandler::SetAsyncActivityL(const RMessage2& aMessage) + { + CheckForManagerL(); + TBool asyncActivity = TBool(aMessage.Int0()); + // Create and then process appropriate request using state machine. + CCntRequest* request = NULL; + if (asyncActivity) + { + request = CReqAsyncActivity::NewLC(iSessionId, aMessage, iTimeOut); + } + else + { + request = CReqNoAsyncActivity::NewLC(iSessionId, aMessage, iTimeOut); + } + iManager->StateMachineL().ProcessRequestL(request); // ownership transferred + + // ProcessRequestL received ownership of the request, the request only need + // to be popped from CleanupStack. + CleanupStack::Pop(request); + } + +void CCntItemMsgHandler::ResourceCount(const RMessage2& aMessage) + { + #if defined(_DEBUG) + TInt totalAllocSize(0); + User::Heap().AllocSize(totalAllocSize); + RDebug::Print(_L("[CNTMODEL] Heap count: %d cells, total heap size: %d bytes"), User::Heap().Count(), User::Heap().Size()); + RDebug::Print(_L("[CNTMODEL] cntsrv heap size: %d bytes"), totalAllocSize); + aMessage.Complete(User::Heap().Count()); + #else + aMessage.Complete(KErrNone); + #endif + } + +void CCntItemMsgHandler::SetHeapFailure(const RMessage2& aMessage) + { + #if defined(_DEBUG) + User::__DbgSetAllocFail(RHeap::EUser,(RHeap::TAllocFail)aMessage.Int0(),aMessage.Int1()); + #endif + aMessage.Complete(KErrNone); + } +