/*
* Copyright (c) 2006-2008 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:  CFContextSourceManager class implementation.
*
*/



#include <ecom/ecom.h>
#include <centralrepository.h>
#include <bautils.h>
#include <cfcontextsourceupgrade.h>
#include <cfcontextsourceinterface.h>
#include <cfcontextsourcecommand.h>
#include <cfcontextsubscriptionlistener.h>

#include "CFContextSourceManager.h"
#include "cfcontextsourcesettingsmanager.h"
#include "ContextFrameworkPrivateCRKeys.h"
#include "cfcontextsourceplugin.h"
#include "cfextendedcontextinterface.h"
#include "cfcontextsourcesettingarray.h"
#include "cftrace.h"

// CONSTANTS

const TInt KUIDNameStartPos = 1;
const TInt KUIDNameEndPos = 8;

// Drive letter hard coded since context source plug-in settings
// can only exist in ROM or RAM
_LIT( KSettingsPathRom, "Z:\\Private\\10282BC4\\Settings\\" );
_LIT( KSettingsPathRam, "C:\\Private\\10282BC4\\Settings\\" );

// Folder extension
_LIT( KFolderExt, "\\" );

// Setting file extension
_LIT( KSettingExtension, "*.xml" );

// Separates SID from filename for client installed settings
_LIT( KUnderscore, "_" );


/**
 * Information about a client acting as a context source.
 * This info is used to keep track of clients acting as context sources to
 * enable sending them context source commands.
 *
 * @lib CFContextSourceManager
 * @since S60 5.0
 */
NONSHARABLE_CLASS( TCFClientContextSourceInfo )
{
public: // Constructors

    TCFClientContextSourceInfo() : iSource( NULL ), iClientSid( KNullUid )
        {
        FUNC_LOG;
        }

    TCFClientContextSourceInfo( MCFContextSource* aSource, const TUid& aSid )
        :   iSource( aSource ), iClientSid( aSid )
        {
        FUNC_LOG;
        }

public: // Data

    /**
    * Context source interface pointer; not owned.
    */
    MCFContextSource* iSource;

    /**
    * Client's secure id (from client thread).
    */
    TUid iClientSid;
};

// ============================= LOCAL FUNCTIONS ==============================

/**
* Clenup operation for RImplInfoPtrArray
*/
LOCAL_C void CleanUpImplInfoArray( TAny* aParams )
    {
    RImplInfoPtrArray* array = static_cast<RImplInfoPtrArray*>( aParams );
    array->ResetAndDestroy();
    }

/**
* Push operations
*/
LOCAL_C void CleanupResetAndDestroyPushL( RImplInfoPtrArray& aArray )
    {
    TCleanupItem item( CleanUpImplInfoArray, &aArray );
    CleanupStack::PushL( item );
    }

/**
* Orders client countext source infos based on their uids.
* @param aFirst First context source info.
* @param aSecond Second context source info.
* @return Zero if the uid of the first and second are equal. Negative value
*   if the uid of the first is less than the uid of the second. Positive
*   value if the uid of the first is greater than the uid of the second.
*/
LOCAL_C TInt ClientContextSourceInfoUidOrder(
    const TCFClientContextSourceInfo& aFirst,
    const TCFClientContextSourceInfo& aSecond )
    {
    TInt orderValue = 1;

    if ( aFirst.iClientSid == aSecond.iClientSid )
        {
        orderValue = 0;
        }
    else if ( aFirst.iClientSid.iUid < aSecond.iClientSid.iUid )
        {
        orderValue = -1;
        }

    return orderValue;
    }

/**
* Context loader information.
*/
NONSHARABLE_CLASS( TCFLoaderInfo )
    {
    public:
    
    TCFLoaderInfo( CImplementationInformation& aImplementationInfo,
                   CCFContextSourceManager& aManager ):
                   iImplUid( aImplementationInfo.ImplementationUid() ),
                   iImplVersion( aImplementationInfo.Version() ),
                   iManager( aManager )
        {
        }
            
    public:
        TUid iImplUid;
        TInt iImplVersion;
        CCFContextSourceManager& iManager;
    };

