omadrm/drmengine/server/src/DRMDbSession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 15:14:55 +0300
changeset 23 493788a4a8a4
parent 0 95b198f216e5
child 48 c68061d56109
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* Copyright (c) 2003-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class handles all client requests.
*
*/


// INCLUDE FILES
#include <s32file.h>
#include <f32file.h>
#include <symmetric.h>
#include <rijndael.h>
#include <caf/caf.h>
#include <x509keys.h>
#include <asn1dec.h>
#include <DcfRep.h>

#include <e32math.h>
#include <utf.h>

#include <sysutil.h>    // Disk space checking

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

#include "Oma2Agent.h"
#include "DrmPermission.h"
#include "DRMDbSession.h"
#include "DRMEngineClientServer.h"
#include "DRMRightsServer.h"
#include "RoapStorageClient.h"
#include "OmaCrypto.h"
#include "CmlaCrypto.h"
#include "DrmKeyStorage.h"
#include "drmrightsdb.h"
#include "drmparentstorage.h"
#include "DRMDomainContext.h"
#include "DRMRIContext.h"
#include "drmenginetypedefs.h"
#include "DRMXOma.h"

#include "DRMNotifier.h"
#include "DRMEventAddRemove.h"
#include "DRMEventModify.h"
#include "DRMRightsCleaner.h"
#include "DRMActiveOperation.h"
#include "drmconsume.h"
#include "drmlog.h"
#include "DRMPointerArray.h"
#include "Base64.h"

#ifdef RD_DRM_METERING
#include "drmmeteringdbdata.h"
#endif

// NAMESPACES
using namespace DRMEngine;

// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS

// MACROS
#define REPLAYCACHE reinterpret_cast< CDRMRightsServer* >\
    (const_cast<CServer2*>(Server()))->ReplayCache()
#define DRMDB ( ( CDRMRightsServer* )( Server() ) )->Database()
#ifdef RD_DRM_METERING
#define METERINGDB reinterpret_cast< CDRMRightsServer* >\
    (const_cast<CServer2*>(Server()))->MeteringDatabase()
#endif
#define RFSSESSION ( ( CDRMRightsServer* )( Server() ) )->FileServerSession()
#define DRMNOTIFIER ( ( CDRMRightsServer* )( Server() ) )->Notifier()
#define XOMAHEADER ( ( CDRMRightsServer* )( Server() ) )->XOmaHeaders()
#define IMEI ( ( CDRMRightsServer* )( Server() ) )->GetIMEIL()
#define IMSI ( ( CDRMRightsServer* )( Server() ) )->GetIMSIL()
#define SERVER reinterpret_cast< CDRMRightsServer* >\
    (const_cast<CServer2*>(Server()))

#define IPCREAD0L( a ) aMessage.ReadL( 0, a )
#define IPCREAD1L( a ) aMessage.ReadL( 1, a )
#define IPCREAD2L( a ) aMessage.ReadL( 2, a )
#define IPCREAD3L( a ) aMessage.ReadL( 3, a )
#define IPCWRITE0L( a ) aMessage.WriteL( 0, a )
#define IPCWRITE1L( a ) aMessage.WriteL( 1, a )
#define IPCWRITE2L( a ) aMessage.WriteL( 2, a )
#define IPCWRITE3L( a ) aMessage.WriteL( 3, a )
#define IPCGETDESLEN0 aMessage.GetDesLength( 0 )
#define IPCGETDESLEN1 aMessage.GetDesLength( 1 )
#define IPCGETDESLEN2 aMessage.GetDesLength( 2 )
#define IPCGETDESLEN3 aMessage.GetDesLength( 3 )
#define IPCGETDESMAXLEN0 aMessage.GetDesMaxLength( 0 )
#define IPCGETDESMAXLEN1 aMessage.GetDesMaxLength( 1 )
#define IPCGETDESMAXLEN2 aMessage.GetDesMaxLength( 2 )
#define IPCGETDESMAXLEN3 aMessage.GetDesMaxLength( 3 )

// LOCAL CONSTANTS AND MACROS

#ifdef RD_MULTIPLE_DRIVE

_LIT( KDbTempPath, "%c:\\system\\temp\\" );
_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

#else

_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

#endif


const TInt KMicrosecondsToSecond = 1000000;
_LIT8( KFLPrefix, "flk" );
_LIT8( KFLLongPrefix, "flk:flk" );

_LIT8( KFLSuffix, "@localhost" );

// These need to be updated if the DRM Filter / Oma1DcfCreator URI's change
// IMPORTANT IMPORTANT IMPORTANT
_LIT8( KDCMUri, "ldf:31415926535@localhost");
_LIT8( KLDFUri, "flk:flkS60_3_0_Hutchinson_2005");

_LIT8(KTimeStamp, "timeStamp");
#ifdef RD_DRM_METERING
_LIT8(KMeteringDelimiter, ":");
_LIT8(KCRLF, "\r\n" );
#endif

LOCAL_C const TUint8 KFLPrefixLength = 3;
const TUint32 KTrustedShutdownClient = 0x10205CB5;
const TUint32 KAppInstSrv = 0x101F875A;


const TInt KSanityDataLengthLow = 0;
const TInt KSanityDataLengthHigh = 32768;

// MODULE DATA STRUCTURES
NONSHARABLE_STRUCT( TDeleteFile )
    {
    RFs* iFs;
    TFileName* iFileName;
    };

// ============================ auto_handde helper class =======================
//Auto handle for easening handle release on exceptional exit situations
template<class T> class auto_handle
    {
public:

    auto_handle() {}
    auto_handle(T aHandle) : iHandle( aHandle ) {}
    auto_handle( auto_handle<T>& aHandle) : iHandle( aHandle.release() ) {}
    ~auto_handle() { iHandle.Close(); }
    const T& operator()() const { return iHandle; }
    T& operator()() { return iHandle; }
    T get() const { return iHandle; }
    T release() { T temp = iHandle; iHandle = 0; return temp; }

private:
    T iHandle;
    };

// DATA TYPES
// LOCAL FUNCTION PROTOTYPES
LOCAL_C void DeleteFile( TAny* aHandle );
LOCAL_C void DeleteObject( TAny* aObject );
LOCAL_C TTime EndTime( const TTime& aTime1, const TTime& aTime2 );

// FORWARD DECLARATIONS
LOCAL_C void ModifyRightsObjectByTimeL( CDRMPermission* aRights,
                                        TTimeIntervalMicroSeconds& aChange,
                                        TBool aModifyInsertionTime );
LOCAL_C void ModifyTimesInListL( CDRMPermissionList* aList,
                                 TTimeIntervalMicroSeconds& aChange,
                                 TBool aModifyInsertionTime );

LOCAL_C void ModifyConstraintByTime( CDRMConstraint* aConstraint,
                                     TTimeIntervalMicroSeconds& aChange );

LOCAL_C TPtrC8 ExtractElement( const TDesC8& aRights, const TDesC8& aElement,
                               TInt& aOffset );

LOCAL_C TTime Iso8601ToTime( TDesC8& aTimeString );

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

// -----------------------------------------------------------------------------
// SanitizeL
// Performs a sanity check on length parameters
// -----------------------------------------------------------------------------
//
LOCAL_C void SanitizeL( TInt aParam )
    {
    if( aParam <= KSanityDataLengthLow || aParam > KSanityDataLengthHigh )
        {
        User::Leave(KErrArgument);
        }
    }


LOCAL_C void ModifyTimesInListL( CDRMPermissionList* aList,
    TTimeIntervalMicroSeconds& aChange,
    TBool aModifyInsertionTime )
    {
    TInt i = 0;

    // Go through the whole list and run the modification for all objects
    for( i = 0; i < aList->Count(); i++ )
        {
        // Call modification for each rights object in the list
        ModifyRightsObjectByTimeL( (*aList)[i], aChange, aModifyInsertionTime );
        }
    };

LOCAL_C void ModifyRightsObjectByTimeL( CDRMPermission* aRights,
    TTimeIntervalMicroSeconds& aChange,
    TBool aModifyInsertionTime )
    {

    // If original insertion time exists and we want to change it, change it
    if ( aModifyInsertionTime && aRights->iOriginalInsertTime != Time::NullTTime() )
        {
        aRights->iOriginalInsertTime += aChange;
        }

    if ( aRights->iAvailableRights & ERightsTopLevel )
        {
        ModifyConstraintByTime( aRights->iTopLevel, aChange );
        }

    // If play rights are available, check if they need to be changed
    if ( aRights->iAvailableRights & ERightsPlay )
        {
        ModifyConstraintByTime( aRights->iPlay, aChange );
        }

    // If display rights are available, check if they need to be changed
    if ( aRights->iAvailableRights & ERightsDisplay )
        {
        ModifyConstraintByTime( aRights->iDisplay, aChange );
        }

    // If execute rights are available, check if they need to be changed
    if ( aRights->iAvailableRights & ERightsExecute )
        {
        ModifyConstraintByTime( aRights->iExecute, aChange );
        }

    // If print rights are available, check if they need to be changed
    if ( aRights->iAvailableRights & ERightsPrint )
        {
        ModifyConstraintByTime( aRights->iPrint, aChange );
        }

    };

LOCAL_C void ModifyConstraintByTime(
    CDRMConstraint* aConstraint,
    TTimeIntervalMicroSeconds& aChange )
    {
    // if start time exists, modify it
    if ( aConstraint->iActiveConstraints & EConstraintStartTime )
        {
        aConstraint->iStartTime += aChange;
        }

    // if end time exists, modify it
    if ( aConstraint->iActiveConstraints & EConstraintEndTime )
        {
        aConstraint->iEndTime += aChange;
        }

    // if activated interval exists, modify it
    if ( aConstraint->iActiveConstraints & EConstraintInterval &&
         aConstraint->iIntervalStart != Time::NullTTime() )
        {
        aConstraint->iIntervalStart += aChange;
        }
    };

LOCAL_C TPtrC8 ExtractElement( const TDesC8& aRights,
                               const TDesC8& aElement,
                               TInt& aOffset )
    {
    DRMLOG( _L("CDRMDbSession::ExtractElement") );

    TPtrC8 temp( KNullDesC8 );
    TInt startPos = ( 0 );
    TInt endPos = ( 0 );
    TInt ret( 0 );
    TInt startLength ( 0 );

    auto_handle< RBuf8 > tagToBeFound;
    // Must be nonleaving since this function is nonleaving
    ret = tagToBeFound().Create( aElement.Length() + 3 ); // max "</" aElement ">"
    if ( ret != KErrNone )
        {
        aOffset = -1;
        return KNullDesC8();
        }

    // First we try to find the start tag (as localname)
    tagToBeFound().SetLength( 0 );
    tagToBeFound().AppendFormat( _L8( "<%S" ), &aElement );

    temp.Set( aRights.Mid( aOffset ) );

    startPos = temp.Find( tagToBeFound() );

    startLength = tagToBeFound().Length();
    startPos += aOffset;
    temp.Set( aRights.Mid( startPos + startLength ) );

    // Now find the end of the start tag
    tagToBeFound().SetLength( 0 );
    tagToBeFound().Append( _L8( ">" ) ); // '>' as last

    // Define the starting point of the data after the start tag
    // and skip the '>' mark.
    startPos = startPos + startLength + temp.Find( tagToBeFound() ) + 1;

    temp.Set( aRights.Mid( startPos ) );

    // Finally find the start of the end tag
    tagToBeFound().SetLength( 0 );
    tagToBeFound().AppendFormat( _L8( "</%S" ), &aElement );

    endPos = startPos + temp.Find(tagToBeFound() );

    if ( endPos < startPos )
        {
        aOffset = -1;
        return KNullDesC8();
        }

    temp.Set( aRights.Mid(startPos, endPos - startPos) );

    aOffset = endPos;
    DRMLOG2( _L( "Calculated length %d" ), endPos - startPos);
    DRMLOG( _L( "Extracted element" ) );

    //auto_handle closes and frees allocated resources
    return temp;
    };

LOCAL_C TTime Iso8601ToTime( TDesC8& aTimeString )
    {

    DRMLOG( _L("CDRMDbSession::Iso8601ToTime") );

    TLex8 lex;
    TInt year = 0;
    TInt month = 0;
    TInt day = 0;
    TInt hour = 0;
    TInt minute = 0;
    TInt second = 0;
    TTime r = Time::NullTTime();
    TLocale l;
    TTimeIntervalSeconds offset(l.UniversalTimeOffset());

    if (aTimeString.Length() > 0)
        {
        lex = aTimeString;
        lex.Val(year);
        lex.Inc();
        lex.Val(month);
        lex.Inc();
        lex.Val(day);
        lex.Inc();
        lex.Val(hour);
        lex.Inc();
        lex.Val(minute);
        lex.Inc();
        lex.Val(second);
        r = TTime(TDateTime(year, static_cast<TMonth>(month - 1), day - 1,
                hour, minute, second, 0));
        if (lex.Get() != 'Z')
            {
            r += offset;
            }
        }
    return r;
    }

#ifdef RD_DRM_METERING
LOCAL_C HBufC8* CreateMeteringDataL( CDRMPointerArray<CDrmMeteringDbData>* meteringArray )
    {
    // Calculate buffer size of cipher data
    TInt size( sizeof( KCRLF ) );
    HBufC8* cipherData = NULL;
    TPtr8 ptr( NULL, 0 );

    _LIT8( KElementStart, "<rawMeteringReportData>");
    _LIT8( KElementEnd, "</rawMeteringReportData>");

    size = KElementStart().Size() + KElementEnd().Size();

    for( TUint i(0); i < meteringArray->Count(); i++ )
        {
        size += sizeof( ( *meteringArray)[i]->iContentId );
        if ( (*meteringArray)[i]->iParentUid &&
             (*meteringArray)[i]->iParentUid->Size() )
            {
            size += (*meteringArray)[i]->iParentUid->Size() + 1;
            }
        switch( (*meteringArray)[i]->iPermission )
            {
            case EPlay:
                size += 4;
                break;
            case EView:
            case EExecute:
                size += 7;
                break;
            case EPrint:
                size+= 5;
                break;
            default:
                break; // Not a valid permission
            }
        size += (*meteringArray)[i]->iContentId->Size();
        size += sizeof( (*meteringArray)[i]->iAccumulatedTime.Int() / 60 );
        size += sizeof( (*meteringArray)[i]->iAccumulatedTime.Int() % 60 );
        if( ( ( *meteringArray)[i]->iAccumulatedTime.Int() % 60 ) < 10 )
            {
            size++; //for precending zero for seconds..
            }
        size += sizeof( ( *meteringArray)[i]->iCount );
        size += 4 * sizeof( KMeteringDelimiter ); // ":" -delimiter
        size += sizeof( KCRLF );
        }

    cipherData = HBufC8::NewLC( size );
    ptr.Set( cipherData->Des() );
    ptr.Append( KElementStart );

    for( TUint i(0); i < meteringArray->Count(); i++ )
        {
        ptr.Append( KCRLF );
        if ( (*meteringArray)[i]->iParentUid &&
             (*meteringArray)[i]->iParentUid->Size() )
            {
            ptr.Append( *(*meteringArray)[i]->iParentUid );
            ptr.Append( _L(";") );
            }
        ptr.Append( *(*meteringArray)[i]->iContentId );
        ptr.Append( KMeteringDelimiter );
        switch( (*meteringArray)[i]->iPermission )
            {
            case EPlay:
                ptr.Append( _L("play") );
                break;
            case EView:
                ptr.Append( _L("display") );
                break;
            case EExecute:
                ptr.Append( _L("execute") );
                break;
            case EPrint:
                ptr.Append( _L("print") );
                break;
            default:
                break; // Not a valid permission
            }          // export not supported
        ptr.Append( KMeteringDelimiter );
        ptr.AppendNum( (*meteringArray)[i]->iCount );
        ptr.Append( KMeteringDelimiter );
        ptr.AppendNum( (*meteringArray)[i]->iAccumulatedTime.Int() / 60 );
        ptr.Append( KMeteringDelimiter );
        if( ( ( *meteringArray)[i]->iAccumulatedTime.Int() % 60 ) < 10 )
            {
            ptr.AppendNum( 0 ); //precending zero for seconds..
            }
        ptr.AppendNum( (*meteringArray)[i]->iAccumulatedTime.Int() % 60 );
        }
    ptr.Append( KCRLF );
    ptr.Append( KElementEnd );
    CleanupStack::Pop( cipherData );
    return cipherData;
    }
#endif

// ----------------------------------------------------------------------------
// DeleteFile
// Deletes the file by TFileName presented by aHandle
// ----------------------------------------------------------------------------
//
void DeleteFile( TAny* aHandle )
    {
    __ASSERT_DEBUG( aHandle, User::Panic( _L( "DeleteFile" ), KErrArgument ) );
    TDeleteFile* handle = reinterpret_cast< TDeleteFile* >( aHandle );

    handle->iFs->Delete( *( handle->iFileName ) );
    }

// ----------------------------------------------------------------------------
// DeleteObject
// Deletes the file by TFileName presented by aHandle
// ----------------------------------------------------------------------------
//
void DeleteObject( TAny* aObject )
    {
    __ASSERT_DEBUG( aObject, User::Panic( _L( "DeleteObject" ), KErrArgument ) );
    MDrmKeyStorage* object = reinterpret_cast< MDrmKeyStorage* >( aObject );
    delete object;
    object = NULL;
    }


