metadataengine/server/src/mdsserver.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 27 May 2010 13:18:43 +0300
changeset 28 c461c7fa72c2
parent 25 8e4539ab1889
child 31 81125601ee77
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* Copyright (c) 2002-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:  Metadata main server class*
*/

// INCLUDE FILES
#include <f32file.h>
#include "mdsserver.h"
#include "mdscommoninternal.h"
#include "mdsserversession.h"
#include "mdsdbconnectionpool.h"
#include "mdssqldbmaintenance.h"
#include "mdssqliteconnection.h"
#include "mdsnotifier.h"
#include "mdsobjectlocklist.h"
#include "mdslogger.h"
#include "mdsmaintenanceengine.h"
#include "mdsmanipulationengine.h"
#include "mdsclausebuffer.h"
#include "mdebackuprestorewatcher.h"
#include "mdsschema.h"
#include "mdcserializationbuffer.h"

__DEFINE_LOGGER

const TInt64 KDiskSpaceGarbageCollectorThreshold = 1024*1024; // 1 MB

_LIT( KSchema, "schema.mde" );
_LIT( KDefaultImportProfile, "defaultimportfile.mde" );
_LIT( KBackupRegistration, "backup_registration.xml" );
_LIT( KSchemaPath, "z:\\private\\200009F3\\schema.mde" );
_LIT( KDefaultImportProfilePath, "z:\\private\\200009F3\\defaultimportfile.mde" );
_LIT( KBackupRegistrationPath, "z:\\private\\200009F3\\backup_registration.xml" );

// ========================= MdS POLICY ==================================

const TUint KMdsRangeCount = EUnknownMdEServRqst + 1;

const TInt KMdsRanges[KMdsRangeCount] = 
    {
    EShutdown,          	// shut down the session
    EAdd,					// add items
    ERemove,				// remove items
    EFind,              	// finds in sync
    EAsyncFind,         	// finds asynchronously
    EContinueAsyncFind, 	// continues existing asynchronous find, fetches next set
    ECancelFind,        	// cancels asynchronous find
    ECancelObject,      	// cancels opened object
    ECheckObject,           // get object's "base" values
    EUpdate,		      	// update items
    ERegister,          	// registers an object to be notified
    EListen,            	// listens for events for a registered profile
    EUnregister,        	// unregisters for no more notifications
    EGetData,           	// (transfers data server->client)
    EImportMetadata,    	// starts metadata importing
    EAsyncImportMetadata,	// starts asynchronous metadata importing
    EExportMetadata,		// starts metadata exporting
    EAsyncExportMetadata,	// starts asynchronous metadata exporting
    EImportSchema,      	// starts schema importing
    EAddRelationDef,		// Add relation def
    EAddEventDef,		    // Add event def
    EAddMemoryCard,
    EGetMemoryCard,
    ECheckMemoryCard,
    ESetMedia,
    EGetMedia,
    EGetPresentMedias,
    ESetFileToPresent,
    ESetFilesToPresent,
    ESetFilesToNotPresent,
    ERemoveFilesNotPresent,
    EGetSchemaVersion,
    ESetObjectToPresentByGuid, 
    ESetHarvestingPrioritizationChunk,
    EAddHarvestingPrioritizationObserver,
    ECancelHarvestingPrioritizationObserver,
    EChangePath, 
    ESetPending,
    EResetPending,
    EGetPendingCount,
    EGetPending,
    EResetDB,
    EChangeMediaId,
    EChangeMassStorageMediaId,
    EUnknownMdEServRqst     // handle for unknown requests
    };

