dvrengine/CommonRecordingEngine/src/CCRRTSPCommand.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:20:37 +0100
branchRCL_3
changeset 48 13a33d82ad98
parent 0 822a42b6c3f1
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201029 Kit: 201035

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:    RTSP command parser and producer*
*/




// INCLUDE FILES
#include "CCRRtspCommand.h"
#include "CCRSock.h"
#include <imcvcodc.h>
#include <Hash.h>
#include "videoserviceutilsLogger.h"

// CONSTANTS
const TReal KRealZero( 0.0 ); 
const TReal KRealMinusOne( -1.0 ); 
// Length of a digest hash before converting to hex.
const TInt KCRRawHashLength( 16 );
// Length of a digest hash when represented in hex
const TInt KCRHashLength( 32 );

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

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

// -----------------------------------------------------------------------------
// CCRRtspCommand::CCRRtspCommand
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CCRRtspCommand::CCRRtspCommand()
  : iCommand( ERTSPCommandNOCOMMAND )
    {  
    // None
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::ConstructL()
    {
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::~CCRRtspCommand
// Destructor.
// -----------------------------------------------------------------------------
//
CCRRtspCommand::~CCRRtspCommand()
    {
    LOG( "CCRRtspCommand::~CCRRtspCommand" );
    
    // iRtspText is deleted in base class destructor
    delete iAuthHeader;
    delete iMD5Calculator;
    delete iUserAgent;
    delete iWapProfile;
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::TryParseL
// 
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::TryParseL( const TDesC8 &aString ) 
    {
    // try to find out if end of the command has been received
    // "RTSP/1.0 XXX\r\n\r\n" at least..
    const TInt KDVRMinCommandLen( 14 ); 
    TInt replyEndOffSet( ( aString.Length() < KDVRMinCommandLen )?
                           KDVRMinCommandLen: aString.Find( KCR2NewLines() ) ); 
    if ( replyEndOffSet == KErrNotFound )
        {
        // need to have more, do nothing yet
        LOG( "CCRRtspCommand::TryParseL() out because response not complete" );
        User::Leave( KErrUnderflow ); 
        }

    // copy the stuff into local variable:      
    delete iRtspText; iRtspText = NULL; 
    iRtspText = aString.AllocL(); 
    iCommand = ERTSPCommandNOCOMMAND;

    // try each command in order: 
    if ( iRtspText->Find( KCROPTIONS() ) == 0 )
        {
        // it was OPTIONS command
        LOG( "CCRRtspCommand::TryParseL() -> OPTIONS" );
        iCommand = ERTSPCommandOPTIONS;
        }
    else if ( iRtspText->Find( KCRDESCRIBE() ) == 0 )
        {
        LOG( "CCRRtspCommand::TryParseL() -> DESCRIBE" );
        iCommand = ERTSPCommandDESCRIBE;
        }  
    else if ( iRtspText->Find( KCRTEARDOWN() ) == 0 )
        {
        LOG( "CCRRtspCommand::TryParseL() -> TEARDOWN" );
        iCommand = ERTSPCommandTEARDOWN;        
        }                   
    else if ( iRtspText->Find( KCRPAUSE() ) == 0 )
        {
        LOG( "CCRRtspCommand::TryParseL() -> PAUSE" );
        iCommand = ERTSPCommandPAUSE;       
        }                                       
    else if ( iRtspText->Find( KCRSETUP() ) == 0 )
        {
        LOG( "CCRRtspCommand::TryParseL() -> SETUP" );
        iCommand = ERTSPCommandSETUP;       
        }
    else if ( iRtspText->Find( KCRPLAY() ) == 0 )
        {
        LOG( "CCRRtspCommand::TryParseL() -> PLAY" );
        iCommand = ERTSPCommandPLAY;        
        }  
    else
        {
        User::Leave( KErrNotSupported ); 
        }

    // then find CSeq
    FindCSeqL();    
    // then find session id
    FindSessionIdL(); 
    // then find possible content. for commands it is usually not there
    FindContentL(); 
    // find URL
    FindURLL(); 
    // find possible transport method
    // IMPORTANT: should be done before parsing client port
    FindTransport();
    // find possible client port
    FindClientPorts();
    // find possible range-header
    ParseRange();
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::FindURLL
// in rtsp the URL is between first and second whitespace.
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::FindURLL( void ) 
    {
#ifdef _DEBUG   
    _LIT( KPanicStr, "RTSPCommon" ); 
    __ASSERT_DEBUG( iRtspText, 
                    User::Panic( KPanicStr, KErrBadHandle ) );
#endif                    
    
    iURL.Set( NULL, 0 );
    TInt spaceOffset( iRtspText->Locate( ' ' ) ); 
    if ( spaceOffset < 0 ) 
        {
        User::Leave( KErrNotSupported ); 
        }
        
    TPtrC8 beginningFromUrl( iRtspText->Right( iRtspText->Length() - 
                                             ( spaceOffset + 1 ) ) ) ;      
    spaceOffset = beginningFromUrl.Locate( ' ' ); 
    if ( spaceOffset < 0 ) 
        {
        User::Leave( KErrNotSupported ); 
        }
    
    iURL.Set( beginningFromUrl.Left( spaceOffset ) ); 
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::URL
//
// method that returns URL
// -----------------------------------------------------------------------------
//  
TInt CCRRtspCommand::URL( TPtrC8& aURL ) 
    {
    if ( iURL.Ptr() != NULL )   
        {
        aURL.Set ( iURL ); 
        return KErrNone;
        }

    return KErrNotFound; 
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::SetURL
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetURL ( const TDesC8& aURL ) 
    {
    iURL.Set ( aURL ); 
    }
    
// -----------------------------------------------------------------------------
// CCRRtspCommand::SetAuthentication
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetAuthentication( TBool aAuth ) 
    {
    iAuthenticationNeeded = aAuth;
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::SetUserAgentL
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetUserAgentL( const TDesC8& aUserAgent )
    {
    delete iUserAgent; iUserAgent = NULL;
    iUserAgent = aUserAgent.AllocL();
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::SetBandwidth
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetBandwidth( TInt aBandwidth )
    {
    iBandwidth = aBandwidth;
    iBandwidthAvailable = ETrue;
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::SetWapProfileL
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetWapProfileL( const TDesC8& aWapProfile )
    {
    delete iWapProfile; iWapProfile = NULL;
    iWapProfile = aWapProfile.AllocL();
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::SetCommand
//
// -----------------------------------------------------------------------------
//  
void CCRRtspCommand::SetCommand( TCommand aCommand ) 
    {
    iCommand = aCommand; 
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::Command
//
// -----------------------------------------------------------------------------
//  
CCRRtspCommand::TCommand CCRRtspCommand::Command( void ) const 
    {
    return iCommand;    
    }       
            
// -----------------------------------------------------------------------------
// CCRRtspCommand::ProduceL
//
// -----------------------------------------------------------------------------
//  
TPtrC8& CCRRtspCommand::ProduceL( void ) 
    {
    // First common part for all commands, except actual command
    delete iRtspText; iRtspText = NULL;
    iRtspText = HBufC8::NewL( KMaxName );
    iRtspText->Des().Zero();
    
    switch ( iCommand )
        {
        case ERTSPCommandOPTIONS:
            AppendL( iRtspText, KCROPTIONS ); 
            break;
        
        case ERTSPCommandDESCRIBE:
            AppendL( iRtspText, KCRDESCRIBE ); 
            break;
        
        case ERTSPCommandTEARDOWN:     
            AppendL( iRtspText, KCRTEARDOWN ); 
            break;
        
        case ERTSPCommandPAUSE:
            AppendL( iRtspText, KCRPAUSE ); 
            break;
        
        case ERTSPCommandSETUP:        
            AppendL( iRtspText, KCRSETUP ); 
            break;
        
        case ERTSPCommandPLAY : 
            AppendL( iRtspText, KCRPLAY ); 
            break;
        
        default:
            User::Leave( KErrNotSupported ); 
            break;
        }
    
    AppendL( iRtspText, iURL ); 
    AppendL( iRtspText, KCRSpace ); 
    AppendL( iRtspText, KCRRTSP10 ); 
    AppendL( iRtspText, KCRNewLine ); 
    AppendL( iRtspText, KCRCSeq ); 
    AppendNumL( iRtspText, iCSeq );
    AppendL( iRtspText, KCRNewLine );

    if ( iUserAgent )
        {
        TPtrC8 useragent( iUserAgent->Des() );
        AppendFormatL( iRtspText, KCRRTSPUserAgentHeader, &useragent );
        }

    // then variable tail depending on command
    switch ( iCommand )
        {
        case ERTSPCommandOPTIONS:
            if ( iSessionId.Ptr() != NULL ) 
                {
                AppendL( iRtspText, KCRSessionStr() ); 
                AppendL( iRtspText, iSessionId ); // now only session number
                AppendL( iRtspText, KCRNewLine );                
                }
            break;
        
        case ERTSPCommandDESCRIBE:
            {
            AppendL( iRtspText, KCRAcceptSDP );
            if ( iWapProfile )
                {
                TPtrC8 profile = iWapProfile->Des();
                AppendFormatL( iRtspText, KCRRTSPXWapProfile, &profile );
                }
            if ( iBandwidthAvailable )
                {
                AppendFormatL( iRtspText, KCRRTSPBandwidth, iBandwidth );
                }
            }
            break;
        
        case ERTSPCommandTEARDOWN:     
            if ( iSessionId.Ptr() != NULL ) 
                {
                AppendL( iRtspText, KCRSessionStr() ); 
                AppendL( iRtspText, iSessionId ); // now only session number
                AppendL( iRtspText, KCRNewLine );                
                }
            break;

        case ERTSPCommandPAUSE:        
            if ( iSessionId.Ptr() != NULL ) 
                {
                AppendL( iRtspText, KCRSessionStr() ); 
                AppendL( iRtspText, iSessionId ); // now only session number
                AppendL( iRtspText, KCRNewLine );                
                }
            break;

        case ERTSPCommandSETUP:        
            {
            // build transport header according to chosen method
            switch ( iTransport )
                {
                case ERTPOverUDP:
                    AppendFormatL( iRtspText, KCRTransportHeaderUDP,
                                   iClientPort, iClientPort + 1 );
                    break;
                case ERTPOverTCP:
                    AppendFormatL( iRtspText, KCRTransportHeaderTCP,
                                   iClientPort, iClientPort + 1 );
                    break;
                
                case ERTPOverMulticast:
                    AppendL( iRtspText, KCRTransportHeaderMulticast );
                    break;
                }

            // Session: 5273458854096827704         
            if ( iSessionId.Ptr() != NULL ) 
                {
                AppendL( iRtspText, KCRSessionStr ); 
                AppendL( iRtspText, iSessionId ); // now only session number
                AppendL( iRtspText, KCRNewLine ); 
                }
            if ( iWapProfile )
                {
                TPtrC8 profile( iWapProfile->Des() );
                AppendFormatL( iRtspText, KCRRTSPXWapProfile, &profile );
                }
            }
            break;
            
        case ERTSPCommandPLAY: 
            {
            if ( !( iLowerRange == KRealZero && iUpperRange == KRealMinusOne ) )
                {
                // Range was something else than 0,-1
                TBuf8<KMaxName> buf( KCRRangeHeader );
                TRealFormat format( 10, 3 ); 
                format.iTriLen = 0; 
                format.iPoint = '.';
                buf.AppendNum( iLowerRange, format );
                buf.Append( '-' ); 
                if ( iUpperRange > KRealZero )
                    {
                    buf.AppendNum( iUpperRange, format );
                    }
                
                buf.Append( KCRNewLine );
                AppendL( iRtspText, buf );
                }
            if ( iSessionId.Ptr() != NULL ) 
                {
                AppendL( iRtspText, KCRSessionStr() ); 
                AppendL( iRtspText, iSessionId ); // now only session number
                AppendL( iRtspText, KCRNewLine ); 
                }
            }
            break;

        default:
            User::Leave( KErrNotSupported ); 
            break;
        }           
    
    if ( iAuthenticationNeeded )
        {
        TBool useDigest( EFalse );
        
        if ( iAuthType && ( iAuthType->FindC( KCRAuthDigest ) != KErrNotFound ) )
            {
            useDigest = ETrue;
            }
        
        switch ( iCommand )
            {
            case ERTSPCommandOPTIONS :
                useDigest ? CalculateDigestResponseL( KCROPTIONSNoSpace ) :
                            CalculateBasicResponseL( KCROPTIONSNoSpace );
                
                if ( iAuthHeader ) 
                    {
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            case ERTSPCommandDESCRIBE :
                useDigest ? CalculateDigestResponseL( KCRDESCRIBENoSpace ) :
                            CalculateBasicResponseL( KCRDESCRIBENoSpace );  
               
                if ( iAuthHeader ) 
                    {
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            case ERTSPCommandTEARDOWN :     
                useDigest ? CalculateDigestResponseL( KCRTEARDOWNNoSpace ) :
                            CalculateBasicResponseL( KCRTEARDOWNNoSpace );
                
                if ( iAuthHeader ) 
                    {               
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            case ERTSPCommandPAUSE :        
                useDigest ? CalculateDigestResponseL( KCRPAUSENoSpace ) :
                            CalculateBasicResponseL( KCRPAUSENoSpace );
                
                if ( iAuthHeader ) 
                    {           
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            case ERTSPCommandSETUP :        
                useDigest ? CalculateDigestResponseL( KCRSETUPNoSpace ) :
                            CalculateBasicResponseL( KCRSETUPNoSpace );
                
                if ( iAuthHeader ) 
                    {
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            case ERTSPCommandPLAY :  
                useDigest ? CalculateDigestResponseL( KCRPLAYNoSpace ) :
                            CalculateBasicResponseL( KCRPLAYNoSpace );
                
                if ( iAuthHeader ) 
                    {           
                    AppendL( iRtspText, iAuthHeader->Des() );
                    }
                break;
            
            default:
                User::Leave( KErrNotSupported ); 
                break;
            }       
        }
        
    AppendL( iRtspText, KCRNewLine ); 
    iProductDescriptor.Set( *iRtspText );
    return iProductDescriptor;
    }   
    
// -----------------------------------------------------------------------------
// CCRRtspCommand::AppendL
//
// -----------------------------------------------------------------------------
//      
void CCRRtspCommand::AppendL( HBufC8*& aBuffer, const TDesC8& aStr )
    {
    TPtr8 ptr( aBuffer->Des() );
    if ( ( ptr.Length() + aStr.Length() ) >= ptr.MaxLength() )
        {
        const TInt newLength( ptr.Length() + aStr.Length() + KMaxName );
        aBuffer = aBuffer->ReAllocL( newLength );
        ptr.Set( aBuffer->Des() );
        }
    
    ptr.Append( aStr );
    }
    
// -----------------------------------------------------------------------------
// CCRRtspCommand::AppendNumL
//
// -----------------------------------------------------------------------------
//      
void CCRRtspCommand::AppendNumL( HBufC8*& aBuffer, const TInt aNum )
    {
    TPtr8 ptr( aBuffer->Des() );
    if ( ( ptr.Length() + KMaxInfoName ) >= ptr.MaxLength() )
        {
        const TInt newLength( ptr.Length() + KMaxInfoName + KMaxName );
        aBuffer = aBuffer->ReAllocL( newLength );
        ptr.Set( aBuffer->Des() );
        }
    
    ptr.AppendNum( aNum );
    }
    
// -----------------------------------------------------------------------------
// CCRRtspCommand::AppendFormatL
//
// -----------------------------------------------------------------------------
//      
void CCRRtspCommand::AppendFormatL(
    HBufC8*& aBuffer,
    TRefByValue<const TDesC8> aFmt, ... )
    {
    VA_LIST list;
    VA_START( list, aFmt );
    HBufC8* buf = HBufC8::NewLC( KMaxDataSize );
    buf->Des().FormatList( aFmt, list );
    VA_END( list );

    TPtr8 ptr( aBuffer->Des() );
    if ( ( ptr.Length() + buf->Length() ) >= ptr.MaxLength() )
        {
        const TInt newLength( ptr.Length() + buf->Length() + KMaxName );
        aBuffer = aBuffer->ReAllocL( newLength );
        ptr.Set( aBuffer->Des() );
        }
    
    ptr.Append( *buf );
    CleanupStack::PopAndDestroy( buf );
    }
    
// -----------------------------------------------------------------------------
// CCRRtspCommand::Hash
// Calculates hash value ( from S60 HttpFilters )
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::HashL( const TDesC8& aMessage, TDes8& aHash )
    {
    LOG( "CCRRtspCommand::HashL() in" );
    // check if md5 calculator is already constructed
    if ( !iMD5Calculator )
        { 
        iMD5Calculator = CMD5::NewL();
        }
    // Calculate the 128 bit (16 byte) hash
    iMD5Calculator->Reset();
    TPtrC8 hash = iMD5Calculator->Hash( aMessage );
    
    // Now print it as a 32 byte hex number
    aHash.Zero();
    _LIT8( formatStr, "%02x" );
    TBuf8<2> scratch;
    for ( TInt i( 0 ); i < KCRRawHashLength; i++ )
        {
        scratch.Zero();
        scratch.Format( formatStr, hash[i] );
        aHash.Append( scratch );
        }
    
    LOG( "CCRRtspCommand::HashL() out" );
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::CalculateBasicResponseL
//
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::CalculateBasicResponseL( const TDesC8& /*aMethod*/ )
    {
    LOG( "CCRRtspCommand::CalculateBasicResponseL() in" );
    
    if ( !( iUserName && iPassword  ) )
        {
        LOG( "CCRRtspCommand::CalculateBasicResponseL() out, username or password not set" );
        delete iAuthHeader; 
        iAuthHeader = NULL;
        return; // no can do
        }
    
    HBufC8* plainData = HBufC8::NewL( iUserName->Length() + 1 + // ':'
                                      iPassword->Length() );
    
    CleanupStack::PushL( plainData );
    
    plainData->Des().Append( *iUserName );
    plainData->Des().Append( ':' );
    plainData->Des().Append( *iPassword );
    
    // Max size = ((Bytes + 3 - (Bytes MOD 3)) /3) x 4 
    TInt base64MaxSize = ( ( plainData->Length() + 3 - 
            ( plainData->Length() % 3 ) ) / 3 ) * 4;
    
    HBufC8* encodedData = HBufC8::NewL( base64MaxSize );
    TPtr8 dataPrt( encodedData->Des() );   
    CleanupStack::PushL( encodedData );
    
    TImCodecB64 b64enc;
    b64enc.Initialise();
    b64enc.Encode( *plainData, dataPrt );
    
    delete iAuthHeader; 
    iAuthHeader = NULL;
    iAuthHeader = HBufC8::NewL( KCRAuthorizationBasicHeader().Length() + encodedData->Length() );           
    iAuthHeader->Des().Format( KCRAuthorizationBasicHeader, encodedData );
    
    CleanupStack::PopAndDestroy( encodedData );
    CleanupStack::PopAndDestroy( plainData );
    
    LOG( "CCRRtspCommand::CalculateBasicResponseL() out" );
    }

// -----------------------------------------------------------------------------
// CCRRtspCommand::CalculateDigestResponseL
//
// -----------------------------------------------------------------------------
//
void CCRRtspCommand::CalculateDigestResponseL( const TDesC8& aMethod )
    {
    LOG( "CCRRtspCommand::CalculateDigestResponseL() in" );

    if ( !( iUserName && iPassword && iNonce && iOpaque && iRealm && iUri ) )
        {
        LOG( "CCRRtspCommand::CalculateDigestResponseL() out, username or password not set" );
        delete iAuthHeader; iAuthHeader = NULL;
        return; // no can do
        }

    TBuf8<KCRHashLength> hash1;
    TBuf8<KCRHashLength> hash2;
    TBuf8<KCRHashLength> finalHash;

    // calculate the hash1 using "username:realm:password"
    HBufC8* hashPtr = HBufC8::NewL ( iUserName->Length() + 1 +  // ':'
                                     iRealm->Length() + 1 +      // ':' 
                                     iPassword->Length() );
    hashPtr->Des().Append( *iUserName );
    hashPtr->Des().Append( ':' );
    hashPtr->Des().Append( *iRealm );
    hashPtr->Des().Append( ':' );
    hashPtr->Des().Append( *iPassword );
    
    HashL( *hashPtr, hash1 );
    delete hashPtr; hashPtr = NULL;

    // calculate hash2 using "Method:uri"
    HBufC8* hashPtr2 = HBufC8::NewL(aMethod.Length() + 1 + iUri->Length() );
    hashPtr2->Des().Append( aMethod );
    hashPtr2->Des().Append( ':' );
    hashPtr2->Des().Append( *iUri );
    
    HashL( *hashPtr2, hash2 );
    delete hashPtr2; hashPtr2 = NULL;

    // calculate finalHash to be sent to remote server using
    // hash1 + ":" + nonce + ":" + hash2
    HBufC8* hashPtr3 = HBufC8::NewL( hash1.Length() + 1 + // ':'
                                     iNonce->Length() + 1 + // ':'
                                     hash2.Length() );
    hashPtr3->Des().Append( hash1 );
    hashPtr3->Des().Append( ':' );
    hashPtr3->Des().Append( *iNonce );
    hashPtr3->Des().Append( ':' );
    hashPtr3->Des().Append( hash2 );

    HashL( *hashPtr3, finalHash );
    delete hashPtr3; hashPtr3 = NULL;

    // generate the authentication header 
    if ( iOpaque->Length()  ) 
        {
        delete iAuthHeader; iAuthHeader = NULL;
        iAuthHeader = HBufC8::NewL( KCRAuthorizationHeader().Length() + 
            iUserName->Length() + iRealm->Length() + iNonce->Length() +
            iUri->Length() + finalHash.Length() + iOpaque->Length() );
        
        iAuthHeader->Des().Format( KCRAuthorizationHeader, iUserName,
            iRealm, iNonce, iUri, &finalHash, iOpaque );
        }
    else
        {
        delete iAuthHeader; iAuthHeader = NULL;
        iAuthHeader = HBufC8::NewL( KCRAuthorizationHeaderNoOpaque().Length() +
            iUserName->Length() + iRealm->Length() + iNonce->Length() +
            iUri->Length() + finalHash.Length() );
                                    
        iAuthHeader->Des().Format( KCRAuthorizationHeaderNoOpaque, iUserName,
            iRealm, iNonce, iUri, &finalHash );
        }

    LOG( "CCRRtspCommand::CalculateDigestResponseL() out" );   
    }

//  End of File