/*
* Copyright (c) 2002 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 CFLDDRMImplementation.
*
*/
// CLASS HEADER
#include "CFLDDRMImplementation.h"
// INTERNAL INCLUDES
#include "CFLDRingingTonePlayer.h" // KFLDResourceFileName
// EXTERNAL INCLUDES
#include <DRMCommon.h>
#include <DRMHelper.h>
#include <FileList.rsg>
#include <MProfilesLocalFeatures.h>
#include <MProfileUtilitySingleton.h>
#ifdef RD_DRM_COMMON_INTERFACE_FOR_OMA_AND_WMDRM
#include <drmutility.h>
#include <drmagents.h>
#endif
// CONSTANTS
namespace
{
_LIT( KFLDROMDriveLetter, "Z:" );
}
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CFLDDRMImplementation::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CFLDDRMImplementation::ConstructL()
{
iProfilesFeatures = &( ProfileUtilityInstanceL().ProfilesLocalFeatures() );
iDRMCommon = DRMCommon::NewL();
User::LeaveIfError( iDRMCommon->Connect() );
iDRMHelper = CDRMHelper::NewL( *CCoeEnv::Static() );
}
// Destructor
CFLDDRMImplementation::~CFLDDRMImplementation()
{
delete iDRMHelper;
if( iDRMCommon )
{
iDRMCommon->Disconnect(); // ignore possible error
delete iDRMCommon;
}
ReleaseProfileUtility();
}
// -----------------------------------------------------------------------------
// CFLDDRMImplementation::SetAutomatedType
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CFLDDRMImplementation::SetAutomatedType(
CDRMHelper::TDRMHelperAutomatedType aAutomatedType )
{
iAutomatedType = aAutomatedType;
}
// -----------------------------------------------------------------------------
// CFLDDRMImplementation::IsFileValidL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CFLDDRMImplementation::IsFileValidL(
const TDesC& aFileName, TIntention aIntention )
{
// If the destructor is empty, return that it's valid
if( aFileName.Compare( KNullDesC ) == 0 )
{
return ETrue;
}
// Tone files on ROM are always valid
if( ( aFileName.Left( KFLDROMDriveLetter().Length() ).CompareF(
KFLDROMDriveLetter ) == 0 ) )
{
return ETrue;
}
// Check if file is WMDRM protected
TBool prot( EFalse );
TRAPD( err, prot = IsFileWMDRMProtectedL( aFileName ) );
if( err != KErrNone )
{
ShowErrorNoteL( R_FLD_QTN_FILE_FORMAT_ERROR );
return EFalse;
}
if( prot )
{
ShowErrorNoteL( R_FLD_QTN_PROFILES_INFO_TONE_DRM_PROTECTED );
return EFalse;
}
ContentAccess::TVirtualPathPtr path( aFileName,
ContentAccess::KDefaultContentObject );
CData* data = CData::NewLC( path, EContentShareReadWrite );
TInt isProtected;
TInt error = data->GetAttribute( EIsProtected, isProtected );
CleanupStack::PopAndDestroy(); // data
if( error != DRMCommon::EOk )
{
// DRM Helper class knows at least rights db corrupted error message.
// Leaves on system-wide error code.
iDRMHelper->HandleErrorL( error, aFileName );
return EFalse;
}
// Obtain information whether the file can be set as automated content
TBool canSetAutomated( EFalse );
TInt canSetAutomatedErr( iDRMHelper->CanSetAutomated( aFileName, canSetAutomated ) );
if( !isProtected && canSetAutomated )
{
// The file in question is not DRM protected.
// Return ETrue if file is also Ok unprotected, otherwise EFalse.
return IsFileValidUnprotectedL( aFileName, aIntention );
}
// Operator requirement: Check restrictions if file is mp4 audio
TBuf<KMaxDataTypeLength> dataType( DataTypeL( aFileName ).Des() );
if( iProfilesFeatures->IsBlockedProtectedType( dataType ) )
{
ShowErrorNoteL( R_FLD_QTN_PROFILES_INFO_TONE_DRM_PROTECTED );
return EFalse;
}
if ( canSetAutomatedErr == DRMCommon::ERightsExpired ||
canSetAutomatedErr == DRMCommon::ENoRights )
{
// Rights are expired, future rights or missing
iDRMHelper->HandleErrorL( canSetAutomatedErr, aFileName );
return EFalse;
}
// Operator requirement: Check DRM v2 tones
if( !canSetAutomated )
{
// This is DRM v2 file OR count based v1 tone
ShowErrorNoteL( aIntention == EPlay ?
R_FLD_QTN_DRM_PREV_RIGHTS_USE : R_FLD_QTN_DRM_PREV_RIGHTS_SET);
return EFalse;
}
TInt32 infoBits( 0x00000000 );
// Find out rights information
if( !CFLDDRMImplementation::GetFileInfoL(
aFileName, infoBits ) )
{
// Corrupted file or "No rights" situation
return EFalse;
}
// Operator requirement: Check CFM protection
if ( infoBits & ENoRingingTone )
{
// This is CFM protected file, ringingtone is set to "no"
ShowErrorNoteL( aIntention == EPlay ?
R_FLD_QTN_DRM_PREV_RIGHTS_USE : R_FLD_QTN_DRM_PREV_RIGHTS_SET);
return EFalse;
}
if( aIntention == ESelect )
{
// Rights are good to go, and intention is selection
// call SetAutomatedPassive to show 'activation query'
iDRMHelper->SetAutomatedType( iAutomatedType );
error = iDRMHelper->SetAutomatedPassive( aFileName );
if( error != KErrCancel )
{
// User accepted dialog
User::LeaveIfError( error );
// New way, does not require DRM capability
data = CData::NewLC( path, EContentShareReadWrite );
error = data->ExecuteIntent( ContentAccess::EPlay );
// Wrongly requires DRM after all. According to Risto Vilkman
// from DRM, KErrAccessDenied can be ignored, since if
// CanSetAutomated says the tone is OK, it's OK.
if ( error != KErrNone && error != KErrAccessDenied )
{
User::Leave( error );
}
CleanupStack::PopAndDestroy(); // data
}
else
{
// User canceled dialog
return EFalse;
}
}
return ETrue;
}
// -----------------------------------------------------------------------------
// CFLDDRMImplementation::GetFileInfo
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CFLDDRMImplementation::GetFileInfoL(
const TDesC& aFileName, TInt32& aInfoBits ) const
{
DRMCommon::TContentProtection contentProtection; // ignored
HBufC8* mimeType = NULL; // ignored
TUint dataLength( 0 ); // ignored
HBufC8* contentURI( NULL );
// Obtain content URI
TInt error = iDRMCommon->GetFileInfo(
aFileName, contentProtection, mimeType, contentURI, dataLength );
delete mimeType;
if( error != DRMCommon::EOk )
{
delete contentURI;
// Handle possible corrupt file situation
iDRMHelper->HandleErrorL( error, aFileName );
return EFalse;
}
// Obtain rights object
CDRMRights* rights = NULL;
error = iDRMCommon->GetActiveRights( *contentURI, DRMCommon::EPlay, rights );
delete contentURI;
if( error == DRMCommon::ENoRights )
{
delete rights;
// There is no rights for given file
// Should never arrive here, ENoRights is handled
// already in IsFileValidL()
iDRMHelper->HandleErrorL( error, aFileName );
return EFalse;
}
// Obtain infobits ( needed only for CFM case )
aInfoBits = rights->GetPermission().iInfoBits;
delete rights;
return ETrue;
}
// -----------------------------------------------------------------------------
//
// Functions related to WMDRM protection check
//
// -----------------------------------------------------------------------------
#ifndef RD_DRM_COMMON_INTERFACE_FOR_OMA_AND_WMDRM
// Some magic constants
static const TInt KMinContentLength( 16 );
//_LIT8( KContentProtectionType, "DRM" );
_LIT8( KASFHeaderObject, "75B22630668E11CFA6D900AA0062CE6C" );
_LIT8( KWrmHeader, "W\0R\0M\0H\0E\0A\0D\0E\0R\0" );
// -----------------------------------------------------------------------------
// FormatGUID
// -----------------------------------------------------------------------------
//
LOCAL_C void FormatGUID( TDes8& aGUID )
{
TBuf8<16> copyGUID( aGUID );
TInt i;
for( i = 0; i < 4; i++ )
{
copyGUID[i] = aGUID[3-i];
}
for( i = 4; i < 6; i++ )
{
copyGUID[i] = aGUID[9 - i];
}
for( i = 6; i < 8; i++ )
{
copyGUID[i] = aGUID[13 - i];
}
for( i = 8; i < 16 ; i++ )
{
copyGUID[i] = aGUID[i];
}
aGUID.Delete( 0, 32 );
for( i = 0; i <16; i++ )
{
aGUID.AppendNumFixedWidthUC( copyGUID[i], EHex, 2 );
}
}
// -----------------------------------------------------------------------------
// ConvertToInt64
// -----------------------------------------------------------------------------
//
LOCAL_C TInt64 ConvertToInt64( TDesC8& aDes )
{
TInt64 num = 0;
TInt i;
for( i = 7 ; i >= 0; i-- )
{
num <<= 8;
num |= aDes[i];
}
return num;
}
// -----------------------------------------------------------------------------
// IsProtectedWmDrmL
// returns ETrue, if file is protected WMDRM file
// EFalse if file is not protected WMDRM file
// Leaves with KErrUnderflow if file has too little data to decide
// whether WmDrm or not
// may also leave with other system wide error code
// -----------------------------------------------------------------------------
//
LOCAL_C TBool IsProtectedWmDrmL( RFile& aFileHandle )
{
TInt r( KErrNone );
HBufC8* buffer( NULL );
TInt pos( 0 );
RFile file;
TBuf8< 32 > header;
TInt64 headerSize( 0 );
TBool isProtectedWmDrm( EFalse );
TPtr8 headerPtr( NULL, 0 );
// Leave if given handle is invalid
if( !aFileHandle.SubSessionHandle() )
{
User::Leave( KErrBadHandle );
}
User::LeaveIfError( file.Duplicate( aFileHandle ) );
CleanupClosePushL( file );
User::LeaveIfError( file.Seek( ESeekStart, pos ) );
// Check if the file is an ASF file
// : Check on runtime wether WM DRM is supporeted or not
User::LeaveIfError( file.Read( 0, header, KMinContentLength ) );
if( header.Length() < KMinContentLength )
{
User::Leave( KErrUnderflow );
}
FormatGUID( header );
if( header == KASFHeaderObject )
{
// It's ASF, check still whether it's WM DRM protected or not
file.Read( header,8 );
headerSize = ConvertToInt64( header );
if( headerSize <= 30 )
{
User::Leave( KErrUnderflow );
}
if ( headerSize > ( ( KMaxTInt32 / 2 ) - 1 ) )
{
User::Leave( KErrOverflow );
}
buffer = HBufC8::NewLC( headerSize );
headerPtr.Set( buffer->Des() );
User::LeaveIfError( file.Read( headerPtr, headerSize - 24 ) );
r = headerPtr.Find( KWrmHeader );
if ( KErrNotFound != r )
{
isProtectedWmDrm = ETrue;
}
CleanupStack::PopAndDestroy( buffer ); // buffer
}
CleanupStack::PopAndDestroy(); // file
return isProtectedWmDrm;
}
#endif // RD_DRM_COMMON_INTERFACE_FOR_OMA_AND_WMDRM
// -----------------------------------------------------------------------------
// CFLDDRMImplementation::IsFileWMDRMProtectedL
// -----------------------------------------------------------------------------
//
TBool CFLDDRMImplementation::IsFileWMDRMProtectedL( const TDesC& aFileName ) const
{
TBool res = EFalse;
RFs& fsSession( CCoeEnv::Static()->FsSession() );
RFile hFile;
TInt err = hFile.Open( fsSession, aFileName,
EFileRead | EFileStream | EFileShareReadersOnly );
if( err == KErrInUse )
{
err = hFile.Open( fsSession, aFileName,
EFileRead | EFileStream | EFileShareAny );
}
if( err != KErrNone )
{
User::Leave( err );
}
CleanupClosePushL( hFile );
#ifdef RD_DRM_COMMON_INTERFACE_FOR_OMA_AND_WMDRM
TPtrC agent( KNullDesC );
DRM::CDrmUtility* drmUtil( DRM::CDrmUtility::NewLC() );
drmUtil->GetAgentL( hFile, agent );
if( agent.Compare( DRM::KDrmWMAgentName ) == 0 )
{
res = ETrue;
}
CleanupStack::PopAndDestroy( drmUtil );
#else
res = IsProtectedWmDrmL( hFile );
#endif
CleanupStack::PopAndDestroy( &hFile );
return res;
}
// -----------------------------------------------------------------------------
//
// End of Functions related to WMDRM protection check
//
// -----------------------------------------------------------------------------
// End of File