omadrm/drmengine/server/src/DRMRightsServer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:27 +0200
changeset 0 95b198f216e5
child 18 8a03a285ab14
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2003 - 2007 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:  DRM3 Engine manages all DRM related database operations.
*
*/


// INCLUDE FILES
#include <e32std.h>
#include <e32test.h>
#include <etelmm.h>
#include <DrmTypes.h>
#include <starterclient.h>
#include <featmgr.h>

#ifdef RD_MULTIPLE_DRIVE
#include <DriveInfo.h>
#endif

#include "DRMRightsServer.h"
#include "DRMRightsDb.h"
#include "DRMDbSession.h"
#include "DRMEngineClientServer.h"
#include "DRMLog.h"
#include "DRMNotifier.h"
#include "DrmKeyStorage.h"
#include "drmnotifierserver.h"
#include "roapstorageserver.h"
#include "drmnotifierclientserver.h"
#include "drmroapclientserver.h"
#include "DRMXOma.h"
#include "DRMBackupObserver.h"
#include "DRMBackup.h"
#include "flogger.h"
#include "drmrightsparser.h"
#include "drmrights.h"
#include "drmhelpercommon.h"

#include  "wmdrmclientwrapper.h"



#ifdef __DRM_CLOCK
#include "DRMClockServer.h"
#include "drmclockclientserver.h"
#endif

#include <utf.h>
#include <DRMIndividualConstraintExtension.h>

/*
_LIT( KLogDir, "drm");
_LIT( KLogName, "backup.log");
*/

// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES 
// CONSTANTS
LOCAL_C const TUint KMaxHeapsize = 0x7A120;

_LIT8( KImsiId,"IMSI:");

// MACROS
#ifdef _DRM_TESTING
_LIT( KDateTimeFormat, "%F%Y%M%D%H%T%S%C" );
#endif

// LOCAL CONSTANTS AND MACROS
const TUint8 KMaxStartTries = 30;
const TInt KWaitingTime = 2000000; // 2 sec
_LIT( KRightsServerThread, "RightsServer" );

#ifdef RD_MULTIPLE_DRIVE

_LIT( KDbTempPath, "%c:\\system\\temp\\" );
_LIT( KIndividualConstraintExtensionDll, "%c:\\sys\\bin\\DRMIndividualConstraintExtension.dll" );
_LIT( KRightsDir, "%c:\\private\\101F51F2\\rdb\\" );
_LIT( KTimedReplayCacheFile, "%c:\\private\\101F51F2\\timererc.dat" );
_LIT( KPlainReplayCacheFile, "%c:\\private\\101F51F2\\plainrc.dat" );
#ifdef RD_DRM_METERING
_LIT( KMeteringDataBaseFile, "%c:\\private\\101F51F2\\meterdb.dat" );
#endif

#define USE_RO_IMPORT

#ifdef USE_RO_IMPORT
_LIT( KInternalImportDir, "%c:\\private\\101F51F2\\import\\" );
_LIT( KUserDiskImportDir, "%c:\\import\\" ); // usually embedded MMC
_LIT( KUserRemovableDiskImportDir, "%c:\\import\\" ); // usually external MMC
_LIT( KDrSuffix, ".dr" );
#endif

#else

_LIT( KRightsDir, "c:\\private\\101F51F2\\rdb\\" );
_LIT( KTimedReplayCacheFile, "c:\\private\\101F51F2\\timererc.dat" );
_LIT( KPlainReplayCacheFile, "c:\\private\\101F51F2\\plainrc.dat" );
#ifdef RD_DRM_METERING
_LIT( KMeteringDataBaseFile, "c:\\private\\101F51F2\\meterdb.dat" );
#endif

#define USE_RO_IMPORT

#ifdef USE_RO_IMPORT
_LIT( KInternalImportDir, "c:\\private\\101F51F2\\import\\" );
_LIT( KUserDiskImportDir, "e:\\import\\" );
_LIT( KDrSuffix, ".dr" );
#endif

#endif

_LIT(KWmDrmClientWrapperName, "wmdrmclientwrapper.dll");

// MODULE DATA STRUCTURES

NONSHARABLE_STRUCT( TUnloadModule )
    {
    RTelServer* iServer;
    const TDesC* iName;
    };

// LOCAL FUNCTION PROTOTYPES

LOCAL_C TInt Startup( void );
LOCAL_C void SignalClient();
LOCAL_C TInt StartDBServer( void );

#if defined( __WINS__ )
#else
#define DRM_USE_SERIALNUMBER_URI
#include <mmtsy_names.h>
#endif


#ifdef DRM_USE_SERIALNUMBER_URI
LOCAL_C void DoUnloadPhoneModule( TAny* aAny );
#endif

// #define USE_RO_IMPORT

// FORWARD DECLARATIONS

// ============================= LOCAL FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// Function Startup().
// This function starts the actual DRM Rights server after initializing
// the cleanup stack and active scheduler.
// Returns: TInt: Symbian OS error code.
// -----------------------------------------------------------------------------
//
LOCAL_C TInt Startup( void ) 
    {
    TInt error = KErrNone;
    CTrapCleanup* trap = CTrapCleanup::New();
    CActiveScheduler* scheduler = new CActiveScheduler();
    
    if ( trap && scheduler )
        {
        CActiveScheduler::Install( scheduler );
    
        error = StartDBServer();
        }
    else
        {
        error = KErrNoMemory;
        }

    delete scheduler; 
    scheduler = NULL;
    
    delete trap;
    trap = NULL;
    
    if ( error )
        {
        // Something went wrong. Release the client (if any).
        SignalClient();
        
        if ( error == KErrAlreadyExists )
            {
            error = KErrNone;
            }
        }
       
    return error;
    }