const TUint8 KMdsElementsIndex[KMdsRangeCount] = 
    {
    CPolicyServer::ECustomCheck,    // EShutdown
    CPolicyServer::ECustomCheck,    // EAdd
    CPolicyServer::ECustomCheck,    // ERemove
    CPolicyServer::ECustomCheck,    // EFind
    CPolicyServer::ECustomCheck,    // EAsyncFind
    CPolicyServer::ECustomCheck,    // EContinueAsyncFind
    CPolicyServer::ECustomCheck,    // ECancelFind
    CPolicyServer::ECustomCheck,    // ECancelObject
    CPolicyServer::ECustomCheck,    // ECheckObject
    CPolicyServer::ECustomCheck,    // EUpdate
    CPolicyServer::ECustomCheck,    // ERegister
    CPolicyServer::ECustomCheck,    // EListen
    CPolicyServer::ECustomCheck,    // EUnregister
    CPolicyServer::ECustomCheck,    // EGetData
    CPolicyServer::ECustomCheck,    // EImportMetadata
    CPolicyServer::ECustomCheck,    // EAsyncImportMetadata
    CPolicyServer::ECustomCheck,    // EExportMetadata
    CPolicyServer::ECustomCheck,    // EAsyncExportMetadata
    CPolicyServer::ECustomCheck,    // EImportSchema
    CPolicyServer::ECustomCheck,	// EAddRelationDef
    CPolicyServer::ECustomCheck,	// EAddEventDef
    CPolicyServer::ECustomCheck, 	// EAddMemoryCard
    CPolicyServer::ECustomCheck, 	// EGetMemoryCard
    CPolicyServer::ECustomCheck, 	// ECheckMemoryCard
    CPolicyServer::ECustomCheck, 	// ESetMedia
    CPolicyServer::ECustomCheck, 	// EGetMedia
    CPolicyServer::ECustomCheck, 	// EGetPresentMedias
    CPolicyServer::ECustomCheck, 	// ESetFileToPresent
    CPolicyServer::ECustomCheck, 	// ESetFilesToPresent
    CPolicyServer::ECustomCheck, 	// ESetFilesToNotPresent
    CPolicyServer::ECustomCheck, 	// ERemoveFilesNotPresent
    CPolicyServer::ECustomCheck, 	// EGetSchemaVersion
    CPolicyServer::ECustomCheck, 	// ESetObjectToPresentByGuid
    CPolicyServer::ECustomCheck, 	// ESetHarvestingPrioritizationChunk
    CPolicyServer::ECustomCheck, 	// EAddHarvestingPrioritizationObserver
    CPolicyServer::ECustomCheck, 	// ECancelHarvestingPrioritizationObserver
    CPolicyServer::ECustomCheck, 	// EChangePath
    CPolicyServer::ECustomCheck, 	// ESetPending
    CPolicyServer::ECustomCheck, 	// EResetPending
    CPolicyServer::ECustomCheck, 	// EGetPendingCount
    CPolicyServer::ECustomCheck, 	// EGetPending
    CPolicyServer::ECustomCheck, 	// EResetDB
    CPolicyServer::ECustomCheck,    // EChangeMediaId
    CPolicyServer::ECustomCheck,    // EChangeMassStorageMediaId
    CPolicyServer::ENotSupported	// EUnknownMdEServRqst
    };


const CPolicyServer::TPolicy KMdsPolicy =
    {
    CPolicyServer::EAlwaysPass, //specifies all connect attempts should pass
    KMdsRangeCount,                   
    KMdsRanges,
    KMdsElementsIndex,
    NULL //mdsElements
    };

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

void CheckAndInitializeFileL( RFs& aFs, TBuf<KMaxFileName>& aFile, const TDesC16& aFilePath,
                                            RFileReadStream& aTempFile, CFileMan* aFileMan )
    {
    __LOG1( ELogAlways, "CheckAndInitializeFileL() - handling file %S", &aFilePath );
    const TInt err = aTempFile.Open( aFs, aFile, EFileRead | EFileShareAny );
    __LOG1( ELogAlways, "CheckAndInitializeFileL() - open file error %d", err );
    aTempFile.Close();
    if ( err != KErrNone )
        {
        if ( err == KErrNotFound )
            {
            // Path found but not schema.mde, copy schema.m
            const TInt error = aFileMan->Copy( aFilePath, aFile, CFileMan::EOverWrite );
            __LOG1( ELogAlways, "CheckAndInitializeFileL() - copy file error %d", error );
            }
        else if ( err == KErrPathNotFound)
            {
            // Create private dir
            User::LeaveIfError( aFs.CreatePrivatePath( EDriveC ) );
            
            // Copy schema.mde
            const TInt error = aFileMan->Copy( aFilePath, aFile, CFileMan::EOverWrite );
            __LOG1( ELogAlways, "CheckAndInitializeFileL() - copy file error %d", error );
            }    
        }    
    }

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