// ----------------------------------------------------------------------------
// EndTime
// Calculate the true end time: pick the smaller one of aTime1 & aTime2,
// but ignore Time::NullTTime anyhow.
// ----------------------------------------------------------------------------
//
TTime EndTime( const TTime& aTime1, const TTime& aTime2 )
    {
    TTime nullTime = Time::NullTTime();

    if ( aTime1 == nullTime )
        {
        return aTime2;
        }

    if ( aTime2 == nullTime )
        {
        return aTime1;
        }

    return Min( aTime1, aTime2 );
    }

// ============================ MEMBER FUNCTIONS ==============================
// ----------------------------------------------------------------------------
// CDRMRightsServer::NewLC
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CDRMDbSession* CDRMDbSession::NewL()
    {
    CDRMDbSession* self = new( ELeave ) CDRMDbSession();

    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ----------------------------------------------------------------------------
// CDRMRightsServer::~CDRMDbSession
// Destructor.
// ----------------------------------------------------------------------------
//
CDRMDbSession::~CDRMDbSession()
    {
    DRMLOG( _L( "CDRMDbSession::~" ) );
    delete iPreparedData;
    iPreparedData = NULL;

    delete iWidePreparedData;
    iWidePreparedData = NULL;

    delete iFileName;
    iFileName = NULL;

    if ( iPendingRequest )
        {
        delete iPendingRequest;
        }

    delete iContentId;
    iContentId = NULL;

    iClient.Close();

    iCek = KNullDesC8;
    iCek.FillZ();

    delete iConsume;
    iRoapClient.Close();
    }

// ----------------------------------------------------------------------------
// CDRMRightsServer::CDRMDbSession
// Default constructor.
// ----------------------------------------------------------------------------
//
CDRMDbSession::CDRMDbSession():
    iCredentialsChecked(ENotChecked),
    iContentId(NULL)
    {
    iRek.SetLength( 0 );
    }


// ----------------------------------------------------------------------------
// CDRMDbSession::RoapClient
// Returns a handle to the Roap client
// ----------------------------------------------------------------------------
Roap::RRoapStorageClient& CDRMDbSession::RoapClient()
    {
    return iRoapClient;
    }

// ----------------------------------------------------------------------------
// CDRMRightsServer::ServiceL
// Forwards requests from clients to helper methods.
// ----------------------------------------------------------------------------
//
void CDRMDbSession::ServiceL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::ServiceL" ) );
    DRMLOG2( _L( "Message Handle: %08x"), aMessage.Handle() );

    // Close the client before opening a new connection over it to avoid
    // leaking memory in the kernel side
    iClient.Close();

    aMessage.ClientL( iClient );

    // This function call is TRAPped by framework, and message is completed
    // with the error in case of leaving operation.
    switch ( aMessage.Function() )
        {
        case EAddRecord:
            AddRecordL( aMessage, ENoProtection );
            break;

        case EAddProtectedRecord:
            AddRecordL( aMessage, EPublicKey );
            break;

        case EAddDomainRecord:
            AddRecordL( aMessage, EDomainKey );
            break;

        case EGetDbEntry:
            GetRecordL( aMessage );
            break;

        case EGetEntryList:
            GetEntryListL( aMessage );
            break;

        case EDeleteWithCID:
            DeleteL( aMessage );
            break;

        case EDeleteRO:
            DeleteRecordL( aMessage );
            break;

        case EExportCIDs:
            ExportCIDsL( aMessage );
            break;

        case EGetKey:
            GetKeyL( aMessage );
            break;

        case ECheckRights:
            CheckRightsL( aMessage );
            break;

        case ECount:
            CountL( aMessage );
            break;

        case EDeleteAll:
            DeleteAllL( aMessage );
            break;

        case EConsume:
            ConsumeL( aMessage );
            break;

        case ECheckConsume:
            CheckConsumeL( aMessage );
            break;

        case ECalculatePadding:
            CalculatePaddingL( aMessage);
            break;

        case ESecureTime:
            SecureTimeL( aMessage );
            break;

        case EGetPreparedData:
            GetPreparedDataL( aMessage );
            break;

        case EAddDomainRO:
            AddDomainROL( aMessage );
            break;

        case EGetDomainRO:
            GetDomainROL( aMessage );
            break;

        case EDeleteDomainRO:
            DeleteDomainROL( aMessage );
            break;

        case EIsInCache:
            IsInCacheL( aMessage );
            break;

        case EAddToCache:
            AddToCacheL( aMessage );
            break;

        case EDecrypt:
            DecryptL( aMessage );
            break;

        case EEncrypt:
            EncryptL( aMessage );
            break;

        case EInitializeKey:
            InitializeKeyL( aMessage );
            break;

        case EInitializeGroupKey:
            InitializeGroupKeyL( aMessage );
            break;

        case EGetDomainRoForCid:
            GetDomainRosForCidL( aMessage );
            break;

        case EDeleteExpired:
            DeleteExpiredPermissionsL( aMessage );
            break;

        case ESetEstimatedArrival:
            SetEstimatedArrivalL( aMessage );
            break;

        case EGetEstimatedArrival:
            GetEstimatedArrivalL( aMessage );
            break;

        case ESetName:
            SetNameL( aMessage );
            break;

        case EGetName:
            GetNameL( aMessage );
            break;

        case EGetWideData:
            GetWideDataL( aMessage );
            break;

        case ECancel:
            Cancel( aMessage );
            break;

        case EGetUdtData:
            GetUdtDataL( aMessage );
            break;

        case EInitiateUdt:
            InitiateUdtL( aMessage );
            break;

        case EInitOrphanedList:
            InitExportOrphanedCIDsL( aMessage );
            break;

        case EGetOrphanedList:
            ExportOrphanedCIDsL( aMessage );
            break;

        case EGetFLUri:
            GetFLUriL( aMessage );
            break;

        case EEncodeRightsIssuerField:
            EncodeRightsIssuerL( aMessage );
            break;

        case EDecodeRightsIssuerField:
            DecodeRightsIssuerL( aMessage );
            break;

        case ESetAuthenticationSeed:
            SetAuthenticationSeedL( aMessage );
            break;

        case EGetAuthenticationSeed:
            GetAuthenticationSeedL( aMessage );
            break;

        case EVerifyMac:
            VerifyMacL( aMessage );
            break;

        case EGetSupportedIndividuals:
            GetSupportedIndividualsL( aMessage );
            break;

        case EStopWatching:
            StopWatchingL( aMessage );
            break;

        case EUnwrapDeviceMacAndRek:
            UnwrapMacAndRekL( aMessage, EFalse );
            break;

        case EUnwrapDomainMacAndRek:
            UnwrapMacAndRekL( aMessage, ETrue );
            break;

        case EGetRandomData:
            GetRandomDataL( aMessage );
            break;

        case EGetMeteringData:
            GetMeteringDataL( aMessage );
            break;

        case EDeleteMeteringData:
            DeleteMeteringDataL( aMessage );
            break;

        default:
            DRMLOG( _L( "CDRMDbSession::DispatchL: Invalid command" ) );
            User::Leave( KErrNotSupported );
        }

    // The message has already completed successfully.
    DRMLOG2( _L( "CDRMDbSession::ServiceL ok (%08x)"), aMessage.Handle() );
    }

// ----------------------------------------------------------------------------
// CDRMRightsServer::ServiceError
// Completes the request with given error code if the request is still pending.
// ----------------------------------------------------------------------------
//
void CDRMDbSession::ServiceError( const RMessage2& aMessage, TInt aError )
    {
    DRMLOG2( _L( "CDRMDbSession::ServiceError: error %d" ), aError );

    if ( !aMessage.IsNull() )
        {
        aMessage.Complete( aError );
        }
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::ConstructL
// Second phase constructor.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::ConstructL()
    {
    iRoapClientConnected = EFalse;
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::AddRecord
// Get the information from the client, construct a rights object, and add
// it to the database.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::AddRecordL(
    const RMessage2& aMessage,
    TProtectionType aProtection )
    {
    DRMLOG( _L( "CDRMDbSession::AddRecordL" ) );
    //__UHEAP_MARK;

    CDRMPermission* permission = NULL;
    HBufC8* wrappedcek = NULL;
    HBufC8* cek = NULL;
    HBufC8* CID = NULL;
    HBufC8* rightsData = NULL;
    TInt size = 0;
    TPtr8 data( NULL, 0 );
    TDRMUniqueID UID;


    CDRMEventAddRemove* event = CDRMEventAddRemove::NewLC( ERightsObjectRecieved );
    TRequestStatus status;

    SanitizeL( aMessage.GetDesLength(0) );
    SanitizeL( aMessage.GetDesLength(1) );

    size = User::LeaveIfError( IPCGETDESLEN1 );
    rightsData = HBufC8::NewMaxLC( size );
    data.Set( const_cast< TUint8* >( rightsData->Ptr() ), 0, size );
    IPCREAD1L( data );
    permission = CDRMPermission::NewLC();
    permission->ImportL( data );

    UpdateSecureTime();

    // Determine whether the RO is legal.
    if ( ( ( permission->iAvailableRights & ERightsPlay ) &&
           ( Invalid( *permission->iPlay ) ) ) ||
         ( ( permission->iAvailableRights & ERightsDisplay ) &&
           ( Invalid( *permission->iDisplay ) ) ) ||
         ( ( permission->iAvailableRights & ERightsExecute ) &&
           ( Invalid( *permission->iExecute ) ) ) ||
         ( ( permission->iAvailableRights & ERightsPrint ) &&
           ( Invalid( *permission->iPrint ) ) ) ||
         ( ( permission->iAvailableRights & ERightsTopLevel ) &&
           ( Invalid( *permission->iTopLevel ) ) ) )
        {
        User::Leave( ENoRights );
        }

    size = User::LeaveIfError( IPCGETDESLEN0 );
    CID = HBufC8::NewLC( size );

    size = User::LeaveIfError( IPCGETDESLEN2 );

    // Always reserve enough space for a key, if it's 0 then it is, length will be as well.
    size = size > KDCFKeySize ? size : KDCFKeySize;
    if( size > KSanityDataLengthHigh )
        {
        User::Leave(KErrArgument);
        }
    wrappedcek = HBufC8::NewLC( size );

    data.Set( CID->Des() );
    IPCREAD0L( data );

    data.Set( wrappedcek->Des() );
    IPCREAD2L( data );


    if ( aProtection != ENoProtection )
        {
        if(!iRek.Length())
            {
            User::Leave(KErrNotReady);
            }

        cek = OmaCrypto::AesUnwrapL(iRek, *wrappedcek);
        CleanupStack::PopAndDestroy( wrappedcek );
        CleanupStack::PushL( cek );
        }
    else
        {
        cek = wrappedcek;
        }

    DRMLOG(_L("CEK:"));
    DRMLOGHEX(( *cek ));

    if ( permission->iOriginalInsertTime == Time::NullTTime() )
        {
        permission->iOriginalInsertTime = iTrustedTime;
        }

    DRMDB.AddDBEntryL( *CID, *permission, *cek, UID );

    // Remove a rights object from the xoma list if it is there
    RPointerArray<CDRMXOma>& array = XOMAHEADER;
    TInt i = 0;

    for( ; i < array.Count(); i++ )
        {
        // if the content id is found, remove it from the list
        if( !CID->Compare( array[i]->ContentID() ) )
            {
            delete array[i];
            array.Remove( i );
            break;
            }
        }

    // Write the UID back to the client.
    data.Set( reinterpret_cast< TUint8* >( &UID ), sizeof( UID ),
        sizeof( UID ) );
    IPCWRITE3L( data );

    // Notify clients
    event->SetContentIDL(CID->Des());

    DRMNOTIFIER.SendEventL(*event,status);
    User::WaitForRequest(status);

    CleanupStack::PopAndDestroy( 5 ); // cek, CID, permission, data, event

    aMessage.Complete( KErrNone );

    //__UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::AddRecordL done" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GetRecordL
// Get record.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetRecordL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetRecordL" ) );

    CDRMPermission* object = NULL;
    TInt size = 0;
    TPckg< TInt > package( size );
    TDRMUniqueID id;
    HBufC8* CID = NULL;
    TPtr8 data( reinterpret_cast< TUint8* >( &id ), 0, sizeof( id ) );

    // Cleanup.
    if ( iPreparedData )
        {
        delete iPreparedData;
        iPreparedData = NULL;
        }

    IPCREAD2L( data );

    SanitizeL( aMessage.GetDesLength(3) );
    CID = HBufC8::NewLC( IPCGETDESLEN3 );

    data.Set( CID->Des() );
    IPCREAD3L( data );

    object = DRMDB.GetDBEntryByContentIDL( *CID, id );
    CleanupStack::PushL( object );

    // modify the times in the rights object to UI time
    UpdateSecureTime();
    TTime currentTime;
    currentTime.HomeTime();
    TTimeIntervalMicroSeconds change = currentTime.Int64() - iTrustedTime.Int64();
    ModifyRightsObjectByTimeL( object, change, ETrue );

    iPreparedData = object->ExportL();
    size = iPreparedData->Length();

    IPCWRITE0L( package );

    CleanupStack::PopAndDestroy( object );
    CleanupStack::PopAndDestroy( CID );

    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::GetRecordL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GetEntryListL
// Create a temporary file from RPointerArray list the database created.
// Return the file name to the client. In case of an error, the temporary file
// is deleted.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetEntryListL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetEntryListL" ) );
    __UHEAP_MARK;

    TFileName tmpFile( KNullDesC );
    HBufC8* CID = NULL;
    TPtr8 data( NULL, 0 );

    SanitizeL( aMessage.GetDesLength(1));

    CID = HBufC8::NewLC( IPCGETDESLEN1 );


    TDeleteFile dodeletefile =
        {
        &RFSSESSION,
        &tmpFile
        };

    CDRMPermissionList* list = CDRMPermissionList::NewLC();
    list->SetAutoCleanup( ETrue );

    data.Set( CID->Des() );
    IPCREAD1L( data );

    DRMDB.GetDBEntryByContentIDL( *CID, *list );

    // Exclude domain rights where we are not part of the domain
    RemoveInvalidPermissionsL( list );
    if ( list->Count() == 0 )
        {
        User::Leave( KErrCANoRights );
        }

    // modify the times in the rights object to UI time
    UpdateSecureTime();
    TTime currentTime;
    currentTime.HomeTime();
    TTimeIntervalMicroSeconds change = currentTime.Int64() - iTrustedTime.Int64();
    ModifyTimesInListL( list, change, ETrue );

    // Delete the file if something goes wrong.
    TCleanupItem fileCleanup( DeleteFile, &dodeletefile );
    CleanupStack::PushL( fileCleanup );

    // Convert the list to a permanent file store.
    ListToFileL( *list, tmpFile );

    // It is virtually impossible to make WriteL to leave in this case,
    // but anything is still possible...
    IPCWRITE0L( tmpFile );

    CleanupStack::Pop( &dodeletefile );
    CleanupStack::PopAndDestroy( 2 ); // list, CID

    __UHEAP_MARKEND;

    // All done
    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::GetEntryListL: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::DeleteL
// Delete all rights objects with a certain CID.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DeleteL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DeleteL" ) );
    __UHEAP_MARK;
    TPtr8 data( NULL, 0 );

    // Check for VendorId

    _LIT_SECURITY_POLICY_V0(vidCheck, VID_DEFAULT); // Check Default VID
    if ( !vidCheck().CheckPolicy(iClient) )
        {
        User::Leave( KErrAccessDenied );
        }

    CDRMEventAddRemove* event = CDRMEventAddRemove::NewLC( ERightsObjectDeletedAll );
    TRequestStatus status;

    HBufC8* CID = HBufC8::NewLC(
        User::LeaveIfError( IPCGETDESLEN2 ) );

    data.Set( CID->Des() );

    IPCREAD2L( data );


    // Check if deletion is allowed:
    if( DeleteAllowedL( *CID ) )
        {
        DRMDB.DeleteDBEntryL( *CID );

        // Notify
        event->SetContentIDL(CID->Des());

        DRMNOTIFIER.SendEventL(*event,status);
        User::WaitForRequest(status);
        }
    CleanupStack::PopAndDestroy( 2 ); // CID, event
    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::DeleteL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::DeleteRecordL
// Delete a single RO.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DeleteRecordL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DeleteRecordL" ) );
    __UHEAP_MARK;
    TDRMUniqueID id;

    _LIT_SECURITY_POLICY_V0(vidCheck, VID_DEFAULT); // Check Default VID
    if ( !vidCheck().CheckPolicy(iClient) )
        {
        User::Leave( KErrAccessDenied );
        }

    CDRMEventAddRemove* event = CDRMEventAddRemove::NewLC( ERightsObjectDeleted );
    TRequestStatus status;

    TPtr8 data(
        reinterpret_cast< TUint8* >( &id ), 0, sizeof( TDRMUniqueID ) );

    HBufC8* CID = HBufC8::NewLC(
        User::LeaveIfError( IPCGETDESLEN3 ) );

    IPCREAD0L( data );

    data.Set( CID->Des() );
    IPCREAD3L( data );

    // Check if deletion is allowed:
    if( DeleteAllowedL( *CID ) )
        {
        DRMDB.DeleteDBEntryL( *CID, id );

        event->SetContentIDL( CID->Des() );

        DRMNOTIFIER.SendEventL( *event, status );
        User::WaitForRequest( status );
        }

    CleanupStack::PopAndDestroy( 2 ); // CID, event

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::DeleteRecordL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::ExportCIDsL
// Create a temporary file for rights database to export the CIDs,
// and write the file name to the client.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::ExportCIDsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::ExportCIDsL" ) );
    __UHEAP_MARK;

    TFileName fileName( KNullDesC );
    TDeleteFile deletefile =
        {
        &RFSSESSION,
        &fileName
        };

    TCleanupItem item( DeleteFile, &deletefile );
    CleanupStack::PushL( item );

    DRMDB.ExportContentIDListL( fileName );

    IPCWRITE0L( fileName );

    CleanupStack::Pop( &deletefile );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::ExportCIDsL: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::GetKeyL
// Ask for a list of rights object based on the given CID.
// If there is even one rights object which allows the required consuming
// operation, get the key from database updating the RO if necessary.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetKeyL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetKeyL" ) );
    __UHEAP_MARK;
    // If credentials haven't been checked, don't return the key
    if (iCredentialsChecked == ECheckedAndAllowed)
        {
        if (iCek.Length() > 0)
            {
            aMessage.Write(2, iCek);
            aMessage.Complete(KErrNone);
            }
        else
            {
            aMessage.Complete(KErrCANoRights);
            }
        }
    else
        {
        aMessage.Complete(KErrAccessDenied);
        }
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::GetKeyL: Ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::CheckRightsL
// Check if there are sufficient rights at the moment. Nothing is changed from
// the database.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::CheckRightsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::CheckRightsL" ) );
    TIntent intent;
    TInt length = 0;
    CDRMPermission* child = NULL;
    HBufC8* cid = NULL;
    HBufC8* buffer = NULL;
    TPtr8 tmp( NULL, 0, 0 );
    TInt r = KErrNone;
    TInt size = 0;
    TPckg<TInt> package( size );
    TTime currentTime;
    TTimeIntervalMicroSeconds change;
    TUint32 reason = 0;
    TPckg<TUint32> package2( reason );
    TInt error = KErrNone;
    HBufC8* uri = NULL;

    delete iPreparedData;
    iPreparedData = NULL;
    intent = static_cast<TIntent>( aMessage.Int0() );
    DRMLOG2(_L("Intent: %d"), intent);

    if ( intent == EPlay || intent == EView ||
         intent == EExecute || intent == EPrint || intent == EUnknown )
        {
        length = User::LeaveIfError( aMessage.GetDesLength( 1 ) );
        cid = HBufC8::NewLC( length );
        tmp.Set( cid->Des() );
        aMessage.ReadL( 1, tmp );
        DRMLOG(_L("CID:"));
        DRMLOGHEX(tmp);
        error = FindRightsObject( intent, *cid, child, uri, reason );
        delete uri;
        uri = NULL; // URI not used anywhere

        // if an error occurs we still need to write the information to the client,
        // but then we can leave
        if( error )
            {
            aMessage.WriteL( 3, package2 );
            User::Leave( error );
            }

        CleanupStack::PopAndDestroy( cid );
        CleanupStack::PushL( child );
        }
    else if ( intent == EInstall || intent == EPeek )
        {
        length = User::LeaveIfError( aMessage.GetDesLength( 1 ) );
        cid = HBufC8::NewLC( length );
        tmp.Set( cid->Des() );
        aMessage.ReadL( 1, tmp );
        DRMLOG(_L("CID:"));
        DRMLOGHEX(tmp);

        // If we have the key, install and peek always have full rights
        buffer = DRMDB.GetDecryptionKeyL( *cid );
        CleanupStack::PopAndDestroy( cid );

        if ( buffer )
            {
            delete buffer;
            child = CDRMPermission::NewL();
            CleanupStack::PushL( child );
            child->iAvailableRights = ERightsAll;
            }
        else
            {
            r = KErrCANoRights;
            }
        }
    else if ( ( intent == EPause || intent == EContinue || intent == EStop ) &&
        iConsume )
        {
        // These intents only make sense if we have an ongoing session
        child = CDRMPermission::NewL();
        CleanupStack::PushL( child );
        child->DuplicateL( iConsume->GetChild() );
        }
    else
        {
        r = KErrArgument;
        }

    if ( child )
        {
        UpdateSecureTime();
        currentTime.HomeTime();
        change = currentTime.Int64() - iTrustedTime.Int64();
        ModifyRightsObjectByTimeL( child, change, ETrue );
        iPreparedData = child->ExportL();
        size = iPreparedData->Length();
        aMessage.WriteL( 2, package );
        CleanupStack::PopAndDestroy( child );
        }

    aMessage.Complete( r );

    DRMLOG2( _L( "CDRMDbSession::CheckRightsL: ok (%d)" ), r );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::CountL
// Tell the client how many ROs there are.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::CountL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::CountL" ) );
    __UHEAP_MARK;
    TInt count = DRMDB.GetAmountOfRightsObjectsL();

    TPtr8 data( reinterpret_cast< TUint8* >( &count ),
                sizeof( TInt ),
                sizeof( TInt ) );

    IPCWRITE0L( data );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::CountL: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::DeleteAll
// Delete all ROs.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DeleteAllL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DeleteAllL" ) );

    User::LeaveIfError( VerifyCredentials(NULL, NULL, EUnknown) );
    if( iCredentialsChecked == ECheckedAndDenied )
        {
        User::Leave( KErrPermissionDenied );
        }

    //__UHEAP_MARK;

    DRMDB.DeleteDBL();

    REPLAYCACHE.Close();

#ifndef RD_MULTIPLE_DRIVE

    #ifdef RD_DRM_METERING
    METERINGDB.Close();
    RFSSESSION.Delete( KMeteringDataBaseFile );
    METERINGDB.InitL( KMeteringDataBaseFile );
    #endif

    RFSSESSION.Delete( KTimedReplayCacheFile );
    RFSSESSION.Delete( KPlainReplayCacheFile );

    REPLAYCACHE.InitL( KTimedReplayCacheFile, KPlainReplayCacheFile );

#else //RD_MULTIPLE_DRIVE

    TFileName tempPath;
    TFileName tempPath2;
    TInt driveNumber( -1 );
    TChar driveLetter;
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );

    RFSSESSION.DriveToChar( driveNumber, driveLetter );

    #ifdef RD_DRM_METERING
    tempPath.Format( KMeteringDataBaseFile, (TUint)driveLetter );

    METERINGDB.Close();
    RFSSESSION.Delete( tempPath );
    METERINGDB.InitL( tempPath );
    #endif

    tempPath.Format( KTimedReplayCacheFile, (TUint)driveLetter );
    tempPath2.Format( KPlainReplayCacheFile, (TUint)driveLetter );

    RFSSESSION.Delete( tempPath );
    RFSSESSION.Delete( tempPath2 );

    REPLAYCACHE.InitL( tempPath, tempPath2 );

#endif

    if ( !iRoapClientConnected )
        {
        User::LeaveIfError( iRoapClient.Connect() );
        iRoapClientConnected = ETrue;
        }

    iRoapClient.DeleteAllL();

    aMessage.Complete( KErrNone );
    //__UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::DeleteAllL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMRightsServer::ListToFileL
// Convert the list to a file representation.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::ListToFileL( RPointerArray< CDRMPermission >& aList,
                                 TFileName& aFile )
    {
    __UHEAP_MARK;
    DRMLOG( _L( "CDRMDbSession::ListToFileL" ) );

    TInt count( 0 );


    RFileWriteStream fileStream;

#ifndef RD_MULTIPLE_DRIVE

    User::LeaveIfError(
        fileStream.Temp( RFSSESSION,
                         KDRMDbTempPath,
                         aFile,
                         EFileWrite | EFileStream ) );

#else //RD_MULTIPLE_DRIVE

    TInt driveNumber( -1 );
    TChar driveLetter;
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );

    RFSSESSION.DriveToChar( driveNumber, driveLetter );

    TFileName dbTempPath;
    dbTempPath.Format( KDbTempPath, (TUint)driveLetter );

    User::LeaveIfError(
      fileStream.Temp( RFSSESSION,
                       dbTempPath,
                       aFile,
                       EFileWrite | EFileStream ) );