/**
* Context source information.
*/
NONSHARABLE_CLASS( TCFContextSourceInfo )
    {
    public:

        TCFContextSourceInfo( CImplementationInformation& aImplInfo,
            CCFContextSourcePlugIn* aPlugIn ):
            iImplUid( aImplInfo.ImplementationUid() ), iImplVersion( aImplInfo.Version() ),
            iPlugIn( aPlugIn ), iMissing( ETrue )
            {
            }
    
    TCFContextSourceInfo( TUid aImplUid,
                          TInt aImplVersion,
                          CCFContextSourcePlugIn* aPlugIn ):
                          iImplUid( aImplUid ),
                          iImplVersion( aImplVersion ),
                          iPlugIn( aPlugIn ),
                          iMissing( ETrue )
        {
        }

    public:

        TUid iImplUid;
        TInt iImplVersion;
        CCFContextSourcePlugIn* iPlugIn;
        TBool iMissing;
    };

// ============================= MEMBER FUNCTIONS =============================

EXPORT_C CCFContextSourceManager* CCFContextSourceManager::NewL(
    MCFExtendedContextInterface& aCF,
    RFs& aFs )
    {
    FUNC_LOG;

    CCFContextSourceManager* self =
        CCFContextSourceManager::NewLC( aCF, aFs );
    CleanupStack::Pop( self );

    return self;
    }

EXPORT_C CCFContextSourceManager* CCFContextSourceManager::NewLC(
    MCFExtendedContextInterface& aCF,
    RFs& aFs )
    {
    FUNC_LOG;

    CCFContextSourceManager* self =
        new( ELeave ) CCFContextSourceManager( aCF, aFs );
    CleanupStack::PushL( self );
    self->ConstructL();

    return self;
    }

EXPORT_C CCFContextSourceManager::~CCFContextSourceManager()
    {
    FUNC_LOG;

    iClientContextSources.Close();

    // Delete plug-ins
    TInt count = iPlugIns.Count();
    for( TInt i = 0; i < count; i++ )
        {
        CCFContextSourcePlugIn* plugIn = iPlugIns[i].iPlugIn;
        ReleasePlugIn( plugIn );
        }
    iPlugIns.Close();
    delete iSettingsManager;
    
    iLoaders.ResetAndDestroy();
    }

CCFContextSourceManager::CCFContextSourceManager(
    MCFExtendedContextInterface& aCF,
    RFs& aFs ):
    iCF( aCF ),
    iFs( aFs )
    {
    FUNC_LOG;

    // Nothing to do
    }

void CCFContextSourceManager::ConstructL()
    {
    FUNC_LOG;

    iSettingsManager = CCFContextSourceSettingsManager::NewL( iFs );
    }