CPolicyServer::TCustomResult CMdSServer::CustomSecurityCheckL(
        const RMessage2& aMsg, TInt& /*aAction*/, TSecurityInfo& /*aMissing*/ )
    {
    CPolicyServer::TCustomResult securityCheckResult = EFail;
    switch ( aMsg.Function() )
        {
        case EAdd:
        case ERemove:
        case ECancelObject:
        case EUpdate:
        case EImportMetadata:
        case EAsyncImportMetadata:
        case EAddRelationDef:
        case EAddEventDef:
        case EImportSchema:
        case EChangeMassStorageMediaId:
        case ESetObjectToPresentByGuid:
            {
            if( aMsg.HasCapability( ECapabilityWriteDeviceData ) )
                {
                securityCheckResult = EPass;
                }
            }
            break;

        case ERegister:
        case EListen:
        case EUnregister:
        case EFind:
        case EAsyncFind:
        case EContinueAsyncFind:
        case ECancelFind:    
        case EGetData:
        case ECheckObject:
            {
            securityCheckResult = EPass;
            }
            break;
            
        case EExportMetadata:
        case EAsyncExportMetadata:
        case EGetSchemaVersion:
            {
            if( aMsg.HasCapability( ECapabilityReadUserData ) || 
            	aMsg.HasCapability( ECapabilityReadDeviceData ) )
                {
                securityCheckResult = EPass;
                }
            }
        	break;
        	
        // Only for internal MdS usage
        case EAddMemoryCard:
    	case EGetMemoryCard:
        case ECheckMemoryCard:
        case ESetMedia:
        case EGetMedia:
        case EGetPresentMedias:
    	case ESetFileToPresent:
    	case ESetFilesToPresent:
    	case ESetFilesToNotPresent:
    	case ERemoveFilesNotPresent:
    	case ESetHarvestingPrioritizationChunk:
    	case EAddHarvestingPrioritizationObserver:
    	case ECancelHarvestingPrioritizationObserver:
    	case EChangePath:
    	case EChangeMediaId:
    	case ESetPending:
    	case EResetPending:
    	case EGetPendingCount:
    	case EGetPending:
    	case EResetDB:
    		{
            if( aMsg.HasCapability( ECapabilityDiskAdmin ) )
                {
                securityCheckResult = EPass;
                }
    		}
        	break;
        	
        default:
            {
            securityCheckResult = EFail;
            }
        }

    return securityCheckResult;
    }

CPolicyServer::TCustomResult CMdSServer::CustomFailureActionL(
        const RMessage2& /*aMsg*/, TInt /*aAction*/, const TSecurityInfo& /*aMissing*/)
    {
    // Not used
    return EFail;
    }


