wvuing/wvuieng/EngSrc/Ccaengine.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wvuing/wvuieng/EngSrc/Ccaengine.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,1205 @@
+/*
+* Copyright (c) 2003-2005 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:  This interface is used by UI to access network services i.e.
+ *                sending messages and joining to groups e.g. This class is
+ *                also used to get different interfaces to the services
+ *                offered by the CCAEngine.dll.
+ *
+*/
+
+
+// INCLUDE FILES
+#include "ChatDebugPrint.h"
+
+#include "CCAEngine.h"
+
+#include "CCAChatContainer.h"
+#include "CCAMessageHandler.h"
+#include "CCAMessageCreator.h"
+
+#include "CCAContactListModel.h"
+#include "CCASearchManager.h"
+#include "MCASearchObserverInterface.h"
+#include "MCASearchData.h"
+#include "CCAGroupManager.h"
+#include "MCAGroupOperations.h"
+#include "CCABlockingManager.h"
+#include "CCAInviteManager.h"
+#include "CCAPartialSuccessData.h"
+#include "CCASettingsManager.h"
+#include "CCARequest.h"
+#include "CCARequestMapper.h"
+#include "MCAPresence.h"
+#include "PublicEngineDefinitions.h"
+#include "PrivateEngineDefinitions.h"
+#include "MCAStoredGroup.h"
+#include "MCAStoredGroups.h"
+#include "MCAExtendedStoredGroup.h"
+#include "CCAStorageManagerFactory.h"
+#include "CCAStorageObserver.h"
+
+#include "CAPresenceManager.h"
+#include "MCAPresence.h"
+
+#include "CCAAdapterDll.h"
+#include "MCAImpsFactory.h"
+#include "MCAImpsGroupClient.h"
+#include "MCAImpsImClient.h"
+#include "MCAImpsFundClient.h"
+#include "MCAError.h"
+#include "MCAStoredContacts.h"
+
+#include "CALoggerManagerFactory.h"
+#include "TCALoggerMessageFactory.h"
+#include "CCALoggerHeadersInterface.h"
+#include "CCAAccessManager.h"
+#include "CCAImageLoader.h"
+#include "MCAContentProcessor.h"
+
+#include "SServerPrefers.h"
+
+#include "ImpsCSPAllErrors.h"
+#include <e32base.h>
+
+// granularity used for small arrays, which usually
+// contains only one elements
+const TInt KSearchPairsSmallGranularity = 1;
+
+// maximum groups in search result. If search results
+// exceeds this then "too many search results" is shown
+const TInt KMaxGroupSearchLimit = 50;
+
+// ================= MEMBER FUNCTIONS =======================
+
+// Two-phased constructor.
+EXPORT_C CCAEngine* CCAEngine::NewL( TUid aAppUid )
+    {
+    CCAEngine* self = new ( ELeave ) CCAEngine( aAppUid );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::~CCAEngine()
+// Note the destruction order of objects.
+// ---------------------------------------------------------
+//
+EXPORT_C CCAEngine::~CCAEngine()
+    {
+    CHAT_DP_FUNC_ENTER( "~CCAEngine" );
+
+    if ( iImpsImServer )
+        {
+        iImpsImServer->Unregister();
+        }
+
+    if ( iImpsGroupServer )
+        {
+        iImpsGroupServer->Unregister();
+        }
+
+    if ( iImpsFundAPI )
+        {
+        iImpsFundAPI->Unregister();
+        }
+
+    // Must be deleted before settings manager
+    delete iContactListModel;
+
+    delete iAccessManager;
+    delete iGroupManager;
+    delete iSearchManager;
+    delete iBlockingManager;
+    delete iInviteManager;
+    delete iSettingsManager;
+    delete iRequestMapper;
+
+    delete iMessageHandler;
+    delete iMessageCreator;
+    delete iChatContainer;
+
+    delete iImageLoader;
+
+    delete iPartialSuccessData;
+
+    // synch stuff. should be already deallocated but let's have a
+    // failsafe delete here
+    delete iLoggedUserId;
+
+    // not reset done, because contains iRequest and don't want delete twice
+    delete iPairs;
+    delete iRequest;
+    delete iStorageObserver;
+
+    // Release singleton instances because we are sure,
+    // that we do not need them anymore.
+    TRAPD( ignore, CALoggerManagerFactory::ReleaseInstanceL() );
+    TRAP( ignore, CCAStorageManagerFactory::ReleaseL() );
+    TRAP( ignore, ReleaseAdapterL() );
+    CAPresenceManager::Release();
+
+    delete iLoggerMessageFactory;
+    delete iLoggerHeadersInterface;
+
+    CHAT_DP_FUNC_DONE( "~CCAEngine" );
+    }
+
+
+// ---------------------------------------------------------
+// CCAEngine::GetInternalSettingsInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C void CCAEngine::ResetLoggers()
+    {
+#ifdef RD_MULTIPLE_DRIVE
+    // Release singleton instances because we are sure,
+    // that we do not need them anymore.
+    TRAPD( ignore, CALoggerManagerFactory::ReleaseInstanceL() ;
+
+           CHAT_DP( D_CHAT_LIT( " ignore %d" ), ignore );
+           //Set message factory to logger    // now create these interfaces again...for newly changed drive....
+
+           CALoggerManagerFactory::ReadInstanceL( iLoggerMessageFactory , EFalse ); );
+#endif
+    }
+
+
+
+// ---------------------------------------------------------
+// CCAEngine::GetInternalSettingsInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCASettings* CCAEngine::GetInternalSettingsInterface() const
+    {
+    return iSettingsManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetSearchInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCASearchInterface* CCAEngine::GetSearchInterface() const
+    {
+    return iSearchManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetInviteInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAInvite* CCAEngine::GetInvitationInterface() const
+    {
+    return iInviteManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetBlockingInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCABlocking* CCAEngine::GetBlockingInterface() const
+    {
+    return iBlockingManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetFundClientInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAImpsFundClient* CCAEngine::GetFundClientInterface() const
+    {
+    return iImpsFundAPI;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetAccessInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAAccessInterface* CCAEngine::GetAccessInterface() const
+    {
+    return iAccessManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::ContactListModel()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAContactListModel& CCAEngine::ContactListModel() const
+    {
+    return *iContactListModel;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::ChatInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAChatInterface& CCAEngine::ChatInterface() const
+    {
+    return *iChatContainer;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::Messageutils()
+// ---------------------------------------------------------
+//
+EXPORT_C const MCAMessageUtils& CCAEngine::MessageUtils() const
+    {
+    return *this;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::GetGroupInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCAGroupManagerInterface* CCAEngine::GetGroupInterface() const
+    {
+    return iGroupManager;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::BackgroundInterface()
+// ---------------------------------------------------------
+//
+EXPORT_C MCABackgroundInterface* CCAEngine::BackgroundInterface() const
+    {
+    return iRequestMapper;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::HandleNetworkStateChangeL
+// ---------------------------------------------------------
+//
+EXPORT_C void CCAEngine::HandleNetworkStateChangeL(
+    TNetworkState aState,
+    TPEngWVCspServicesTree2* aServicesSupported,
+    const SServerPrefers& aServerPrefers,
+    CPEngNWSessionSlotID2* aSessionSlotID /* = NULL */ )
+    {
+    CHAT_DP_FUNC_ENTER( "HandleNetworkStateChangeL" );
+    CHAT_DP( D_CHAT_LIT( " * old state %d, new state %d" ), iState, aState );
+
+    if ( ! iFullyConstructed )
+        {
+        // user cancelled login before it had even started,
+        // engine is constructed half-way. so get out.
+        CHAT_DP_TXT( "  Engine not fully constructed, get out." );
+        return;
+        }
+
+    if ( iState == aState )
+        {
+        // If new state is the same as previous, then do nothing
+        CHAT_DP_TXT( "CCAEngine::HandleNetworkStateChangeL with same state as \
+                previously! -> ignoring..." );
+        return;
+        }
+
+    if ( aState == ELoggedIn )
+        {
+        // logged in, reconstruct contact list model for new server (change sorting order)
+        MCAContactListModel* model = iContactListModel;
+        model->SetSort();
+        }
+
+    TNetworkState oldState = iState;
+
+    if ( aState != EServerPrefers )
+        {
+        iState = aState;
+        }
+
+    if ( aServicesSupported && iSearchManager )
+        {
+        TBool searchSupported =
+            aServicesSupported->iFundamentalFeat.FunctionSupported(
+                KPEngFFSearchFunction );
+        iSearchManager->SetSearchSupported( searchSupported );
+        }
+
+    iMessageHandler->SetLocalEchoInGroup( aServerPrefers.iLocalEchoInGroup );
+
+    if ( aState != ESyncPresence && aState != EServerPrefers )
+        {
+        // ESyncPresence is a special case for presence manager only
+
+        // notify RequestMapper
+        if ( iRequestMapper )
+            {
+            iRequestMapper->HandleNetworkStateChange( aState );
+            }
+
+        // notify BlockingManager
+        if ( iBlockingManager )
+            {
+            iBlockingManager->HandleNetworkStateChange(
+                aState, aServerPrefers.iUseGrant );
+            }
+
+        // notify GroupManager
+        if ( iGroupManager )
+            {
+            iGroupManager->HandleNetworkStateChangeL( aState );
+            }
+
+        if ( aState == ELoggedIn )
+            {
+            SynchronizeGroupsL( aServicesSupported );
+            }
+        }
+
+    // presence manager
+    if ( iPresenceManager )
+        {
+        switch ( aState )
+            {
+            case ELoggedIn:
+                {
+                iPresenceManager->HandleNetworkStateL( MCAPresence::ELoggedIn,
+                                                       aServerPrefers,
+                                                       aSessionSlotID );
+                break;
+                }
+
+            case ELoggingOut:
+                {
+                iPresenceManager->HandleNetworkStateL( MCAPresence::ELoggingOut,
+                                                       aServerPrefers,
+                                                       aSessionSlotID );
+                break;
+                }
+
+            case ELoggedOut:
+                {
+                iPresenceManager->HandleNetworkStateL( MCAPresence::ELoggedOut,
+                                                       aServerPrefers,
+                                                       aSessionSlotID );
+                break;
+                }
+            case EServerPrefers:
+                {
+                iPresenceManager->HandleNetworkStateL( MCAPresence::EUpdateBrand,
+                                                       aServerPrefers,
+                                                       aSessionSlotID );
+                return;
+                }
+            case ESyncPresence:
+                {
+                CHAT_DP_TXT( "**ESyncPresence event**" );
+                if ( oldState != ELoggedIn )
+                    {
+                    CHAT_DP_TXT( "**Synchronizing presence settings**" );
+                    // do not synchronize anything if we're logging out
+                    iPresenceManager->SynchronizePresenceSettingsL(
+                        aServerPrefers );
+                    }
+                }
+
+            default:
+                {
+                // Presence module does not support -> ignore
+                break;
+                }
+            }
+        }
+
+    CHAT_DP_FUNC_DONE( "HandleNetworkStateChangeL" );
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::SynchronizeGroupsL()
+// ---------------------------------------------------------
+//
+void CCAEngine::SynchronizeGroupsL(
+    TPEngWVCspServicesTree2* aServicesSupported )
+    {
+    CHAT_DP_FUNC_DP( "StartSyn", "Logging in" );
+
+    TBool searchSupported = EFalse;
+
+    // state changed to logged in
+    if ( aServicesSupported )
+        {
+        searchSupported =
+            aServicesSupported->iFundamentalFeat.FunctionSupported(
+                KPEngFFSearchFunction );
+        iSearchManager->SetSearchSupported( searchSupported );
+        CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleNetworkStateChangeL \
+                    - Search supported: %d" ), searchSupported );
+        }
+    else
+        {
+        CHAT_DP_FUNC_DP( "HandleNetworkStateChangeL",
+                         "Services are not supported" );
+        }
+
+    // check if the groups are supported at all
+
+    TBool groupsSupported = EFalse;
+
+    if ( aServicesSupported )
+        {
+        // find out if the group stuff is supported
+        groupsSupported = aServicesSupported->iGroupFeat.FeatureSupported();
+        }
+
+    if ( groupsSupported )
+        {
+        CHAT_DP_FUNC_DP( "SynchronizeGroupsL", "Groups are supported" );
+
+        // groups are supported. search only if we can...
+        if ( searchSupported )
+            {
+            // but make sure the search is not started yet
+            if ( iRequestMapper->BackgroundTaskStatus(
+                     MCABackgroundInterface::EGroupFetch ) &
+                 ( MCABackgroundInterface::EUnknown |
+                   MCABackgroundInterface::ECompleted |
+                   MCABackgroundInterface::ECancelled |
+                   MCABackgroundInterface::EFailed
+                 ) )
+                {
+                CHAT_DP_FUNC_DP( "HandleNetworkStateChangeL",
+                                 "Registering group list fetch" );
+                iRequestMapper->RegisterBackgroundTask( this,
+                                                        MCABackgroundInterface::EGroupFetch );
+                }
+            }
+        else
+            {
+            CHAT_DP_FUNC_DP( "SynchronizeGroupsL", "Search is not supported" );
+            // Search is not supported, so show all the groups the user has.
+            // This is the only thing the IM Application can do about this
+            // at the moment.
+            iStoredGroups = CCAStorageManagerFactory::GroupListInterfaceL();
+            iStoredGroups->ShowAllGroups();
+            }
+        }
+    else
+        {
+        CHAT_DP_FUNC_DP( "SynchronizeGroupsL",
+                         "Groups are not supported: hiding groups, \
+                          not searching" );
+
+        // groups are not supported
+        // hide all our groups from storage
+        iStoredGroups = CCAStorageManagerFactory::GroupListInterfaceL();
+        iStoredGroups->HideAllGroups( ETrue );  // hides all groups
+        }
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::PartialSuccessData()
+// ---------------------------------------------------------
+//
+EXPORT_C const RPointerArray<MCAError>* CCAEngine::PartialSuccessData() const
+    {
+    return iPartialSuccessData->PartialSuccessData();
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::HandleErrorL()
+// ---------------------------------------------------------
+//
+void CCAEngine::HandleErrorL(
+    TInt           aStatus,
+    TInt           aOpId,
+    const TDesC*   aDescription,
+    const CImpsDetailed* aDetailedRes,
+    TImpsCspIdentifier& /*aCspId*/ )
+    {
+    CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleErrorL, opid %d, status %d" ),
+             aOpId, aStatus );
+
+    if ( aDescription )
+        {
+        TPtrC descr( *aDescription );
+        CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleErrorL, description: %S" ),
+                 &descr );
+        }
+
+    // In case of partial success store the data if it exists
+    if ( ( aStatus == ECSPPartiallySuccessful ) && aDetailedRes )
+        {
+        CHAT_DP_TXT( "CCAEngine::HandleErrorL, \
+                      partially successful situation.." );
+        // must be trapped although this is an L-method because the request must
+        // be handled in every case
+        TRAPD( err,
+               iPartialSuccessData->SetPartialSuccessDataL( *aDetailedRes ) );
+        if ( err != KErrNone )
+            {
+            CActiveScheduler::Current()->Error( err );
+            }
+        }
+
+    // in debug builds, print out the partial success data
+#ifdef _DEBUG
+    const RPointerArray<MCAError>* myerrors =
+        iPartialSuccessData->PartialSuccessData();
+    if ( myerrors )
+        {
+        TInt limit( ( *myerrors ).Count() );
+        for ( TInt i( 0 ); i < limit; i++ )
+            {
+            CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleErrorL PSD code %d" ),
+                     ( *myerrors )[i]->Code() );
+            }
+        }
+#endif
+
+    // redirect the error code to appropriate manager
+    TPtrC recipientPtr( KNullDesC );
+
+    TInt error( KErrNotFound );
+
+    if ( aOpId != 0 )
+        {
+        // This is not a push message, so try to find recipient
+        recipientPtr.Set( iChatContainer->MessageRecipient( aOpId, error ) );
+        }
+
+    if ( ( error == KErrNotFound ) || ( recipientPtr.Length() == 0 ) )
+        {
+        // In this case the recipient doesn't exist which means that
+        // this is not a sent message error
+        // => redirect to requestmapper
+
+        CHAT_DP_TXT( "CCAEngine::HandleErrorL, redirecting to RequestMapper" );
+        iRequestMapper->HandleRequest( aOpId, aStatus );
+        if ( aOpId == 0 )
+            {//server pushed event
+            iGroupManager->LastImpsError( aStatus );
+            }
+        }
+    else
+        {
+        // We found a recipient for the message so this is a sent message error
+        // => redirect to chatdatamanager
+
+        const RPointerArray<MCAError>* partialData =
+            iPartialSuccessData->PartialSuccessData();
+
+        // If partially success data has error code ECSPRecipientBlockedSender
+        // we can show the message as it was sent succesfully.
+        TBool blockedSender( EFalse );
+        if ( partialData )
+            {
+            if ( partialData->Count() == 1 ) // only one error code
+                {
+                if ( ( *partialData )[0]->Code() == ECSPRecipientBlockedSender )
+                    {
+                    blockedSender = ETrue;
+                    }
+                }
+            }
+
+        if ( aStatus == ECSPPartiallySuccessful && blockedSender )
+            {
+            // In this case show that message sending was successful
+            CHAT_DP_TXT( "CCAEngine::HandleErrorL, ECSPRecipientBlockedSender, \
+                    redirecting to ChatDataManager" );
+            iMessageHandler->HandleMessageSentL( KErrNone, aOpId, ETrue );
+            }
+        else
+            {
+            // Message sending was not successful,
+            // "IM.Recipient.Blocked.Messages" functionality
+            CHAT_DP_TXT( "CCAEngine::HandleErrorL, other error, redirecting to \
+                    ChatDataManager" );
+            CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleErrorL, indicating error, \
+                        recipient: %S" ), &recipientPtr );
+            iMessageHandler->HandleMessageSentL( aStatus, aOpId, EFalse );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::HandleSettingsChangeL()
+// ---------------------------------------------------------
+//
+void CCAEngine::HandleSettingsChangeL( TInt aChangedSettingEnum )
+    {
+    CHAT_DP_TXT( "CCAEngine::HandleSettingsChange" );
+
+    if ( iPresenceManager )
+        {
+        iPresenceManager->HandleSettingsChangeL( aChangedSettingEnum );
+        }
+    }
+
+// Symbian OS default constructor can leave.
+void CCAEngine::ConstructL()
+    {
+    // Construct request mapper
+    iRequestMapper = CCARequestMapper::NewL();
+
+    // Setting engine to listen errors in group fetching in background task
+    iRequestMapper->RegisterBackgroundObserver(
+        this,
+        MCABackgroundInterface::EGroupFetch,
+        MCABackgroundInterface::EFailed );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCARequestMapper" );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCASettingsManager" );
+
+    // Create manager for internal settings handling
+    iSettingsManager = CCASettingsManager::NewL( iAppUid );
+    iSettingsManager->AddObserverL( this );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating iChatContainer" );
+
+    iContactListModel = CCAContactListModel::NewL( *iSettingsManager );
+    CHAT_DP( D_CHAT_LIT( "iContactListModel constructed..." ) );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCAPresenceManager" );
+    // it's a singleton and always present
+    iPresenceManager = CAPresenceManager::InstanceL( iSettingsManager );
+
+    CHAT_DP( D_CHAT_LIT( "iPresenceManager constructed..." ) );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCAMessageCreator" );
+
+    iMessageCreator = CCAMessageCreator::NewL();
+
+    CHAT_DP( D_CHAT_LIT( "CCAMessageCreator constructed..." ) );
+
+    // Construct the partial success data holder also
+    iPartialSuccessData = CCAPartialSuccessData::NewL();
+
+    //This T-class is heap-allocated only because we do not want to
+    //include T-class header in header file of CCAEngine.
+    iLoggerMessageFactory = new ( ELeave ) TCALoggerMessageFactory;
+
+    //Set message factory to logger
+    CALoggerManagerFactory::ReadInstanceL( iLoggerMessageFactory );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, done." );
+    iGroupSynchronizing = EFalse;
+    }
+
+EXPORT_C TBool CCAEngine::ReadyForShutdown()
+    {
+    if ( iRequestMapper )
+        {
+        if ( iRequestMapper->WaitCount() )
+            {
+            return EFalse;
+            }
+        }
+    return ETrue;
+    }
+
+EXPORT_C void CCAEngine::CancelAllRequests()
+    {
+    if ( iRequestMapper )
+        {
+        iRequestMapper->CancelAllRequests();
+        }
+
+    if ( iPresenceManager )
+        {
+        iPresenceManager->CancelPendingRequests();
+        }
+    }
+
+EXPORT_C MCALoggerHeadersInterface* CCAEngine::GetLoggerHeadersInterface()
+    {
+    return iLoggerHeadersInterface;
+    }
+
+// stop synchronizing the groups
+void CCAEngine::StopSynchronizeGroupsL()
+    {
+    CHAT_DP_FUNC_ENTER( "StopSynchronizeGroupsL" );
+
+    if ( ! iGroupSynchronizing )
+        {
+        // don't bother, group synchronizing already stopped
+        // or not yet started
+        return;
+        }
+
+    // Make sure that our state will be right one.
+    // Sync should be over after this method.
+
+    CHAT_DP_FUNC_DP( "StopSynchronizeGroupsL", "Ending search" );
+    TInt status = KErrNone;
+    TRAPD( err, status = iSearchManager->EndSearchL() );
+
+    iGroupSynchronizing = EFalse;
+
+    User::LeaveIfError( err );
+
+    // Ignore the cancel error code. We don't want to show
+    // error note when exiting the application while search was
+    // active
+    if ( status != EOperationCancelled )
+        {
+        User::LeaveIfError( status );
+        }
+
+    CHAT_DP_FUNC_DP( "StopSynchronizeGroupsL", "Deallocating stuff" );
+
+    // make sure we're done
+    if ( iLoggedUserId )
+        {
+        delete iLoggedUserId;
+        iLoggedUserId = NULL;
+        }
+
+    if ( iPairs )
+        {
+        // not reset done, because contains iRequest
+        // and don't want delete twice
+        delete iPairs;
+        iPairs = NULL;
+        }
+
+    if ( iRequest )
+        {
+        delete iRequest;
+        iRequest = NULL;
+        }
+
+    iSearchResults = NULL;
+
+    CHAT_DP_FUNC_DONE( "StopSynchronizeGroupsL" );
+    }
+
+// synchronize the groups in storage with those in the server
+void CCAEngine::StartSynchronizeGroupsL()
+    {
+    CHAT_DP_FUNC_ENTER( "StartSynchronizeGroupsL" );
+
+    // make sure we're stopped
+    StopSynchronizeGroupsL();
+
+    if ( ! iStoredGroups )
+        {
+        // lazy initialization
+        iStoredGroups = CCAStorageManagerFactory::GroupListInterfaceL();
+        }
+
+    // make all groups invisible
+    iStoredGroups->HideAllGroups();
+
+    delete iLoggedUserId;
+    iLoggedUserId = NULL;
+    iLoggedUserId = iSettingsManager->ValueL( MCASettings::EOwnWVUserID );
+
+    CSearchPairs* tempPairs =
+        new ( ELeave ) CSearchPairs( KSearchPairsSmallGranularity );
+    CleanupStack::PushL( tempPairs );
+    CImpsSearchRequest* tempRequest = CImpsSearchRequest::NewL();
+    CleanupStack::PushL( tempRequest );
+    tempRequest->SetRequestL( EImpsGroupUserIDOwner, *iLoggedUserId );
+    tempPairs->AppendL( tempRequest );
+    CleanupStack::Pop( tempRequest );
+    CleanupStack::Pop( tempPairs );
+    delete iPairs;
+    delete iRequest;
+    iPairs = tempPairs;
+    iRequest = tempRequest;
+
+    // If there is error in search, return so we don't send stop error request
+    TInt searchError( KErrNone );
+    TInt err( KErrNone );
+    TRAP( err, searchError =
+              iSearchManager->StartSearchL( *iPairs, KMaxGroupSearchLimit, this ) );
+
+    iGroupSynchronizing = ETrue;
+
+    // it's synchronous
+    if ( ( err != KErrNone ) || ( searchError != KErrNone ) )
+        {
+        // we must cleanup so we can't just leave
+        CHAT_DP( D_CHAT_LIT( "CCAEngine::StartSynchronizeGroupsL - error from \
+                              StartSearchL %d, err %d" ), searchError, err );
+        StopSynchronizeGroupsL();
+
+        // leave now, when it's all clean and tidy
+        // Leave also with cancel --> but leave quietly
+        if ( KErrNone == searchError || EOperationCancelled == searchError )
+            {
+            User::Leave( err );
+            }
+        else
+            {
+            User::Leave( searchError );
+            }
+        }
+
+    DoHandleSearchFinishedL();
+    StopSynchronizeGroupsL();
+
+    CHAT_DP_FUNC_DONE( "StartSynchronizeGroupsL" );
+    }
+
+// from MCASearchObserverInterface
+void CCAEngine::HandleSearchError( TInt /* aErrorCode */ )
+    {
+    CHAT_DP_FUNC_ENTER( "HandleSearchError" );
+
+    // something bad happened
+    TRAPD( err, StopSynchronizeGroupsL() );
+    if ( err != KErrNone )
+        {
+        CHAT_DP( D_CHAT_LIT( "CCAEngine::HandleSearchError - Unexpected, \
+                              left with %d" ), err );
+        CActiveScheduler::Current()->Error( err );
+        }
+
+    CHAT_DP_FUNC_DONE( "HandleSearchError" );
+    }
+
+// the actual leaving handler for finished searches
+void CCAEngine::DoHandleSearchFinishedL()
+    {
+    CHAT_DP_FUNC_ENTER( "DoHandleSearchFinishedL" );
+
+    TInt resultCount(
+        iSearchManager->SearchDataInterface()->SearchDataCount() );
+
+    CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - found %d \
+                          groups from joined user" ), resultCount );
+    CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - From index \
+                          %d to %d" ), iSearchResults, resultCount - 1 );
+    TInt status = KErrNone;
+    for ( TInt counter( iSearchResults ); counter < resultCount; counter++ )
+        {
+        // handle requests, but don't handle the groups which were already there
+        if ( status == EOperationCancelled )
+            {
+            CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - \
+                                  Operation Cancelled" ) );
+            break;
+            }
+
+        // see if this group is already in storage
+        TPtrC groupId( iSearchManager->SearchDataInterface()->SearchData(
+                           counter ) );
+        MCAStoredGroup* group = iStoredGroups->FindGroup( groupId );
+
+        if ( !group )
+            {
+            CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - Group\
+                                  %S is not in storage, adding" ), &groupId );
+
+            // not found
+            // so create group to storage with valid parameters:
+            // must have groupid (before group operations), groupname, owngroup
+
+            MCAExtendedStoredGroup* exGrp = iStoredGroups->CreateGroupL();  // CSI: 35 # Ownership is not transferred to caller.
+            exGrp->SetGroupIdL( groupId );
+            // make it invisible
+            exGrp->SetVisible( EFalse );
+            MCAGroupOperations* grOp =
+                iGroupManager->GroupOperationsL( groupId );
+
+            CImpsCommonGroupProps* commonProps = NULL;
+            CImpsPrivateGroupProps* privProps = NULL;
+
+            // fetch properties from network
+            CHAT_DP_FUNC_DP( "DoHandleSearchFinishedL", "Getting properties" );
+            status = grOp->GetPropertiesL( commonProps, privProps ) ;
+            if ( status == EOperationCancelled )
+                {
+                CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - \
+	                                  Operation Cancelled" ) );
+                break;
+                }
+            if ( commonProps )
+                {
+                // group name has to be known
+                TPtrC name( commonProps->GroupName() );
+                CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - \
+                                      Group has name '%S'" ), &name );
+                if ( name.Length() > 0 )
+                    {
+                    exGrp->SetGroupNameL( name );
+                    }
+                else
+                    {
+                    exGrp->SetGroupNameL( KNullDesC );
+                    }
+
+                // our very own group
+                exGrp->SetOwnGroup( ETrue );
+
+                // make it visible
+                exGrp->SetVisible( ETrue );
+
+                // save the group and signal the UI the group changed
+                iStoredGroups->SaveGroupL( groupId );
+                }
+            else
+                {
+                CHAT_DP_FUNC_DP( "DoHandleSearchFinishedL",
+                                 "No common properties" );
+                // if the name can't be fetched,
+                // name the group with group's wvid
+                exGrp->SetGroupNameL( groupId );
+                }
+
+            }
+        else
+            {
+            CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - \
+                Group %S is already in storage, making it visible" ), &groupId );
+            ( static_cast<MCAExtendedStoredGroup *>( group ) )->SetVisible( ETrue );
+            iStoredGroups->SignalGroupAddedL( groupId );
+            }
+        }
+
+    // add only number of new ones
+    iSearchResults += ( resultCount - iSearchResults );
+    CHAT_DP( D_CHAT_LIT( "CCAEngine::DoHandleSearchFinishedL - Searching, index \
+                          is now %d" ), iSearchResults );
+
+    CHAT_DP_FUNC_DONE( "DoHandleSearchFinishedL" );
+    }
+
+// from MCASearchObserverInterface
+void CCAEngine::HandleSearchFinished( )
+    {
+    CHAT_DP_FUNC_ENTER( "HandleSearchFinished" );
+
+    CHAT_DP_FUNC_DONE( "HandleSearchFinished" );
+    }
+
+// from MCABackgroundTask
+void CCAEngine::HandleBackgroundTaskL( TInt aSubTask )
+    {
+    CHAT_DP_FUNC_ENTER( "HandleBackgroundTaskL" );
+    CHAT_DP( D_CHAT_LIT( "CCABlockingManager::HandleBackgroundTaskL Subtask \
+	                      is: %d" ), aSubTask );
+
+    StartSynchronizeGroupsL();
+
+    // imps errors are ignored at the moment as we don't have any
+    // notes specified for them
+
+    CHAT_DP_FUNC_DONE( "HandleBackgroundTaskL" );
+    }
+
+// from MCABackgroundObserver
+void CCAEngine::HandleBackgroundEvent(
+    MCABackgroundInterface::TCABackgroundTasks aEventSource,
+    MCABackgroundInterface::TCABackgroundStatus aStatus,
+    TInt /*aSubTaskNumber*/,
+    TInt aLeaveCode )
+    {
+    // Currently we are interested only group fetching problems
+    if ( ( aEventSource == MCABackgroundInterface::EGroupFetch ) &&
+         ( aStatus == MCABackgroundInterface::EFailed ) )
+        {
+        if ( ( aLeaveCode > Imps_ERROR_BASE ) && ( aLeaveCode < KErrNone ) )
+            {
+            // propagate system errors to current active scheduler,
+            // it should show a note
+            CActiveScheduler::Current()->Error( aLeaveCode );
+            }
+        // imps errors are ignored at the moment as we don't have any
+        // notes specified for them
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CCAEngine::MessageCreator()
+// ---------------------------------------------------------
+//
+MCAMessageCreator& CCAEngine::MessageCreator() const
+    {
+    return *iMessageCreator;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::MessageErrorInformer()
+// ---------------------------------------------------------
+//
+MCAMessageErrorInformer& CCAEngine::MessageErrorInformer() const
+    {
+    return *iMessageHandler;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::ImageScaler()
+// ---------------------------------------------------------
+//
+MCAContentProcessor& CCAEngine::ImageScaler() const
+    {
+    return *iImageLoader;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::MemoryHandler
+// ---------------------------------------------------------
+//
+MCABufferMemoryHandler& CCAEngine::MemoryHandler() const
+    {
+    return *iChatContainer;
+    }
+
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CCAEngine::CCAEngine( TUid aAppUid )
+        :   iAppUid( aAppUid ),
+        iState( ELoggedOut )
+    {
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::FinalizeEngineConstructionL()
+// ---------------------------------------------------------
+//
+EXPORT_C void CCAEngine::FinalizeEngineConstructionL()
+    {
+    CHAT_DP_FUNC_ENTER( "FinalizeEngineConstructionL" );
+
+    if ( iFullyConstructed )
+        {
+        // nothing to do
+        CHAT_DP_TXT( "  Already fully constructed, all done" );
+        CHAT_DP_FUNC_DONE( "FinalizeEngineConstructionL" );
+        return;
+        }
+
+    MCAImpsFactory* impsFactory = CreateImpsFactoryL();
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, CCAAccessManager::NewL" );
+    iAccessManager = CCAAccessManager::NewL( *iRequestMapper );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCASearchManager for searching \
+            and synchronizing groups" );
+    iSearchManager = CCASearchManager::NewL( impsFactory, iRequestMapper );
+
+    iChatContainer = CCAChatContainer::NewL( *iSettingsManager );
+    CHAT_DP( D_CHAT_LIT( "iChatContainer constructed..." ) );
+
+    iImageLoader = CCAImageLoader::NewL( *iChatContainer, *impsFactory );
+    CHAT_DP( D_CHAT_LIT( "iImageLoader constructed..." ) );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCAGroupManager" );
+    iGroupManager = CCAGroupManager::NewL( *iSearchManager,
+                                           *iSettingsManager, *iRequestMapper, impsFactory,
+                                           *iChatContainer, *this );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCABlockingManager" );
+
+    iBlockingManager = CCABlockingManager::NewL(
+                           impsFactory,
+                           iRequestMapper,
+                           iSettingsManager );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCAMessageHandler" );
+
+    iMessageHandler = CCAMessageHandler::NewL( *iChatContainer, *this,
+                                               impsFactory );
+
+    CHAT_DP( D_CHAT_LIT( "CCAMessageHandler constructed..." ) );
+
+    iSettingsManager->AddObserverL( iBlockingManager );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, creating CCAInviteManager" );
+
+    iInviteManager = CCAInviteManager::NewL( impsFactory,
+                                             *iSettingsManager,
+                                             *iRequestMapper,
+                                             *iGroupManager );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, registering APIs" );
+
+    // Register observers and error handlers
+    CHAT_DP_TXT( "CCAEngine::ConstructL, CreateFundClientL" );
+    iImpsFundAPI = impsFactory->CreateFundClientL();
+    iImpsFundAPI->RegisterL( iSearchManager, iInviteManager );
+    iImpsFundAPI->RegisterErrorObserverL( *this );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, CreateImClientL" );
+    iImpsImServer = impsFactory->CreateImClientL();
+    iImpsImServer->RegisterL( iMessageHandler, iBlockingManager, iAppUid,
+                              CActive::EPriorityIdle );
+    iImpsImServer->RegisterErrorObserverL( *this );
+
+    CHAT_DP_TXT( "CCAEngine::ConstructL, CreateGroupClientL" );
+    iImpsGroupServer = impsFactory->CreateGroupClientL();
+
+    iImpsGroupServer->RegisterL( iGroupManager, iAppUid,
+                                 CActive::EPriorityIdle );
+    iImpsGroupServer->RegisterErrorObserverL( *this );
+
+    iStorageObserver = CCAStorageObserver::NewL(
+                           *iSettingsManager,
+                           *CCAStorageManagerFactory::ContactListInterfaceL(),
+                           *iPresenceManager,
+                           *iBlockingManager );
+
+    //Create interface for access to history headers
+    iLoggerHeadersInterface =
+        CCALoggerHeadersInterface::NewL( *iChatContainer, iSettingsManager );
+
+    // whip up the IMPS server
+    impsFactory->ConnectL();
+
+    iFullyConstructed = ETrue;
+
+    CHAT_DP_FUNC_DONE( "FinalizeEngineConstructionL" );
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::IsEngineFinalized()
+// ---------------------------------------------------------
+//
+EXPORT_C TBool CCAEngine::IsFinalized()
+    {
+    return iFullyConstructed;
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::IsBackgroundTaskPending()
+// ---------------------------------------------------------
+
+EXPORT_C TBool CCAEngine::IsBackgroundTaskPending()
+    {
+    return iRequestMapper->IsBackgroundTaskPending();
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::RegisterBackGroundTaskObserver()
+// ---------------------------------------------------------
+//
+EXPORT_C void CCAEngine::RegisterBackGroundTaskObserver( MCABackGroundTaskObserver* aObserver )
+    {
+    iRequestMapper->RegisterBackGroundTaskObserver( aObserver );
+    }
+
+// ---------------------------------------------------------
+// CCAEngine::UnRegisterBackGroundTaskObserver()
+// ---------------------------------------------------------
+//
+EXPORT_C void CCAEngine::UnRegisterBackGroundTaskObserver( MCABackGroundTaskObserver* aObserver )
+    {
+    iRequestMapper->UnRegisterBackGroundTaskObserver( aObserver );
+    }
+
+
+
+//  End of File