void CCFContextSourceManager::SetEventHandler( MCFStarterEventHandler& aEventHandler )
    {
    FUNC_LOG;
	  iEventHandler = &aEventHandler;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::InstallSettingL
// ---------------------------------------------------------------------------
//
EXPORT_C void CCFContextSourceManager::InstallSettingL( RFile& aSettingFile,
    const TUid& aContextSourceUid,
    RThread& aClientThread )
    {
    FUNC_LOG;

    // Get plugin.
    MCFContextSourceUpgrade* sourceUpgrade = PlugInL( aContextSourceUid );

    // Parse setting file.
    CCFContextSourceSettingArray* settings
            = CCFContextSourceSettingArray::NewLC();    // CLEANUP<< settings
    RFile parseFile;
    User::LeaveIfError( parseFile.Duplicate( aSettingFile ) );
    // parseFile handle closed by the parser.
    iSettingsManager->ParseSettingsL( parseFile, *settings );

    // Check setting validity from plugin.
    TInt err = sourceUpgrade->CheckValidity( aClientThread, *settings );
    CleanupStack::PopAndDestroy( settings );            // CLEANUP>> settings
    ERROR( err, "CCFContextSourceManager::InstallSettingL - Context source CheckSecurity for new settings failed" );
    User::LeaveIfError( err );

    // Copy the setting file.
    CopySettingFileL( aSettingFile, aContextSourceUid, aClientThread );

    // Read all settings and give them to the plugin.
    CCFContextSourceSettingArray* settingArray
            = PlugInSettingsL( aContextSourceUid );
    // Ownership of settingArray is transferred to plugin.
    sourceUpgrade->UpdateSettingsL( settingArray );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::UninstallSettingL
// ---------------------------------------------------------------------------
//
EXPORT_C void CCFContextSourceManager::UninstallSettingL(
    const TDesC& aSettingFilename,
    const TUid& aContextSourceUid,
    RThread& aClientThread )
    {
    FUNC_LOG;

    // Get plugin.
    MCFContextSourceUpgrade* sourceUpgrade = PlugInL( aContextSourceUid );

    // Delete the setting file.
    DeleteSettingFileL( aSettingFilename, aContextSourceUid, aClientThread );

    // Read all settings and give them to the plugin.
    CCFContextSourceSettingArray* settingArray
            = PlugInSettingsL( aContextSourceUid );
    // Ownership of settingArray is transferred to plugin.
    sourceUpgrade->UpdateSettingsL( settingArray );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::UninstallSettingsL
// ---------------------------------------------------------------------------
//
EXPORT_C void CCFContextSourceManager::UninstallSettingsL(
    const TUid& aContextSourceUid,
    RThread& aClientThread )
    {
    FUNC_LOG;

    // Get plugin.
    MCFContextSourceUpgrade* sourceUpgrade = PlugInL( aContextSourceUid );

    // Delete all setting files installed by the client.
    DeleteSettingFileL( KSettingExtension, aContextSourceUid, aClientThread );

    // Read all settings and give them to the plugin.
    CCFContextSourceSettingArray* settingArray
            = PlugInSettingsL( aContextSourceUid );
    // Ownership of settingArray is transferred to plugin.
    sourceUpgrade->UpdateSettingsL( settingArray );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::HandleContextSourceCommandL
// ---------------------------------------------------------------------------
//
EXPORT_C void CCFContextSourceManager::HandleContextSourceCommandL(
    const CCFContextSourceCommand& aCommand )
    {
    FUNC_LOG;

    const TUid sourceUid = aCommand.SourceUid();
    // Find plugin.
    CCFContextSourcePlugIn* plugIn = NULL;
    for( TInt i = 0; i < iPlugIns.Count(); ++i )
        {
        if( iPlugIns[ i ].iImplUid == sourceUid )
            {
            plugIn = iPlugIns[ i ].iPlugIn;
            break;
            }
        }

    MCFContextSource* contextSource = NULL;
    if ( plugIn )
        {
        // Check plugin's support for MCFContextSource extension.
        contextSource = reinterpret_cast< MCFContextSource* >(
                plugIn->Extension( KCFContextSourceInterfaceUid ) );
        if ( !contextSource )
            {
            User::Leave( KErrExtensionNotSupported );
            }
        }
    else
        {
        TLinearOrder< TCFClientContextSourceInfo > uidOrder(
                ClientContextSourceInfoUidOrder );
        TCFClientContextSourceInfo clientInfo;
        clientInfo.iClientSid = sourceUid;
        TInt pos = iClientContextSources.FindInOrder( clientInfo, uidOrder );
        if ( pos == KErrNotFound )
            {
            User::Leave( KErrBadHandle );
            }
        contextSource = iClientContextSources[ pos ].iSource;
        }

    // Process source command
    if ( contextSource )
        {
        contextSource->HandleCommand( aCommand );
        }
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::RegisterClientContextSource
// ---------------------------------------------------------------------------
//
EXPORT_C TInt CCFContextSourceManager::RegisterClientContextSource(
    MCFContextSource* aPublisher,
    const TUid& aPublisherUid )
    {
    FUNC_LOG;

    TLinearOrder< TCFClientContextSourceInfo > uidOrder(
            ClientContextSourceInfoUidOrder );
    TCFClientContextSourceInfo clientInfo( aPublisher, aPublisherUid );

    TInt err = iClientContextSources.InsertInOrder( clientInfo, uidOrder );
    if ( err == KErrAlreadyExists )
        {
        err = KErrNone;
        }

    ERROR( err, "CCFContextSourceManager::RegisterContextSourceClient - Failed" );

    return err;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::DeregisterClientContextSource
// ---------------------------------------------------------------------------
//
EXPORT_C void CCFContextSourceManager::DeregisterClientContextSource(
    const MCFContextSource& aPublisher )
    {
    FUNC_LOG;

    for ( TInt i = 0; i < iClientContextSources.Count(); ++i )
        {
        if ( &aPublisher == iClientContextSources[ i ].iSource )
            {
            iClientContextSources.Remove( i );
            break; // Stop, no duplicate entries are allowed.
            }
        }
    }


// ---------------------------------------------------------------------------
// CCFContextSourceManager::InitializePhaseL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::InitializePhaseL(
    CCFPhaseBase::TCFPhaseId aPhase )
    {
    FUNC_LOG;

    switch( aPhase )
        {
        case CCFPhaseBase::ECFDeviceStarting:
            {
            InitDeviceStartingPhaseL();
            break;
            }
        case CCFPhaseBase::ECFLoadingPlugins:
            {
            InitLoadingPluginsPhaseL();
            break;
            }
        default:
            {
            break;
            }
        }
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::UpdatePlugInsL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::UpdatePlugInsL()
	{
    FUNC_LOG;

    // List all plugins
    RImplInfoPtrArray implInfoArray;
    CleanupResetAndDestroyPushL( implInfoArray );
    REComSession::ListImplementationsL( KContextSourcePlugInInterface,
        implInfoArray );
    RemoveBlackListed( implInfoArray );

    // Check if the update is install or uninstall based
    TInt allCount = implInfoArray.Count();
    TInt loadedCount = iPlugIns.Count();
    INFO_1( "Found %d context source plug-in implementations from ecom", allCount );
    INFO_1( "%d context source plug-ins currently loaded", loadedCount );

    // Check if there were plugins installed
    if( allCount >= loadedCount )
        {
        for( TInt i = iPlugIns.Count() - 1; i >= 0; i-- )
            {
            TCFContextSourceInfo& pluginInfo = iPlugIns[i];
            for( TInt ii = 0; ii < implInfoArray.Count(); ii++ )
                {
                CImplementationInformation* implInfo = implInfoArray[ii];
                if( implInfo->ImplementationUid() == pluginInfo.iImplUid )
                    {
                    TInt oldVer = pluginInfo.iImplVersion;
                    TInt newVer = implInfo->Version();

                    // Check if the version has increased
                    if( newVer > oldVer )
                        {
                        // Delete old plugin
                        ReleasePlugIn( pluginInfo.iPlugIn );
                        iPlugIns.Remove( i );

                        // Clean up garbage
                        REComSession::FinalClose();

                        // Load the new version
                        TRAPD( err, LoadPluginL( implInfo->ImplementationUid(), implInfo->Version() ) );
                        ERROR_3( err, "Upgrade of new version of context source plugin [%x], oldVer: [%d], newVer: [%d] failed",
                            implInfo->ImplementationUid().iUid, oldVer, newVer );
                        if( err == KErrNone )
                            {
                            INFO_3( "Upgraded new version of context source plugin [%x], oldVer: [%d], newVer: [%d]",
                                implInfo->ImplementationUid().iUid, oldVer, newVer );
                            }
                        }

                    delete implInfo;
                    implInfoArray.Remove( ii );
                    break;
                    }
                }
            }

        // Check if the installed plugin was not an updgrade but a new plugin
        for( TInt i = 0; i < implInfoArray.Count(); i++ )
            {
            CImplementationInformation* implInfo = implInfoArray[i];
            
            // Prepare loaders
            PrepareLoaderL( implInfo );
            }
            // Execute loaders
           ExecuteLoaders();
        }

    // Check if there were plugins unistalled
    else
        {
        for( TInt i = 0; i < iPlugIns.Count(); i++ )
            {
            TCFContextSourceInfo& pluginInfo = iPlugIns[i];
            pluginInfo.iMissing = ETrue;
            }

        // Check that which plugins are missing
        for( TInt i = 0; i < implInfoArray.Count(); i++ )
            {
            CImplementationInformation* implInfo = implInfoArray[i];
            for( TInt i = 0; i < iPlugIns.Count(); i++ )
                {
                TCFContextSourceInfo& pluginInfo = iPlugIns[i];
                if( pluginInfo.iImplUid == implInfo->ImplementationUid() )
                    {
                    pluginInfo.iMissing = EFalse;
                    break;
                    }
                }
            }

        // Delete missing plugins
        for( TInt i = iPlugIns.Count() - 1; i >= 0; i-- )
            {
            TCFContextSourceInfo& pluginInfo = iPlugIns[i];
            if( pluginInfo.iMissing )
                {
                INFO_2( "Removed uninstalled context source plugin [%x], ver: [%d]",
                    pluginInfo.iImplUid.iUid, pluginInfo.iImplVersion );

                ReleasePlugIn( pluginInfo.iPlugIn );
                iPlugIns.Remove( i );

                // Clean up garbage
                REComSession::FinalClose();
                }
            }
        }

    // Cleanup
    CleanupStack::PopAndDestroy( &implInfoArray );
	}

// ---------------------------------------------------------------------------
// CCFContextSourceManager::PrepareLoaderL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::PrepareLoaderL( CImplementationInformation* aImplementationInfo )
    {
    FUNC_LOG;

    TCFLoaderInfo* loaderInfo = new(ELeave)TCFLoaderInfo( *aImplementationInfo, *this );
    CleanupStack::PushL( loaderInfo );
    TCallBack cb( LoaderCallBack, loaderInfo );
    CAsyncCallBack* loader = new( ELeave ) CAsyncCallBack( cb, CActive::EPriorityStandard );
    CleanupStack::PushL( loader );
    iLoaders.AppendL( loader );
    CleanupStack::Pop( loader );
    CleanupStack::Pop( loaderInfo );    
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::ExecuteLoaders
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::ExecuteLoaders()
    {
    FUNC_LOG;
    
    for( TInt i = 0; i < iLoaders.Count(); i++ )
        {
        CAsyncCallBack* loader = iLoaders[i];
        loader->CallBack();
        }
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::LoaderCallBack
// ---------------------------------------------------------------------------
//
TInt CCFContextSourceManager::LoaderCallBack( TAny* aLoaderInfo )
    {
    FUNC_LOG;
    
    TCFLoaderInfo* loaderInfo = static_cast<TCFLoaderInfo*>( aLoaderInfo );
    CCFContextSourceManager& manager = loaderInfo->iManager;    
    
    TRAPD( err, manager.LoadPluginL( loaderInfo->iImplUid,
                                     loaderInfo->iImplVersion ));                

    if( err == KErrNone )
        {
        INFO_2( "Loaded context source plugin [%x], ver: [%d]",
                 loaderInfo->iImplUid.iUid, loaderInfo->iImplVersion );
        }
    else
        {
        ERROR_2( err, "Failed to load context source plugin [%x], ver: [%d]",
                 loaderInfo->iImplUid.iUid, loaderInfo->iImplVersion );
        }
    
    manager.iLoadedCount++;
    
    if( manager.iLoadedCount == manager.iLoaders.Count() )
        {
        manager.iLoaders.ResetAndDestroy();
        manager.iLoadedCount = 0;

        if( manager.iEventHandler )
            {
        	manager.iEventHandler->HandleEvent( MCFStarterEventHandler::EContextSourcePluginsLoaded );
            }
        }
    delete loaderInfo;    
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::CreateAndInitializePlugInL
// ---------------------------------------------------------------------------
//
CCFContextSourcePlugIn* CCFContextSourceManager::CreateAndInitializePlugInL(
    const TUid& aImplementationUid,
    TContextSourceInitParams& aParams )
    {
    FUNC_LOG;

    // Create plug-in
    CCFContextSourcePlugIn* plugIn = CCFContextSourcePlugIn::NewL(
        aImplementationUid,
        &aParams );
    CleanupStack::PushL( plugIn );

    // Handle settings
    CCFContextSourceSettingArray* settings
            = PlugInSettingsL( aImplementationUid );

    if ( settings->Count() )
        {
        // Forward settings to plug-in
        // Plug-in takes ownership of the array.
        plugIn->HandleSettingL( settings );
        }
    else
        {
        // Manager owns the array, cleanup now.
        delete settings;
        settings = NULL;
        }

    // Define context
    plugIn->DefineContextsL();

    // Initialize
    plugIn->InitializeL();

    // Cleanup
    CleanupStack::Pop( plugIn );

    return plugIn;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::InitDeviceStartingPhaseL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::InitDeviceStartingPhaseL()
    {
    FUNC_LOG;

    // List all plugins
    RImplInfoPtrArray implInfoArray;
    CleanupResetAndDestroyPushL( implInfoArray );
    REComSession::ListImplementationsL( KContextSourcePlugInInterface,
        implInfoArray );

    // Load context source manager configuration cenrep
    CRepository* cenRep = CRepository::NewLC( KCRUidCFContextSourceConf );
    TInt count = 0;
    TInt err = cenRep->Get( KContextSourceNumberOfMandatoryPlugIns, count );
    if( err == KErrNone && count )
        {
        INFO_1( "Found %d context source plug-in implementations from cenrep", count );
        TUint32 key = KContextSourceNumberOfMandatoryPlugIns + 1;
        for( TInt i = 0; i < count; i++ )
            {
            TInt uid = 0;

            // Ignore first key
            err = cenRep->Get( key + i, uid );
            if( err == KErrNone && uid )
                {
                CImplementationInformation* info = NULL;
                for( TInt ii = 0; ii < implInfoArray.Count(); ii++ )
                    {
                    info = implInfoArray[ii];
                    if( info->ImplementationUid() == TUid::Uid( uid ) )
                        {
                        break;
                        }
                    info = NULL;
                    }
                if( info )
                    {
                    TRAPD( err, LoadPluginL( info->ImplementationUid(), info->Version() ) );
                    if( err == KErrNone )
                        {
                        INFO_2( "Loaded context source plugin [%x], ver: [%d]",
                            info->ImplementationUid().iUid, info->Version() );
                        }
                    else
                        {
                        ERROR_2( err, "Failed to load context source plugin [%x], ver: [%d]",
                            info->ImplementationUid().iUid, info->Version() );
                        }
                    }
                }
            else
                {
                INFO_2( "UID 0x%08x skipped, error code %d", uid, err );
                }
            }
        }

    // Clean up
    CleanupStack::PopAndDestroy( cenRep );
    CleanupStack::PopAndDestroy( &implInfoArray );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::InitLoadingPluginsPhaseL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::InitLoadingPluginsPhaseL()
    {
    FUNC_LOG;

    UpdatePlugInsL();
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::LoadPluginL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::LoadPluginL( TUid aUid,
                                           TInt aImplVersion )
    {
    FUNC_LOG;

    INFO_2( "Loading context source plug-in with UID [%x], version [%d]",
    		aUid.iUid,
    		aImplVersion );
    HEAP_2( "Before loading context source plug-in with UID [%x], version [%d]",
            aUid.iUid,
            aImplVersion );
    TContextSourceInitParams initParams( static_cast<MCFContextInterface&>( iCF ) );
    CCFContextSourcePlugIn* plugIn = NULL;
    TRAPD( err, plugIn = CreateAndInitializePlugInL( aUid,
    		                                         initParams ) );
    if( err == KErrNone )
        {
        // Plug-in loaded succesfully, store it
        TCFContextSourceInfo info( aUid, aImplVersion, plugIn );
        TInt err = iPlugIns.Append( info );
        if( err != KErrNone )
            {
            ERROR_1( err, "Context source plug-in: %x could not be appended in array",
            		aUid.iUid );
            ReleasePlugIn( plugIn );
            }
        else
            {
            INFO_1( "Context source plug-in: %x succesfully loaded",
            		aUid.iUid );
            }
        }
    else
        {
        ERROR_2( err, "Context source plug-in %x load error: %d",
        		aUid.iUid,
    	    	err );

        err = AddToBlackList( aUid );
        ERROR( err, "Failed to add UID to blacklist" );
        }

    HEAP_2( "After loading context source plug-in with UID [%x], version [%d]",
            aUid.iUid,
            aImplVersion );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::ConfigureRomSettingFolder
// ---------------------------------------------------------------------------
//
TBool CCFContextSourceManager::ConfigureRomSettingFolder( TDes& aFile,
    const TUid& aUid )
    {
    FUNC_LOG;

    // Check rom
    // '[12345678]' -> 'z:\private\10282BC4\Settings\12345678\'
    aFile.Copy( KSettingsPathRom );
    aFile.Append( aUid.Name().Mid(
        KUIDNameStartPos,
        KUIDNameEndPos ) );
    aFile.Append( KFolderExt );

    return BaflUtils::PathExists( iFs, aFile );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::ConfigureRamSettingFolder
// ---------------------------------------------------------------------------
//
TBool CCFContextSourceManager::ConfigureRamSettingFolder( TDes& aFile,
    const TUid& aUid )
    {
    FUNC_LOG;

    // Check rom
    // '[12345678]' -> 'c:\private\10282BC4\Settings\12345678\'
    aFile.Copy( KSettingsPathRam );
    aFile.Append( aUid.Name().Mid(
        KUIDNameStartPos,
        KUIDNameEndPos ) );
    aFile.Append( KFolderExt );

    return BaflUtils::PathExists( iFs, aFile );
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::ParsePlugInSettingsL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::ParsePlugInSettingsL( const TDesC& aFolder,
    CCFContextSourceSettingArray& aSettings )
    {
    CDir* dirList = NULL;
    TInt err = iFs.GetDir( aFolder,
        KEntryAttMaskSupported,
        ESortByName,
        dirList );
    if( err == KErrNone )
        {
        CleanupStack::PushL( dirList );
        TInt count = dirList->Count();
        INFO_1( "Found %d setting files", count );

        HBufC* file = HBufC::NewLC( KMaxFileName );
        TPtr filePtr = file->Des();
        for( TInt i = 0; i < count; i++ )
            {
            // Configure full file path
            filePtr.Copy( aFolder.Left(
                aFolder.Length() - KSettingExtension().Length() ) );
            filePtr.Append( (*dirList)[i].iName );
            INFO_1( "Parsing setting file '%S'", &(*dirList)[i].iName );

            // Parse settings
            iSettingsManager->ParseSettingsL( filePtr, aSettings );
            }

        CleanupStack::PopAndDestroy( file );
        CleanupStack::PopAndDestroy( dirList );
        }
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::PlugInSettingsL
// ---------------------------------------------------------------------------
//
CCFContextSourceSettingArray* CCFContextSourceManager::PlugInSettingsL(
    const TUid& aImplementationUid )
    {
    // Get settings for the plugin.
    CCFContextSourceSettingArray* settings
            = CCFContextSourceSettingArray::NewLC();    // CLEANUP<< settings
    HBufC* settingFile = HBufC::NewLC( KMaxFileName );  // CLEANUP<< settingFile
    TPtr settingFilePtr = settingFile->Des();
    if( ConfigureRomSettingFolder( settingFilePtr, aImplementationUid ) )
        {
        INFO_1( "Found context source ROM setting folder '%S'", &settingFilePtr );
        // Setting folder found, parse settings.
        settingFilePtr.Append( KSettingExtension );
        ParsePlugInSettingsL( settingFilePtr, *settings );
        }

    if( ConfigureRamSettingFolder( settingFilePtr, aImplementationUid ) )
        {
        INFO_1( "Found context source RAM setting folder '%S'", &settingFilePtr );
        // Setting folder found, parse settings.
        settingFilePtr.Append( KSettingExtension );
        ParsePlugInSettingsL( settingFilePtr, *settings );
        }

    CleanupStack::PopAndDestroy( settingFile );         // CLEANUP>> settingFile
    CleanupStack::Pop( settings );                      // CLEANUP>> settings
    return settings;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::PlugInL
// ---------------------------------------------------------------------------
//
MCFContextSourceUpgrade* CCFContextSourceManager::PlugInL(
    const TUid& aContextSourceUid ) const
    {
    FUNC_LOG;

    // Find plugin.
    CCFContextSourcePlugIn* plugIn = NULL;
    for( TInt i = 0; i < iPlugIns.Count(); ++i )
        {
        if( iPlugIns[ i ].iImplUid == aContextSourceUid )
            {
            plugIn = iPlugIns[ i ].iPlugIn;
            break;
            }
        }
    if ( !plugIn )
        {
        User::Leave( KErrBadHandle );
        }

    // Check plugin's support for MCFContextSourceUpgrade extension.
    MCFContextSourceUpgrade* contextSourceUpgrade =
            ( MCFContextSourceUpgrade* )plugIn->Extension(
                    KCFContextSourceUpgradeUid );
    if ( !contextSourceUpgrade )
        {
        User::Leave( KErrExtensionNotSupported );
        }

    return contextSourceUpgrade;
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::CopySettingFileL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::CopySettingFileL( const RFile& aSettingFile,
    const TUid& aContextSourceUid,
    RThread& aClientThread )
    {
    FUNC_LOG;

    HBufC* settingFile = HBufC::NewLC( KMaxFileName );  // CLEANUP<< settingFile
    TPtr settingFilePtr = settingFile->Des();

    ConfigureRamSettingFolder( settingFilePtr, aContextSourceUid );

    HBufC* filename = HBufC::NewLC( KMaxFileName );     // CLEANUP<< filename
    TPtr filenamePtr = filename->Des();

    User::LeaveIfError( aSettingFile.Name( filenamePtr ) );

    TUid clientSid( aClientThread.SecureId() );
    settingFilePtr.Append( clientSid.Name().Mid( KUIDNameStartPos,
            KUIDNameEndPos ) );
    settingFilePtr.Append( KUnderscore );
    settingFilePtr.Append( filenamePtr );
    BaflUtils::EnsurePathExistsL( iFs, settingFilePtr );

    CleanupStack::PopAndDestroy( filename );            // CLEANUP>> filename

    CFileMan* fileMan = CFileMan::NewL( iFs );
    CleanupStack::PushL( fileMan );                     // CLEANUP<< fileMan

    TInt err = fileMan->Copy( aSettingFile, settingFilePtr );
    ERROR( err, "CCFContextSourceManager::CopySettingFileL - Copying setting file failed" );
    User::LeaveIfError( err );
    TInt clearMask = KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem;
    err = fileMan->Attribs( settingFilePtr, 0, clearMask, 0 );
    User::LeaveIfError( err );

    CleanupStack::PopAndDestroy( fileMan );             // CLEANUP>> fileMan
    CleanupStack::PopAndDestroy( settingFile );         // CLEANUP>> settingFile
    }

// ---------------------------------------------------------------------------
// CCFContextSourceManager::DeleteSettingFileL
// ---------------------------------------------------------------------------
//
void CCFContextSourceManager::DeleteSettingFileL( const TDesC& aSettingFile,
    const TUid& aContextSourceUid,
    RThread& aClientThread )
    {
    FUNC_LOG;

    HBufC* settingFile = HBufC::NewLC( KMaxFileName );  // CLEANUP<< settingFile
    TPtr settingFilePtr = settingFile->Des();

    ConfigureRamSettingFolder( settingFilePtr, aContextSourceUid );

    TUid clientSid( aClientThread.SecureId() );
    settingFilePtr.Append( clientSid.Name().Mid( KUIDNameStartPos,
            KUIDNameEndPos ) );
    settingFilePtr.Append( KUnderscore );
    settingFilePtr.Append( aSettingFile );

    TInt err = BaflUtils::DeleteFile( iFs, settingFilePtr );
    ERROR( err, "CCFContextSourceManager::DeleteSettingFileL - Deleting setting file(s) failed" );
    User::LeaveIfError( err );

    CleanupStack::PopAndDestroy( settingFile );         // CLEANUP>> settingFile
    }

//------------------------------------------------------------------------------
// CCFContextSourceManager::ReleasePlugIn
//------------------------------------------------------------------------------
//
void CCFContextSourceManager::ReleasePlugIn( CCFContextSourcePlugIn*& aPlugIn )
    {
    FUNC_LOG;

    // Deregister publisher
    TAny* extension = aPlugIn->Extension( KCFContextSourceInterfaceUid );
    if( extension )
        {
        MCFContextSource* contextSource =
            reinterpret_cast<MCFContextSource*>( extension );
        iCF.DeregisterPublisher( *contextSource );
        }
    // Unsubscribe all contexts if the plug-in is uninstalled
    extension = aPlugIn->Extension( KCFSubscriptionListenerInterfaceUid );
    if( extension )
        {
        MCFContextSubscriptionListener* interface =
            static_cast<MCFContextSubscriptionListener*>( extension );
        iCF.UnsubscribeContexts( *interface );
        }
    delete aPlugIn;
    aPlugIn = NULL;
    }
