natplugins/natpnatfwsdpprovider/src/nspcontentparser.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 01:04:58 +0200
changeset 0 1bce908db942
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* 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 "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:  Class implementation for Sdp content parser.
*
*/

#include <e32cmn.h>
#include <in_sock.h>
#include <sdpcodecstringpool.h>
#include <sdpcodecstringconstants.h>
#include <sdpdocument.h>
#include <sdpconnectionfield.h>
#include <sdpattributefield.h>
#include <sdpmediafield.h>
#include "natfwcandidate.h"
#include "natfwcredentials.h"
#include "nspcontentparser.h"
#include "nspdefs.h"

const TInt KAttributesNumber = 7;
static const TText8* const AttributeArray[ KAttributesNumber ] =
    {
    _S8("candidate"),
    _S8("remote-candidates"),
    _S8("ice-lite"),
    _S8("ice-passive"),
    _S8("ice-ufrag"),
    _S8("ice-pwd"),
    _S8("ice-mismatch")
    };
const TInt KIceAttrCandidateIndex = 0;
const TInt KIceAttrRemoteCandidatesIndex = 1;
const TInt KIceAttrLiteIndex = 2;
const TInt KIceAttrPassiveIndex = 3;
const TInt KIceAttrUfragIndex = 4;
const TInt KIceAttrPwdIndex = 5;
const TInt KIceAttrMismatchIndex = 6;

_LIT8( KAttrRtcp, "rtcp" );
_LIT8( KAttrEmpty, " " );
_LIT8( KFieldSeparator, " " );

const TInt KTypeAttrNumber = 9;
static const TText8* const CandidateTypeArray[ KTypeAttrNumber ] = 
    {
    _S8( "typ" ),
    _S8( "host" ),
    _S8( "local" ),
    _S8( "srflx" ),
    _S8( "prflx" ),
    _S8( "relay" ),
    _S8( "tcp-so" ),
    _S8( "tcp-act" ),
    _S8( "tcp-pass" )
    };
const TInt KTypeAttrIndexType = 0;
const TInt KTypeAttrIndexHost = 1;
const TInt KTypeAttrIndexLocal = 2;
const TInt KTypeAttrIndexServerReflex = 3;
const TInt KTypeAttrIndexPeerReflex = 4;
const TInt KTypeAttrIndexRelay = 5;

const TUint KRejecPort = 0;

const TInt KMaxCandidateLength = 200;       // Max for candidate creation.
const TInt KMaxLengthNumberConversion = 40; // Priority field max length.
const TInt KMaxLengthTInetAddr = 40;        // Must support IPv4/IPv6
const TInt KMaxLengthOfFQDN = 255;          // For FQDNs
const TInt KMaxLengthRtcpField = 60;        // Max for rctp attr. value

#define FINDFIELD_L( aField, aMediafield, aFieldarray ) \
    User::LeaveIfNull( aField = CNSPContentParser::FindMediaField( aMediafield, aFieldarray ) )

// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// CNSPContentParser::CNSPContentParser
// ---------------------------------------------------------------------------
//
CNSPContentParser::CNSPContentParser()
    {
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::ConstructL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::ConstructL()
    {
    RStringPool pool = SdpCodecStringPool::StringPoolL();
    
    // ICE attributes
    iCandidate = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrCandidateIndex ] ) );
    iRemoteCandidates = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrRemoteCandidatesIndex ] ) );
    iLite = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrLiteIndex ] ) );
    iPassive = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrPassiveIndex ] ) );
    iUfrag = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrUfragIndex ] ) );
    iPwd = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrPwdIndex ] ) );
    iMismatch = pool.OpenFStringL( 
            TPtrC8( AttributeArray[ KIceAttrMismatchIndex ] ) );
    
    // Other
    iRTCP = pool.OpenFStringL( KAttrRtcp() );    
    iUdp = pool.StringF( SdpCodecStringConstants::EProtocolUdp,
                         SdpCodecStringPool::StringTableL() );
    iTcp = pool.StringF( SdpCodecStringConstants::EProtocolTcp,
                         SdpCodecStringPool::StringTableL() );
    iIN = pool.StringF( SdpCodecStringConstants::ENetType,
                         SdpCodecStringPool::StringTableL() );
    iIPv4 = pool.StringF( SdpCodecStringConstants::EAddressTypeIP4,
                         SdpCodecStringPool::StringTableL() );
    iIPv6 = pool.StringF( SdpCodecStringConstants::EAddressType,
                         SdpCodecStringPool::StringTableL() );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::NewL
