omadrm/drmengine/agentv2/src/Oma2AgentData.cpp
changeset 0 95b198f216e5
child 18 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/agentv2/src/Oma2AgentData.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,609 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Implementation of the CAF Agent Data class
+*
+*/
+
+// INCLUDE FILES
+#include <caf/caf.h>
+#include <caf/bitset.h>
+#include <caf/attribute.h>
+#include <e32test.h>
+#include "drmcommon.h"
+#include "oma2agentdata.h"
+#include "oma2agentattributes.h"
+#include "oma1dcf.h"
+#include "oma2dcf.h"
+#include "symmetric.h"
+#include "drmrightsclient.h"
+#include "drmprotectedroparser.h"
+#include "dcfcache.h"
+#include "cleanupresetanddestroy.h"
+
+using namespace ContentAccess;
+//TRACE macros
+#ifdef _DEBUG
+#include <e32debug.h> // RDebug
+#define TRACE( x ) RDebug::Print( _L( x ) )
+#define TRACE2( x, y ) RDebug::Print( _L( x ), y )
+#define TRACE3( x, y, z ) RDebug::Print( _L( x ), y, z )
+#else
+#define TRACE( x )
+#define TRACE2( x, y )
+#define TRACE3( x, y, z )
+#endif
+// CONSTANTS
+_LIT8(KMimeAudio, "audio");
+_LIT8(KMimeImage, "image");
+// LOCAL FUNCTION PROTOTYPES
+LOCAL_C TInt MapContentShareMode( TContentShareMode aMode );
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// MapContentShareMode
+// Maps the CAF specific file share mode to the RFs/RFile sharing mode
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TInt MapContentShareMode( TContentShareMode aMode )
+    {
+    TInt r = EFileRead | EFileShareAny;
+
+    switch ( aMode )
+        {
+        case EContentShareReadOnly:
+            r = EFileRead | EFileShareReadersOnly;
+            break;
+        case EContentShareReadWrite:
+            r = EFileRead | EFileShareReadersOrWriters;
+            break;
+        case EContentShareExclusive:
+            r = EFileRead | EFileShareExclusive;
+            break;
+        }
+    return r;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::COma2AgentData
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+COma2AgentData::COma2AgentData() :
+    iDcf( NULL ),
+    iDataPosition( 0 ),
+    iRightsStatus( KErrNone ),
+    iVirtualPath( KNullDesC ),
+    iCache( NULL ),
+    iGroupKeyUsed( EFalse ),
+    iLastFileSize( 0 )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::ConstructL(
+    const TVirtualPathPtr& aVirtualPath,
+    TContentShareMode aShareMode )
+    {
+    User::LeaveIfError( iRdb.Connect() );
+    User::LeaveIfError( iFs.Connect() );
+    User::LeaveIfError( iFs.ShareAuto() );
+    User::LeaveIfError( iFile.Open( iFs, aVirtualPath.URI(),
+        MapContentShareMode( aShareMode ) ) );
+    iDcf = CDcfCommon::NewL( iFile );
+    iVirtualPath = aVirtualPath;
+    User::LeaveIfError( iDcf->OpenPart( iVirtualPath.UniqueId() ) );
+    InitializeL();
+    }
+
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::ConstructL(
+    RFile& aFile,
+    const TDesC& aUniqueId )
+    {
+    User::LeaveIfError( iRdb.Connect() );
+    User::LeaveIfError( iFs.Connect() );
+    User::LeaveIfError( iFs.ShareAuto() );
+    User::LeaveIfError( iFile.Duplicate( aFile ) );
+    iDcf = CDcfCommon::NewL( iFile );
+    User::LeaveIfError( iDcf->OpenPart( aUniqueId ) );
+    InitializeL();
+    iUniqueId = aUniqueId.AllocL();
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::InitializeL
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::InitializeL()
+    {
+    TInt r = KErrNone;
+    TBuf8<KDCFKeySize * 2> blocks;
+    CDrmProtectedRoParser* parser;
+    TInt pos;
+    COma2Dcf* dcf2 = NULL;
+    TInt i;
+    TBool reinit = EFalse;
+    TInt error = KErrNone;
+
+    if ( iDcf->iVersion == EOma2Dcf )
+        {
+        dcf2 = static_cast<COma2Dcf*> ( iDcf );
+        // Encrypted images are not supported, but plain ones are:
+        if ( dcf2->iMimeType->Left( KMimeImage().Length() ).CompareF(
+            KMimeImage ) == 0 && iDcf->iEncryptionMethod != EMethodNULL )
+            {
+            User::Leave( KErrNotSupported );
+            }
+        }
+
+    // Set the session key for this file
+    if ( iDcf->iEncryptionMethod == EMethodAES_128_CBC )
+        {
+        // Check if we can use the group key first
+        if ( dcf2 && dcf2->iGroupId )
+            {
+            r = iRdb.InitializeGroupKey( *dcf2->iGroupId, *dcf2->iGroupKey,
+                dcf2->iGkEncryptionMethod );
+            if ( r == KErrNone )
+                {
+                iGroupKeyUsed = ETrue;
+                }
+            }
+        else
+            {
+            r = iRdb.InitializeKey( *iDcf->iContentID );
+            }
+
+        // If the DCF contains a domain RO, try to save and use it
+        if ( dcf2 && dcf2->iRightsObjects.Count() )
+            {
+            error = r;
+            __UHEAP_MARK;
+            for ( i = 0; i < dcf2->iRightsObjects.Count(); i++ )
+                {
+                RPointerArray<CDRMRights> rights;
+                CleanupResetAndDestroyPushL( rights );
+                parser = CDrmProtectedRoParser::NewL();
+                CleanupStack::PushL( parser );
+                // NOTE:
+                // This is trapped for a reason, the file opening must not fail
+                // even if the parsing of the embedded rights object fails
+                // for some reason it is possible that the rights are already
+                // put into the database and the leave occurs because of this,
+                // also it's possible that there are existing rights
+                // that work with the given content.
+                TRAP( r, parser->ParseAndStoreL( *dcf2->iRightsObjects[i],
+                    rights) );
+                CleanupStack::PopAndDestroy( parser );
+                CleanupStack::PopAndDestroy( &rights );
+                if ( r == KErrNone && !reinit )
+                    {
+                    reinit = ETrue;
+                    }
+                }
+            __UHEAP_MARKEND;
+            if ( reinit && !iGroupKeyUsed )
+                {
+                r = iRdb.InitializeKey( *iDcf->iContentID );
+                }
+            else
+                {
+                r = error;
+                }
+            }
+
+        if ( r != KErrCANoRights && r != KErrCANoPermission &&
+            r != KErrCAPendingRights && r != KErrNone )
+            {
+            User::Leave( r );
+            }
+        iRightsStatus = r;
+        }
+    else if ( iDcf->iEncryptionMethod != EMethodNULL )
+        {
+        User::Leave( KErrNotSupported );
+        }
+
+    iCache = CDcfCache::NewL( iRdb, iFile, *iDcf, 0, 0 );
+    if ( iDcf->iPadding == -1 && iRightsStatus == KErrNone )
+        {
+        pos = iDcf->iOffset + iDcf->iDataLength - 2 * KDCFKeySize;
+        iFile.Seek( ESeekStart, pos );
+        iFile.Read( blocks );
+        iDcf->iPadding = iRdb.CalculatePadding( blocks );
+        if ( iDcf->iPadding >= 0 )
+            {
+            iDcf->iPlainTextLength -= iDcf->iPadding;
+            iDcf->iPlainTextLengthValid = ETrue;
+            }
+        }
+    User::LeaveIfError( iFile.Size( iLastFileSize ) );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+COma2AgentData* COma2AgentData::NewL(
+    const TVirtualPathPtr& aVirtualPath,
+    TContentShareMode aShareMode )
+    {
+    COma2AgentData* self = NewLC( aVirtualPath, aShareMode );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::NewLC
+// -----------------------------------------------------------------------------
+//
+COma2AgentData* COma2AgentData::NewLC(
+    const TVirtualPathPtr& aVirtualPath,
+    TContentShareMode aShareMode )
+    {
+    COma2AgentData* self = new ( ELeave ) COma2AgentData();
+    CleanupStack::PushL( self );
+    self->ConstructL( aVirtualPath, aShareMode );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::NewL
+// -----------------------------------------------------------------------------
+//
+COma2AgentData* COma2AgentData::NewL(
+    RFile& aFile,
+    const TDesC& aUniqueId )
+    {
+    COma2AgentData* self = COma2AgentData::NewLC( aFile, aUniqueId );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::NewLC
+// -----------------------------------------------------------------------------
+//
+COma2AgentData* COma2AgentData::NewLC(
+    RFile& aFile,
+    const TDesC& aUniqueId )
+    {
+    COma2AgentData* self = new ( ELeave ) COma2AgentData();
+    CleanupStack::PushL( self );
+    self->ConstructL( aFile, aUniqueId );
+    return self;
+    }
+
+// Destructor
+COma2AgentData::~COma2AgentData()
+    {
+    iRdb.Close();
+    iFile.Close();
+    iFs.Close();
+    delete iDcf;
+    delete iCache;
+    delete iUniqueId;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::DataSizeL
+// Re-create the DCF because it's size may have changed.
+// for progressive download etc.
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::DataSizeL( TInt &aSize )
+    {
+    TInt fileSize = 0;
+    TInt seekPos = 0;
+
+    User::LeaveIfError( iFile.Size( fileSize ) );
+
+    if ( iDcf )
+        {
+        // if the size of the file has changed update info:
+        if ( fileSize != iLastFileSize )
+            {
+            // Delete the old dcf
+            delete iDcf;
+            iDcf = NULL;
+
+            // seek the file to the beginning
+            iFile.Seek( ESeekStart, seekPos );
+
+            // Create new dcf as the size may have changed
+            iDcf = CDcfCommon::NewL( iFile );
+
+            // open the content part
+            if ( iUniqueId )
+                {
+                User::LeaveIfError( iDcf->OpenPart( iUniqueId->Des() ) );
+                }
+            else
+                {
+                User::LeaveIfError( iDcf->OpenPart( iVirtualPath.UniqueId() ) );
+                }
+            // re-initialize the dcf, this updates the iLastFileSize
+            InitializeL();
+            }
+
+        aSize = iDcf->iPlainTextLength;
+        }
+    else
+        {
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::EvaluateIntent
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::EvaluateIntent( TIntent aIntent )
+    {
+    TInt r = KErrNone;
+
+    // Check for a mismatch in the MIME type and the intent
+    if ( ( iDcf->iMimeType->Left(
+            KMimeAudio().Length() ).CompareF( KMimeAudio ) == 0 &&
+            ( aIntent == EView || aIntent == EPrint || aIntent == EExecute ) )
+        ||
+        ( iDcf->iMimeType->Left(
+            KMimeImage().Length() ).CompareF( KMimeImage ) == 0 &&
+            ( aIntent == EPlay || aIntent == EExecute ) ) )
+        {
+        r = KErrArgument;
+        }
+    else if ( iDcf->iEncryptionMethod )
+        {
+        if ( iGroupKeyUsed )
+            {
+            r = iRdb.CheckConsume( aIntent,
+                *( static_cast<COma2Dcf*> ( iDcf )->iGroupId ) );
+            }
+        else
+            {
+            r = iRdb.CheckConsume( aIntent, *iDcf->iContentID );
+            }
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::ExecuteIntent
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::ExecuteIntent( TIntent aIntent )
+    {
+    TInt r = KErrNone;
+    TBuf8<KDCFKeySize> key;
+
+    // Check for a mismatch in the MIME type and the intent
+    if ( ( iDcf->iMimeType->Left(
+            KMimeAudio().Length() ).CompareF( KMimeAudio ) == 0 &&
+            ( aIntent == EView || aIntent == EPrint || aIntent == EExecute ) )
+        ||
+        ( iDcf->iMimeType->Left(
+            KMimeImage().Length() ).CompareF( KMimeImage ) == 0 &&
+            ( aIntent == EPlay || aIntent == EExecute ) ) )
+        {
+        r = KErrArgument;
+        }
+    else if ( iDcf->iEncryptionMethod )
+        {
+        // If the MIME type allows it, do the consumption
+        if ( iGroupKeyUsed )
+            {
+            r = iRdb.Consume( aIntent,
+                *( static_cast<COma2Dcf*> ( iDcf )->iGroupId ) );
+            }
+        else
+            {
+            r = iRdb.Consume( aIntent, *iDcf->iContentID );
+            }
+
+        // If the consumption succeeded, try to get the decryption key.
+        // This is possible at this time because the permission is now known on
+        // the server side, and the server can return the key if the
+        // security level allows it. The decision is made based on the
+        // used permission and the caller identity.
+        if ( r == KErrNone && iRdb.GetDecryptionKey( aIntent,
+            *iDcf->iContentID, key ) == KErrNone && key.Length()
+            == KDCFKeySize )
+            {
+            iCache->SetKey( key );
+            }
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Read
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::Read( TDes8& aDes )
+    {
+    return Read( aDes, aDes.MaxLength() );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Read
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::Read(
+    TDes8& aDes,
+    TInt aLength )
+    {
+    return iCache->Read( iDataPosition, aDes, aLength );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Read
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::Read(
+    TDes8& aDes,
+    TRequestStatus& aStatus )
+    {
+    TRequestStatus* status = &aStatus;
+    User::RequestComplete( status, Read( aDes, aDes.MaxLength() ) );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Read
+// asynchronous read
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::Read(
+    TDes8& aDes,
+    TInt aLength,
+    TRequestStatus& aStatus )
+    {
+    TRequestStatus* status = &aStatus;
+    User::RequestComplete( status, Read( aDes, aLength ) );
+    }
+
+#ifdef ASYNC_READ
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Read
+// asynchronous read (not really asynchronous)
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::Read(
+    TInt aPos,
+    TDes8& aDes,
+    TInt aLength,
+    TRequestStatus& aStatus )
+    {
+    return iCache->Read( aPos, aDes, aLength, aStatus );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::ReadCancel
+// -----------------------------------------------------------------------------
+//
+void COma2AgentData::ReadCancel( TRequestStatus& aStatus )
+    {
+    TRACE("+ COma2AgentData::ReadCancel");
+    iCache->ReadCancel( aStatus );
+    TRACE("- COma2AgentData::ReadCancel");
+    }
+#endif
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::Seek
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::Seek( TSeek aMode, TInt& aPos )
+    {
+    TInt r = KErrNone;
+
+    switch ( aMode )
+        {
+        case ESeekStart:
+            break;
+        case ESeekEnd:
+            aPos = iDcf->iPlainTextLength + aPos;
+            break;
+        case ESeekCurrent:
+            aPos = iDataPosition + aPos;
+            break;
+        default:
+            r = KErrNotSupported;
+            break;
+        }
+    aPos = Max( aPos, 0 );
+    aPos = Min( aPos, iDcf->iPlainTextLength );
+    iDataPosition = aPos;
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::SetProperty
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::SetProperty(
+    TAgentProperty /*aProperty*/,
+    TInt /*aValue*/)
+    {
+    return KErrCANotSupported;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::GetAttribute
+// -----------------------------------------------------------------------------
+//
+TInt COma2AgentData::GetAttribute(
+    TInt aAttribute,
+    TInt& aValue )
+    {
+    TInt ret( KErrCANotSupported );
+    ret = TOma2AgentAttributes::GetAttribute( *iDcf, aAttribute,
+        iVirtualPath, &iRdb );
+    if ( ret >= KErrNone )
+        {
+        aValue = ret;
+        ret = KErrNone;
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::GetAttributeSet
+// -----------------------------------------------------------------------------
+//
+
+TInt COma2AgentData::GetAttributeSet(
+    RAttributeSet& aAttributeSet )
+    {
+    return TOma2AgentAttributes::GetAttributeSet( *iDcf, aAttributeSet,
+        iVirtualPath, &iRdb );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::GetStringAttribute
+// -----------------------------------------------------------------------------
+//
+
+TInt COma2AgentData::GetStringAttribute(
+    TInt aAttribute,
+    TDes& aValue )
+    {
+    return TOma2AgentAttributes::GetStringAttribute( *iDcf, aAttribute,
+        aValue, iVirtualPath, &iRdb );
+    }
+
+// -----------------------------------------------------------------------------
+// COma2AgentData::GetStringAttributeSet
+// -----------------------------------------------------------------------------
+//
+
+TInt COma2AgentData::GetStringAttributeSet(
+    RStringAttributeSet& aStringAttributeSet )
+    {
+    return TOma2AgentAttributes::GetStringAttributeSet( *iDcf,
+        aStringAttributeSet, iVirtualPath, &iRdb );
+    }
+
+//  End of File