// ========================= MEMBER FUNCTIONS ==================================
void CMdSServer::HandleDiskSpaceNotificationL( TDiskSpaceDirection aDiskSpaceDirection )
	{
	// skip db cleaning if drive's free space is over limit or
	// backup or restore is running
	if( MMdSDiskSpaceNotifierObserver::EMore == aDiskSpaceDirection ||
		iBackupOrRestoreRunning )
		{
		return;
		}

	// delete only objects which are in "not present" state and
	// object was not located in last (count = KMemoryCardLimit) 
	// inserted memory cards and object doesn't have any relations
	_LIT( KMemoryCardCleanup, "DELETE FROM Object%u WHERE ObjectId IN(SELECT ObjectId FROM Object%u WHERE((Flags&?) AND (MediaId NOT IN(SELECT DISTINCT Value FROM MdE_Preferences WHERE Key=? ORDER BY ExtraValue DESC LIMIT ?)) AND (ObjectId NOT IN(SELECT DISTINCT LeftObjectId FROM Relations%u)) AND (ObjectId NOT IN(SELECT DISTINCT RightObjectId FROM Relations%u))) ORDER BY LastModifiedDate ASC LIMIT ?);" );

	const TInt KMaxLenghtForNamespaceIdsAsText = 4 * KMaxUintValueLength;
	CMdsClauseBuffer* clause = CMdsClauseBuffer::NewLC( 
			KMemoryCardCleanup.iTypeLength + KMaxLenghtForNamespaceIdsAsText );
	
	clause->BufferL().Format( KMemoryCardCleanup, 
		KDefaultNamespaceDefId, 
		KDefaultNamespaceDefId, 
		KDefaultNamespaceDefId, 
		KDefaultNamespaceDefId );
	
	RRowData variables;
    CleanupClosePushL( variables );

	_LIT( KMemoryCardKey, "MC" );
	const TInt KMemoryCardLimit = 1;
	const TInt KObjectCleanupLimit = 1024;
	
	variables.AppendL( TColumn( EMdEObjectFlagNotPresent ) );
	variables.AppendL( TColumn( KMemoryCardKey ) );
	variables.AppendL( TColumn( KMemoryCardLimit ) );
	variables.AppendL( TColumn( KObjectCleanupLimit ) );
	
	const TInt rowCount = iDefaultDBConnection->ExecuteL( clause->ConstBufferL(), variables );

	CleanupStack::PopAndDestroy( 2, clause ); // variables, clause
	}


void CMdSServer::HandleDiskSpaceError(TInt /*aError*/)
	{
	}


CMdSServer* CMdSServer::NewL()
    {
    CMdSServer* MdSServer = CMdSServer::NewLC();
    CleanupStack::Pop( MdSServer );
    return MdSServer;
    }


CMdSServer* CMdSServer::NewLC()
    {
    CMdSServer* MdSServer = new ( ELeave ) CMdSServer( CActive::EPriorityStandard );
    CleanupStack::PushL( MdSServer );
    MdSServer->ConstructL();
    return MdSServer;
    }


void CMdSServer::ConstructL()
    {
    __INIT_LOGGER;
    StartL( KMdSServerName );
    __LOGLB( ELogAlways, "Server start" );

    RProcess process;
    process.SetPriority( EPriorityBackground );
    process.Close();
    
    CheckInitSriptL();
    
    iLockList = CMdSObjectLockList::NewL();
    CMdSSqLiteConnection* conn = CMdSSqLiteConnection::NewLC();
    iDefaultDBConnection = conn;
    MMdSDbConnectionPool::SetDefaultDB( conn );
    CleanupStack::Pop( conn );

    CMdSMaintenanceEngine::InitConnectionL();    
    
    iNotifier = CMdSNotifier::NewL();

    InitializeL();

    iDiskSpaceGarbageCollectorNotifier = 
    	CMdSDiskSpaceNotifierAO::NewL( *this, 
    								   KDiskSpaceGarbageCollectorThreshold,
    								   KMdsSqlDbDefaultName );
    
    iDiskFullNotifier = 
    	CMdSDiskSpaceNotifierAO::NewL( *this, 
    									KDiskFullThreshold,
    									KMdsSqlDbDefaultName );

    // Create a backup & restore watcher and add this server as its observer.								   
    iBURWatcher = CMdEBackupRestoreWatcherAO::NewL(*this);
    
    // create shutdown observer
    iShutdownObserver = CMDSShutdownObserver::NewL( *this );
    iShutdown = EFalse;   
    }