#endif

    CleanupClosePushL( fileStream );

    TInt size( sizeof( TUint32 ) ); // streams store also other info there.

    for( count = 0; count < aList.Count(); count++ )
        {
        size += aList[ count ]->Size();
        }

    // Reset count variable:
    count = 0;

#ifndef RD_MULTIPLE_DRIVE

    if ( SysUtil::DiskSpaceBelowCriticalLevelL( &RFSSESSION,
                                                size,
                                                EDriveC ) )

#else //RD_MULTIPLE_DRIVE

    if ( SysUtil::DiskSpaceBelowCriticalLevelL( &RFSSESSION,
                                                size,
                                                driveNumber ) )

#endif
        {
        DRMLOG( _L( "CDRMDbSession::ListToFileL: KErrDiskFull" ) );
        User::Leave( KErrDiskFull );
        }

    fileStream.WriteInt32L( aList.Count() );

    // Write the whole stuff into the file.
    // URIs are ignored. No use to put them to file (always the same
    // and the client knows it already).
    while( count < aList.Count() )
        {
        aList[ count ]->ExternalizeL( fileStream );
        ++count;
        }

    fileStream.CommitL();

    CleanupStack::PopAndDestroy( &fileStream );

    DRMLOG( _L( "CDRMDbSession::ListToFileL: ok" ) );
    __UHEAP_MARKEND;
    }


// -----------------------------------------------------------------------------
// CDRMRightsServer::FindRightsObjectL
// Try to locate the best RO from the given list which allows consuming of
// content.
// If end time is defined or an interval activated, the smallest endtime
// is always chosen first.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::FindRightsObjectL( TIntent aIntent,
                                       const TDesC8& aURI,
                                       CDRMPermission*& aChild,
                                       HBufC8*& aUsedURI,
                                       TUint32& aReason )
    {
    DRMLOG( _L( "CDRMDbSession::FindRightsObjectL" ) );
    TInt res = KErrNotFound;

    if ( aUsedURI || aChild )
        {
        // Check that return parameters are null initially.
        User::Leave( KErrArgument );
        }

    CDRMPermissionList *perms = CDRMPermissionList::NewLC();
    TTime time;

    perms->SetAutoCleanup( ETrue );
    DRMDB.GetDBEntryByContentIDL( aURI , *perms );

    UpdateSecureTime();

    if ( iSecureTime )
        {
        time = iTrustedTime;
        }
    else
        {
        time = Time::NullTTime();
        }

    if ( aIntent == EPeek || aIntent == EInstall )
        {
        // There is at least one RO available.
        // Use any RO, whether they are valid or not.
        // Pick the first RO in the list.

        aChild = (*perms)[0];
        (*perms).Remove( 0 );

        CleanupStack::PopAndDestroy( perms );
        return;
        }
    else if ( aIntent == EUnknown )
        {
        // Pick one that works, no matter what the intent is
        for ( TInt i = 0; res == KErrNotFound && i < perms->Count(); i++ )
            {
            if ( (*perms)[i]->Valid( time, IMSI, aReason ) )
                {
                res = i;
                }
            }
        if ( res != KErrNotFound )
            {
            aChild = (*perms)[res];
            perms->Remove( res );
            }
        else
            {
            User::Leave( KErrCANoPermission );
            }
        }
    else
        {
        res = FindBestROsL( *perms, aURI, aIntent, aUsedURI, aReason );
        if ( res >= 0 )
            {
            aChild = (*perms)[res];
            perms->Remove( res );
            }
        else
            {
            User::Leave( KErrCANoPermission );
            }
        }
    CleanupStack::PopAndDestroy( perms );
    }