// -----------------------------------------------------------------------------
// Function SignalClient().
// Signal the waiting client (one of them if any exists).
// -----------------------------------------------------------------------------
//
void SignalClient( void )
    {
    RSemaphore semaphore;
    if ( !semaphore.OpenGlobal( DRMEngine::KDRMSemaphore ) )
        {
        semaphore.Signal();
        semaphore.Close();
        }
    }

// -----------------------------------------------------------------------------
// Function StartDBServer().
// This function starts the actual server under TRAP harness and starts
// waiting for connections. This function returns only if there has been
// errors during server startup or the server is stopped for some reason.
// 
// Returns: TInt: Symbian OS error code.
// -----------------------------------------------------------------------------
TInt StartDBServer( void ) 
    {
    TInt error = KErrNone;
    CDRMRightsServer* server = NULL;
    TUint8 count = 0;
    
    do
        {
        DRMLOG2( _L( "RightsServer.exe: StartDBServer: %d" ), error );
        
        ++count;
        
        TRAP( error, ( server = CDRMRightsServer::NewL() ) );
        
        if ( error ) 
            {
            User::After( TTimeIntervalMicroSeconds32(KWaitingTime) );
            }
        
        } while( error && ( count <= KMaxStartTries ) );
        
    if( error ) 
        {
        DRMLOG2( _L( "RightsServer.exe: CDRMRightsServer::NewL failed: %d " ), error );
        // Failed
        return error;
        }
    
    // Release the semaphore if necessary.
    SignalClient();
   
    // Start waiting for connections
    CActiveScheduler::Start();
    
    // Dying...
    // Delete CDRMRigntsServer
        
    DRMLOG( _L( "RightsServer.exe: DB server dying..." ) );

    delete server;
    
    return KErrNone;
    }

#ifdef DRM_USE_SERIALNUMBER_URI
// -----------------------------------------------------------------------------
// Function DoUnloadPhoneModule
// Unload phone module
// -----------------------------------------------------------------------------
//
void DoUnloadPhoneModule( TAny* aAny )
    {
    __ASSERT_DEBUG( aAny, User::Invariant() );
    TUnloadModule* module = ( TUnloadModule* ) aAny;
    module->iServer->UnloadPhoneModule( *( module->iName ) );
    }
#endif

#ifdef USE_RO_IMPORT
// -----------------------------------------------------------------------------
// PointerArrayResetDestroyAndClose
// Template method used to push RPointerArrays to the cleanup stack. Takes
// care of deleting all pointers in the array.
// -----------------------------------------------------------------------------
//
template<class S>
void PointerArrayResetDestroyAndClose(TAny* aPtr)
    {
    (reinterpret_cast<RPointerArray<S>*>(aPtr))->ResetAndDestroy();
    (reinterpret_cast<RPointerArray<S>*>(aPtr))->Close();
    }
#endif    

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