void CMdSServer::InitializeL()
    {
    iMaintenance = CMdSMaintenanceEngine::NewL();

    iSchema = CMdsSchema::NewL();

    iManipulate = CMdSManipulationEngine::NewL( *iSchema, *iNotifier, 
        *iLockList );

    iMaintenance->InstallL( *iManipulate, *iSchema );
    }

void CMdSServer::DeInitializeL()
    {
    if ( iMaintenance )
    	{
    	delete iMaintenance;
    	iMaintenance = NULL;
    	}
    if ( iManipulate )
    	{
    	delete iManipulate;
    	iManipulate = NULL;
    	}
    if ( iSchema )
    	{
    	delete iSchema;
    	iSchema = NULL;
    	}
    }

TInt CMdSServer::ResetDBL()
	{
	DeInitializeL();

	CMdSMaintenanceEngine::DeleteDatabase();
	CMdSMaintenanceEngine::InitConnectionL();
	
    InitializeL();
	return KErrNone;
	}

CMdSServer::CMdSServer( TInt aPriority ) : 
	CPolicyServer(aPriority, KMdsPolicy), 
	iBackupOrRestoreRunning( EFalse ),
	iHarvestingPrioritizationSerializationBuffer( NULL )
    {
    iServerErrorStatus = KErrNone;
    }


CMdSServer::~CMdSServer()
    {
    iShutdown = ETrue;
    iClientThread.Close();
    
	delete iBURWatcher;
	delete iDiskSpaceGarbageCollectorNotifier;
	delete iDiskFullNotifier;
    delete iManipulate;
    delete iSchema;
    delete iNotifier;
    delete iLockList;
    delete iMaintenance;
    delete iDefaultDBConnection;

    delete iHarvestingPrioritizationSerializationBuffer;
	iHarvestingPrioritizationChunk.Close();
	
	delete iShutdownObserver;

    __LOGLB( ELogAlways, "Server stop" );
    __DESTROY_LOGGER;
    }


CSession2* CMdSServer::NewSessionL( const TVersion& aVersion, const RMessage2& /*aMessage*/ ) const
    {
    // Check we are the right version
    if ( !User::QueryVersionSupported( TVersion( KMdSServMajorVersionNumber,
                                                 KMdSServMinorVersionNumber,
                                                 KMdSServBuildVersionNumber ),
                                       aVersion ) )
        {
        User::Leave( KErrNotSupported );
        }

	if ( iShutdownObserver->UpdateInProgress() )
        {
        __LOGLB( ELogAlways, "CMdSServer::NewSessionL: iad update in progress: KErrLocked");
        User::Leave(KErrLocked);
        }

    if ( iServerErrorStatus != KErrNone )
        {
        // leave with the same error code that the server has
        User::Leave ( iServerErrorStatus );
        }

    __LOGLB( ELogAlways, "New Session" );
    // Make new session
    return CMdSServerSession::NewL( *const_cast<CMdSServer*> ( this ) );
    }

CMdsSchema& CMdSServer::Schema()
    {
    return *iSchema;
    }

CMdSObjectLockList& CMdSServer::LockList()
    {
    return *iLockList;
    }

CMdSNotifier& CMdSServer::Notifier()
    {
    return *iNotifier;
    }

CMdSMaintenanceEngine& CMdSServer::Maintenance()
    {
    return *iMaintenance;
    }

CMdSManipulationEngine& CMdSServer::Manipulate()
    {
    return *iManipulate;
    }

TBool CMdSServer::DiskFull() const
	{
	return iDiskFullNotifier->DiskFull();
	}
   
TBool CMdSServer::BackupOrRestoreRunning() const
	{
	return iBackupOrRestoreRunning;
	}
  
TBool CMdSServer::ShutdownInProgress() const
    {
    return iShutdown;
    }

// -----------------------------------------------------------------------------
// CMdSServer::ShutdownNotification
// -----------------------------------------------------------------------------
//
void CMdSServer::ShutdownNotification()
    {
    if (!iShutdown)
        {    
        CActiveScheduler::Stop();
        iShutdown = ETrue;
        }
    }