// -----------------------------------------------------------------------------
// CDRMRightsServer::FindRightsObject
// Try to locate the best RO from the given list which allows consuming of
// content.
// If end time is defined or an interval activated, the smallest endtime
// is always chosen first.
// -----------------------------------------------------------------------------
//
TInt CDRMDbSession::FindRightsObject( TIntent aIntent,
                                      const TDesC8& aURI,
                                      CDRMPermission*& aChild,
                                      HBufC8*& aUsedURI,
                                      TUint32& aReason )
    {
    DRMLOG( _L( "CDRMDbSession::FindRightsObject" ) );
    TInt error = KErrNone;

    TRAP( error, FindRightsObjectL( aIntent, aURI, aChild, aUsedURI, aReason ) );
    if ( ( error == KErrCANoRights || error == KErrCANoPermission ) &&
        PendingRights(aURI) )
        {
        error = KErrCAPendingRights;
        }
    return error;
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::CheckConsumeL
// Check if Consume is possible
// -----------------------------------------------------------------------------
//
void CDRMDbSession::CheckConsumeL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::CheckConsumeL" ) );

    __UHEAP_MARK;

    HBufC8* CID = NULL;
    TPtr8 cid( NULL, 0, 0 );
    TInt length = 0;
    TIntent intent;
    TUint32 reason = 0;

    length = User::LeaveIfError( IPCGETDESLEN1 );
    CID = HBufC8::NewLC( length );
    cid.Set( CID->Des() );
    IPCREAD1L( cid );
    intent = static_cast<TIntent>(aMessage.Int0());

    // Check only intents which are actually consuming something. All others
    // always succeed, because CheckConsume is called by default when a file
    // is opened.
    if ( intent == EPlay || intent == EView ||
         intent == EExecute || intent == EPrint || intent == EUnknown )
        {
        // Count constraints are valid for the duration of the
        // session after they have been consumed earlier
        if ( !( iConsume && iConsume->CountConstraintActive() ||
                SERVER->HasActiveCountConstraint( *CID ) ) )
            {
            CDRMPermission* child( NULL );
            HBufC8* uri( NULL );
            TInt error( FindRightsObject( intent, *CID, child, uri, reason ) );
            delete child;
            delete uri;
            User::LeaveIfError( error );
            }
        }
/* Enable this code as soon as clients use EUnknown, and it is safe to fail
   when no key is available
    else if ( intent == EPeek || EInstall )
        {
        // We need at least the key for peek and install. This will leave if no
        // key is there.
        HBufC8* key = DRMDB.GetDecryptionKeyL( *CID );
        delete key;
        }
*/

    CleanupStack::PopAndDestroy( CID );
    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::CheckConsumeL: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::ConsumeL
// Consume the right and register the consumption.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::ConsumeL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::ConsumeL" ) );

    const TIntent intent = static_cast<TIntent>(aMessage.Int0());
    HBufC8* CID = NULL;
    TInt length = 0;
    TPtr8 cid( NULL, 0, 0 );

    length = User::LeaveIfError( IPCGETDESLEN1 );

    CID = HBufC8::NewLC( length );

    cid.Set( CID->Des() );
    IPCREAD1L( cid );

    if ( intent != EUnknown )
        {
        if ( intent == EPeek || intent == EInstall )
            {
            User::LeaveIfError( VerifyCredentials( CID, NULL, intent ) );
            }
        else
            {
            if ( intent == EPlay ||
                 intent == EView ||
                 intent == EExecute ||
                 intent == EPrint ||
                 intent == EStop )
                {

                if ( iConsume )
                    {
                    delete iConsume;
                    iConsume = NULL;
                    }
                if ( intent != EStop )
                    {
                    CDRMConsume* consume( NULL );
                    consume = CDRMConsume::NewLC( *this, *CID, NULL );
                    consume->HandleL( intent );
                    CleanupStack::Pop( consume );
                    iConsume = consume;
                    }
                }
            else
                {
                if ( !iConsume )
                    {
                    User::Leave( KErrNotReady );
                    }

                if ( intent == EPause )
                    {
                    iConsume->Pause();
                    }
                else if ( intent == EContinue )
                    {
                    iConsume->ContinueL();
                    }
                else
                    {
                    iConsume->Stop();
                    }
                }
            }
        }
    else
        {
        // None of the other intents are allowed here, fail
        User::Leave( KErrArgument );
        }


    CleanupStack::PopAndDestroy( CID );
    aMessage.Complete( KErrNone );
    DRMLOG( _L( "CDRMDbSession::ConsumeL: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::CalculatePaddingL
//
// -----------------------------------------------------------------------------
//
void CDRMDbSession::CalculatePaddingL( const RMessage2& aMessage )
    {
    __UHEAP_MARK;
    DRMLOG( _L( "CDRMDbSession::CalculatePaddingL" ) );

    CAESDecryptor* decryptor( NULL );
    TInt i( 0 );

    TBuf8<KDCFKeySize * 2> data;
    TBuf8<KDCFKeySize> iv;
    TBuf8<KDCFKeySize> block;
    TPtr8 tmp( NULL, 0, 0 );

    aMessage.ReadL( 0, data );

    // Check that the data we read is actually of the proper length
    if( data.Length() != KDCFKeySize*2 )
        {
        User::Leave(KErrArgument);
        }

    iv.Copy(data.Left(KDCFKeySize));
    block.Copy(data.Right(KDCFKeySize));

    if( iCek.Length() != KDRMKeyLength )
        {
        User::Leave(KErrNotReady);
        }

    decryptor = CAESDecryptor::NewLC(iCek);
    decryptor->Transform(block);
    CleanupStack::PopAndDestroy( decryptor );

    for (i = 0; i < KDCFKeySize; i++)
        {
        block[i] ^= iv[i];
        }

    if ( block[ KDCFKeySize - 1 ] > 0 && block[ KDCFKeySize - 1 ] <= 16 )
        {
        for ( i = KDCFKeySize - block[ KDCFKeySize - 1 ];
              i < KDCFKeySize - 1;
              ++i )
            {
            if ( block[ i ] != block[ KDCFKeySize - 1 ] )
                {
                User::Leave( KErrCorrupt );
                }
            }

        aMessage.Complete( block[ KDCFKeySize - 1 ] );
        DRMLOG2( _L( "CDRMDbSession::CalculatePaddingL: Padding = %d" ),
                 block[ KDCFKeySize - 1 ] );

        return;
        }

    User::Leave( KErrCorrupt );

__UHEAP_MARKEND;
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::SecureTimeL
// returns the secure time
// -----------------------------------------------------------------------------
//
void CDRMDbSession::SecureTimeL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::SecureTimeL" ) );
    __UHEAP_MARK;
    TPckgBuf< TInt64 > time;
    TPckg< TBool > levelPckg( iSecureTime );

    UpdateSecureTime();

    time() = iTrustedTime.Int64();

    IPCWRITE0L( time );
    IPCWRITE1L( levelPckg );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::SecureTime: ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::EncryptL
//
// -----------------------------------------------------------------------------
//
void CDRMDbSession::EncryptL(const RMessage2& aMessage)
    {
    TBuf8<KDCFKeySize> iv;
    HBufC8* data = NULL;
    TPtr8 ptr(NULL, 0, 0);
    TBool addPadding;
    __UHEAP_MARK;

    DRMLOG(_L("CDRMDbSession::EncryptL"));

    if( iCek.Length() != KDRMKeyLength )
        {
        User::Leave( KErrNotReady );
        }

    SanitizeL( aMessage.GetDesLength(0) );

    addPadding = aMessage.Int2() != 0 ? ETrue : EFalse;
    aMessage.Read(0, iv);
    data = HBufC8::NewLC(aMessage.GetDesMaxLength(1));
    ptr.Set(data->Des());
    aMessage.Read(1, ptr);

    AesEncryptL( iCek, iv, addPadding, ptr );

    aMessage.Write(1, ptr);
    aMessage.Complete(KErrNone);
    CleanupStack::PopAndDestroy( data );
    __UHEAP_MARKEND;
    DRMLOG(_L("CDRMDbSession::EncryptL: Ok"));
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::DecryptL
// Decrypt data and return it to the caller, using the CEK for this session
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DecryptL(const RMessage2& aMessage)
    {
    DRMLOG(_L("CDRMDbSession::DecryptL"));

    // If credentials haven't been checked, do it now, check for expired rights
    if (iCredentialsChecked == ECheckedAndDenied ||
        iCredentialsChecked == ENotChecked &&
        VerifyCredentials(iContentId, NULL, EUnknown) != KErrNone)
        {
        DRMLOG(_L("Decrypt failed: untrusted client"));
        aMessage.Complete(KErrAccessDenied);
        }
    else if ( iConsume && iConsume->IsExpired() )
        {
        DRMLOG(_L("Decrypt failed: rights expired"));
        aMessage.Complete(KErrCANoPermission);
        }
    else
        {
        if (iCek.Length() > 0)
            {
            TBuf8<KDCFKeySize> iv;
            HBufC8* data = NULL;
            TPtr8 ptr(NULL, 0, 0);
            TBool removePadding;

            removePadding = aMessage.Int2() != 0 ? ETrue : EFalse;
            aMessage.Read(0, iv);

            data = HBufC8::NewMaxLC(aMessage.GetDesMaxLength(1));

            ptr.Set(data->Des());
            aMessage.Read(1, ptr);

            AesDecryptL( iCek,
                         iv,
                         removePadding,
                         ptr );

            aMessage.Write(1, ptr);
            aMessage.Complete(KErrNone);
            CleanupStack::PopAndDestroy( data );
            }
        else
            {
            aMessage.Complete(KErrCANoRights);
            }
        }
    DRMLOG(_L("CDRMDbSession::DecryptL: Ok"));
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::InitializeKeyL
// Initialize the CEK for this session based on the content ID. Also sets the
// content ID for later usage.
// -----------------------------------------------------------------------------
//
void CDRMDbSession::InitializeKeyL( const RMessage2& aMessage )
    {
    TPtr8 tmp(NULL, 0, 0);
    HBufC8* key = NULL;
    TInt error = KErrNone;

    DRMLOG( _L( "CDRMDbSession::InitializeKeyL"));
    if ( iContentId )
        {
        delete iContentId;
        iContentId = NULL;
        }
    iContentId  = HBufC8::NewL( User::LeaveIfError( IPCGETDESLEN0 ) );
    tmp.Set( iContentId->Des() );
    IPCREAD0L( tmp );

    __UHEAP_MARK;
    TRAP( error, key = DRMDB.GetDecryptionKeyL( *iContentId  ) );
    if ( ( error == KErrCANoRights || error == KErrCANoPermission ) &&
        PendingRights( *iContentId , EFalse ) )
        {
        error = KErrCAPendingRights;
        }

    if ( error == KErrNone )
        {
        iCek.Copy( *key );
        delete key;
        aMessage.Complete( KErrNone );
        }
    else
        {
        aMessage.Complete( error );
        }
    __UHEAP_MARKEND;
    DRMLOG2( _L( "CDRMDbSession::InitializeKeyL: %d" ), error );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::InitializeGroupKeyL
// Initialize the CEK for this session from a given group key
// -----------------------------------------------------------------------------
//
void CDRMDbSession::InitializeGroupKeyL(const RMessage2& aMessage )
    {
    HBufC8* groupId = NULL;
    HBufC8* groupKey = NULL;
    TPtr8 tmp(NULL, 0, 0 );
    HBufC8* key = NULL;
    TRequestStatus status;
    CAESDecryptor* aes = NULL;
    CModeCBCDecryptor* cbc = NULL;

    __UHEAP_MARK;

    SanitizeL( aMessage.GetDesLength(0) );
    SanitizeL( aMessage.GetDesLength(1) );

    DRMLOG(_L("CDRMDbSession::InitializeGroupKeyL"));
    if (aMessage.Int2() == EMethodAES_128_CBC)
        {
        groupId = HBufC8::NewLC(aMessage.GetDesLength(0));
        tmp.Set(groupId->Des());
        aMessage.Read(0, tmp);

        groupKey = HBufC8::NewLC(aMessage.GetDesLength(1));
        tmp.Set(groupKey->Des());
        aMessage.Read(1, tmp);

        key = DRMDB.GetDecryptionKeyL(*groupId);
        CleanupStack::PushL(key);

        if ( key )
            {
            aes = CAESDecryptor::NewLC(*key);
            cbc = CModeCBCDecryptor::NewL(aes, groupKey->Left(KDCFKeySize));
            CleanupStack::Pop( aes );
            iCek.Copy(groupKey->Mid(KDCFKeySize, KDCFKeySize));
            cbc->Transform(iCek);
            delete cbc;
            aMessage.Complete(KErrNone);
            }
        else
            {
            aMessage.Complete(KErrCANoRights);
            }
        CleanupStack::PopAndDestroy(3); // key, groupKey, groupId
        }
    else
        {
        aMessage.Complete(KErrNotSupported);
        }

    __UHEAP_MARKEND;
    DRMLOG(_L("CDRMDbSession::InitializeGroupKeyL: Ok"));
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::GetPreparedDataL
// Returns data which has been allocated before
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetPreparedDataL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetPreparedDataL" ) );

    if( !iPreparedData )
        {
        User::Leave( KErrNotReady );
        }

    if( iPreparedData->Length() > aMessage.GetDesMaxLength(0) )
        {
        User::Leave(KErrArgument);
        }

    IPCWRITE0L( iPreparedData->Des() );

    aMessage.Complete( KErrNone );
    DRMLOG( _L( "CDRMDbSession::GetPreparedDataL: ok" ) );

    // Delete the data
    delete iPreparedData;
    iPreparedData = NULL;
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::IsInCacheL
// Checks whether the given entry is in replay cache or not.
// -----------------------------------------------------------------------------
void CDRMDbSession::IsInCacheL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::IsInCacheL" ) );

    HBufC8* buf = HBufC8::NewLC(
        User::LeaveIfError( IPCGETDESLEN0 ) );

    TPckgBuf< TBool > res;
    TPtr8 data( buf->Des() );

    IPCREAD0L( data );

    if ( aMessage.Ptr1() )
        {
        TPckgBuf< TTime > time;

        IPCREAD1L( time );

        res = REPLAYCACHE.InCacheL( *buf, time() );
        }
    else
        {
        res = REPLAYCACHE.InCacheL( *buf );
        }

    CleanupStack::PopAndDestroy( buf );

    IPCWRITE2L( res );

    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::IsInCache ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::AddToCacheL
// Adds an entry to replay cache.
// -----------------------------------------------------------------------------
void CDRMDbSession::AddToCacheL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::AddToCacheL" ) );

    HBufC8* buf = NULL;

    UpdateSecureTime();

    if ( !iSecureTime )
        {
        // DoSomething!
        }

    buf = HBufC8::NewLC(
        User::LeaveIfError( IPCGETDESLEN0 ) );

    TPtr8 data( buf->Des() );

    IPCREAD0L( data );

    if ( aMessage.Ptr1() )
        {
        TPckgBuf< TTime > time;

        IPCREAD1L( time );

        REPLAYCACHE.AddL( *buf, time(), iTrustedTime );
        }

    else
        {
        REPLAYCACHE.AddL( *buf, iTrustedTime );
        }

    CleanupStack::PopAndDestroy( buf );

    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::AddToCacheL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::AddDomainROL
// Add domain ro xml data
// -----------------------------------------------------------------------------
//
void CDRMDbSession::AddDomainROL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::AddDomainROL" ) );
    __UHEAP_MARK;
    HBufC8* RoId = NULL;
    HBufC8* XMLData = NULL;
    TInt size = 0;
    TPtr8 data( NULL, 0 );

    size = User::LeaveIfError( IPCGETDESLEN0 );
    RoId = HBufC8::NewLC( size );

    size = User::LeaveIfError( IPCGETDESLEN1 );
    XMLData = HBufC8::NewLC( size );

    data.Set( RoId->Des() );
    IPCREAD0L( data );

    data.Set( XMLData->Des() );
    IPCREAD1L( data );

    DRMDB.AddDomainROL( *RoId, *XMLData );

    CleanupStack::PopAndDestroy( 2 ); // RoId, XMLData

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::AddDomainROL done" ) );
    };

// -----------------------------------------------------------------------------
// CDRMDbSession::GetDomainROL
// Get domain ro xml data
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetDomainROL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetDomainROL" ) );

    TInt size = 0;
    TPckg< TInt > package( size );
    HBufC8* RoId = NULL;
    TPtr8 data(NULL, 0);

    // Cleanup.
    if ( iPreparedData )
        {
        delete iPreparedData;
        iPreparedData = NULL;
        }

    size = User::LeaveIfError( IPCGETDESLEN1 );

    RoId = HBufC8::NewLC( size );

    data.Set( RoId->Des() );
    IPCREAD1L( data );

    iPreparedData = DRMDB.GetDomainROL( *RoId );

    size = iPreparedData->Length();

    IPCWRITE0L( package );

    CleanupStack::PopAndDestroy( RoId );

    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::GetDomainROL ok" ) );
    };

// -----------------------------------------------------------------------------
// CDRMDbSession::DeleteDomainROL
// Delete domain ro xml data
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DeleteDomainROL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DeleteDomainROL" ) );
    __UHEAP_MARK;
    TPtr8 data( NULL, 0 );
    TInt size = 0;

    size = User::LeaveIfError( IPCGETDESLEN0 );


    HBufC8* RoId = HBufC8::NewLC( size );

    data.Set( RoId->Des() );

    IPCREAD0L( data );

    DRMDB.DeleteDomainROL( *RoId );

    CleanupStack::PopAndDestroy( RoId );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::DeleteDomainROL ok" ) );
    };


// -----------------------------------------------------------------------------
// CDRMDbSession::GetDomainRosForCidL
// Return the domain ROs for a content ID in a buffer. Each RO is preceded
// by a length field
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetDomainRosForCidL(
    const RMessage2& aMessage)
    {
    DRMLOG(_L("CDRMDbSession::GetDomainRosForCidL"));
    TInt size(0);
    TInt roSize(0);
    TInt pos = 0;
    TInt indexLatest = -1;
    TTime timeStamp = 0;
    TTime timeLatest = 0;
    TPckg<TInt> pkg(size);
    TPtr8 ptr(NULL, 0);
    TPtrC8 elementPtr(KNullDesC8);
    TPckg<TInt> roSizePkg(roSize);
    HBufC8* element = NULL;
    HBufC8* id(NULL);
    HBufC8* ro(NULL);
    CDRMPointerArray<CDRMPermission>*
        rights( CDRMPointerArray<CDRMPermission>::NewLC() );
    rights->SetAutoCleanup(ETrue);

    delete iPreparedData;
    iPreparedData = NULL;

    SanitizeL( aMessage.GetDesLength(0) );

    id = HBufC8::NewLC(aMessage.GetDesLength(0));
    ptr.Set(id->Des());
    aMessage.Read(0, ptr);

    TRAPD(r, DRMDB.GetDBEntryByContentIDL(*id, *rights));

    if (r == KErrCANoRights || r == KErrCANoPermission )
        {
        r = KErrNone;
        }
    User::LeaveIfError(r);

    for (TInt i(0); i < rights->Count(); i++)
        {
        if ( (*rights)[i]->iDomainID )
            {
            ro = DRMDB.GetDomainROL(*(*rights)[i]->iRoID);
            CleanupStack::PushL(ro);

            elementPtr.Set(ExtractElement(*ro, KTimeStamp, pos));

            /* Check whether the timestamp was found or not and whether it is
               the newest one so far or not */
            if (pos >= 0)
                {
                element = elementPtr.AllocLC();
                timeStamp = Iso8601ToTime(*element);
                CleanupStack::PopAndDestroy(element);

                if (timeStamp > timeLatest)
                    {
                    indexLatest = i;
                    }
                }
            CleanupStack::PopAndDestroy(ro);
            ro = NULL;
            }
        pos = 0;
        }

    /* At least one timestamp was found */
    if (indexLatest >= 0 && indexLatest < rights->Count())
        {
        ro = DRMDB.GetDomainROL(*(*rights)[indexLatest]->iRoID);
        CleanupStack::PushL(ro);

        roSize = ro->Size();
        if ( !iPreparedData )
            {
            iPreparedData = HBufC8::NewL(sizeof (TInt) + roSize);
            }
        else
            {
            iPreparedData = iPreparedData->ReAllocL(
                size + sizeof (TInt) + roSize );
            }
        ptr.Set(iPreparedData->Des());
        ptr.Append(roSizePkg);
        ptr.Append(*ro);
        size += sizeof (TInt) + roSize;
        CleanupStack::PopAndDestroy(ro);
        }

    aMessage.Write(1, pkg);
    CleanupStack::PopAndDestroy( id );
    CleanupStack::PopAndDestroy( rights );

    aMessage.Complete(KErrNone);
    DRMLOG(_L("CDRMDbSession::GetDomainRosForCidL ok"));
    }


//------------------------------------------------------------------------------
// CDRMDbSession::DeleteExpiredPermissionsL
// Delete expired permissions if we have secure time.
//------------------------------------------------------------------------------
void CDRMDbSession::DeleteExpiredPermissionsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DeleteExpiredPermissionsL" ) );
    CDRMActiveOperation* active( NULL );
    TTime time;

    User::LeaveIfError( VerifyCredentials(NULL, NULL, EUnknown) );
    if( iCredentialsChecked == ECheckedAndDenied )
        {
        User::Leave( KErrPermissionDenied );
        }

    UpdateSecureTime();

    if ( iSecureTime )
        {
        time = iTrustedTime;
        }
    else
        {
        time = Time::NullTTime();
        }

    if ( iPendingRequest )
        {
        User::Leave( KErrAlreadyExists );
        }

    active = CDRMActiveOperation::NewLC( aMessage, *this,
                                         CDRMActiveOperation::EOperationDeleteExpired );
    active->ActivateL( DRMDB, iTrustedTime );

    iPendingRequest = active;

    CleanupStack::Pop( active );

    DRMLOG( _L( "CDRMDbSession::DeleteExpiredPermissionsL ok" ) );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::SetEstimatedArrivalL
// set the estimated arrival time for the content uri
// -----------------------------------------------------------------------------
//
void CDRMDbSession::SetEstimatedArrivalL( const RMessage2& aMessage )
    {
    HBufC8* CID = NULL;
    TFileName fileName;
    TInt length = 0;
    TPtr8 inRead( NULL, 0 );
    TTimeIntervalSeconds interval = 0;
    TPckg<TTimeIntervalSeconds> package( interval );
    RPointerArray<CDRMXOma>& array = XOMAHEADER;
    CDRMXOma* omaData = NULL;

    // Read the content id
    length = User::LeaveIfError( IPCGETDESLEN0 );
    CID = HBufC8::NewLC( length );
    inRead.Set( CID->Des() );
    IPCREAD0L( inRead );

    // Read the interval
    IPCREAD1L( package );


    for( TInt i = 0; i < array.Count(); i++ )
        {
        if( !CID->Compare( (array)[i]->ContentID() ) )
            {
            omaData = (array)[i];
            break;
            }
        }

    // Update the secure time
    UpdateSecureTime();

    if( omaData ) // Exists, update
        {
        omaData->SetWaitTimeL( interval );
        omaData->SetTimeStampL( iTrustedTime );
        }
    else // Doesn't exist, create a new one
        {
        omaData = CDRMXOma::NewLC( *CID, iTrustedTime, interval );
        array.AppendL( omaData );
        CleanupStack::Pop( omaData );
        }

    CleanupStack::PopAndDestroy( CID );

    // Complete the command
    aMessage.Complete( KErrNone );
    };

// -----------------------------------------------------------------------------
// CDRMDbSession::GetEstimatedArrivalL
// get the estimated arrival time for the content uri
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetEstimatedArrivalL( const RMessage2& aMessage )
    {
    HBufC8* CID = NULL;
    TInt length = 0;
    TPtr8 inRead( NULL, 0 );
    RPointerArray<CDRMXOma>& array = XOMAHEADER;
    CDRMXOma* omaData = NULL;
    TInt64 interval = 0;
    TInt i = 0;
    TTimeIntervalSeconds result = 0;

    // Read the content id
    length = User::LeaveIfError( IPCGETDESLEN0 );
    CID = HBufC8::NewLC( length );
    inRead.Set( CID->Des() );
    IPCREAD0L( inRead );

    for( ; i < array.Count(); i++ )
        {
        if( !CID->Compare( (array)[i]->ContentID() ) )
            {
            omaData = (array)[i];
            break;
            }
        }

    // Update the secure time
    UpdateSecureTime();

    if( omaData ) // Exists, update
        {

        // Special case, the rights have expired before, but have not been removed
        // so that we do not lose the notification
        if( omaData->WaitTime().Int() == KErrCAPendingRights )
            {
            interval = -1; // Fixed value for this case:
                           // -1 means the rights should have arrived already

            delete omaData;
            omaData = 0;

            array.Remove( i );
            }
        else
            {
            // Update the secure time
            UpdateSecureTime();

            interval = omaData->WaitTime().Int();
            interval -= ( iTrustedTime.Int64() - omaData->TimeStamp().Int64() ) /
                KMicrosecondsToSecond;

            if( interval <= 0 )
                {
                interval = -1; // Fixed value for this case:
                               // -1 means the rights should have arrived already

                // Clean up the data: if the function fails before this
                // the instance remains like it should
                delete omaData;
                omaData = 0;

                array.Remove( i ); // Remove from the array
                }
            }
        result = I64INT(interval);
        TPckg<TTimeIntervalSeconds> package( result );
        IPCWRITE1L( package );
        }
    else // Doesn't exist, create a new one
        {
        User::Leave( KErrNotFound );
        }

    CleanupStack::PopAndDestroy( CID );

    // Complete the command
    aMessage.Complete( KErrNone );
    };



//------------------------------------------------------------------------------
// CDRMDbSession::PendingRights
// Check if rights are pending
//------------------------------------------------------------------------------
TBool CDRMDbSession::PendingRights(const TDesC8& aCid, TBool aRemoval)
    {
    TBool f = EFalse;
    RPointerArray<CDRMXOma>& array = XOMAHEADER;
    CDRMXOma* omaData = NULL;
    TInt64 interval = 0;
    TInt i = 0;
    TTimeIntervalSeconds result = 0;

    for( ; i < array.Count() && !f; i++ )
        {
        if( !aCid.Compare( (array)[i]->ContentID() ) )
            {
            omaData = (array)[i];
            // Exists and is different from KErrCAPendingRights -> update
            if( omaData && omaData->WaitTime().Int() != KErrCAPendingRights )
                {
                // Update the secure time
                UpdateSecureTime();
                interval = omaData->WaitTime().Int();
                interval -= ( iTrustedTime.Int64() - omaData->TimeStamp().Int64() ) /
                    KMicrosecondsToSecond;

                // check if removal from the list is needed
                if( aRemoval && interval <= 0 )
                    {
                    TRAPD( error, omaData->SetWaitTimeL( KErrCAPendingRights ) );
                    error = error; // remove error
                    }
                f = ETrue;
                }
            }
        }
    return f;
    }



//------------------------------------------------------------------------------
// CDRMDbSession::GetUdtDataL
// Gets the user data transfer header data
//------------------------------------------------------------------------------
void CDRMDbSession::GetUdtDataL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetUdtDataL" ) );
    __UHEAP_MARK;
    // Usage intent.
    HBufC8* udtData = NULL;

    // Get the key
    udtData = DRMDB.GetUdtDataLC();

    // Write the udt data to the client.
    // This shouldn't fail anyway.
    IPCWRITE0L( *udtData );

    CleanupStack::PopAndDestroy( udtData );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::GetUdtDataL: Ok" ) );
    };

//------------------------------------------------------------------------------
// CDRMDbSession::InitiateUdtL
// Initiate user data transfer
//------------------------------------------------------------------------------
void CDRMDbSession::InitiateUdtL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::InitiateUdtL" ) );
    __UHEAP_MARK;

    HBufC8* encryptionKey = NULL;
    TInt size = 0;
    TPtr8 data( NULL, 0 );

    SanitizeL( aMessage.GetDesLength(0));

    size = User::LeaveIfError( IPCGETDESLEN0 );
    encryptionKey = HBufC8::NewLC( size );

    data.Set( encryptionKey->Des() );
    IPCREAD0L( data );

    // The encrypted data is encrypted with 2048 byte key, it always needs to be atleast this long
    if( encryptionKey->Length() < 254)
        {
        User::Leave(KErrArgument);
        }

    DRMDB.InitiateUdtL( *encryptionKey );

    CleanupStack::PopAndDestroy( encryptionKey );

    aMessage.Complete( KErrNone );
    __UHEAP_MARKEND;

    DRMLOG( _L( "CDRMDbSession::InitiateUdtL done" ) );
    };

//------------------------------------------------------------------------------
// CDRMDbSession::InitExportOrhanedCIDsL
// Create and export the list of orphaned content id's
//------------------------------------------------------------------------------
void CDRMDbSession::InitExportOrphanedCIDsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::InitExportOrphanedCIDsL" ) );
    CDRMActiveOperation* active( NULL );
    TBool performScan = EFalse;

    User::LeaveIfError( VerifyCredentials(NULL,NULL,ContentAccess::EUnknown) );

    if ( iPendingRequest )
        {
        User::Leave( KErrAlreadyExists );
        }

    // if the old filename exists, delete it, a new operation starts
    if( iFileName )
        {
        delete iFileName;
        iFileName = NULL;
        }

    // Read the scan data:
    performScan = aMessage.Int0() != 0 ? ETrue : EFalse;


    active = CDRMActiveOperation::NewLC( aMessage, *this,
                                         CDRMActiveOperation::EOperationExportObsolete );

#ifndef RD_MULTIPLE_DRIVE

    active->ActivateL( DRMDB, RFSSESSION, KDRMDbTempPath, performScan );

#else //RD_MULTIPLE_DRIVE

    TInt driveNumber( -1 );
    TChar driveLetter;
    DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber );

    RFSSESSION.DriveToChar( driveNumber, driveLetter );

    TFileName dbTempPath;
    dbTempPath.Format( KDbTempPath, (TUint)driveLetter );

    active->ActivateL( DRMDB, RFSSESSION, dbTempPath, performScan );

#endif

    iPendingRequest = active;

    CleanupStack::Pop( active );

    DRMLOG( _L( "CDRMDbSession::InitExportOrphanedCIDsL: ok" ) );
    };


//------------------------------------------------------------------------------
// CDRMDbSession::ExportOrhanedCIDsL
// Create and export the list of orphaned content id's
//------------------------------------------------------------------------------
void CDRMDbSession::ExportOrphanedCIDsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::ExportOrphanedCIDsL" ) );
    if( !iFileName )
        {
        aMessage.Complete( KErrNotReady );
        return;
        }

    if( iFileName->Length() > aMessage.GetDesMaxLength(0) )
        {
        User::Leave(KErrArgument);
        }

    // It is virtually impossible to make WriteL to leave in this case,
    // but anything is still possible...
    IPCWRITE0L( *iFileName );

    // if everything went well, delete the filename if not leave it
    delete iFileName;
    iFileName = NULL;

    // All done
    aMessage.Complete( KErrNone );

    DRMLOG( _L( "CDRMDbSession::ExportOrphanedCIDsL: ok" ) );
    };