// ---------------------------------------------------------------------------
//
CNSPContentParser* CNSPContentParser::NewL()
    {
    CNSPContentParser* self = CNSPContentParser::NewLC();
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::NewLC
// ---------------------------------------------------------------------------
//
CNSPContentParser* CNSPContentParser::NewLC()
    {
    CNSPContentParser* self = new( ELeave ) CNSPContentParser;
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::CNSPContentParser
// ---------------------------------------------------------------------------
//
CNSPContentParser::~CNSPContentParser()
    {
    iCandidate.Close();
    iRemoteCandidates.Close();
    iLite.Close();
    iPassive.Close();
    iUfrag.Close();
    iPwd.Close();
    iMismatch.Close();
    iRTCP.Close();
    iUdp.Close();
    iTcp.Close();
    iIN.Close();
    iIPv4.Close();
    iIPv6.Close();
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::IsIceSupported
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::IsIceSupported( CSdpDocument& aDocument ) const
    {
    RPointerArray<CSdpMediaField>& mediafields = aDocument.MediaFields();
    
    const TInt mediafieldcount( mediafields.Count() );
    for ( TInt index = 0; index < mediafieldcount; index++ )
        {
        RPointerArray<CSdpAttributeField>& attributes =
                mediafields[index]->AttributeFields();
        
        const TInt attributecount( attributes.Count() );
        for ( TInt jndex = 0; jndex < attributecount; jndex++ )
            {
            if ( iCandidate == attributes[jndex]->Attribute() )
                {
                return ETrue;
                }
            }
        }
    
    return EFalse;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::IsMismatchL
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::IsMismatchL( CSdpDocument& aDocument ) const
    {
    const CSdpConnectionField* connField = aDocument.ConnectionField();
    const TDesC8& address = ( connField ? connField->Address() : KNullDesC8 );
    RPointerArray<CSdpMediaField>& mediafields = aDocument.MediaFields();
    
    TBool mismatch( EFalse );
    const TInt mediafieldcount( mediafields.Count() );
    for ( TInt index = 0; index < mediafieldcount && !mismatch; index++ )
        {
        const TDesC8& addr = CONN_ADDR( *mediafields[index], address );
        mismatch = IsMismatchAttribute( *mediafields[index] );
        
        if ( !mismatch && IsMismatchL( *mediafields[index], addr ) )
            {
            AddMismatchL( *mediafields[index] );
            mismatch = ETrue;
            }
        }
    
    return mismatch;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::IsMismatchL
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::IsMismatchL( CSdpMediaField& aMediaField,
        const TDesC8& aAddress ) const
    {
    const TDesC8& rtpAddr = CONN_ADDR( aMediaField, aAddress );
    const TUint rtpPort = aMediaField.Port();
    
    RBuf8 rtcpAddr;
    rtcpAddr.CreateL( KMaxLengthOfFQDN );
    rtcpAddr.CleanupClosePushL();
    rtcpAddr = rtpAddr;
    TUint rtcpPort = rtpPort;
    TBool isRtcp = FindRTCP( aMediaField, rtcpAddr, rtcpPort );
    
    RPointerArray<CNATFWCandidate> remotecand;
    CleanupStack::PushL( TCleanupItem(
            CNSPContentParser::CleanupArrayItem, &remotecand ) );
    
	GetCandidatesL( aMediaField, remotecand );
    
    const TInt candidatecount( remotecand.Count() );
    TBool mismatch = ( candidatecount ? ETrue : EFalse );
    for ( TInt index = 0; index < candidatecount; index++ )
        {
        const TDesC8& addr = remotecand[index]->TransportDomainAddr();
        const TUint port = remotecand[index]->TransportDomainPort();
        
        if ( ( !rtpAddr.Compare( addr ) && port == rtpPort ) ||
             ( isRtcp && !rtcpAddr.Compare( addr ) && port == rtcpPort ) )
            {
            mismatch = EFalse;
            break;
            }
        }
    
    CleanupStack::PopAndDestroy( &remotecand );
    CleanupStack::PopAndDestroy( &rtcpAddr );
    
    NSPLOG_INT( "CNSPContentParser::IsMismatchL, ret:", mismatch )
    return mismatch;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::IsMismatchAttribute
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::IsMismatchAttribute( CSdpMediaField& aMediaField ) const
    {
    RPointerArray<CSdpAttributeField>& attributes = aMediaField.AttributeFields();
    
    const TInt attributecount( attributes.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iMismatch == attributes[index]->Attribute() )
            {
            return ETrue;
            }
        }
    
    return EFalse;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::IsLiteAttribute
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::IsLiteAttribute( CSdpDocument& aDocument ) const
    {
    const RPointerArray<CSdpAttributeField>& attributes =
            aDocument.AttributeFields();
    
    const TInt attributecount( attributes.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iLite == attributes[index]->Attribute() )
            {
            return ETrue;
            }
        }
    
    return EFalse;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::FindRTCP
// ---------------------------------------------------------------------------
//
TBool CNSPContentParser::FindRTCP( CSdpMediaField& aMediaField,
        TDes8& aAddress, TUint& aPort ) const
    {
    const RPointerArray<CSdpAttributeField>& attributes =
            aMediaField.AttributeFields();
    
    const TInt attributecount( attributes.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iRTCP == attributes[index]->Attribute() )
            {
            TLex8 lexer( attributes[index]->Value() );
            
            TUint port( KRejecPort );
            TRAPD( error, LexTDesC8ToTUintL( lexer.NextToken(), port ) );
            aPort = ( KErrNone == error ? port : aPort );
            
            if ( KErrNone == error && !lexer.Eos() )
                {
                lexer.NextToken(); // nettype, not needed
                lexer.NextToken(); // addresstype, not needed
                aAddress = lexer.NextToken();
                }
            
            return ETrue;
            }
        }
    
    return EFalse;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::ModifyRTCPL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::ModifyRTCPL( CSdpMediaField& aMediaField,
        const TDesC8& aAddress, TUint aPort ) const
    {
    TInetAddr address;
    CSdpAttributeField* attr = NULL;
    const RPointerArray<CSdpAttributeField>& attributes =
            aMediaField.AttributeFields();
    
    const TInt attributecount( attributes.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        attr = attributes[index];
        
        if ( iRTCP == attr->Attribute() )
            {
            HBufC8* newattribute = HBufC8::NewLC( KMaxLengthRtcpField );
            TPtr8 ptr( newattribute->Des() );
            
            AppendNumToTDes8L( ptr, aPort );
            AppendTDesC8ToTDes8L( ptr, iIN.DesC() );
            InputTDesC8ToTInetAddrL( aAddress, address );
            AppendTDesC8ToTDes8L( ptr, KAfInet == address.Family() ?
                    iIPv4.DesC() : iIPv6.DesC() );
            AppendTDesC8ToTDes8L( ptr, aAddress, EFalse );
            
            attr->SetL( attr->Attribute(), newattribute->Des() );
            CleanupStack::PopAndDestroy( newattribute );
            break;
            }
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddLiteL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddLiteL( CSdpDocument& aDocument ) const
    {
    CSdpAttributeField* attr = CSdpAttributeField::NewLC( iLite, KNullDesC8 );
    User::LeaveIfError( aDocument.AttributeFields().Append( attr ) );
    CleanupStack::Pop( attr );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddMismatchL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddMismatchL( CSdpDocument& aMismatch,
        CSdpDocument& aMismatched ) const
    {
    CSdpMediaField* field = NULL;
    RPointerArray<CSdpMediaField>& mismatchmedia = aMismatch.MediaFields();
    RPointerArray<CSdpMediaField>& mismatchedmedia = aMismatched.MediaFields();
    
    const TInt mediacount( mismatchmedia.Count() );
    for ( TInt index = 0; index < mediacount; index++ )
        {
        if ( IsMismatchAttribute( *mismatchmedia[index] ) )
            {
            FINDFIELD_L( field, *mismatchmedia[index], mismatchedmedia );
            AddMismatchL( *field );
            RemoveIceContent( *mismatchmedia[index] );
            }
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddMismatchL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddMismatchL( CSdpMediaField& aMediaField ) const
    {
    CSdpAttributeField* attr = CSdpAttributeField::NewLC( iMismatch, KNullDesC8 );
    User::LeaveIfError( aMediaField.AttributeFields().Append( attr ) );
    CleanupStack::Pop( attr );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddCandidatesL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddCandidatesL( CSdpMediaField& aMediaField,
        const RPointerArray<CNATFWCandidate>& aCandidates ) const
    {
    CSdpAttributeField* attr = NULL;
    RPointerArray<CSdpAttributeField>& attributeArray =
            aMediaField.AttributeFields();
    
    const TInt candidatecount( aCandidates.Count() );
    for ( TInt index = 0; index < candidatecount; index++ )
        {
        TRAPD( error, attr = EncodeCandidateLineL( *aCandidates[index] ) )
        User::LeaveIfError( KErrNone == error ?
                attributeArray.Append( attr ) : error );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddRemoteCandidatesL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddRemoteCandidatesL( CSdpMediaField& aMediaField,
        const RPointerArray<CNATFWCandidate>& aCandidates ) const
    {
    RPointerArray<CSdpAttributeField>& attributeArray =
            aMediaField.AttributeFields();
    
    CSdpAttributeField* attribute = EncodeRemoteCandidatesL( aCandidates );
    CleanupStack::PushL( attribute );
    User::LeaveIfError( attributeArray.Append( attribute ) );
    CleanupStack::Pop( attribute );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddCredentialsL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddCredentialsL( CSdpMediaField& aMediaField,
        const CNATFWCredentials& aCredentials ) const
    {
    RPointerArray<CSdpAttributeField>& attributeArray =
            aMediaField.AttributeFields();
    
    CSdpAttributeField* user = EncodeUfragL( aCredentials );
    CleanupStack::PushL( user );
    User::LeaveIfError( attributeArray.Append( user ) );
    CleanupStack::Pop( user );
    
    CSdpAttributeField* pwd = EncodePwdL( aCredentials );
    CleanupStack::PushL( pwd );
    User::LeaveIfError( attributeArray.Append( pwd ) );
    CleanupStack::Pop( pwd );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AddCredentialsL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AddCredentialsL( CSdpDocument& aDocument,
        const CNATFWCredentials& aCredentials ) const
    {
    RPointerArray<CSdpAttributeField>& attributeArray =
            aDocument.AttributeFields();
    
    CSdpAttributeField* user = EncodeUfragL( aCredentials );
    CleanupStack::PushL( user );
    User::LeaveIfError( attributeArray.Append( user ) );
    CleanupStack::Pop( user );
    
    CSdpAttributeField* pwd = EncodePwdL( aCredentials );
    CleanupStack::PushL( pwd );
    User::LeaveIfError( attributeArray.Append( pwd ) );
    CleanupStack::Pop( pwd );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::GetCandidatesL
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::GetCandidatesL( CSdpMediaField& aMediaField,
        RPointerArray<CNATFWCandidate>& aCandidates ) const
    {
    TInt warning = KErrNone;
    CNATFWCandidate* cand = NULL;
    const RPointerArray<CSdpAttributeField>& attrArray =
            aMediaField.AttributeFields();
    
    const TInt attributecount( attrArray.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iCandidate == attrArray[index]->Attribute() )
            {
            cand = CNATFWCandidate::NewLC();
            
            TRAPD( error, DecodeCandidateLineL( *attrArray[index], *cand ) );
            
            if ( KErrNone == error )
                {
                User::LeaveIfError( aCandidates.Append( cand ) );
                CleanupStack::Pop( cand );
                }
            else if ( KErrNoMemory == error )
            	{
            	User::Leave( KErrNoMemory );
            	}
            else
                {
                warning = error;
                CleanupStack::PopAndDestroy( cand );
                }
            }
        }
    
    return warning;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::GetRemoteCandidatesL
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::GetRemoteCandidatesL( CSdpDocument& aDocument,
        RPointerArray<CNATFWCandidate>& aRemoteCands ) const
    {
    const RPointerArray<CSdpMediaField>& mediafieldArray =
            aDocument.MediaFields();
    
    const TInt mediafieldcount( mediafieldArray.Count() );
    for ( TInt index = 0; index < mediafieldcount; index++ )
        {
        GetRemoteCandidatesL( *mediafieldArray[index], aRemoteCands );
        }
    
    return KErrNone;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::GetRemoteCandidatesL
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::GetRemoteCandidatesL( CSdpMediaField& aMediaField,
        RPointerArray<CNATFWCandidate>& aRemoteCands ) const
    {
    const RPointerArray<CSdpAttributeField>& attributeArray =
            aMediaField.AttributeFields();
    
    const TInt attributecount( attributeArray.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iRemoteCandidates == attributeArray[index]->Attribute() )
            {
            DecodeRemoteCandidatesL( attributeArray[index]->Value(),
                                     aRemoteCands );
            }
        }
    
    return KErrNone;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::GetCredentialsL
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::GetCredentialsL( CSdpMediaField& aMediaField,
        CNATFWCredentials& aCredentials ) const
    {
    const RPointerArray<CSdpAttributeField>& attributeArray =
            aMediaField.AttributeFields();
    
    const TInt attributecount( attributeArray.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iUfrag == attributeArray[index]->Attribute() )
            {
            DecodeUfragL( *attributeArray[index], aCredentials );
            }
        else if ( iPwd == attributeArray[index]->Attribute() )
            {
            DecodePwdL( *attributeArray[index], aCredentials );
            }
        else
            {
            // Nothing to do here
            }
        }
    
    return KErrNone;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::GetCredentialsL
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::GetCredentialsL( CSdpDocument& aDocument,
        CNATFWCredentials& aCredentials ) const
    {
    const RPointerArray<CSdpAttributeField>& attributeArray =
            aDocument.AttributeFields();
    
    const TInt attributecount( attributeArray.Count() );
    for ( TInt index = 0; index < attributecount; index++ )
        {
        if ( iUfrag == attributeArray[index]->Attribute() )
            {
            DecodeUfragL( *attributeArray[index], aCredentials );
            }
        else if ( iPwd == attributeArray[index]->Attribute() )
            {
            DecodePwdL( *attributeArray[index], aCredentials );
            }
        else
            {
            // Nothing to do here
            }
        }
    
    return KErrNone;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::RemoveIceContent
// ---------------------------------------------------------------------------
//
void CNSPContentParser::RemoveIceContent( CSdpDocument& aDocument ) const
    {
    RPointerArray<CSdpAttributeField>& attributes = aDocument.AttributeFields();
    
    for ( TInt index = 0; index < attributes.Count() ; )
        {
        RStringF attribute = attributes[index]->Attribute();
        
        if ( iCandidate == attribute ||
             iRemoteCandidates == attribute ||
             iLite == attribute ||
             iPassive == attribute ||
             iUfrag == attribute ||
             iPwd == attribute || 
             iMismatch == attribute )
            {
            delete ( attributes[index] );
            attributes.Remove( index );
            attributes.Compress();
            }
        else
            {
            index++;
            }
        }
    
    RPointerArray<CSdpMediaField>& mediafields = aDocument.MediaFields();
    
    const TInt mediafieldcount( mediafields.Count() );
    for ( TInt index = 0; index < mediafieldcount ; index++ )
        {
        RemoveIceContent( *mediafields[index] );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::RemoveIceContent
// ---------------------------------------------------------------------------
//
void CNSPContentParser::RemoveIceContent( CSdpMediaField& aMediaField ) const
    {
    RPointerArray<CSdpAttributeField>& attributes = aMediaField.AttributeFields();
    
    for ( TInt index = 0; index < attributes.Count() ; )
        {
        RStringF attribute = attributes[index]->Attribute();
        
        if ( iCandidate == attribute ||
             iRemoteCandidates == attribute ||
             iLite == attribute ||
             iPassive == attribute ||
             iUfrag == attribute ||
             iPwd == attribute ||
             iMismatch == attribute )
            {
            delete ( attributes[index] );
            attributes.Remove( index );
            attributes.Compress();
            }
        else
            {
            index++;
            }
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::EncodeCandidateLineL
// ---------------------------------------------------------------------------
//
CSdpAttributeField* CNSPContentParser::EncodeCandidateLineL(
        const CNATFWCandidate& aCandidate ) const
    {
    HBufC8* content = HBufC8::NewLC( KMaxCandidateLength );
    TPtr8 ptr( content->Des() );
    
    // 1. Foundation
    AppendTDesC8ToTDes8L( ptr, aCandidate.Foundation() );
    
    // 2. Component Id
    AppendNumToTDes8L( ptr, aCandidate.ComponentId() );
    
    // 3. Protocol
    AppendProtocolToTDes8L( ptr, aCandidate.TransportProtocol() );
    
    // 4. Priority
    AppendNumToTDes8L( ptr, aCandidate.Priority() );
    
    // 5. IP address & Port
    AppendTDesC8ToTDes8L( ptr, aCandidate.TransportDomainAddr() );
    AppendNumToTDes8L( ptr, aCandidate.TransportDomainPort() );
    
    // 6. Type
    AppendTypeToTDes8L( ptr, aCandidate.Type(), EFalse );
    
    // 7. Optional information, i.e. related address and etc.
    
    CSdpAttributeField* attribute = CSdpAttributeField::NewL( iCandidate, *content );
    CleanupStack::PopAndDestroy( content );
    
    return attribute;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::DecodeCandidateLineL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::DecodeCandidateLineL(
        const CSdpAttributeField& aAttribute, CNATFWCandidate& aCandidate ) const
    {
    TLex8 lex( aAttribute.Value() );
    TUint unsignedInteger( 0 );
    
    // 1. Foundation( char(s) )
    aCandidate.SetFoundationL( lex.NextToken() );
    
    // 2. Component Id( single digit )
    LexTDesC8ToTUintL( lex.NextToken(), unsignedInteger );
    aCandidate.SetComponentId( unsignedInteger );
    
    // 3. Protocol( string: UDP, TCP )
    TUint protocol( KProtocolInetUdp );
    SolveTransportProtocolL( lex.NextToken(), protocol );
    aCandidate.SetTransportProtocol( protocol );
    
    // 4. Priority( multiple digits, positive large integer )
    LexTDesC8ToTUintL( lex.NextToken(), unsignedInteger );
    aCandidate.SetPriority( unsignedInteger );
    
    // 5. IP address & Port
    TPtrC8 address = lex.NextToken();
    LexTDesC8ToTUintL( lex.NextToken(), unsignedInteger );
    aCandidate.SetTransportDomainAddrL( address, unsignedInteger );
    
    // 6. Type( typ "value" )
    CNATFWCandidate::TCandidateType type;
    TPtrC8 typ = lex.NextToken();
    TPtrC8 value = lex.NextToken();
    SolveCandidateTypeL( typ, value, type );
    aCandidate.SetType( type );
    
    // 7. Optional information, i.e. related address and etc.
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::EncodeRemoteCandidatesL
// ---------------------------------------------------------------------------
//
CSdpAttributeField* CNSPContentParser::EncodeRemoteCandidatesL(
        const RPointerArray<CNATFWCandidate>& aCandidates ) const
    {
    HBufC8* content = HBufC8::NewLC( KMaxCandidateLength );
    TPtr8 ptr( content->Des() );
    
    const TInt remotecandidatecount( aCandidates.Count() );
    for ( TInt index = 0; index < remotecandidatecount; index++ )
        {
        EncodeRemoteCandidateL( ptr, *aCandidates[index] );
        }

    CSdpAttributeField* attribute = CSdpAttributeField::NewL(
            iRemoteCandidates, *content );
    CleanupStack::PopAndDestroy( content );
    return attribute;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::EncodeRemoteCandidatesL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::EncodeRemoteCandidateL( TDes8& aBuffer,
        const CNATFWCandidate& aCandidate ) const
    {
    // 1. Component Id( single digit )
    AppendNumToTDes8L( aBuffer, aCandidate.ComponentId() );
    
    // 2. IP address & Port
    AppendTDesC8ToTDes8L( aBuffer, aCandidate.TransportDomainAddr() );
    AppendNumToTDes8L( aBuffer, aCandidate.TransportDomainPort() );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::DecodeRemoteCandidatesL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::DecodeRemoteCandidatesL( const TDesC8& aValue,
        RPointerArray<CNATFWCandidate>& aCandidates ) const
    {
    TLex8 lex( aValue );
    TUint unsignedInteger( 0 );
    
    CNATFWCandidate* candidate = CNATFWCandidate::NewLC();
    
    // 1. Component Id( single digit )
    LexTDesC8ToTUintL( lex.NextToken(), unsignedInteger );
    candidate->SetComponentId( unsignedInteger );
    
    // 2. IP address & Port
    const TPtrC8 address = lex.NextToken();
    LexTDesC8ToTUintL( lex.NextToken(), unsignedInteger );
    candidate->SetTransportDomainAddrL( address, unsignedInteger );
    
    User::LeaveIfError( aCandidates.Append( candidate ) );
    CleanupStack::Pop( candidate );
    
    if ( !lex.Eos() )
        {
        DecodeRemoteCandidatesL( lex.Remainder(), aCandidates );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::EncodeUfragL
// ---------------------------------------------------------------------------
//
CSdpAttributeField* CNSPContentParser::EncodeUfragL(
        const CNATFWCredentials& aCredentials ) const
    {
    CSdpAttributeField* attribute = NULL;
    const TDesC8& username = aCredentials.Username();
    
    if ( !username.Length() )
        {
        attribute = CSdpAttributeField::NewL( iUfrag, KAttrEmpty );
        }
    else
        {
        attribute = CSdpAttributeField::NewL( iUfrag, username );
        }
    
    return attribute;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::DecodeUfragL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::DecodeUfragL( const CSdpAttributeField& aAttribute,
        CNATFWCredentials& aCredentials ) const
    {
    aCredentials.SetUsernameL( aAttribute.Value() );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::EncodePwdL
// ---------------------------------------------------------------------------
//
CSdpAttributeField* CNSPContentParser::EncodePwdL(
        const CNATFWCredentials& aCredentials ) const
    {
    CSdpAttributeField* attribute = NULL;
    const TDesC8& password = aCredentials.Password();
    
    if ( !password.Length() )
        {
        attribute = CSdpAttributeField::NewL( iPwd, KAttrEmpty );
        }
    else
        {
        attribute = CSdpAttributeField::NewL( iPwd, password );
        }
    
    return attribute;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::DecodePwdL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::DecodePwdL( const CSdpAttributeField& aAttribute,
        CNATFWCredentials& aCredentials ) const
    {
    aCredentials.SetPasswordL( aAttribute.Value() );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::LexTDesC8ToTUintL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::LexTDesC8ToTUintL( const TDesC8& aDesC8,
        TUint& aUint ) const
    {
    TLex8 lex8( aDesC8 );
    User::LeaveIfError( lex8.Val( aUint, EDecimal ) );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::SolveTransportProtocolL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::SolveTransportProtocolL( const TDesC8& aDesC8,
        TUint& aProto ) const
    {
    if ( !aDesC8.CompareF( iUdp.DesC() ) )
        {
        aProto = KProtocolInetUdp;
        }
    else if ( !aDesC8.CompareF( iTcp.DesC() ) )
        {
        aProto = KProtocolInetTcp;
        }
    else
        {
        User::Leave( KErrArgument );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::InputTDesC8ToTInetAddrL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::InputTDesC8ToTInetAddrL( const TDesC8& aDesC8,
        TInetAddr& aAddress ) const
    {
    HBufC* buffer = HBufC::NewLC( aDesC8.Length() );
    TPtr ptr( buffer->Des() );
    ptr.Copy( aDesC8 );
    User::LeaveIfError( aAddress.Input( buffer->Des() ) );
    CleanupStack::PopAndDestroy( buffer );
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::SolveCandidateTypeL
// ---------------------------------------------------------------------------
//    
void CNSPContentParser::SolveCandidateTypeL( const TDesC8& aDesC8Typ,
        const TDesC8& aDesC8Value, CNATFWCandidate::TCandidateType& aType ) const
    {
    TPtrC8 type( CandidateTypeArray[ KTypeAttrIndexType ] );
    User::LeaveIfError( !aDesC8Typ.CompareF( type ) );
    
    const TInt candidatetypeindex = FindCandidateType( aDesC8Value );
    
    if ( KErrNotFound == candidatetypeindex )
        {
        NSPLOG_STR(
        "CNSPContentParser::SolveCandidateTypeL(),KErrNotFound" )
        User::Leave( KErrArgument );
        }
    
    switch ( candidatetypeindex )
        {
        case KTypeAttrIndexHost:
        case KTypeAttrIndexLocal:
            {
            aType = CNATFWCandidate::EHost;
            break;
            }
        
        case KTypeAttrIndexServerReflex:
            {
            aType = CNATFWCandidate::EServerReflexive;
            break;
            }
        
        case KTypeAttrIndexPeerReflex:
            {
            aType = CNATFWCandidate::EPeerReflexive;
            break;
            }
        
        case KTypeAttrIndexRelay:
            {
            aType = CNATFWCandidate::ERelay;
            break;
            }
        
        default:
            {
            NSPLOG_STR(
            "CNSPContentParser::SolveCandidateTypeL(),default!" )
            User::Leave( KErrArgument ); // should never come here
            break;
            }
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::FindCandidateType
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::FindCandidateType( const TDesC8& aDesC8Value ) const
    {
    for ( TInt index = 0; index < KTypeAttrNumber; index++ )
        {
        if ( !aDesC8Value.CompareF( TPtrC8( CandidateTypeArray[index] ) ) )
            {
            return index;
            }
        }
    
    return KErrNotFound;
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::FindCandidateType
// ---------------------------------------------------------------------------
//
TInt CNSPContentParser::FindCandidateTypeString(
        const CNATFWCandidate::TCandidateType& aType ) const
    {
    switch ( aType )
        {
        case CNATFWCandidate::EHost:
            {
            return KTypeAttrIndexHost;
            }
        
        case CNATFWCandidate::EServerReflexive:
            {
            return KTypeAttrIndexServerReflex;
            }
        
        case CNATFWCandidate::EPeerReflexive:
            {
            return KTypeAttrIndexPeerReflex;
            }
        
        case CNATFWCandidate::ERelay:
            {
            return KTypeAttrIndexRelay;
            }
        
        default:
            {
            return KErrNotFound;
            }
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AppendTDesC8ToTDes8L
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AppendTDesC8ToTDes8L( TDes8& aDes8,
        const TDesC8& aDesC8, TBool aAddFieldSeparator ) const
    {
    LeaveIfTooLongL( aDes8, aDesC8.Length() );
    aDes8.Append( aDesC8 );
    
    if ( aAddFieldSeparator )
        {
        LeaveIfTooLongL( aDes8, 1 );
        aDes8.Append( KFieldSeparator );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AppendNumToTDes8L
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AppendNumToTDes8L( TDes8& aDes8,
        TUint aNumber, TBool aAddFieldSeparator ) const
    {
    TBuf< KMaxLengthNumberConversion > buffer;
    buffer.AppendNum( aNumber, EDecimal );
    LeaveIfTooLongL( aDes8, buffer.Length() );
    aDes8.AppendNum( aNumber, EDecimal );
    
    if ( aAddFieldSeparator )
        {
        LeaveIfTooLongL( aDes8, 1 );
        aDes8.Append( KFieldSeparator );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AppendProtocolToTDes8L
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AppendProtocolToTDes8L( TDes8& aDes8,
        const TUint& aProtocol, TBool aAddFieldSeparator ) const
    {
    LeaveIfTooLongL( aDes8, Max( iUdp.DesC().Length(), iTcp.DesC().Length() ) );
    
    if ( KProtocolInetUdp == aProtocol )
        {
        aDes8.Append( iUdp.DesC() );
        }
    else if ( KProtocolInetTcp == aProtocol )
        {
        aDes8.Append( iTcp.DesC() );
        }
    else // EUndefined
        {
        User::Leave( KErrNotSupported );
        }
    
    if ( aAddFieldSeparator )
        {
        LeaveIfTooLongL( aDes8, 1 );
        aDes8.Append( KFieldSeparator );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AppendTInetAddrToTDes8L
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AppendTInetAddrToTDes8L( TDes8& aDes8,
        const TInetAddr& aAddress, TBool aAddFieldSeparator ) const
    {
    TBuf<KMaxLengthTInetAddr> buffer;
    aAddress.Output( buffer );
    LeaveIfTooLongL( aDes8, buffer.Length() );
    aDes8.Append( buffer );
    
    if ( aAddFieldSeparator )
        {
        LeaveIfTooLongL( aDes8, 1 );
        aDes8.Append( KFieldSeparator );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::AppendTypeToTDes8L
// ---------------------------------------------------------------------------
//
void CNSPContentParser::AppendTypeToTDes8L( TDes8& aDes8,
        const CNATFWCandidate::TCandidateType& aType,
        TBool aAddFieldSeparator ) const
    {
    const TInt candidatetypeindex = FindCandidateTypeString( aType );
    
    if ( KErrNotFound != candidatetypeindex )
        {
        TPtrC8 type( CandidateTypeArray[ KTypeAttrIndexType ] );
        TPtrC8 value( CandidateTypeArray[ candidatetypeindex ] );
        
        LeaveIfTooLongL( aDes8, type.Length() + 
                KFieldSeparator().Length() + value.Length() );
        
        aDes8.Append( type );
        aDes8.Append( KFieldSeparator );
        aDes8.Append( value );
        
        if ( aAddFieldSeparator )
            {
            LeaveIfTooLongL( aDes8, 1 );
            aDes8.Append( KFieldSeparator );
            }
        }
    else
        {
        NSPLOG_STR(
        "CNSPContentParser::AppendTypeToTDes8L(),KErrNotFound!" )
        User::Leave( KErrArgument );
        }
    }


// ---------------------------------------------------------------------------
// CNSPContentParser::LeaveIfTooLongL
// ---------------------------------------------------------------------------
//
void CNSPContentParser::LeaveIfTooLongL( const TDes8& aDes8,
        const TInt aLength ) const
    {
    const TInt free = aDes8.MaxLength() - aDes8.Length();
    
    if ( free < aLength )
        {
        User::Leave( KErrTooBig );
        }
    }

// ---------------------------------------------------------------------------
// CNSPContentParser::FindMediaField
// ---------------------------------------------------------------------------
//
CSdpMediaField* CNSPContentParser::FindMediaField( const CSdpMediaField& aMediaField,
        const RPointerArray<CSdpMediaField>& aMediaFields ) const
    {
    const TInt mediafieldscount( aMediaFields.Count() );
    for ( TInt index = 0; index < mediafieldscount; index++ )
        {
        if ( aMediaFields[index]->Media() == aMediaField.Media() )
            {
            return aMediaFields[index];
            }
        }
    
    return NULL;    
    }

// ---------------------------------------------------------------------------
// CNSPContentParser::CleanupArrayItem
// ---------------------------------------------------------------------------
//
void CNSPContentParser::CleanupArrayItem( TAny* anArray )
    {
    if ( anArray )
        {
        reinterpret_cast< RPointerArray<CNATFWCandidate>* >( anArray )->
            ResetAndDestroy();
        reinterpret_cast< RPointerArray<CNATFWCandidate>* >( anArray )->
            Close();
        }
    }


// end of file