// -----------------------------------------------------------------------------
// CMdSServer::ShutdownNotification
// -----------------------------------------------------------------------------
//
void CMdSServer::RestartNotification()
    {
    }


TInt CMdSServer::SetHarvestingPrioritizationChunkL( const RMessagePtr2 aMessage, TInt aParam )
	{
	// if there happens to be old chunk, close it
	iHarvestingPrioritizationChunk.Close();

	const TInt error = iHarvestingPrioritizationChunk.Open( aMessage, aParam, EFalse );

	if( error != KErrNone )
		{
		return error;
		}

	if( iHarvestingPrioritizationSerializationBuffer )
		{
		delete iHarvestingPrioritizationSerializationBuffer;
		iHarvestingPrioritizationSerializationBuffer = NULL;
		}

	iHarvestingPrioritizationSerializationBuffer = 
		CMdCSerializationBuffer::NewL( 
			iHarvestingPrioritizationChunk.Base(), 
			iHarvestingPrioritizationChunk.Size() );
	
	iHarvestingPrioritizationLocked = EFalse;

	return KErrNone;
	}

TInt CMdSServer::AddHarvestingPrioritizationObserver( RMessagePtr2 aMessage )
	{
	if( iHarvestingPrioritizationObserver.IsNull() )
		{
		iHarvestingPrioritizationLocked = EFalse;

		iClientThread.Close();
		iHarvestingPrioritizationObserver = aMessage;
		iHarvestingPrioritizationObserver.Client( iClientThread );

		// reserve space for harvesting prioritization URI count
		iHarvestingPrioritizationLimit = CMdCSerializationBuffer::KRequiredSizeForTInt32;
		iHarvestingPrioritizationUriCount = 0;
		
		return KErrNone;
		}
	else
	    {
        TExitType exitType = iClientThread.ExitType();
        if( EExitPending != exitType )
            {
            iHarvestingPrioritizationLocked = EFalse;

            iClientThread.Close();
            iHarvestingPrioritizationObserver = aMessage;
            iHarvestingPrioritizationObserver.Client( iClientThread );

            // reserve space for harvesting prioritization URI count
            iHarvestingPrioritizationLimit = CMdCSerializationBuffer::KRequiredSizeForTInt32;
            iHarvestingPrioritizationUriCount = 0;
        
            return KErrNone;
            }
	    }

	return KErrAlreadyExists;
	}

TInt CMdSServer::CancelHarvestingPrioritizationObserver()
	{	
	iHarvestingPrioritizationLocked = EFalse;

	if( iHarvestingPrioritizationObserver.IsNull() )
		{
		return KErrNotFound;
		}
	
	NotifyHarvestingPrioritizationObserver( KErrCancel );
	return KErrNone;
	}

TBool CMdSServer::ReserveSpaceHarvestingPrioritizationUri( const TDesC16& aUri )
	{
	if( !iHarvestingPrioritizationLocked && 
		iHarvestingPrioritizationObserver.IsNull() == EFalse && 
		iHarvestingPrioritizationSerializationBuffer )
		{
		// reserve space for URI offset and URI
		const TInt reserveSpace = 
			CMdCSerializationBuffer::KRequiredSizeForTUint32 + 
			CMdCSerializationBuffer::RequiredSize( aUri );

		const TInt maxBufferSize = 
			iHarvestingPrioritizationSerializationBuffer->Size();

		// check if buffer has enough space for the new URI
		if( maxBufferSize >= ( iHarvestingPrioritizationLimit + reserveSpace ) )
			{			
			iHarvestingPrioritizationLimit += reserveSpace;
			iHarvestingPrioritizationUriCount++;
			return ETrue;
			}
		// if buffer doesn't have enough space for the new uri, 
		// discard current URI and all following URIs
		else
			{
			iHarvestingPrioritizationLimit = maxBufferSize;
			return EFalse;
			}
		}
	return EFalse;
	}