// ----------------------------------------------------------------------------
// CDRMDbSession::UnwrapMacAndRekL
// Unwraps public key encrypted MAC and REK keys
// ----------------------------------------------------------------------------
//
void CDRMDbSession::UnwrapMacAndRekL( const RMessage2& aMessage, TBool aDomainRo )
    {
    DRMLOG( _L( "CDRMDbSession::UnwrapMacAndRekL" ) );

    __UHEAP_MARK;

    MDrmKeyStorage* storage;
    TBuf8<OmaCrypto::KMacSize> mac;
    TBuf8<OmaCrypto::KKeySize> rek;
    HBufC8* data = NULL;
    TPtr8 dataPtr(0, 0);
    TPtrC8 macAndRekPtr(0, 0);
    HBufC8* riId = NULL;
    TPtr8 riIdPtr(0, 0);
    HBufC8* domainId = NULL;
    TPtr8 domainIdPtr(0, 0);
    CDRMRIContext* riContext = NULL;
    TInt size = 0;
    TKeyTransportScheme transport;
    HBufC8* unwrappedMacAndRek = NULL;
    CDRMDomainContext* domainContext;
    HBufC8* domainKey = NULL;

    DRMLOG(_L("CDRMDbSession::UnwrapMacAndRekL"));



    SanitizeL( aMessage.GetDesLength(0) );
    SanitizeL( aMessage.GetDesLength(1) );

    size = User::LeaveIfError( IPCGETDESLEN0 );
    data = HBufC8::NewLC( size );

    size = User::LeaveIfError( IPCGETDESLEN1 );
    riId = HBufC8::NewLC( size );

    if(aDomainRo)
        {
        SanitizeL( aMessage.GetDesLength(2) );
        size = User::LeaveIfError( IPCGETDESLEN2 );
        domainId = HBufC8::NewLC( size );
        }

    dataPtr.Set( data->Des() );
    IPCREAD0L( dataPtr );

    riIdPtr.Set( riId->Des() );
    IPCREAD1L( riIdPtr );

    if(aDomainRo)
        {
        domainIdPtr.Set( domainId->Des() );
        IPCREAD2L( domainIdPtr );
        }

    // The first byte defines the transport scheme
    transport = static_cast<TKeyTransportScheme>(dataPtr[0]);
    macAndRekPtr.Set(dataPtr.Mid(1));

    DRMLOG2(_L("Transport scheme: %d"), transport);
    DRMLOG(_L("MAC + REK:"));
    DRMLOGHEX(macAndRekPtr);

    if ( !iRoapClientConnected )
        {
        User::LeaveIfError( iRoapClient.Connect() );
        iRoapClientConnected = ETrue;
        }

    if (!aDomainRo)
        {
        // get the trusted root from the rights issuer context
        riContext = iRoapClient.GetRIContextL(riIdPtr);
        if ( !riContext )
            {
            DRMLOG(_L("RI not registered"));
            User::Leave(KErrRightsServerRiNotRegistered);
            }
        CleanupStack::PushL(riContext);
        // connect to the storage of our PKI keys
        storage = DrmKeyStorageNewL();
        TCleanupItem storageCleanup( DeleteObject, storage );
        CleanupStack::PushL(storageCleanup);
        storage->SelectTrustedRootL(riContext->SelectedDeviceRoot());

        if (transport == EOma)
            {
            OmaCrypto::RsaKemKwsDecryptL(storage, macAndRekPtr, rek, mac);
            }
        else
            {
            CmlaCrypto::CmlaIpDecryptL(transport, storage, macAndRekPtr, rek, mac);
            }
        CleanupStack::PopAndDestroy(4, data);
        }
    else
        {
        domainContext = iRoapClient.GetDomainContextL(domainIdPtr);
        if ( !domainContext )
            {
            DRMLOG(_L("Domain not registered"));
            User::Leave(KErrRightsServerDomainNotRegistered);
            }
        CleanupStack::PushL(domainContext);

        // last three digits presents the domain generation
        TInt generation = 0;
        TLex8 lex( domainIdPtr.Right(3));
        lex.Val(generation);

        domainKey = domainContext->DomainKeyL(generation);
        CleanupStack::PushL( domainKey );

        // unwrap MAC and REK first with the domain key, the CEK with REK
        unwrappedMacAndRek = OmaCrypto::AesUnwrapL(*domainKey, macAndRekPtr);
        CleanupStack::PushL(unwrappedMacAndRek);

        mac.Copy( unwrappedMacAndRek->Left( OmaCrypto::KKeySize) );
        rek.Copy( unwrappedMacAndRek->Right( OmaCrypto::KKeySize) );
        CleanupStack::PopAndDestroy(6, data);
        }

    DRMLOG(_L("REK:"));
    DRMLOGHEX(rek);
    DRMLOG(_L("MAC:"));
    DRMLOGHEX(mac);

    iMac.Copy(mac);
    iRek.Copy(rek);

    aMessage.Complete( KErrNone );

    __UHEAP_MARKEND;

    DRMLOG( _L( "CDRMDbSession::UnwrapMacAndRekL: ok" ) );
    }

//------------------------------------------------------------------------------
// CDRMDbSession::FindParentsAndRemoveUnusableL()
// Find the best ROs from aList and store references to aBest.
//------------------------------------------------------------------------------
void CDRMDbSession::FindParentsAndRemoveUnusableL( RDRMPermissionList& aList,
                                                   const TDesC8& aURI,
                                                   CDRMPointerArray<HBufC8>& aCids,
                                                   const TIntent aIntent,
                                                   const TTime& aDrmTime,
                                                   TUint32& aReason )
    {

    CDRMPermissionList *permList = NULL;
    TInt error = KErrNone;
    HBufC8* uri = NULL;

    aCids.ResetAndDestroy();


    // to separate parents and children we store the content id, since the content id is needed
    // by drm consume:
    for( TInt count = 0; count < aList.Count(); count++ )
        {
        uri = aURI.AllocLC();
        aCids.AppendL( uri );
        CleanupStack::Pop( uri ); // uri
        }


    // Go though the list and remove the unusable RO's
    for( TInt i = aList.Count() - 1 ; i >= 0; i-- )
        {
        // If the RO has valid parent rights add them to the list
        if( aList[i]->iParentUID )
            {
            permList = CDRMPermissionList::NewLC();
            permList->SetAutoCleanup( ETrue );

            TRAP( error, DRMDB.GetDBEntryByContentIDL( *aList[i]->iParentUID, *permList ));
            if( !error )
                {
                for( TInt j = 0; j < permList->Count(); j++ )
                    {
                    // check if the permission is valid and if the RI ID for child and parent
                    // match
                    if ( aList[i]->iRiId.Compare( (*permList)[j]->iRiId ) == 0 &&
                        IsValidPermissionL( *(*permList)[j], aIntent, aDrmTime, aReason ) )
                        {
                        aList.AppendL( (*permList)[j] );
                        (*permList)[j] = 0;
                        uri = aList[i]->iParentUID->AllocLC();
                        aCids.AppendL( uri );
                        CleanupStack::Pop( uri );
                        }
                    }
                }
            CleanupStack::PopAndDestroy( permList );
            }

        // If the child is not valid remove it from the list
        if ( !IsValidPermissionL( *aList[i], aIntent, aDrmTime, aReason ) )
            {
            CDRMPermission* perm = aList[i];
            delete perm;
            aList.Remove( i );

            uri = aCids[i];
            delete uri;
            aCids.Remove( i );
            perm = NULL;
            uri = NULL;
            }
        }
    // Now the list should contain only valid RO's or parents of the RO's
    // which are valid
    }