// -----------------------------------------------------------------------------
// CDRMRightsServer::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CDRMRightsServer* CDRMRightsServer::NewL()
    {
    CDRMRightsServer* self = new( ELeave ) CDRMRightsServer();
    
    CleanupStack::PushL( self );
    
    self->ConstructL();
    
    CleanupStack::Pop( self );
    
    return self;
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
CDRMRightsServer::~CDRMRightsServer() 
    {
    DRMLOG( _L( "CDRMRightsServer::~" ) );
    
    delete iIMEI; iIMEI = NULL;
    
    delete iIMSI; iIMSI = NULL;
    
    delete iDb; iDb = NULL;
    
    iClock.Close();
    iCache.Close();
    
    iMeteringDb.Close();
    
    iFs.Close();
    iActiveCountConstraints.ResetAndDestroy();
    iActiveCountConstraints.Close();
    
    delete iBackupObserver;
    delete iBackupHandler;    
    delete iActiveBackupClient;
    delete iDbWatcher;

#if 0    
    // Close and delete the shared data client
    if( iSharedDataClient ) 
        {
        iSharedDataClient->Close();
        delete iSharedDataClient;
        iSharedDataClient = NULL;
        }
#endif

    if( iNotifier )
        {
        delete iNotifier; iNotifier = NULL;
        }
        
    //An empty semaphore
    RSemaphore semaphore;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GetSecureTime
// Fetch the time from (secure) source.
// -----------------------------------------------------------------------------
//
TBool CDRMRightsServer::GetSecureTime( TTime& aTime ) const
    {
    DRMClock::ESecurityLevel secLevel = DRMClock::KInsecure;
	
	TInt timezone( 0 );
	
    iClock.GetSecureTime( aTime, timezone, secLevel );
	
    if( secLevel == DRMClock::KSecure )
        {
        DRMLOG( _L( "CDRMRightsServer::GetSecureTime: Time is secure\r\n" ) );
        return ETrue;		
        }	
        
    DRMLOG( _L( "CDRMRightsServer::GetSecureTime: Time is not secure\r\n" ) );    	

    return EFalse;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::Notifier
// Return a handle to DRM Notifier.
// -----------------------------------------------------------------------------
//
CDRMNotifier& CDRMRightsServer::Notifier()
    {
    return *iNotifier;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::Notifier
// Return a handle to DRM Notifier.
// -----------------------------------------------------------------------------
//
CDRMRightsDB& CDRMRightsServer::Database()
    {
    return *iDb;
    }

RFs& CDRMRightsServer::FileServerSession()
    {
    return iFs;
    }
    
    
RDRMReplayCache& CDRMRightsServer::ReplayCache()
    {
    return iCache;
    }


RDrmMeteringDb& CDRMRightsServer::MeteringDatabase()
    {
    return iMeteringDb;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::HandleNotifyL
// Forward the event to the database.
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::HandleNotifyL(const TUid /*aUid*/,
                                     const TDesC& /*aKey*/,
                                     const TDesC& /*aValue*/)  
    {   
    /* XXX Backup via Publish/Subscribe
    __ASSERT_DEBUG( iDb, User::Invariant() );
    TInt value = -1;
    TLex16 parser( aValue );

    if ( aUid == KSDUidSystem )
        {
        // Check if it's a backup / restore status event
        if( !aKey.Compare( KBackupRestoreStatus ) )
            {
            User::LeaveIfError( parser.Val( value ) );
            if( value == 3 ) // Complete
                {
                iDb->MergeDBL();
                }
            }
        // Check if it's a drm backup restore status event
        else if ( aUid == KSDUidSystem )
            {
            if( !aKey.Compare( KDRMBackupRestoreStatus ) )
                {
                User::LeaveIfError( parser.Val( value ) );

                if( value == 1 ) // PrepareForBackup
                    {
                    TRAPD( error, iDb->BackupDBL( KNullDesC, 
                                                  KNullDesC8 ) );
                    // Notify that it's done
                    User::LeaveIfError( iSharedDataClient->AssignToTemporaryFile(
                                        KSDUidSystem ) );
                    User::LeaveIfError( iSharedDataClient->SetInt( 
                                        KDRMBackupRestoreStatus, 0 ) );
                    iSharedDataClient->Flush();
                    }
                }
            }
        }
    */
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::RunErrorL
// From CActive. Complete the request and restart the scheduler.
// -----------------------------------------------------------------------------
//
TInt CDRMRightsServer::RunError( TInt aError ) 
    {
    DRMLOG2( _L( "CDRMRightsServer::RunError: %d" ), aError );

    // Inform the client.
    if ( !Message().IsNull() )
        {
        Message().Complete( aError );
        }
    
    // Restart the scheduler.
    ReStart();
    
    // Error handled.
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::NewSessionL
// Called when a client requires a new instance.
// -----------------------------------------------------------------------------
CSession2* CDRMRightsServer::NewSessionL( const TVersion& aVersion,
                                          const RMessage2& /*aMessage*/ ) const
    {
    DRMLOG( _L( "CDRMRightsServer::NewSessionL" ) );

    if ( ! User::QueryVersionSupported( TVersion( DRMEngine::KServerMajorVersion,
        DRMEngine::KServerMinorVersion,
        DRMEngine::KServerBuildVersion ), 
        aVersion ) ) 
        {
        // Sorry, no can do.
        User::Leave( KErrNotSupported );
        }

    DRMLOG( _L( "CDRMRightsServer::NewSessionL: Creating a new session" ) );

    return CDRMDbSession::NewL();
    }
// -----------------------------------------------------------------------------
// CDRMRightsServer::CDRMRightsServer
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CDRMRightsServer::CDRMRightsServer() : 
    CServer2( EPriorityStandard ),
    iIMEI( NULL ),
    iArmed( EFalse ),    
    iIMSI( NULL ),
    iGetImsi( ETrue )
    {
    // Nothing
    }
    
// -----------------------------------------------------------------------------
// CDRMRightsServer::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::ConstructL() 
    {
    DRMLOG( _L( "CDRMRightsServer::ConstructL" ) );

    TDRMKey key;
    RSemaphore semaphore;
    RProcess currentprocess;
    
    // Ignore errors
    User::RenameThread( KRightsServerThread );
    User::LeaveIfError( iFs.Connect() );
    
#ifndef RD_MULTIPLE_DRIVE
    
    // Ignore errors
    iFs.MkDirAll( KDRMDbTempPath );
    
#else //RD_MULTIPLE_DRIVE
    
    TFileName tempPath;
    TFileName tempPath2;
    TFileName tempRemovablePath;
    TInt driveNumber( -1 );
    TChar driveLetter;
    TChar driveLetterRemovable;
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );
	iFs.DriveToChar( driveNumber, driveLetter );
	
	tempPath.Format( KDbTempPath, (TUint)driveLetter );
    
    // Ignore errors
    iFs.MkDirAll( tempPath );
    
#endif
        
    DRMLOG( _L( "CDRMRightsServer::ConstructL: SharedDataClient" ) );

    // Create and instance of the shared data client
    // iSharedDataClient = new (ELeave) RSharedDataClient(this);

    // Connecting to the shared data server
    // User::LeaveIfError(iSharedDataClient->Connect());

    /* XXX Backup via Publish/Subscribe
    User::LeaveIfError(iSharedDataClient->NotifyChange(
        KSDUidSystem, &KBackupRestoreStatus ) );
    User::LeaveIfError(iSharedDataClient->NotifyChange(
        KSDUidSystem, &KDRMBackupRestoreStatus) );
    */  
      
      
    GetDbKeyL( key );
    
    
    DRMLOG( _L( "CDRMRightsServer::ConstructL: database" ) );

    GetIMEIL();
    
    // Create the imsi pointer array:
    iIMSI = CDRMPointerArray<HBufC8>::NewL();
    iIMSI->SetAutoCleanup(ETrue);
    
    GetIMSIL();
    
#ifndef RD_MULTIPLE_DRIVE
    
    iDb = CDRMRightsDB::NewL( iFs, KRightsDir, key, *iIMEI );
    
#else //RD_MULTIPLE_DRIVE
    
    tempPath.Format( KRightsDir, (TUint)driveLetter );
    
    iDb = CDRMRightsDB::NewL( iFs, tempPath, key, *iIMEI );
    
#endif
        
    key.FillZ();
        
    DRMLOG( _L( "CDRMRightsServer::ConstructL: DB started." ) );

    DRMLOG( _L( "CDRMRightsServer::ConstructL: Starting Notifier ." ) );
        
    User::LeaveIfError( semaphore.CreateGlobal( KDRMEngCommonSemaphore, 0 ) );
    CleanupClosePushL( semaphore );
    
    StartThreadL( DRMNotifier::KServerName, StartupNotifier, semaphore );
    DRMLOG( _L( "CDRMRightsServer::ConstructL: Notifier thread created." ) );
    
    StartThreadL( Roap::KServerName, StartupRoapStorage, semaphore );
    DRMLOG( _L( "CDRMRightsServer::ConstructL: ROAP thread created." ) );
    
#ifdef __DRM_CLOCK
    StartThreadL( DRMClock::KServerName, StartupClock, semaphore );
    DRMLOG( _L( "CDRMRightsServer::ConstructL: clock thread created." ) );
#endif
    
    CleanupStack::PopAndDestroy(); // semaphore
    
    iNotifier = CDRMNotifier::NewL();
    
    iCache.Set( iFs );

#ifndef RD_MULTIPLE_DRIVE
    
    iCache.InitL( KTimedReplayCacheFile, KPlainReplayCacheFile );

#ifdef RD_DRM_METERING               
    iMeteringDb.Set( iFs );
    iMeteringDb.InitL( KMeteringDataBaseFile );
#endif
    
#else //RD_MULTIPLE_DRIVE
    
    tempPath.Format( KTimedReplayCacheFile, (TUint)driveLetter );
    tempPath2.Format( KPlainReplayCacheFile, (TUint)driveLetter );
    
    iCache.InitL( tempPath, tempPath2 );
    
#ifdef RD_DRM_METERING               
    
    tempPath.Format( KMeteringDataBaseFile, (TUint)driveLetter );
    
    iMeteringDb.Set( iFs );
    iMeteringDb.InitL( tempPath );

#endif
    
#endif
    
    User::LeaveIfError( iClock.Connect() );

    // xoma header list creation
    iXOmaHeaders = new (ELeave) RPointerArray< CDRMXOma >();
    
    // p/s
    iBackupObserver = CDRMBackupObserver::NewL( *(const_cast<CDRMRightsServer*>(this)));
    iBackupObserver->Start();
    
#ifdef USE_RO_IMPORT
    // Import any OMA DRM 1.0 RO in the import directory, ignore all errors (except
    // when checking the default removable mass storage)
    TInt r = KErrNone;
    
#ifndef RD_MULTIPLE_DRIVE
    
    TRAP( r, ImportRightsObjectsL( KInternalImportDir ) );
    TRAP( r, ImportRightsObjectsL( KUserDiskImportDir ) );
    
#else //RD_MULTIPLE_DRIVE
    
    tempPath.Format( KInternalImportDir, (TUint)driveLetter );
    
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultMassStorage, driveNumber );
	iFs.DriveToChar( driveNumber, driveLetter );
    
	// Default mass storage is usually eMMC
    tempPath2.Format( KUserDiskImportDir, (TUint)driveLetter );
    
    // Find out if a removable mass storage also exists
    r = DriveInfo::GetDefaultDrive( DriveInfo::EDefaultRemovableMassStorage, driveNumber );
    iFs.DriveToChar( driveNumber, driveLetterRemovable );
    
    // Import is not needed from the default removable mass storage drive if the drive 
    // letter of the default mass storage and the default removable mass storage are 
    // the same or the removable mass storage is not supported
    if ( ( driveLetter != driveLetterRemovable ) && ( r == KErrNone ) ) 
        {
        tempRemovablePath.Format( KUserRemovableDiskImportDir, (TUint)driveLetterRemovable );
        TRAP( r, ImportRightsObjectsL( tempRemovablePath ) );
        }
    
    TRAP( r, ImportRightsObjectsL( tempPath ) );
    TRAP( r, ImportRightsObjectsL( tempPath2 ) );
    
#endif
    
#endif

    // Add the server to the scheduler.
    StartL( DRMEngine::KServerName );

    // Start watching our RDB
    iDbWatcher = CDbWatcher::NewL( *this );
    iDbWatcher->StartWatching();
    
    // Start watching the helper server
    iProcWatcher = CProcWatcher::NewL( *this, _L( "*DcfRepSrv*" ), _L( "DcfRepSrv" ) );
    iProcWatcher->StartWatching();
    
    // Ready to watch
    iArmed = ETrue;

    __UHEAP_MARK;
    TRAP( r, FeatureManager::InitializeLibL() );
    if( !r && FeatureManager::FeatureSupported( KFeatureIdWindowsMediaDrm ) ) 
        {
        static const TInt KGateOrdinal = 1;
        RLibrary library;
        r = library.Load( KWmDrmClientWrapperName );
        if( !r )
            {
            CWmDrmClientWrapper* wrapper = NULL;
            TLibraryFunction function = library.Lookup( KGateOrdinal );
            if( function != NULL )
                {
                __UHEAP_MARK;
                TRAP( r, wrapper = reinterpret_cast<CWmDrmClientWrapper*>( function() ) );
                if( !r )
                    {
                    r = wrapper->Connect();
                    }
                delete wrapper;
                __UHEAP_MARKEND;
                }
            }
        library.Close();    
        }
    FeatureManager::UnInitializeLib();
    __UHEAP_MARKEND;  
    }
 
// -----------------------------------------------------------------------------   
// CDRMRightsServer::StartThreadL
// Start a new thread.
// -----------------------------------------------------------------------------    
void CDRMRightsServer::StartThreadL( const TDesC& aThreadName,
                                     TThreadFunction aFunc,
                                     RSemaphore& aSemaphore )
    {
    RThread thread;
    
    User::LeaveIfError( 
          thread.Create( aThreadName,
                         aFunc, 
                         KDefaultStackSize,
                         KMinHeapSize, 
                         KMaxHeapsize,
                         NULL ) );
    
    thread.Resume();
    
    aSemaphore.Wait();
    
    thread.Close();
    }
    
// -----------------------------------------------------------------------------
// CDRMRightsServer::GetDbKeyL
// Fetches the rights database key from Wallet or uses a constant 
// key if Wallet is not supported.
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::GetDbKeyL( TDRMKey& aKey  ) 
    {
    TInt r = KErrNone;
    
    DRMLOG( _L( "CDRMRightsServer::GetDbKey" ) );
    MDrmKeyStorage* storage = DrmKeyStorageNewL();
    TRAP( r, storage->GetDeviceSpecificKeyL( aKey ) );
    delete storage;
    User::LeaveIfError( r );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GenerateKeyL
// Generates the actual key based on the given key seed.
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::GenerateKeyL( HBufC*& aKeySeed, 
                                    TDRMKey& aKey ) const
    {
    __ASSERT_ALWAYS( aKeySeed->Size() >= KDRMKeyLength, 
        User::Leave( KErrUnderflow ) );
    
    TPtrC8 key( reinterpret_cast< TUint8* >( const_cast< TUint16* >( aKeySeed->Ptr() ) ),
                KDRMKeyLength );
    
    aKey = key;
    }


// -----------------------------------------------------------------------------
// CDRMRightsServer::XOmaHeaders()
// return the pointer of the X-Oma headers list 
// -----------------------------------------------------------------------------
//
RPointerArray< CDRMXOma >& CDRMRightsServer::XOmaHeaders( void )
	{
	return *iXOmaHeaders;
	}



// -----------------------------------------------------------------------------
// CDRMRightsServer::GetIMEIL
// -----------------------------------------------------------------------------
//
const TDesC& CDRMRightsServer::GetIMEIL()
    {
    if ( iIMEI )
        {
        return *iIMEI;
        }
    
#ifdef DRM_USE_SERIALNUMBER_URI
    TInt error( KErrNone );
    TInt count( 0 );
    TInt count2( 0 );
    TUint32 caps( 0 );
    TBool found (EFalse);
    
    RTelServer etelServer;
    RMobilePhone phone;
    
    TUint KMaxImeiTries = 5;
    
    for ( TUint8 i = 0; i < KMaxImeiTries; ++i )
        {
        error = etelServer.Connect();
        if ( error )
            {
            User::After( TTimeIntervalMicroSeconds32( KWaitingTime ) );
            }
        else 
            {
            break;
            }
        }
    
    User::LeaveIfError( error );
    CleanupClosePushL( etelServer );
    
    User::LeaveIfError( etelServer.LoadPhoneModule( KMmTsyModuleName ) );  
    
    TUnloadModule unload;
    unload.iServer = &etelServer;
    unload.iName = &KMmTsyModuleName;
    
    TCleanupItem item( DoUnloadPhoneModule, &unload );
    CleanupStack::PushL( item );
    User::LeaveIfError( etelServer.EnumeratePhones( count ) );
        
    for ( count2 = 0; count2 < count && !found; ++count2 )
        {
        RTelServer::TPhoneInfo phoneInfo;
        User::LeaveIfError( etelServer.GetTsyName( count2, phoneInfo.iName ) );
        
        if ( phoneInfo.iName.CompareF(KMmTsyModuleName()) == 0 )   
           {
            User::LeaveIfError( etelServer.GetPhoneInfo( count2, phoneInfo ) );
            User::LeaveIfError( phone.Open( etelServer, phoneInfo.iName ) );
            CleanupClosePushL( phone );
            found = ETrue;
            }
        }

    if ( !found )
        {
        // Not found.
        User::Leave( KErrNotFound );
        }
   
    User::LeaveIfError( phone.GetIdentityCaps( caps ) );
    if ( caps & RMobilePhone::KCapsGetSerialNumber )
        {
        RMobilePhone::TMobilePhoneIdentityV1 id;
        TRequestStatus status;
    
        phone.GetPhoneId( status, id );
        
        User::WaitForRequest( status );
        
        User::LeaveIfError( status.Int() );
        
        iIMEI = id.iSerialNumber.AllocL();
        
        CleanupStack::PopAndDestroy( 3 ); // phone, item, etelServer
        
        HBufC8* buf = HBufC8::NewL( iIMEI->Size() );
        TPtr8 ptr( buf->Des() );
        ptr.Copy( *iIMEI );
        
        DRMLOG(_L("IMEI:"));
        DRMLOGHEX(ptr);
        delete buf;
    
        return *iIMEI;
        }
    
    User::Leave( KErrNotFound );
    
    // Never happens...
    return *iIMEI; 
    
#else
    _LIT( KDefaultSerialNumber, "123456789123456789" );
    iIMEI = KDefaultSerialNumber().AllocL();
        
    return *iIMEI;
#endif
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GetIMSIL
// -----------------------------------------------------------------------------
//
const CDRMPointerArray<HBufC8>& CDRMRightsServer::GetIMSIL()
    {
    
    if ( !iGetImsi )
        {
        return *iIMSI;
        }

#ifndef __WINS__   
    TInt error( KErrNone );
    TInt count( 0 );
    TInt count2( 0 );
    TUint32 caps( 0 );
    TBool found (EFalse);
    HBufC8* imsi = NULL;
    HBufC8* imsiNumber = NULL;
    
    RTelServer etelServer;
    RMobilePhone phone;
    
    TUint KMaxImeiTries = 5;    
    for ( TUint8 i = 0; i < KMaxImeiTries; ++i )
        {
        error = etelServer.Connect();
        if ( error )
            {
            User::After( TTimeIntervalMicroSeconds32( KWaitingTime ) );
            }
        else 
            {
            break;
            }
        }
    
    User::LeaveIfError( error );
    CleanupClosePushL( etelServer );     
    User::LeaveIfError( etelServer.LoadPhoneModule( KMmTsyModuleName ) );  
    
    TUnloadModule unload;
    unload.iServer = &etelServer;
    unload.iName = &KMmTsyModuleName;
    
    TCleanupItem item( DoUnloadPhoneModule, &unload );
    CleanupStack::PushL( item );
    
    User::LeaveIfError( etelServer.EnumeratePhones( count ) );
        
    for ( count2 = 0; count2 < count && !found; ++count2 )
        {
        RTelServer::TPhoneInfo phoneInfo;
        User::LeaveIfError( etelServer.GetTsyName( count2, phoneInfo.iName ) );
        
        if ( phoneInfo.iName.CompareF(KMmTsyModuleName()) == 0 )   
           {
            User::LeaveIfError( etelServer.GetPhoneInfo( count2, phoneInfo ) );
            User::LeaveIfError( phone.Open( etelServer, phoneInfo.iName ) );
            CleanupClosePushL( phone );
            found = ETrue;
            }
        }

    if ( !found )
        {
        // Not found.
        User::Leave( KErrNotFound );
        }
   
 
    User::LeaveIfError( phone.GetIdentityCaps( caps ) );

    if( caps & RMobilePhone::KCapsGetSubscriberId )
        {
        RMobilePhone::TMobilePhoneSubscriberId imsiId;        
        TRequestStatus status;
    
        phone.GetSubscriberId( status, imsiId );
        
        User::WaitForRequest( status );
        
        if( ! status.Int() )
            {             
            imsi = HBufC8::NewMaxLC( imsiId.Length() + KImsiId().Size() );
            TPtr8 imsiPtr(const_cast<TUint8*>(imsi->Ptr()), 0, imsi->Size());
      
            imsiNumber = CnvUtfConverter::ConvertFromUnicodeToUtf8L( imsiId );
            CleanupStack::PushL( imsiNumber );
            
            imsiPtr.Copy( KImsiId() );
            imsiPtr.Append( *imsiNumber );
            CleanupStack::PopAndDestroy(); // imsiNumber
            }
        else
            {            
            imsi = NULL;
            }
        }
    else
        {         
        imsi = NULL;
        } 
    
    
    // Clean up whatever is in there
    iIMSI->ResetAndDestroy();
    
    if( imsi ) 
        { 
        // if we got it we wont try again             
        iIMSI->AppendL( imsi );
        CleanupStack::Pop(); // imsi
        iGetImsi = EFalse;            
        }

    // Check for possible extra IMSI individual constraints
    AppendExtendedIndividualConstraintsL(&phone);
    
    CleanupStack::PopAndDestroy(); // phone
    CleanupStack::PopAndDestroy(); // cleanup item
    CleanupStack::PopAndDestroy(); // etel server

    return *iIMSI; 
    
#else
    HBufC8* imsi = NULL;
    
    if( iGetImsi ) 
        {
        iGetImsi = EFalse;
        _LIT8( KDefaultSerialNumber, "IMSI:123456789123456789" );
        imsi = KDefaultSerialNumber().AllocLC();
        iIMSI->AppendL( imsi );
        CleanupStack::Pop();        
        AppendExtendedIndividualConstraintsL();
        }

        
    return *iIMSI;
#endif // __WINS__
    }

// -----------------------------------------------------------------------------   
// CDRMRightsServer::AppendExtendedIndividualConstraintsL
// If the extension DLL exists it is loaded and used to obtain additional
// valid individual constraints
// -----------------------------------------------------------------------------    
void CDRMRightsServer::AppendExtendedIndividualConstraintsL(RMobilePhone* aMobilePhone)
    {    	    	
    // Load the externsion DLL
    RLibrary lib;
    
#ifndef RD_MULTIPLE_DRIVE
    
    if (lib.LoadRomLibrary(KDRMIndividualConstraintExtensionDll,KNullDesC)==KErrNone)
    
#else //RD_MULTIPLE_DRIVE
    
    TInt driveNumber( -1 );
    TChar driveLetter;
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultRom, driveNumber );
	iFs.DriveToChar( driveNumber, driveLetter );
	
	TFileName individualConstraindExtensionDll;
	individualConstraindExtensionDll.Format( 
	                    KIndividualConstraintExtensionDll, (TUint)driveLetter );
    
    if ( lib.LoadRomLibrary( individualConstraindExtensionDll, KNullDesC ) == KErrNone )
    
#endif
    
    	{
        CleanupClosePushL(lib);

        // Get first exported ordinal - factory method returning 
        // MDRMIndividualConstraintExtension*
        TLibraryFunction factory = lib.Lookup(1); 

        if (factory)
            {
            // Instantiate object
            MDRMIndividualConstraintExtension* extendedConstraints = 
                reinterpret_cast<MDRMIndividualConstraintExtension*>(factory());

            if (extendedConstraints)
                {
			    CleanupStack::PushL(TCleanupItem(Release,extendedConstraints));
                extendedConstraints->AppendConstraintsL(*iIMSI,aMobilePhone);
			    CleanupStack::PopAndDestroy(extendedConstraints); //calls Release
                }
            }

        // unload library
        CleanupStack::PopAndDestroy(&lib); //close
        }
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::Release
// -----------------------------------------------------------------------------
void CDRMRightsServer::Release(TAny* aIndividualConstraintExtension)
    {
    MDRMIndividualConstraintExtension* extendedConstraints = 
    	reinterpret_cast<MDRMIndividualConstraintExtension*>(aIndividualConstraintExtension);
    extendedConstraints->Release(); //free resources
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::HandleBackupEventL
// Handle Backup Events
// -----------------------------------------------------------------------------
//

void CDRMRightsServer::HandleBackupEventL( TInt aBackupEvent )
    {
	//RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::BackupCalled\n\r"));    

    //conn::TBURPartType eventType;
    //conn::TBackupIncType incType;
    TDriveList aDriveList;
    
    //RFileLogger::WriteFormat(KLogDir, KLogName, EFileLoggingModeAppend, _L8("backupevent: %d"), aBackupEvent);              
    
    // If there is no operation going or state is normal
    // Delete the client and handler

    if( aBackupEvent == conn::EBURUnset ||
        aBackupEvent & conn::EBURNormal )
        {
        /*
        if( aBackupEvent == conn::EBURUnset )
            {
            	        RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Unset\n\r"));                
            }
        else 
            {
	        RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Normal\n\r"));                
            } 
        */                 
        if( iActiveBackupClient )
            {
            delete iActiveBackupClient;
            iActiveBackupClient = NULL;    
            }
        
        if( iBackupHandler )
            {
            delete iBackupHandler;
            iBackupHandler = NULL;    
            }
        }  
    else if( aBackupEvent & conn::EBURBackupFull ||
             aBackupEvent & conn::EBURRestoreFull )
        {
	    //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Full\n\r"));         
        // ab handler
        iBackupHandler = CDRMBackup::NewL( iDb, iFs );
    
        // ab client
        iActiveBackupClient = conn::CActiveBackupClient::NewL( iBackupHandler );
        
        // Confirm that we have done everything if there even was anything to do
	    //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Confirm F \n\r"));         
        iActiveBackupClient->ConfirmReadyForBURL( KErrNone );        
        }
    else if( aBackupEvent & conn::EBURBackupPartial ||
             aBackupEvent & conn::EBURRestorePartial )
        {
	    //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Partial\n\r"));         
        // ab handler
        iBackupHandler = CDRMBackup::NewL( iDb, iFs );
    
        // ab client
        iActiveBackupClient = conn::CActiveBackupClient::NewL( iBackupHandler );                

        if( !iActiveBackupClient->DoesPartialBURAffectMeL() ) 
            {
	        //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::NotMe\n\r"));             
            delete iActiveBackupClient;
            iActiveBackupClient = NULL;    

            delete iBackupHandler;
            iBackupHandler = NULL;    
            }
        else
            {
	        //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Confirm P \n\r"));            
            // Confirm that we have done everything if there even was anything to do
            iActiveBackupClient->ConfirmReadyForBURL( KErrNone );
	        //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Confirm P Done \n\r"));                             
            }    
        }
    else 
        {
	    //RFileLogger::Write(KLogDir, KLogName, EFileLoggingModeAppend, _L8("Handle::Argument\n\r"));         
        // Unknown operation
        User::Leave(KErrArgument);    
        }
    };  

// -----------------------------------------------------------------------------
// CDRMRightsServer::WatchedObjectChangedL
// Handle Backup Events
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::WatchedObjectChangedL( const TDesC& aObject )
    {
    DRMLOG( _L( "CDRMRightsServer::WatchedObjectChangedL ->" ) );
    DRMLOG( aObject );
    
    if ( aObject.Left( KDirIdentifier().Length() ) == KDirIdentifier &&
         !iDb->Updating() && iArmed )
        {
#ifdef _DEBUG
        DRMLOG( _L( "RDB modified by outside party (DEBUG mode, not deleting the DB)" ) );
#else
        DRMLOG( _L( "RDB modified by outside party, deleting the DB" ) );
        iDb->MarkAsCorrupted();
        RStarterSession starter;
        User::LeaveIfError( starter.Connect() );
        starter.Reset( RStarterSession::EDRMReset );
        starter.Close();
#endif        
        }
    else if ( aObject.Left( KProcIdentifier().Length() ) == KProcIdentifier && iArmed )
        {
#ifdef _DEBUG
        DRMLOG( _L( "Peer process killed (DEBUG mode, not rebooting)" ) );
#else
        DRMLOG( _L( "Peer process killed, rebooting" ) );
        RStarterSession starter;
        User::LeaveIfError( starter.Connect() );
        starter.Reset( RStarterSession::EDRMReset );
        starter.Close();
#endif
        }
    
    DRMLOG( _L( "CDRMRightsServer::WatchedObjectChangedL <-" ) );
    }
    
// -----------------------------------------------------------------------------
// CDRMRightsServer::HasActiveCountConstraint
// Check ID for active count constraint
// -----------------------------------------------------------------------------
//
TBool CDRMRightsServer::HasActiveCountConstraint( const TDesC8& aContentId )
    {
    TInt i;
    TBool r = EFalse;
    
    for ( i = 0; r == EFalse && i < iActiveCountConstraints.Count(); i++ )
        {
        if ( iActiveCountConstraints[i]->CompareF( aContentId ) == 0 )
            {
            r = ETrue;
            }
        }
    return r;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::RemoveActiveCountConstraint
// Remove ID from count constraint list
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::RemoveActiveCountConstraint( const TDesC8& aContentId )
    {
    TInt i;
    TInt r = KErrNotFound;
    HBufC8* id = NULL;
    
    for ( i = 0; r == KErrNotFound && i < iActiveCountConstraints.Count(); i++ )
        {
        if ( iActiveCountConstraints[i]->CompareF( aContentId ) == 0 )
            {
            r = i;
            }
        }
    if ( r != KErrNotFound )
        {
        id = iActiveCountConstraints[r];	
        iActiveCountConstraints.Remove( r );
        delete id;
        id = NULL;
        }
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::AddActiveCountConstraint
// Add ID to count constraint list
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::AddActiveCountConstraintL( const TDesC8& aContentId )
    {
    if ( !HasActiveCountConstraint( aContentId ) )
        {
        iActiveCountConstraints.AppendL( aContentId.AllocL() );
        }
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::StopWatchingL
// Delete the watchers
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::StopWatchingL()
    {
    iArmed = EFalse;
    }

#ifdef USE_RO_IMPORT
// -----------------------------------------------------------------------------
// CDRMRightsServer::ImportRightsObjectsL
// Open the import directory and add all ROs that can be found there. ROs file
// names must end with .dr. Only OMA DRM 1.0 ROs in XML format are supported for
// security reasons
// -----------------------------------------------------------------------------
//
void CDRMRightsServer::ImportRightsObjectsL( const TDesC& aImportDir )
    {
    CDrmRightsParser* p;
    HBufC8* d = NULL;
    HBufC8* k = NULL;
    RFs fs;
    RFile file;
    TInt size;
    RPointerArray<CDRMRights> rights;
    CDir* dir;
    TFileName name;
    TPtr8 ptr( NULL, 0 );
    TInt i;
    TInt r = KErrNone;
    TCleanupItem listCleanup(PointerArrayResetDestroyAndClose<CDRMRights>,
        &rights);
    TDRMUniqueID id;
    TTime time;
    
    DRMLOG( _L( "CDRMRightsServer::ImportRightsObjectsL" ) );
    DRMLOG( aImportDir );
    __UHEAP_MARK;
    GetSecureTime( time );
    p = CDrmRightsParser::NewL();
    CleanupStack::PushL( p );
    User::LeaveIfError( iFs.GetDir( aImportDir, KEntryAttNormal,
        ESortNone, dir ) );
    CleanupStack::PushL( dir );
    for (i = 0; i < dir->Count(); i++)
        {
        name.Copy( aImportDir );
        name.Append( (*dir)[i].iName );
        if ( ( name.Length() > 3 && name.Right(3).CompareF( KDrSuffix ) == 0 ) )
            {
            User::LeaveIfError( file.Open( iFs, name, EFileRead ) );
            CleanupClosePushL( file );
            User::LeaveIfError( file.Size( size ) );
            d = HBufC8::NewLC( size );
            ptr.Set( d->Des() );
            User::LeaveIfError( file.Read( ptr ) );
            p->ParseL( ptr, rights );
            if ( rights.Count() > 0 )
                {
                k = NULL;
                CleanupStack::PushL( listCleanup );
                CDRMPermission& permission = rights[0]->GetPermission();
                CDRMAsset& asset = rights[0]->GetAsset();
                
                // Add RO only if no rights are available at all for this content
                TRAP( r, k = iDb->GetDecryptionKeyL( *asset.iUid ) );
                if (k == NULL )
                    {
                    iDb->AddDBEntryL( *asset.iUid, permission, asset.iKey, id );
                    }
                else
                    {
                    delete k;
                    }
                CleanupStack::PopAndDestroy(); // listCleanup
                }
            CleanupStack::PopAndDestroy( 2 ); // d, file
            iFs.Delete( name );
            }
        }
    CleanupStack::PopAndDestroy( 2 ); // dir, p
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMRightsServer::ImportRightsObjectsL done" ) );
    }
#endif    
    
// ========================== OTHER EXPORTED FUNCTIONS =========================


TInt E32Main() 
    {
    return Startup(); 
    }


//  End of File