TBool CMdSServer::StartAddingHarvestingPrioritizationUrisL()
	{
	if( !iHarvestingPrioritizationLocked && 
		iHarvestingPrioritizationObserver.IsNull() == EFalse && 
		iHarvestingPrioritizationSerializationBuffer )
		{
		iHarvestingPrioritizationLocked = ETrue;

		// add URI count to harvesting prioritization buffer
		iHarvestingPrioritizationSerializationBuffer->PositionL( 0 );
		iHarvestingPrioritizationSerializationBuffer->InsertL( 
			iHarvestingPrioritizationUriCount );

		iHarvestingPrioritizationBufferUriCount = 0;

		// set URI offset to position of the first URI
		iHarvestingPrioritizationBufferUriOffset = 
			CMdCSerializationBuffer::KRequiredSizeForTInt32 + 
			CMdCSerializationBuffer::KRequiredSizeForTUint32 * 
			iHarvestingPrioritizationUriCount;

		return ETrue;
		}

	return EFalse;
	}

TBool CMdSServer::AddHarvestingPrioritizationUriL( TDesC16& aUri )
	{
	if( iHarvestingPrioritizationObserver.IsNull() == EFalse && 
		iHarvestingPrioritizationSerializationBuffer )
		{
		const TUint32 offset = 
			CMdCSerializationBuffer::KRequiredSizeForTInt32 + 
			CMdCSerializationBuffer::KRequiredSizeForTUint32 * 
			iHarvestingPrioritizationBufferUriCount;

		iHarvestingPrioritizationSerializationBuffer->PositionL( offset );
		iHarvestingPrioritizationSerializationBuffer->InsertL( 
			iHarvestingPrioritizationBufferUriOffset );

		// move to URI offset, insert URI and get new URI offset
		iHarvestingPrioritizationSerializationBuffer->PositionL( 
			iHarvestingPrioritizationBufferUriOffset );
		iHarvestingPrioritizationBufferUriOffset = 
			iHarvestingPrioritizationSerializationBuffer->InsertL( aUri );

		iHarvestingPrioritizationBufferUriCount++;
		
		return ETrue;
		}
	return EFalse;
	}

void CMdSServer::NotifyHarvestingPrioritizationObserver( TInt aStatus ) const
	{
	if( !iHarvestingPrioritizationObserver.IsNull() )
		{
	    TExitType exitType = iClientThread.ExitType();
	    if( EExitPending == exitType )
	        {
	        iHarvestingPrioritizationObserver.Complete( aStatus );
	        }
		}
	}

TInt CMdSServer::RunError( TInt aError )
    {
    __LOG1( ELogAlways, "Server::RunError %d", aError );

    if ( aError == KErrBadDescriptor )
        {
        // A bad descriptor error implies a badly programmed client,
        // so panic it; otherwise report the error to the client
        PanicClient( Message(), KErrBadDescriptor );
        }
    else
        {
        Message().Complete( aError );
        }

    // The leave will result in an early return from CServer::RunL(), skipping
    // the call to request another message. So do that now in order to keep the
    // server running.
    ReStart();

    return KErrNone;    // Handled the error fully
    }



void CMdSServer::PanicClient( const RMessage2& aMessage, TInt aPanic )
    {
    __LOG1( ELogAlways, "Server::PanicClient %d", aPanic );
    aMessage.Panic( KMetadataEngine, aPanic );
    }


void CMdSServer::PanicServer( TMetadataPanic aPanic )
    {
    __LOG1( ELogAlways, "Server::PanicServer %d", aPanic );
    MMdCCommon::Panic( aPanic );
    }