//------------------------------------------------------------------------------
// CDRMDbSession::FindBestROsL
// Find the best ROs from aList and store references to aBest.
//------------------------------------------------------------------------------
TInt CDRMDbSession::FindBestROsL(
    RDRMPermissionList& aList,
    const TDesC8& aURI,
    const TIntent aIntent,
    HBufC8*& aUsedURI,
    TUint32& aReason )
    {
    TTime time = Time::NullTTime();
    CDRMPointerArray<HBufC8>* uriList = CDRMPointerArray<HBufC8>::NewLC();
    uriList->SetAutoCleanup(ETrue);

    TInt bestRo = -1;

    if ( iSecureTime )
        {
        time = iTrustedTime;
        }
    else
        {
        time = Time::NullTTime();
        }

    FindParentsAndRemoveUnusableL( aList, aURI, *uriList, aIntent, time, aReason );

    if( aList.Count() == 0 )
        {
        User::Leave(KErrCANoPermission);
        }

    bestRo = GetBestROL( aList, aIntent, aReason );

    // Delete if it already exists
    if( aUsedURI )
        {
        delete aUsedURI;
        }
    aUsedURI = NULL;

    // if it's not the same as the normal URI return a value otherwise NULL
    if( (*uriList)[ bestRo ]->Compare( aURI ) )
        {
        aUsedURI = (*uriList)[ bestRo ]->AllocL();
        }

    CleanupStack::PopAndDestroy( uriList );
    return bestRo;
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::IsValidPermissionL
// ETrue if not expired. If the candidate has expired permission (intent,
// not top level), ETrue is returned if the child knows it is a child.
// -----------------------------------------------------------------------------
TBool CDRMDbSession::IsValidPermissionL(
    CDRMPermission& aPermission,
    const ContentAccess::TIntent aIntent,
    const TTime& aTime,
    TUint32& aReason )
    {
    CDRMConstraint* toplevel = NULL;
    CDRMConstraint* constraint = NULL;
    CDRMDomainContext* domainContext = NULL;
    TBool r = ETrue;
    #ifdef RD_DRM_METERING
    CDRMRIContext* riContext = NULL;
    #endif

    toplevel = aPermission.TopLevelConstraint();
    if ( toplevel && ( !( toplevel->Valid( aTime, IMSI, aReason ) ) ) )
        {
        r = EFalse;
        }
    else
        {
        constraint = aPermission.ConstraintForIntent( aIntent );
        if ( !constraint || constraint &&
            ( !( constraint->Valid( aTime, IMSI, aReason ) ) ) )
            {
            r = EFalse;
            }
        else if ( aPermission.iDomainID )
            {
            if ( !iRoapClientConnected )
                {
                User::LeaveIfError( iRoapClient.Connect() );
                iRoapClientConnected = ETrue;
                }
            domainContext = iRoapClient.GetDomainContextL( *aPermission.iDomainID );
            if ( domainContext )
                {
                delete domainContext;
                }
            else
                {
                r = EFalse;
                }

            }

        // If the constraint is software constrained and the sw secureid does not match
        // remove it from the list handling
        if( r && aPermission.SoftwareConstrained() )
            {
            _LIT_SECURITY_POLICY_S0(swSidCheck, constraint->iSecureId.iUid);
            if (constraint->iActiveConstraints & EConstraintSoftware)
                {
                if (!swSidCheck().CheckPolicy(iClient))
                    {
                    r = EFalse;
                    }
                }
            }
        }

    #ifdef RD_DRM_METERING

    // Check if metering restricts the content usage
    if ( r != EFalse && constraint->iDrmMeteringInfo &&
        !constraint->iDrmMeteringInfo->iAllowUseWithoutMetering )
        {
        if ( !iRoapClientConnected )
            {
            User::LeaveIfError( iRoapClient.Connect() );
            iRoapClientConnected = ETrue;
            }
        riContext = iRoapClient.GetRIContextL( aPermission.iRiId );
        if ( !riContext || !riContext->IsMeteringAllowed() )
            {
            aReason |= EConstraintMetering;
            return EFalse;
            }
        }

    delete riContext;

    #endif

    return r;
    }

//------------------------------------------------------------------------------
// CDRMDbSession::GetBestROL
// Find the best ROs from aList and store references to aBest.
//------------------------------------------------------------------------------
TInt CDRMDbSession::GetBestROL(
    RDRMPermissionList& aList,
    const TIntent aIntent,
    TUint32& aReason )
    {
    TInt count( 0 );
    TTime time;

    CDRMConstraint* normalized = CDRMConstraint::NewLC();
    CDRMConstraint* bestOne = CDRMConstraint::NewLC();

    TInt bestRo( -1 );

    if ( iSecureTime )
        {
        time = iTrustedTime;
        }
    else
        {
        time = Time::NullTTime();
        }

    // 'count' is updated if something useful is found, and aList is
    // updated if the permission cannot be used.
    while  ( count < aList.Count() )
        {
        CDRMPermission* perm = aList[ count ];
        TBool found( EFalse );

        // If there is no constraint for the intent, there is no need to normalize
        // There can be no rights to use in that permission
        if( perm->ConstraintForIntent( aIntent ) )
            {
            Normalize( *perm, *normalized, aIntent );
            if ( normalized->Valid( time, IMSI, aReason ) )
                {
                found = ETrue;
                }
            }

        if ( found )
            {
            // Compare whether "normalized" is more suitable than "bestOne".
            // If this is the first usable child & parent combination,
            // take it.
            if ( ( bestRo < 0 ) || BetterPermission( *normalized, *bestOne ) )
                {
                // "normalized" is the new "bestOne"
                CDRMConstraint* temp = bestOne;
                bestOne = normalized;
                normalized = temp;

                bestRo = count;

                ++count;
                }
            else
                {
                // This isn't any better than the previous ones. Throw it away.
                found = EFalse;
                }
            }

        if ( !found )
            {
            // Unusable child.
            delete perm; perm = NULL;
            aList.Remove( count );
            }
        }

    CleanupStack::PopAndDestroy( 2 ); // bestOne, normalized

    return bestRo;
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::Normalize
// Normalizes a permission.
// -----------------------------------------------------------------------------
void CDRMDbSession::Normalize( CDRMPermission& aPermission,
                               CDRMConstraint& aNormalized,
                               const ContentAccess::TIntent aIntent )
    {
    __ASSERT_DEBUG( aPermission.ConstraintForIntent( aIntent ), User::Invariant() );

    TRAPD( error, aNormalized.DuplicateL( *( aPermission.ConstraintForIntent( aIntent ) ) ) );
    if( !error )
        {
        if ( aPermission.TopLevelConstraint() )
            {
            aNormalized.Merge( *( aPermission.TopLevelConstraint() ) );
            }
        }
    }
// -----------------------------------------------------------------------------
// CDRMDbSession::BetterPermission
// Compares two permissions, and returns ETrue if aNewOne is more suitable
// for the usage. Assumes both are valid, i.e. not expired.
// -----------------------------------------------------------------------------
TBool CDRMDbSession::BetterPermission( const CDRMConstraint& aNewOne,
                                       const CDRMConstraint& aOldOne )
    {
    // Check Order:
    // 1. Full
    // 2. Start End, closest end time first
    // 3. Interval, shortest first
    // 4. Accumulated, shortest first
    // 5. Timed Counter, least counters first, longest time first
    // 6. Counter, least counters first or the first one found

    const TTime nullTime = Time::NullTTime();
    TTime oldTime = nullTime;
    TTime newTime = nullTime;
    TTime oldTimePos = nullTime;
    TTime newTimePos = nullTime;

    // 1. Full
    // If the old or new one is the ultimate one, don't bother to
    // check anything else.
    if ( aOldOne.iActiveConstraints == EConstraintNone )
        {
        return EFalse;
        }

    if ( aNewOne.iActiveConstraints == EConstraintNone )
        {
        return ETrue;
        }

    // 2. Start & End Time
    // Choose the one with the closest end time first
    // All RO's to this check are already checked to be valid
    // ActiveIntervals Also hit this spot

    // First get the start and end times from the intervals if they are active or inactive:
    if ( aOldOne.iActiveConstraints & EConstraintInterval )
        {
        if( aOldOne.iIntervalStart == nullTime )
            {
            oldTimePos = iTrustedTime;
            oldTimePos += TTimeIntervalSeconds( aOldOne.iInterval );
            }
        else
            {
            oldTime = aOldOne.iIntervalStart;
            oldTime += TTimeIntervalSeconds( aOldOne.iInterval );
            }
        }

    if( aNewOne.iActiveConstraints & EConstraintInterval )
        {
        if( aNewOne.iIntervalStart == nullTime )
            {
            newTimePos = iTrustedTime;
            newTimePos += TTimeIntervalSeconds( aNewOne.iInterval );
            }
        else
            {
            newTime = aNewOne.iIntervalStart;
            newTime += TTimeIntervalSeconds( aNewOne.iInterval );
            }
        }

    if ( aOldOne.iActiveConstraints & EConstraintEndTime || oldTime != nullTime )
        {
        oldTime = EndTime( oldTime, aOldOne.iEndTime );

        if ( aNewOne.iActiveConstraints & EConstraintEndTime || newTime != nullTime )
            {
            newTime = EndTime( newTime, aNewOne.iEndTime );

            if( newTime != oldTime )
                {
                return ( newTime < oldTime );
                }
            }
        else
            {
            return EFalse;
            }
        }
    else if ( aNewOne.iActiveConstraints & EConstraintEndTime || newTime != nullTime )
        {
        return ETrue;
        }


    // 3. Inactive Intervals:
    // Choose the one with the interval ending first:
    // Continue here if the no SE's exist or SE's are the same
    if( aOldOne.iActiveConstraints & EConstraintInterval )
        {
        if( aNewOne.iActiveConstraints & EConstraintInterval )
            {
            oldTimePos = EndTime( oldTime, oldTimePos );
            newTimePos = EndTime( newTime, newTimePos );

            if( oldTimePos != newTimePos )
                {
                return ( newTimePos < oldTimePos );
                }
            }
        else
            {
            if( aNewOne.iActiveConstraints & EConstraintAccumulated ||
                aNewOne.iActiveConstraints & EConstraintTimedCounter ||
                aNewOne.iActiveConstraints & EConstraintCounter )
                {
                return EFalse;
                }
            else
                {
                return ETrue;
                }
            }
        }
    else if( aNewOne.iActiveConstraints & EConstraintInterval )
        {
        if( aOldOne.iActiveConstraints & EConstraintAccumulated ||
            aOldOne.iActiveConstraints & EConstraintTimedCounter ||
            aOldOne.iActiveConstraints & EConstraintCounter )
            {
            return ETrue;
            }
        else
            {
            return EFalse;
            }
        }

    // 4. Accumulated:
    // Choose the shortest accumulated first
    // Continue here if SE's or intervals do not exist or they are the same
    if( aOldOne.iActiveConstraints & EConstraintAccumulated )
        {
        if( aNewOne.iActiveConstraints & EConstraintAccumulated )
            {
            if( aNewOne.iAccumulatedTime != aOldOne.iAccumulatedTime )
                {
                return ( aNewOne.iAccumulatedTime < aOldOne.iAccumulatedTime );
                }
            }
        else
            {
            if( aNewOne.iActiveConstraints & EConstraintTimedCounter ||
                aNewOne.iActiveConstraints & EConstraintCounter )
                {
                return EFalse;
                }
            else
                {
                return ETrue;
                }
            }
        }
    else if( aNewOne.iActiveConstraints & EConstraintAccumulated )
        {
        if( aOldOne.iActiveConstraints & EConstraintTimedCounter ||
            aOldOne.iActiveConstraints & EConstraintCounter )
            {
            return ETrue;
            }
        else
            {
            return EFalse;
            }
        }


    // 5. Timed Counter
    // Choose the one with least counters first. If there is an equal number of counters
    // left, use the one with the longest time
    // Continue here if SE's or intervals or accumulateds do not exist or they are the same
    if( aOldOne.iActiveConstraints & EConstraintTimedCounter )
        {
        if( aNewOne.iActiveConstraints & EConstraintTimedCounter )
            {
            if( aNewOne.iTimedCounter == aOldOne.iTimedCounter )
                {
                if( aNewOne.iTimedInterval != aOldOne.iTimedInterval )
                    {
                    return ( aNewOne.iTimedInterval < aOldOne.iTimedInterval );
                    }
                else
                    {
                    if( aNewOne.iActiveConstraints & EConstraintCounter )
                        {

                        }
                    }
                }
            else
                {
                return ( aNewOne.iTimedCounter < aOldOne.iTimedCounter );
                }

            }
        else
            {
            if( aNewOne.iActiveConstraints & EConstraintCounter )
                {
                return EFalse;
                }
            else
                {
                return ETrue;
                }
            }
        }
    else if( aNewOne.iActiveConstraints & EConstraintTimedCounter )
        {
        if( aOldOne.iActiveConstraints & EConstraintCounter )
            {
            return ETrue;
            }
        else
            {
            return EFalse;
            }
        }

    // 6. Counter
    // Choose the one with least counters:
    // if they are the same choose the first one.
    // Continue here if SE's or intervals or accumulateds or timed counters
    // do not exist or they are the same
    if( aOldOne.iActiveConstraints & EConstraintCounter )
        {
        if( aNewOne.iActiveConstraints & EConstraintCounter )
            {
            return ( aNewOne.iCounter < aOldOne.iCounter );
            }
        else
            {
            return ETrue;
            }
        }

    // If all else fails use the old one:
    return EFalse;
    }


// -----------------------------------------------------------------------------
// CDRMDbSession::BetterPermission
// Compares two permissions, and returns ETrue if aNewOne is more suitable
// for the usage. Assumes both are valid, i.e. not expired.
// -----------------------------------------------------------------------------
TBool BetterPermissionOld( const CDRMConstraint& aNewOne,
    const CDRMConstraint& aOldOne ) //const
    {

    const TTime nullTime = Time::NullTTime();
    TTime oldTime = nullTime;
    TTime newTime = nullTime;
    TBool inactiveIntervals = EFalse;

    // If the old or new one is the ultimate one, don't bother to
    // check anything else.
    if ( aOldOne.iActiveConstraints == EConstraintNone )
        {
        return EFalse;
        }

    if ( aNewOne.iActiveConstraints == EConstraintNone )
        {
        return ETrue;
        }

    // If old one has count constraints but the new doesn't, the new
    // is better. If the old one doesn't have counters but the
    // new has, the old one is better.
    if ( aOldOne.iActiveConstraints & EConstraintCounter )
        {
        if ( !( aNewOne.iActiveConstraints & EConstraintCounter ) ||
             ( aNewOne.iCounter < aOldOne.iCounter ) )
            {
            return ETrue;
            }
        }
    else
        {
        if ( aNewOne.iActiveConstraints & EConstraintCounter )
            {
            return EFalse;
            }
        }

    if ( aOldOne.iActiveConstraints & EConstraintTimedCounter )
        {
        if ( !( aNewOne.iActiveConstraints & EConstraintTimedCounter ) ||
             ( aNewOne.iTimedCounter < aOldOne.iTimedCounter ) )
            {
            return ETrue;
            }
        }
    else
        {
        if ( aNewOne.iActiveConstraints & EConstraintTimedCounter )
            {
            return EFalse;
            }
        }

    if ( aOldOne.iActiveConstraints & EConstraintAccumulated )
        {
        if ( !( aNewOne.iActiveConstraints & EConstraintAccumulated ) ||
             ( aNewOne.iAccumulatedTime < aOldOne.iAccumulatedTime ) )
            {
            return ETrue;
            }
        }
    else
        {
        if ( aNewOne.iActiveConstraints & EConstraintAccumulated )
            {
            return EFalse;
            }
        }

    // - No intervals is better than inactive intervals.
    // - No intervals compared to activated interval goes to
    //   end time constraint comparison.
    // - Activated interval is better than inactive interval.
    // - Two inactive intervals go to end time constraint comparison.
    if ( aOldOne.iActiveConstraints & EConstraintInterval )
        {
        if ( aNewOne.iActiveConstraints & EConstraintInterval )
            {
            if ( aOldOne.iIntervalStart == nullTime )
                {
                if ( aNewOne.iIntervalStart != nullTime )
                    {
                    return ETrue;
                    }

                // Both have inactive intervals.
                inactiveIntervals = ETrue;

//                oldTime = iTrustedTime;
                oldTime += TTimeIntervalSeconds( aOldOne.iInterval );

//                newTime = iTrustedTime;
                newTime += TTimeIntervalSeconds( aNewOne.iInterval );
                }
            else
                {
                // Old one has activated interval.
                if ( aNewOne.iIntervalStart == nullTime )
                    {
                    return EFalse;
                    }

                // Both have activated intervals.
                oldTime = aOldOne.iIntervalStart;
                oldTime += TTimeIntervalSeconds( aOldOne.iInterval );

                newTime = aNewOne.iIntervalStart;
                newTime += TTimeIntervalSeconds( aNewOne.iInterval );
                }
            }
        else
            {
            // No intervals in the new one.
            if ( aOldOne.iIntervalStart == nullTime )
                {
                return ETrue;
                }

            oldTime = aOldOne.iIntervalStart;
            oldTime += TTimeIntervalSeconds( aOldOne.iInterval );
            }
        }
    else
        {
        // The old one doesn't have intervals.
        if ( aNewOne.iActiveConstraints & EConstraintInterval )
            {
            if ( aNewOne.iIntervalStart == nullTime )
                {
                return EFalse;
                }

            newTime = aNewOne.iIntervalStart + TTimeIntervalSeconds( aNewOne.iInterval );
            }
        }

    if ( inactiveIntervals )
        {
        // The one with end time goes first.
        if ( aOldOne.iActiveConstraints & EConstraintEndTime )
            {
            if ( aNewOne.iActiveConstraints & EConstraintEndTime )
                {
                oldTime = EndTime( oldTime, aOldOne.iEndTime );
                newTime = EndTime( newTime, aNewOne.iEndTime );

                return ( newTime < oldTime );
                }

            return EFalse;
            }

        if( aNewOne.iActiveConstraints & EConstraintEndTime )
            {
            return ETrue;
            }

        // Both have just inactive intervals.
        return ( newTime < oldTime );
        }

    // Check end times and/or activated intervals.
    if ( aOldOne.iActiveConstraints & EConstraintEndTime || oldTime != nullTime )
        {
        oldTime = EndTime( oldTime, aOldOne.iEndTime );

        if ( aNewOne.iActiveConstraints & EConstraintEndTime || newTime != nullTime )
            {
            newTime = EndTime( newTime, aNewOne.iEndTime );

            return ( newTime < oldTime );
            }

        // The new one doesn't have end time constraint and/or activated intervals.
        return EFalse;
        }

    if ( aNewOne.iActiveConstraints & EConstraintEndTime || newTime != nullTime )
        {
        return ETrue;
        }

    // Start time does not expire, so let's keep the old one.

    return EFalse;
    }


// ----------------------------------------------------------------------------
// UnwrapProtectedCekL
// Unwraps the protected CEK aProtectedCek. Caller owns the returned buffer.
// ----------------------------------------------------------------------------
//
HBufC8* CDRMDbSession::UnwrapProtectedCekL(
    const TDesC8& aProtectedCek )
    {
    MDrmKeyStorage* storage;
    TBuf8<OmaCrypto::KMacSize> mac;
    TBuf8<OmaCrypto::KKeySize> rek;
    HBufC8* cek = NULL;
    TPtrC8 macAndRek(0, 0);
    TPtrC8 wrappedCek(0, 0);
    TKeyTransportScheme transport;
    TBuf8<KRiIdSize> rightsIssuer;
    CDRMRIContext* riContext = NULL;
    TInt i;
    TInt len;

    DRMLOG(_L("CDRMDbSession::UnwrapProtectedCekL"));

    // first element: one byte for the transport scheme
    i = 0;
    transport = static_cast<TKeyTransportScheme>(aProtectedCek[i]);
    i++;

    DRMLOG2(_L("Transport scheme: %d"), transport);

    // second element: the concatenated MAC and REK wrapped with the KEK
    len = aProtectedCek[i];
    macAndRek.Set(aProtectedCek.Mid(i + 1, len));
    i = i + 1 + len;
    DRMLOG(_L("MAC + REK:"));
    DRMLOGHEX(macAndRek);

    // third element: 20 bytes with the rights issuer ID
    len = aProtectedCek[i];
    rightsIssuer.Copy(aProtectedCek.Mid(i + 1, len));
    i = i + 1 + len;
    DRMLOG(_L("RI ID:"));
    DRMLOGHEX(rightsIssuer);

    // get the trusted root from the rights issuer context
    if ( !iRoapClientConnected )
        {
        User::LeaveIfError( iRoapClient.Connect() );
        iRoapClientConnected = ETrue;
        }
    riContext = iRoapClient.GetRIContextL(rightsIssuer);
    if ( !riContext )
        {
        DRMLOG(_L("RI not registered"));
        User::Leave(KErrRightsServerRiNotRegistered);
        }
    CleanupStack::PushL(riContext);

    // connect to the storage of our PKI keys
    storage = DrmKeyStorageNewL();
    TCleanupItem storageCleanup( DeleteObject, storage );
    CleanupStack::PushL(storageCleanup);
    storage->SelectTrustedRootL(riContext->SelectedDeviceRoot());

    if (transport == EOma)
        {
        OmaCrypto::RsaKemKwsDecryptL(storage, macAndRek, rek, mac);
        }
    else
        {
        CmlaCrypto::CmlaIpDecryptL(transport, storage, macAndRek, rek, mac);
        }

    DRMLOG(_L("REK:"));
    DRMLOGHEX(rek);
    DRMLOG(_L("MAC:"));
    DRMLOGHEX(mac);

    iMac.Copy(mac);
    iRek.Copy(rek);

    // fourth element: 24 bytes for the CEK (wrapped with the REK),
    // this can be empty, e.g. for a parent RO (indicated by a zero length)
    len = aProtectedCek[i];
    if (len > 0)
        {
        wrappedCek.Set(aProtectedCek.Mid(i + 1, len));
        DRMLOG(_L("Wrapped CEK:"));
        DRMLOGHEX(wrappedCek);
        cek = OmaCrypto::AesUnwrapL(rek, wrappedCek);
        DRMLOG(_L("CEK:"));
        DRMLOGHEX(( *cek ));
        }
    else
        {
        DRMLOG(_L("No CEK"));
        cek = KNullDesC8().AllocL();
        }

    CleanupStack::PopAndDestroy(2); // riContext, storageCleanup
    return cek;
    }

// ----------------------------------------------------------------------------
// UnwrapDomainCekL
// Unwraps CEK with is wrapped with a domain key. Caller owns the returned
// buffer.
// ----------------------------------------------------------------------------
//
HBufC8* CDRMDbSession::UnwrapDomainCekL(
    const TDesC8& aProtectedCek,
    const TDesC8& aDomainId )
    {
    HBufC8* unwrappedMacAndRek = NULL;
    HBufC8* cek = NULL;
    TPtrC8 macAndRek(0, 0);
    TPtrC8 wrappedCek(0, 0);
    CDRMDomainContext* domainContext;
    HBufC8* domainKey = NULL;
    TInt i;
    TInt len;

    DRMLOG(_L("CDRMDbSession::UnwrapDomainCekL"));

    // first element (one byte for the transport scheme) is ignored
    i = 1;

    // second element: MAC and REK wrapped with the domain key (40 bytes)
    len = aProtectedCek[i];
    macAndRek.Set(aProtectedCek.Mid(i + 1, len));
    i = i + 1 + len;
    DRMLOG(_L("MAC + REK:"));
    DRMLOGHEX(macAndRek);

    // third element: 20 bytes with the rights issuer ID, is ignored
    len = aProtectedCek[i];
    i = i + 1 + len;

    // fourth element: 24 bytes for the CEK (wrapped with the REK)
    len = aProtectedCek[i];
    wrappedCek.Set(aProtectedCek.Mid(i + 1, len));
    DRMLOG(_L("Wrapped CEK:"));
    DRMLOGHEX(wrappedCek);

    // get the domain key from the domain context
    if ( !iRoapClientConnected )
        {
        User::LeaveIfError( iRoapClient.Connect() );
        iRoapClientConnected = ETrue;
        }
    domainContext = iRoapClient.GetDomainContextL(aDomainId);
    if ( !domainContext )
        {
        DRMLOG(_L("Domain not registered"));
        User::Leave(KErrRightsServerDomainNotRegistered);
        }
    CleanupStack::PushL(domainContext);

    // last three digits presents the domain generation
    TInt generation = 0;
    TLex8 lex( aDomainId.Right(3));
    lex.Val(generation);

    domainKey = domainContext->DomainKeyL(generation);
    CleanupStack::PushL( domainKey );

    // unwrap MAC and REK first with the domain key, the CEK with REK
    unwrappedMacAndRek = OmaCrypto::AesUnwrapL(*domainKey, macAndRek);
    CleanupStack::PushL(unwrappedMacAndRek);
    cek = OmaCrypto::AesUnwrapL(unwrappedMacAndRek->Right(
            OmaCrypto::KKeySize), wrappedCek);
    iMac.Copy( unwrappedMacAndRek->Left( OmaCrypto::KKeySize) );
    CleanupStack::PopAndDestroy(3); // unwrappedMacAndRek, domainKey, domainContext

    return cek;
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::VerifyCredentials
// Check if the client has enough credentials to grant access to later
// decryption.
// ----------------------------------------------------------------------------
//
TInt CDRMDbSession::VerifyCredentials(
    HBufC8* aContentId,
    CDRMPermission* aPermission,
    TIntent aIntent)
    {
    CDRMConstraint* constraint = NULL;
    _LIT_SECURITY_POLICY_C1(drmCheck, ECapabilityDRM);
    _LIT_SECURITY_POLICY_V0(vidCheck, VID_DEFAULT); // Check Default VID
    RPointerArray<CDRMPermission> permissions;
    TInt r = KErrAccessDenied;
    TBool hasOma2Permissions = EFalse;
    TBool hasSoftwareConstraints = EFalse;
    TInt i;

    __UHEAP_MARK;
    // Get the applicable permission, and check if there are OMA 2 permissions or
    // software constraints
    if (aPermission)
        {
        constraint = aPermission->ConstraintForIntent(aIntent);
        }
    if ( aContentId )
        {
        TRAP_IGNORE( DRMDB.GetDBEntryByContentIDL(*aContentId, permissions) );
        for (i = 0; i < permissions.Count(); i++)
            {
            if (permissions[i]->iRightsObjectVersion.iVersionMain == EOma2Rights ||
                permissions[i]->iRightsObjectVersion.iVersionMain == ECmlaRights)
                {
                hasOma2Permissions = ETrue;
                }
            if (permissions[i]->SoftwareConstrained())
                {
                hasSoftwareConstraints = ETrue;
                }
            }
        permissions.ResetAndDestroy();
        permissions.Close();
        }

    // First, check for DRM capability, access granted only if there are no software
    // constraints.
    if (drmCheck().CheckPolicy(iClient) && !hasSoftwareConstraints)
        {
        r = KErrNone;
        }

    // If a permission is given, check for license manager cases as well as
    // OMA DRM 1.0 case
    if ( r != KErrNone && aPermission )
        {
        // Fallback: Check if the vendor ID is the default vendor ID,
        // allow access for OMA DRM 1.0 rights
        if ((aPermission->iRightsObjectVersion.iVersionMain == EOma1Rights &&
             vidCheck().CheckPolicy(iClient)))
            {
            r = KErrNone;
            }

        // Check the software constraint, this can override the fallback above!
        if ( constraint )
            {
            _LIT_SECURITY_POLICY_S0(swSidCheck, constraint->iSecureId.iUid);
            _LIT_SECURITY_POLICY_V0(swVidCheck, constraint->iVendorId.iUid);
            if (constraint->iActiveConstraints & EConstraintVendor)
                {
                if (swVidCheck().CheckPolicy(iClient))
                    {
                    r = KErrNone;
                    }
                else
                    {
                    r = KErrAccessDenied;
                    }
                }
            if (constraint->iActiveConstraints & EConstraintSoftware)
                {
                if (swSidCheck().CheckPolicy(iClient))
                    {
                    r = KErrNone;
                    }
                else
                    {
                    r = KErrAccessDenied;
                    }
                }
            }

        }

    // Application installer needs to be able to use the content even if it has SW constraints
    _LIT_SECURITY_POLICY_S0(swSidCheck2, KAppInstSrv);

    if( swSidCheck2().CheckPolicy(iClient) && hasSoftwareConstraints )
        {
        r = KErrNone;
        }


    // Check if access can be granted when only
    // OMA DRM 1.0 permissions are currently available, and the client
    // has the default vendor ID
    if ( r != KErrNone && !hasOma2Permissions &&
        !hasSoftwareConstraints && vidCheck().CheckPolicy( iClient ) )
        {
        r = KErrNone;
        }
    __UHEAP_MARKEND;

    if ( r == KErrNone )
        {
        iCredentialsChecked = ECheckedAndAllowed;
        }
    else
        {
        iCredentialsChecked = ECheckedAndDenied;
        }
    return r;
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::RemoveInvalidPermissionsL
// Remove all permissions where the domain context is not available
// ----------------------------------------------------------------------------
//
void CDRMDbSession::RemoveInvalidPermissionsL(
    CDRMPermissionList* aList )
    {
    CDRMDomainContext* domainContext = NULL;
    TInt i;
    if ( !iRoapClientConnected )
        {
        User::LeaveIfError( iRoapClient.Connect() );
        iRoapClientConnected = ETrue;
        }
    for ( i = aList->Count() - 1; i >= 0; i-- )
        {
        if ( (*aList)[i]->iDomainID )
            {
            domainContext = iRoapClient.GetDomainContextL(
                *(*aList)[i]->iDomainID );
            if ( domainContext )
                {
                delete domainContext;
                }
            else
                {
                aList->Remove( i );
                }
            }
        }
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::SetNameL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::SetNameL" ) );
    __UHEAP_MARK;

    SanitizeL( aMessage.GetDesLength( 0 ) );
    SanitizeL( aMessage.GetDesLength( 1 ) );

    TInt namelength = User::LeaveIfError( IPCGETDESLEN1 );
    HBufC8* cid = HBufC8::NewLC( IPCGETDESLEN0 );
    HBufC* name = HBufC::NewLC( namelength > 0 ? namelength : 1 );
    TPtr8 tmp( cid->Des() );

    IPCREAD0L( tmp );
    if ( namelength )
        {
        TPtr tmp2( name->Des() );
        IPCREAD1L( tmp2 );
        }

    DRMDB.NameContentL( *cid, *name );

    CleanupStack::PopAndDestroy( 2 );
    __UHEAP_MARKEND;
    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetNameL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetNameL" ) );
    HBufC8* cid = NULL;
    TPckgBuf< TInt > size( 0 );

    // Cleanup.
    if ( iWidePreparedData )
        {
        delete iWidePreparedData;
        iWidePreparedData = NULL;
        }

    SanitizeL( aMessage.GetDesLength( 0 ) );
    cid = HBufC8::NewLC( IPCGETDESLEN0 );
    TPtr8 tmp( cid->Des() );
    IPCREAD0L( tmp );

    iWidePreparedData = DRMDB.ContentNameLC( *cid );

    CleanupStack::Pop( iWidePreparedData );
    CleanupStack::PopAndDestroy( cid );

    size() = iWidePreparedData->Length();
    if ( iWidePreparedData->Length() == 0 )
        {
        // Empty name --> not asked.
        delete iWidePreparedData;
        iWidePreparedData = NULL;
        }

    IPCWRITE1L( size );

    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetWideDataL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSesion::GetWideDataL" ) );
    if ( iWidePreparedData )
        {
        if( iWidePreparedData->Length() > aMessage.GetDesMaxLength(0) )
            {
            User::Leave(KErrArgument);
            }

        IPCWRITE0L( *iWidePreparedData );

        delete iWidePreparedData;
        iWidePreparedData = NULL;

        aMessage.Complete( KErrNone );
        return;
        }

    aMessage.Complete( KErrNotReady );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::Cancel( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::Cancel" ) );
    if ( iPendingRequest )
        {
        static_cast<CDRMActiveOperation*>(iPendingRequest)->Remove();
        }

    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetFLUriL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetFLUriL" ) );

    TBuf8< KMaxOmaV1CIDLength > URI;

    GetFlURI( URI );

    if( URI.Length() > aMessage.GetDesMaxLength(0) )
        {
        User::Leave(KErrArgument);
        }

    IPCWRITE0L( URI );
    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::EncodeRightsIssuerL( const RMessage2& aMessage )
    {
    __UHEAP_MARK;

    DRMLOG( _L( "CRMDbSession::EncodeRightsIssuerL" ) );
    TBuf8< KDCFKeySize > iv;
    HBufC8* data( NULL );
    HBufC8* tmp( NULL );
    iv.SetLength( KDCFKeySize );

    TInt size( User::LeaveIfError( IPCGETDESLEN0 ) );
    TPtr8 des( NULL, 0, 0 );

    if ( size < 1 )
        {
        User::Leave( KErrArgument );
        }

    // Calculate the size. It could be retrieved also from GetDesMaxLength,
    // but at least now we can be sure we won't panic in case of
    // descriptor overflow.
    size += KDCFKeySize - ( size % KDCFKeySize ); //padding
    size += KDCFKeySize; //iv
    size = ( size + 2 ) / 3 * 4; //base64
    size += IMEI.Length();
    size += KFLPrefixLength;

    data = HBufC8::NewLC( size < KMaxOmaV1CIDLength ? KMaxOmaV1CIDLength : size );
    des.Set( data->Des() );

    GetFlURI( des );

    tmp = DRMDB.GetDecryptionKeyL( *data );
    CleanupStack::PushL( tmp );

    // Get the data from client.
    IPCREAD0L( des );
    GenerateIVL( iv );

    // Fits ok.
    AesEncryptL( *tmp, iv, ETrue, des );

    CleanupStack::PopAndDestroy( tmp );

    // Fits ok.
    des.Insert( 0, iv );

    tmp = Base64EncodeL( *data );

    __ASSERT_DEBUG( tmp->Length() + KFLPrefixLength + IMEI.Length() <= size,
        User::Invariant() );

    // Overwrite the original data.
    des = KFLPrefix;
    des.Append( IMEI );
    des.Append( *tmp );

    delete tmp;
    tmp = NULL;

    IPCWRITE0L( *data );

    CleanupStack::PopAndDestroy( data );

    aMessage.Complete( KErrNone );

    __UHEAP_MARKEND;
    }


// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::DecodeRightsIssuerL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::DecodeRightsIssuerL" ) );
    __UHEAP_MARK;

    HBufC8* data( NULL );
    TInt size( IPCGETDESLEN0 );
    TPtr8 des( NULL, 0, 0 );

    if ( !size )
        {
        User::Leave( KErrArgument );
        }

    SanitizeL( size );

    data = HBufC8::NewLC( size );
    des.Set( data->Des() );

    IPCREAD0L( des );

    if ( des.Left( KFLPrefixLength ).Compare( KFLPrefix ) == 0 )
        {
        HBufC8* tmp( NULL );
        HBufC8* tmp2( NULL );
        TPtr8 des2( NULL, 0, 0 );

        tmp = CnvUtfConverter::ConvertFromUnicodeToUtf8L( IMEI );
        CleanupStack::PushL( tmp );

        if ( des.Mid( KFLPrefixLength, IMEI.Length() ).Compare( *tmp ) )
            {
            User::Leave( KErrCANoPermission );
            }

        tmp2 = Base64DecodeL( des.Mid( KFLPrefixLength + tmp->Length() ) );

        *data = *tmp2;

        delete tmp2;
        tmp2 = NULL;

        CleanupStack::PopAndDestroy( tmp );

        if ( ( data->Length() % KDCFKeySize ) ||
             data->Length() < ( KDCFKeySize << 1 ) )
            {
            User::Leave( KErrArgument );
            }

        tmp = HBufC8::NewLC( KMaxOmaV1CIDLength );

        des.Set( tmp->Des() );

        GetFlURI( des );

        tmp2 = DRMDB.GetDecryptionKeyL( *tmp );

        CleanupStack::PopAndDestroy( tmp );
        CleanupStack::PushL( tmp2 );

        des2.Set( const_cast< TText8* >( data->Ptr() ),
            KDCFKeySize,
            KDCFKeySize );

        // AesDecrypt overwrites the data.
        des.Set( const_cast< TText8* >( data->Ptr() ) + KDCFKeySize,
            data->Length() - KDCFKeySize,
            data->Length() - KDCFKeySize );

        AesDecryptL( *tmp2, des2, ETrue, des );

        // Erase the key.
        des2.Set( tmp2->Des() );
        des2.FillZ();

        CleanupStack::PopAndDestroy( tmp2 );

        if( des.Length() > aMessage.GetDesMaxLength(1) )
            {
            User::Leave(KErrArgument);
            }
        IPCWRITE1L( des );
        }

    // Something else, can't handle it. Leave it as it is.
    CleanupStack::PopAndDestroy( data );

    aMessage.Complete( KErrNone );

    __UHEAP_MARKEND;

    DRMLOG( _L( "CDRMDbSession::DecodeRightsIssuerL ok" ) );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetFlURI( TDes8& aURI )
    {
    aURI = KFLLongPrefix;
    aURI.Append( IMEI );
    aURI.Append( KFLSuffix );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::AesEncryptL
// Encrypt data using a given key
// ----------------------------------------------------------------------------
//
void CDRMDbSession::AesEncryptL( const TDesC8& aKey,
                                 const TDesC8& aIV,
                                 const TBool aAddPadding,
                                 TDes8& aData )
    {
    DRMLOG( _L( "CDRMDbSession::AesEncryptL" ) );

    __UHEAP_MARK;

    CModeCBCEncryptor* cbc( NULL );
    TInt lastBlockStart( 0 );
    TPtr8 data( NULL, 0, 0 );

    if( aIV.Length() % KDCFKeySize ||
        aKey.Length() % KDCFKeySize )
        {
        User::Leave( KErrArgument );
        }

    cbc = CModeCBCEncryptor::NewL( CAESEncryptor::NewLC( aKey ), aIV );
    CleanupStack::Pop(); // CAESEncryptor, owned by cbc.
    CleanupStack::PushL( cbc );

    lastBlockStart = aData.Length() - ( aData.Length() % KDCFKeySize );
    for ( TInt i = 0; i  < lastBlockStart; i+= KDCFKeySize )
        {
        data.Set( aData.MidTPtr( i, KDCFKeySize ) );

        cbc->Transform( data );
        }

    if ( aAddPadding )
        {
        TInt dataLength = aData.Length();
        TUint8 padding( static_cast< TUint8 >
            ( lastBlockStart + KDCFKeySize - dataLength ) );

        __ASSERT_DEBUG( lastBlockStart + KDCFKeySize - dataLength <= KDCFKeySize,
                        User::Invariant() );

        aData.SetLength( lastBlockStart + KDCFKeySize );

        for ( TInt i = dataLength; i < aData.Length(); ++i )
            {
            aData[ i ] = padding;
            }

        data.Set( aData.MidTPtr( lastBlockStart, KDCFKeySize ) );
        cbc->Transform( data );
        }

    CleanupStack::PopAndDestroy( cbc );

    __UHEAP_MARKEND;

    DRMLOG( _L( "CDRMDbSession::AesEncryptL ok" ) );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::AesDecryptL
// Decrypt data using a given key
// ----------------------------------------------------------------------------
//
void CDRMDbSession::AesDecryptL( const TDesC8& aKey,
                                 const TDesC8& aIV,
                                 const TBool aRemovePadding,
                                 TDes8& aData )
    {
    DRMLOG( _L( "CDRMDbSession::AesDecryptL" ) );

    __UHEAP_MARK;

    CModeCBCDecryptor* cbc( NULL );

    cbc = CModeCBCDecryptor::NewL(
        CAESDecryptor::NewLC( aKey ), aIV );

    CleanupStack::Pop(); // CAESDecryptor

    __ASSERT_DEBUG( ( aData.Length() >= 0 ) &&
                    ( aData.Length() % KDCFKeySize == 0 ),
                    User::Invariant() );

    for ( TInt count = 0; count < aData.Length(); count += KDCFKeySize )
        {
        TPtr8 d( aData.MidTPtr( count, KDCFKeySize ) );

        cbc->Transform( d );
        }

    delete cbc; cbc = NULL;

    if ( aRemovePadding )
        {
        TInt count( aData.Length() );
        TUint8 c( aData[ count - 1 ] );

        if ( c > KDCFKeySize )
            {
            User::Leave( KErrCorrupt );
            }

        aData.SetLength( count - c );
        }

    __UHEAP_MARKEND;

    DRMLOG( _L( "CDRMDbSession::AesDecryptL ok" ) );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GenerateIVL( TDes8& aIV )
    {
    DRMLOG( _L( "CDRMDbSession::GenerateIVL" ) );
    __UHEAP_MARK;

    __ASSERT_DEBUG( aIV.MaxSize() >= KDCFKeySize, User::Invariant() );
    MDrmKeyStorage* storage = DrmKeyStorageNewL();
    TCleanupItem storageCleanup( DeleteObject, storage );
    CleanupStack::PushL(storageCleanup);

    storage->RandomDataGetL(aIV,KDCFKeySize);
    CleanupStack::PopAndDestroy( storage );

    DRMLOG(_L("random aIV:"));
    DRMLOGHEX(aIV);


    __UHEAP_MARKEND;
    DRMLOG( _L( "CDRMDbSession::GenerateIVL ok" ) );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::AsyncOperationDone()
    {
    DRMLOG( _L( "CDRMDbSession::AsyncOperationDone" ) );
    // All done.
    delete iPendingRequest;
    iPendingRequest = NULL;
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::
//
// ----------------------------------------------------------------------------
//
void CDRMDbSession::AsyncOperationDone( TFileName* aFileName )
    {
    DRMLOG( _L( "CDRMDbSession::AsyncOperationDone" ) );
    // All done.
    delete iPendingRequest;
    iPendingRequest = NULL;

    iFileName = aFileName;
    }


// ----------------------------------------------------------------------------
// CDRMDbSession::SetAuthenticationSeedL
// Sets the authentication seed for a content ID. Requires that the REK and KEK
// have been set during a previous AddRecord operation
// ----------------------------------------------------------------------------
//
void CDRMDbSession::SetAuthenticationSeedL( const RMessage2& aMessage )
    {
    DRMLOG(_L("CDRMDbSession::SetAuthenticationSeedL"));

    __UHEAP_MARK;
    SanitizeL( aMessage.GetDesLength(0));
    SanitizeL( aMessage.GetDesLength(1));

    HBufC8* cid = HBufC8::NewLC(IPCGETDESLEN0);
    HBufC8* wrappedSeed = HBufC8::NewLC(IPCGETDESLEN1);
    HBufC8* seed = NULL;

    if (iRek.Length() == 0)
        {
        User::Leave(KErrNotReady);
        }

    TPtr8 tmp(cid->Des());
    IPCREAD0L(tmp );
    TPtr8 tmp2(wrappedSeed->Des());
    IPCREAD1L(tmp2);

    seed = OmaCrypto::AesUnwrapL(iRek, *wrappedSeed);
    CleanupStack::PushL(seed);
    DRMDB.SetAuthenticationSeedL(*cid, *seed);
    CleanupStack::PopAndDestroy(3); // seed, wrappedSeed, cid
    __UHEAP_MARKEND;
    aMessage.Complete(KErrNone);
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::GetAuthenticationSeedL
// Returns the authentication seed for a content ID
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetAuthenticationSeedL( const RMessage2& aMessage )
    {
    DRMLOG(_L("CDRMDbSession::GetAuthenticationSeedL"));

    __UHEAP_MARK;
    HBufC8* cid = NULL;
    HBufC8* seed = NULL;

    SanitizeL( aMessage.GetDesLength(0));
    cid = HBufC8::NewLC(IPCGETDESLEN0);

    TPtr8 tmp(cid->Des());
    IPCREAD0L(tmp);
    User::LeaveIfError(VerifyCredentials(cid, NULL, EUnknown));
    seed = DRMDB.GetAuthenticationSeedL(*cid);
    CleanupStack::PushL(seed);

    if( seed->Length() > aMessage.GetDesMaxLength(1) )
        {
        User::Leave(KErrArgument);
        }

    IPCWRITE1L(*seed);
    CleanupStack::PopAndDestroy(2); // seed, cid
    __UHEAP_MARKEND;
    aMessage.Complete(KErrNone);
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::VerifyMacL
// Integrity protection for protecets ROs
// ----------------------------------------------------------------------------
//
void CDRMDbSession::VerifyMacL( const RMessage2& aMessage )
    {
    DRMLOG(_L("CDRMDbSession::VerifyMacL"));

    if( !iMac.Length() )
        {
        User::Leave(KErrNotReady);
        }

    __UHEAP_MARK;

    CHMAC* hMac = NULL;
    CSHA1* sha = NULL;
    TPtrC8 hmac_value( KNullDesC8 );
    TPtrC8 sha1_value( KNullDesC8 );
    HBufC8* signedInfo = NULL;
    HBufC8* macValue = NULL;
    TInt ret = KErrNone;

    signedInfo = HBufC8::NewLC(IPCGETDESLEN0);
    TPtr8 signedInfoPtr(signedInfo->Des());
    macValue = HBufC8::NewLC(IPCGETDESLEN1);
    TPtr8 macValuePtr(macValue->Des());

    IPCREAD0L(signedInfoPtr);
    IPCREAD1L(macValuePtr);

    DRMLOG(_L("Signed info:"));
    DRMLOGHEX(signedInfoPtr);
    DRMLOG(_L("MAC value:"));
    DRMLOGHEX(macValuePtr);

    sha = CSHA1::NewL();
    CleanupStack::PushL( sha );
    hMac = CHMAC::NewL( iMac, sha );
    CleanupStack::Pop( sha ); // sha is now owned by hMac
    CleanupStack::PushL( hMac );
    hMac->Update( signedInfoPtr );
    hmac_value.Set( hMac->Final() );

    DRMLOG(_L("Calculated MAC value:"));
    DRMLOGHEX(hmac_value);
    if ( hmac_value.Compare( macValuePtr ) != 0 )
        {
        // MAC validation failed
        ret = KErrRightsServerMacFailed;
        }

    CleanupStack::PopAndDestroy(3, signedInfo); // hMac, macValue, signedInfo
    __UHEAP_MARKEND;
    aMessage.Complete(ret);
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::GetSupportedIndividualsL
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetSupportedIndividualsL( const RMessage2& aMessage )
    {
    DRMLOG( _L( "CDRMDbSession::GetSupportedIndividualsL" ) );
    TPckgBuf< TInt > size( 0 );
    TInt stringSize = 0;
    TInt offset = 0;
    TUint8* ptr = 0;

    // Cleanup.
    if ( iPreparedData )
        {
        delete iPreparedData;
        iPreparedData = NULL;
        }

    for ( TInt i = 0; i < IMSI.Count(); i++ )
        {
        stringSize += sizeof(TInt);
        stringSize += IMSI[i]->Size();
        }


    // If it's empty, just return right away
    if( !stringSize )
        {
        IPCWRITE0L( size );
        aMessage.Complete(KErrNone);
        return;
        }

    // Otherwise create a buffer and fill it:
    iPreparedData = HBufC8::NewMaxL( stringSize );
    ptr = const_cast<TUint8*>( iPreparedData->Ptr() );

    size() = stringSize;

    for(  TInt i = 0; i < IMSI.Count(); i++ )
        {
        // Write the size:
        stringSize = IMSI[i]->Size();
        Mem::Copy(ptr+offset, &stringSize, sizeof(TInt));
        offset += sizeof(TInt);

        // Write the data:
        Mem::Copy(ptr+offset, IMSI[i]->Ptr(), IMSI[i]->Size());
        offset += IMSI[i]->Size();
        }
    IPCWRITE0L( size );

    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::StopWatchingL
// ----------------------------------------------------------------------------
//
void CDRMDbSession::StopWatchingL( const RMessage2& aMessage )
    {
    _LIT_SECURITY_POLICY_S0( sidCheck, KTrustedShutdownClient );
    if ( sidCheck.CheckPolicy( aMessage ) )
        {
        SERVER->StopWatchingL();
        }
    aMessage.Complete( KErrNone );
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::DeleteAllowedL
// ----------------------------------------------------------------------------
//
TBool CDRMDbSession::DeleteAllowedL( const TDesC8& aContentId )
    {
    TBuf8< KMaxOmaV1CIDLength > URI;

    // Get the FL uri
    GetFlURI( URI );

    if( aContentId.Compare( URI ) &&
        aContentId.Compare( KDCMUri ) &&
        aContentId.Compare( KLDFUri ) )
        {
        return ETrue;
        }
    return EFalse;
    }

// ----------------------------------------------------------------------------
// CDRMDbSession::GetRandomDataL
// ----------------------------------------------------------------------------
//
void CDRMDbSession::GetRandomDataL( const RMessage2& aMessage )
    {
    DRMLOG(_L("CDRMDbSession::GetRandomDataL"));

    HBufC8* data = NULL;
    SanitizeL( aMessage.GetDesMaxLength(0) );
    SanitizeL( aMessage.GetDesLength(0));

    data = HBufC8::NewMaxLC(IPCGETDESLEN0);
    TPtr8 ptr(data->Des());

    MDrmKeyStorage* storage = DrmKeyStorageNewL();
    TCleanupItem storageCleanup( DeleteObject, storage );
    CleanupStack::PushL(storageCleanup);
    storage->RandomDataGetL(ptr,ptr.Size());
    IPCWRITE0L(*data);

    CleanupStack::PopAndDestroy(2, data);
    aMessage.Complete( KErrNone );
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::GetMeteringDataL
// -----------------------------------------------------------------------------
//
void CDRMDbSession::GetMeteringDataL( const RMessage2& aMessage )
    {
#ifndef RD_DRM_METERING
    aMessage.Complete ( KErrNotSupported );
#else
    HBufC8* riId = NULL;
    HBufC8* meteringData = NULL;
    CDRMPointerArray<CDrmMeteringDbData>* meteringArray =
        CDRMPointerArray<CDrmMeteringDbData>::NewLC();
    meteringArray->SetAutoCleanup( ETrue );

    TInt size = 0;
    TPtr8 data( NULL, 0 );
    TPckg<TInt> package( size );

    SanitizeL( aMessage.GetDesLength(0));
    // Empty old data
    delete iPreparedData;
    iPreparedData = NULL;

    riId = HBufC8::NewLC( User::LeaveIfError( IPCGETDESLEN1 ) );
    data.Set( riId->Des() );
    IPCREAD1L( data );

    if ( METERINGDB.GetL( *riId, *meteringArray ) )
        {
        meteringData = CreateMeteringDataL( meteringArray );
        CleanupStack::PushL( meteringData );
        }
    else
        {
        _LIT8( KEmptyMetering, "<rawMeteringReportData>\r\n</rawMeteringReportData>");
        meteringData = KEmptyMetering().AllocLC();
        }
    DRMLOGHEX( *meteringData );
    size = meteringData->Size();
    iPreparedData = meteringData;
    CleanupStack::Pop( meteringData );

    IPCWRITE0L( package );
    CleanupStack::PopAndDestroy( 2 ); // riId, meteringArray
    if ( !iPreparedData )
        {
        aMessage.Complete( KErrNotFound );
        return;
        }
    aMessage.Complete( KErrNone );
#endif
    }

// -----------------------------------------------------------------------------
// CDRMDbSession::DeleteMeteringDataL
// -----------------------------------------------------------------------------
//
void CDRMDbSession::DeleteMeteringDataL( const RMessage2& aMessage )
    {
#ifndef RD_DRM_METERING
    aMessage.Complete ( KErrNotSupported );
#else
// Metering supported
    HBufC8* riId = NULL;
    TPtr8 data( NULL, 0 );
    TBool meteringDataDeleted;

    riId = HBufC8::NewLC( User::LeaveIfError( IPCGETDESLEN0 ) );
    data.Set( riId->Des() );
    IPCREAD0L( data );
    meteringDataDeleted = METERINGDB.DeleteL( *riId );

        if( meteringDataDeleted )
            {
            DRMLOG( _L("CDRMDbSession::DeleteMeteringDataL -> some records were destroyed") );
            }
    // Do we have to do something else?
    CleanupStack::PopAndDestroy( riId );
    aMessage.Complete( KErrNone );
#endif
    }
// -----------------------------------------------------------------------------
// CDRMDbSession::ConnectRoapClient()
// -----------------------------------------------------------------------------
//
TInt CDRMDbSession::ConnectRoapClient()
    {
    if( iRoapClientConnected )
        {
        return KErrNone;
        }
    TInt err( iRoapClient.Connect() );
    if ( !err )
        {
        iRoapClientConnected = ETrue;
        }
    return err;
    }

//  End of File