omadrm/drmengine/server/src/DRMRightsServer.cpp
changeset 0 95b198f216e5
child 18 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/server/src/DRMRightsServer.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,1437 @@
+/*
+* 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