void CMdSServer::ThreadFunctionL()
    {
    User::LeaveIfError(User::RenameThread(KMdSServerName));
    // Construct active scheduler
    CActiveScheduler* activeScheduler = new ( ELeave ) CActiveScheduler;
    CleanupStack::PushL( activeScheduler );

    // Install active scheduler
    // We don't need to check whether an active scheduler is already installed
    // as this is a new thread, so there won't be one
    CActiveScheduler::Install( activeScheduler );

    // Construct our server
    CMdSServer::NewLC();    // Anonymous

    RProcess::Rendezvous(KErrNone);

    // Start handling requests
    CActiveScheduler::Start();

    CleanupStack::PopAndDestroy( 2, activeScheduler ); 
    }


TInt CMdSServer::ThreadFunction( TAny* /*aNone*/ )
    {
    CTrapCleanup* cleanupStack = CTrapCleanup::New();
    if ( !( cleanupStack ) )
        {
        PanicServer( ECreateTrapCleanup );
        }

    TRAPD( err, ThreadFunctionL() );
    if ( err != KErrNone )
        {
        PanicServer( ESrvCreateServer );
        }

    delete cleanupStack;
    cleanupStack = NULL;

    return KErrNone;
    }
    

// Backup & restore methods
void CMdSServer::HandleBackup()
	{
	iBackupOrRestoreRunning = ETrue;
	
	// Free resources for back up.
	iManipulate->GarbageCollector().Pause();
	
	// disconnect all DB connections
	CMdSMaintenanceEngine::CloseDatabase();
	}

void CMdSServer::HandleRestore()
	{
	iBackupOrRestoreRunning = ETrue;

	// Free resources for restore.
	iManipulate->GarbageCollector().Pause();

	// disconnect all DB connections
	CMdSMaintenanceEngine::CloseDatabase();
	
	// Currently trust that device will reboot after restore.
	}

void CMdSServer::ResumeOperation()
	{
	iBackupOrRestoreRunning = EFalse;

	// Resume normal operation after back up.

	// restore all DB connections
	TRAPD( error, CMdSMaintenanceEngine::InitConnectionL() );

	// if setting back DB connections fails 
	// something very bad has happened during backup or restore
	if( KErrNone != error )
		{
		MMdCCommon::Panic( EServerBackupOrRestore );
		}

	// Restore resources
	iManipulate->GarbageCollector().Resume();
	}

void CMdSServer::CheckInitSriptL()
    {
    RFs fs;
    User::LeaveIfError( fs.Connect() );
    CleanupClosePushL( fs );
    
    TBuf<KMaxFileName> privatePath;
    TBuf<KMaxFileName> schema;
    TBuf<KMaxFileName> defaultImportProfile;
    TBuf<KMaxFileName> backupRegistration;
    RFileReadStream tmpFile;
    
    fs.PrivatePath( privatePath );
    
    schema.Copy( privatePath );
    schema.Append( KSchema );
    
    defaultImportProfile.Copy( privatePath );
    defaultImportProfile.Append( KDefaultImportProfile );
    
    backupRegistration.Copy( privatePath );
    backupRegistration.Append( KBackupRegistration );
    
    CFileMan* fileMan = CFileMan::NewL( fs );
    CleanupStack::PushL( fileMan );
    
    CheckAndInitializeFileL( fs, schema, KSchemaPath(), tmpFile, fileMan );
    
    CheckAndInitializeFileL( fs, defaultImportProfile, KDefaultImportProfilePath(), tmpFile, fileMan );    
    
    CheckAndInitializeFileL( fs, backupRegistration, KBackupRegistrationPath(), tmpFile, fileMan );

    CleanupStack::PopAndDestroy( 2 ); //fileman, fs
    }

// ========================== OTHER EXPORTED FUNCTIONS =========================

TInt E32Main()
    {
    __UHEAP_MARK;
 	CTrapCleanup* cleanup=CTrapCleanup::New();
 	TInt result = KErrNoMemory;
 	if (cleanup)
 		{
 		TRAP(result, CMdSServer::ThreadFunctionL());
		delete cleanup;
 		}
    __UHEAP_MARKEND;
 	return result;
    }
    
// End of File