voipplugins/sipmxresolver/src/sipmxresolver.cpp
branchRCL_3
changeset 22 d38647835c2e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/voipplugins/sipmxresolver/src/sipmxresolver.cpp	Wed Sep 01 12:29:57 2010 +0100
@@ -0,0 +1,759 @@
+/*
+* Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  implementation of sipmxresolver
+*
+*/
+
+
+// INCLUDE FILES
+#include "sipmxresolver.h"
+#include "csipclientresolverutils.h"
+#include <e32base.h>
+#include <e32std.h>
+#include <e32property.h>
+
+//for checking CS call status
+#include <ctsydomainpskeys.h>
+
+//SIP message content parsing APIs
+#include <sipheaderbase.h>
+#include <sipacceptcontactheader.h>
+#include <sipaddress.h>
+#include <sdpdocument.h>
+#include <sdpmediafield.h>
+#include <sdpcodecstringpool.h>
+#include <sdpcodecstringconstants.h>
+#include <sdpattributefield.h>
+#include <sipstrings.h>
+#include <sipallowheader.h>
+#include <sipsupportedheader.h>
+
+//For checking dynamic voip status and MuS availability
+#include <featmgr.h>
+#include <centralrepository.h>
+#include <settingsinternalcrkeys.h>
+
+//Multimedia Sharing client API
+#include <musmanager.h>
+
+//Incoming Call Monitor API
+#include <icmapi.h>
+
+
+// CONSTANTS
+_LIT8( KFTagChar, "+" ); 						// All feature tags start with +
+_LIT8( KVSFeatureTag, "+g.3gpp.cs-voice" );		// For checking VS specific tag
+_LIT8( KPoCFeatureTag, "+g.poc.talkburst" ); 	// PoC specific tag (for ruling out)
+_LIT8( KContentType, "application/sdp" );		// For content-type header
+_LIT8( KMediaTypeApp, "application" );        	// For content-type header checks
+_LIT8( KMediaSubtypeSdp, "sdp" );            	// For content-type header checks
+_LIT8( KSendOnly, "sendonly" );            		// For attribute checks
+_LIT8( KApplicationAttr, "application" );   	// For attribute checks
+_LIT8( KXApplicationAttr, "X-application" );	// For attribute checks
+_LIT8( KNokiaRtvs, "com.nokia.rtvs" );       	// For attribute checks
+_LIT8( KSIPMethodsInAllowHeader, "INVITE,ACK,CANCEL,OPTIONS,BYE,PRACK,SUBSCRIBE,REFER,NOTIFY,UPDATE");	// SIP Methods allowed by various plugins
+_LIT8( KSIPExtensionsSupported, "100rel,timer,sec-agree"); //Extensions supported by various plugins
+
+/**
+ * Cleanup function for RPointerArray
+ * Called in case of a leave in SupportedSdpMediasL
+ */
+void CleanupSdpMediasArray( TAny* aObj )
+    {
+    if ( aObj )
+        {
+        static_cast<RPointerArray<CSdpMediaField>*>( aObj )->ResetAndDestroy();
+        }
+    }
+
+
+// ============================ MEMBER FUNCTIONS =============================
+// ---------------------------------------------------------------------------
+// CSipMXResolver::CSipMXResolver
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------------------------
+//
+CSipMXResolver::CSipMXResolver() 
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::ConstructL
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+// 
+void CSipMXResolver::ConstructL()
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::ConstructL()" )
+    
+    // Open sdp string pool (needed in media field checks)
+    TRAPD( err, SdpCodecStringPool::OpenL() );
+    
+    switch ( err )
+	    {
+    	case KErrNone:
+	    	{
+	    	//close pool at destructor, not opened by others
+			iCloseStringPool = ETrue;
+			break;
+	    	}
+	    
+	    case KErrAlreadyExists:
+	    	{
+	    	//already opened, do not try to close at destructor
+	    	iCloseStringPool = EFalse;
+	    	break;
+	    	}
+	    
+	    default:
+	    	{
+	    	User::Leave( err );
+	    	}
+	    }
+    
+    // Check VoIP and Multimedia Sharing availability
+    FeatureManager::InitializeLibL();
+    
+    TInt dynvoip = 0;
+    CRepository* repository = CRepository::NewL( KCRUidTelephonySettings );
+    repository->Get( KDynamicVoIP, dynvoip );
+    delete repository;
+    
+    iVoIPEnabled = ( dynvoip && FeatureManager::FeatureSupported( KFeatureIdCommonVoip ) );
+    
+    if ( FeatureManager::FeatureSupported( KFeatureIdMultimediaSharing ) )
+        {
+        iMuSManager = CMusManager::NewL();
+        }
+    
+    FeatureManager::UnInitializeLib();
+    
+    // initialize media type strings
+    iAudioType = SdpCodecStringPool::StringPoolL().StringF(
+                    SdpCodecStringConstants::EMediaAudio,
+                        SdpCodecStringPool::StringTableL() );
+    
+    iVideoType = SdpCodecStringPool::StringPoolL().StringF(
+                    SdpCodecStringConstants::EMediaVideo,
+                        SdpCodecStringPool::StringTableL() );
+    
+    SIPMXRLOG( "[SIPMXRESOLVER] <- CSipMXResolver::ConstructL()" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::NewL
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+// 
+CSipMXResolver* CSipMXResolver::NewL()
+    {
+    CSipMXResolver* self = new( ELeave ) CSipMXResolver;
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self);
+    return self;
+    }
+
+
+// Destructor
+CSipMXResolver::~CSipMXResolver()
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::~CSipMXResolver()" )
+    
+    delete iMuSManager;
+    iAudioType.Close();
+    iVideoType.Close();
+    
+    if ( iCloseStringPool )
+	    {
+	    SdpCodecStringPool::Close();
+	    }
+    
+    SIPMXRLOG( "[SIPMXRESOLVER] <- CSipMXResolver::~CSipMXResolver()" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::MatchAcceptContactsL
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::MatchAcceptContactsL(
+            RStringF aMethod,
+            const CUri8& /*aRequestUri*/,
+            const RPointerArray<CSIPHeaderBase>& aHeaders,
+            const TDesC8& /*aContent*/,
+            const CSIPContentTypeHeader* /*aContentType*/,
+            TUid& aClientUid )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::MatchAcceptContactsL()" )
+    
+    TBool match = EFalse;
+    
+    // check if we have active CS call
+    // and MM Sharing is enabled (otherwise this can't be MuS)
+    if ( iMuSManager && IsCSCallActive() )
+        {
+        if ( CheckForACHeaderTagL( aHeaders, KVSFeatureTag ) )
+            {
+            match = ETrue;
+            aClientUid = ResolveVSUidL( aMethod );
+            }
+        }
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::MatchAcceptContactsL(), ret:%d", match )
+    return match;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::MatchEventL
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::MatchEventL(
+            RStringF /*aMethod*/,
+            const CUri8& /*aRequestUri*/,
+            const RPointerArray<CSIPHeaderBase>& /*aHeaders*/,
+            const TDesC8& /*aContent*/,
+            const CSIPContentTypeHeader* /*aContentType*/,
+            TUid& /*aClientUid*/)
+    {
+    //SipMXResolver returns always EFalse for MatchEventL calls
+    SIPMXRLOG( "[SIPMXRESOLVER] <-> CSipMXResolver::MatchEventL()" )
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::MatchRequestL
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::MatchRequestL(
+            RStringF aMethod,
+            const CUri8& aRequestUri,
+            const RPointerArray<CSIPHeaderBase>& aHeaders,
+            const TDesC8& aContent,
+            const CSIPContentTypeHeader* aContentType,
+            TUid& aClientUid )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::MatchRequestL()" )
+    
+    TBool match = EFalse;
+    
+    //poc specific requests will not be processed
+    TBool poc = CheckForACHeaderTagL( aHeaders, KPoCFeatureTag );
+    
+    //OPTIONS and INVITE requests are processed
+    TBool requestok = ( aMethod == SIPStrings::StringF( SipStrConsts::EOptions ) ||
+         aMethod == SIPStrings::StringF( SipStrConsts::EInvite ) );
+    
+    //application/sdp content type is required
+    TBool contentok = ( aContent.Length() > 0 && aContentType &&
+         aContentType->MediaType().CompareF( KMediaTypeApp ) == 0 &&
+         aContentType->MediaSubtype().CompareF( KMediaSubtypeSdp ) == 0 );
+    
+    // do further checks only if we have either VoIP and/or MuS active,
+    // content type must be valid and accept-contact is not poc specific
+    if ( ( iVoIPEnabled || iMuSManager ) && requestok && contentok && !poc )
+        {
+        CSdpDocument* sdpDocument = CSdpDocument::DecodeLC( aContent );
+        
+        // determine the parameters
+        TBool hasAudio = CheckForMedia( sdpDocument, iAudioType );
+        TBool hasVideo = CheckForMedia( sdpDocument, iVideoType );
+        TBool cscall = IsCSCallActive();
+        
+        if ( iMuSManager && hasVideo && hasAudio && cscall )
+            {
+            // both audio and video medias present and cs call on
+            // and multimedia sharing enabled =>
+            // we need to do some further resolving for client
+            if ( CheckForVSAttributes( sdpDocument->MediaFields() ) )
+                {
+                // this is VS
+                match = ETrue;
+                aClientUid = ResolveVSUidL( aMethod );
+                }
+            else if ( iVoIPEnabled )
+                {
+                // no vs attributes and voip status is enabled
+                match = ETrue;
+                ResolveCPPluginUidL( aClientUid, aRequestUri );
+                }
+            else
+                {
+                // possible voip match, but voip not activated
+                match = EFalse;
+                }
+            }
+        else if ( iMuSManager && hasVideo && cscall )
+            {
+            //video media only && cs call ongoing && multimedia sharing enabled
+            // => Multimedia Sharing
+            match = ETrue;
+            aClientUid = ResolveVSUidL( aMethod );
+            }
+        else if ( hasAudio && iVoIPEnabled )
+            {
+            // audio only or audio and video and no cs call + voip supported
+            // => this is VoIP
+            match = ETrue;
+            ResolveCPPluginUidL( aClientUid, aRequestUri );
+            }
+        else
+            {
+            // no medias or has video but no CS call or has audio
+            // but voip status is disabled 
+            // => no match
+            match = EFalse;
+            }
+        
+        CleanupStack::PopAndDestroy( sdpDocument );
+        }
+    else if ( aMethod == SIPStrings::StringF( SipStrConsts::EInvite ) &&
+    		  iVoIPEnabled && !poc && aContent.Length() == 0 )
+    	{
+    	// Pull model: this is a re-Invite without content
+    	ResolveCPPluginUidL( aClientUid, aRequestUri );
+    	match = ETrue;
+    	}
+    else
+    	{
+    	//no match
+    	match = EFalse;
+        }
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::MatchRequestL(), ret:%d", match )
+    return match;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::ConnectSupported
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::ConnectSupported()
+    {
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::ConnectL
+// ---------------------------------------------------------------------------
+//
+void CSipMXResolver::ConnectL( const TUid& aClientUid )
+    {
+    SIPMXRLOGP(\
+    "[SIPMXRESOLVER] -> CSipMXResolver::ConnectL(), uid:%d", aClientUid.iUid )
+    
+    // If Uid matches with MuS, forward to MusManager
+    if ( iMuSManager &&
+         ( aClientUid.iUid == CMusManager::ESipOptions ||
+           aClientUid.iUid == CMusManager::ESipInviteDesired ||
+           aClientUid.iUid == CMusManager::ESipInviteNotDesired ) )
+        {
+        iMuSManager->HandleSipRequestL(
+                  ( CMusManager::TRequestType ) aClientUid.iUid );
+        }
+    else
+        {
+        // start through ICM
+        TInt result = RProperty::Set( KPSUidICMIncomingCall,
+        		KPropertyKeyICMPluginUID, aClientUid.iUid );
+        User::LeaveIfError( result );
+        }
+    
+    SIPMXRLOG( "[SIPMXRESOLVER] <- CSipMXResolver::ConnectL()" )
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::CancelConnect
+// ---------------------------------------------------------------------------
+// 
+void CSipMXResolver::CancelConnect( const TUid& /*aClientUid*/ )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] <-> CSipMXResolver::CancelConnect()" )
+    // No implementation for VoIP / MuS.
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::SupportedContentTypesL
+// ---------------------------------------------------------------------------
+// 
+RPointerArray<CSIPContentTypeHeader> CSipMXResolver::SupportedContentTypesL()
+    {
+    RPointerArray<CSIPContentTypeHeader> ret;
+    
+    CSIPContentTypeHeader* ctype = CSIPContentTypeHeader::DecodeL( KContentType );
+    CleanupStack::PushL( ctype );
+    ret.AppendL( ctype );
+    CleanupStack::Pop( ctype );
+    
+    return ret;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::SupportedSdpMediasL
+// ---------------------------------------------------------------------------
+// 
+RPointerArray<CSdpMediaField> CSipMXResolver::SupportedSdpMediasL()
+    {
+    // Initialise return array
+    RPointerArray<CSdpMediaField> ret;
+    TCleanupItem tci( CleanupSdpMediasArray, &ret );
+    CleanupStack::PushL( tci );
+    
+    // media field descriptors
+    _LIT8( KMuSField1, "m=video 0 RTP/AVP 96\r\na=application:com.nokia.rtvs\r\na=X-application:com.nokia.rtvs\r\n" );
+    _LIT8( KMuSField2, "m=audio 0 RTP/AVP 97\r\n" );
+    _LIT8( KVoIPField1, "m=video 0 RTP/AVP 0\r\n" );
+    _LIT8( KVoIPField2, "m=application 0 tcp wb\r\n" );
+    _LIT8( KVoIPField3, "m=audio 0 RTP/AVP 0\r\n" );
+    _LIT8( KVoIPField4, "m=audio 0 RTP/SAVP 0\r\n" );
+    
+    CSdpMediaField* field = NULL;
+    
+    // add media fields to array
+    if ( iMuSManager )
+        {
+        field = CSdpMediaField::DecodeLC( KMuSField1 );
+        ret.AppendL( field ); // ownership to array
+        CleanupStack::Pop( field );
+        
+        field = CSdpMediaField::DecodeLC( KMuSField2 );
+        ret.AppendL( field );
+        CleanupStack::Pop( field );
+        }
+    
+    if ( iVoIPEnabled )
+        {
+        field = CSdpMediaField::DecodeLC( KVoIPField1 );
+        ret.AppendL( field );
+        CleanupStack::Pop( field );
+        
+        field = CSdpMediaField::DecodeLC( KVoIPField2 );
+        ret.AppendL( field );
+        CleanupStack::Pop( field );
+        
+        field = CSdpMediaField::DecodeLC( KVoIPField3 );
+        ret.AppendL( field );
+        CleanupStack::Pop( field );
+        
+        field = CSdpMediaField::DecodeLC( KVoIPField4 );
+        ret.AppendL( field );
+        CleanupStack::Pop( field );
+        }
+    
+    CleanupStack::Pop(); // tcleanupitem
+    return ret;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::AddClientSpecificHeadersForOptionsResponseL
+// ---------------------------------------------------------------------------
+// 
+void CSipMXResolver::AddClientSpecificHeadersForOptionsResponseL(
+    RPointerArray<CSIPHeaderBase>& aHeaders )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> \
+    CSipMXResolver::AddClientSpecificHeadersForOptionsResponseL()" )
+	//Add Allow Header		
+	RPointerArray<CSIPAllowHeader> allowheaders = 
+	    CSIPAllowHeader::DecodeL(KSIPMethodsInAllowHeader);
+	TInt count = allowheaders.Count();
+	for(TInt i = 0; i<count; i++)
+		{
+		User::LeaveIfError(aHeaders.Append(allowheaders[i]));
+		}
+	allowheaders.Reset();
+
+	//Add Supported Header
+	RPointerArray<CSIPSupportedHeader> supportedheaders = 
+	    CSIPSupportedHeader::DecodeL(KSIPExtensionsSupported);
+	count = supportedheaders.Count();
+	for(TInt j = 0; j<count; j++)
+		{
+		User::LeaveIfError(aHeaders.Append(supportedheaders[j]));
+		}
+	supportedheaders.Reset();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::IsCsCallActive
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::IsCSCallActive() const
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::IsCSCallActive()" )
+    
+    TBool retval = EFalse;
+    
+    TInt callType = KErrNone;
+    RProperty::Get( KPSUidCtsyCallInformation,
+    		KCTsyCallType, callType );
+    
+    if ( EPSCTsyCallTypeCSVoice == callType )
+        {
+        TInt callState = KErrNone;
+        RProperty::Get( KPSUidCtsyCallInformation,
+        		KCTsyCallState, callState );
+        
+        if ( EPSCTsyCallStateConnected == callState ||
+             EPSCTsyCallStateHold == callState )
+            {
+            retval = ETrue;
+            }
+        }
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::IsCSCallActive(), ret:%d", retval )
+    
+    return retval;
+    }
+
+// -----------------------------------------------------------------------------
+// CSipMXResolver::CheckForMedia
+// -----------------------------------------------------------------------------
+//
+TBool CSipMXResolver::CheckForMedia( CSdpDocument* aSdpDoc,
+    const RStringF& aMediaType ) const
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::CheckForMedia()" )
+    
+    TBool present = EFalse;
+    
+    if ( aSdpDoc )
+        {
+        RPointerArray<CSdpMediaField>& mFields = aSdpDoc->MediaFields();
+        const TInt count = mFields.Count();
+        
+        // if there is media fields, check them for type
+        for ( TInt i = 0; i < count && !present; i++ )
+            {
+            if ( aMediaType == mFields[ i ]->Media() )
+                {
+                present = ETrue;
+                }
+            }
+        }
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::CheckForMedia(), ret:%d", present )
+    
+    return present;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::CheckForACHeaderTagL
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::CheckForACHeaderTagL(
+    const RPointerArray<CSIPHeaderBase>& aHeaders,
+    const TDesC8& aTag ) const
+    {
+    TBool match = EFalse;
+    TInt ftagcount = 0;
+    
+    for ( TInt i = 0; i < aHeaders.Count(); i++ )
+        {
+        if ( aHeaders[i]->Name() ==
+             SIPStrings::StringF( SipStrConsts::EAcceptContactHeader ) ||
+             aHeaders[i]->Name() ==
+             SIPStrings::StringF( SipStrConsts::EAcceptContactHeaderCompact ) )
+            {
+            RStringF featureTagStr = SIPStrings::Pool().OpenFStringL( aTag );
+            CleanupClosePushL( featureTagStr );
+            
+            CSIPAcceptContactHeader* ach = 
+                static_cast<CSIPAcceptContactHeader*>(aHeaders[i]);
+            TInt pcount = ach->ParamCount();
+            
+            for ( TInt p = 0; p < pcount; p++ )
+                {
+                RStringF mparam;
+                CleanupClosePushL( mparam );
+                
+                if ( KErrNone == ach->Param( p, mparam ) )
+                    {
+                    //we need to count all feature tags
+                    if ( mparam.DesC().Left(1).Compare( KFTagChar ) == 0 )
+                        {
+                        ftagcount++;
+                        }
+                    if ( mparam == featureTagStr )
+                        {
+                        match = ETrue;
+                        //loop is continued after match to count feature tags
+                        }
+                    }
+                
+                CleanupStack::PopAndDestroy( 1 ); //mparam
+                }
+            
+            // Use the dynamic string.
+            CleanupStack::PopAndDestroy( 1 ); // featureTagStr
+            }
+        }
+    
+    //return ETrue only if there's only one feature tag and it is MuS specific
+    return ( match && ftagcount == 1 );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::CheckForVSAttributesL
+// ---------------------------------------------------------------------------
+// 
+TBool CSipMXResolver::CheckForVSAttributes(
+    RPointerArray<CSdpMediaField>& aFields ) const
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::CheckForVSAttributes()" )
+    
+    TBool vsattributefound = EFalse;
+    TInt sendonlycount = 0; 
+    TInt videofields = 0;
+    const TInt fieldcount = aFields.Count();
+    
+    for ( TInt i = 0; i < fieldcount; i++ )
+        {
+        CSdpMediaField* mField = aFields[i];
+        
+        //only check audio/video fields
+        TBool audio = mField->Media() == iAudioType;
+        TBool video = mField->Media() == iVideoType;
+        
+        if ( video )
+            {
+            videofields++;
+            }
+        
+        if ( video || audio )
+            {
+            RPointerArray< CSdpAttributeField > attrList =
+                mField->AttributeFields();
+            
+            TInt attrCount = attrList.Count();
+            for (TInt j = 0; j < attrCount && !vsattributefound; j++ )
+                {
+                CSdpAttributeField* attributeField = attrList[j];
+                RStringF attribute = attributeField->Attribute();
+                
+                // for each sendonly attribute, add counter
+                if ( KErrNotFound != attribute.DesC().FindF( KSendOnly ) )
+                    {
+                    sendonlycount++;                        
+                    }
+                
+                // check m=video fields for com.nokia.rtvs attribute
+                if ( video )
+                    {
+                    if ( ( KErrNotFound !=
+                           attribute.DesC().FindF( KApplicationAttr ) ||
+                           KErrNotFound !=
+                           attribute.DesC().FindF( KXApplicationAttr ) ) &&
+                         KErrNotFound !=
+                         attributeField->Value().FindF( KNokiaRtvs ) )
+                        {
+                        //attribute found
+                        vsattributefound = ETrue;
+                        }
+                    }
+                }
+            }
+        }
+    
+    // Video Sharing is assumed if nokia vs specific attributes are found
+    // or if there is at least one m=video line and all media fields have
+    // sendonly attribute.
+    TBool retval = ( vsattributefound ||
+        		     ( videofields > 0 && fieldcount == sendonlycount ) );
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::CheckForVSAttributes(),ret:%d", retval )
+    
+    return retval;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSipMXResolver::ResolveVSUid
+// ---------------------------------------------------------------------------
+// 
+TUid CSipMXResolver::ResolveVSUidL( const RStringF& aMethod )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::ResolveVSUidL()" )
+    
+    TUid muid  = KNullUid;
+    
+    if ( iMuSManager )
+        {
+        if ( aMethod == SIPStrings::StringF( SipStrConsts::EOptions ) )
+            {
+            muid.iUid = ( TInt32 ) CMusManager::ESipOptions;
+            }
+        else
+            {
+            MultimediaSharing::TMusAvailabilityStatus capability =
+            	iMuSManager->AvailabilityL();
+            
+            //check if availability value is from non-error-range
+            if( capability >= KErrNone &&
+                capability < MultimediaSharing::EErrSipRegistration )
+                {
+                muid.iUid = ( TInt32 ) CMusManager::ESipInviteDesired;
+                }
+            else
+                {
+                muid.iUid = ( TInt32 ) CMusManager::ESipInviteNotDesired;
+                }
+            }
+        }
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::ResolveVSUidL(), ret:%d", muid.iUid )
+    
+    return muid;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CSipMXResolver::ResolveCPPluginUidL
+// -----------------------------------------------------------------------------
+// 
+void CSipMXResolver::ResolveCPPluginUidL( TUid& aUid, const CUri8& aRequestUri )
+    {
+    SIPMXRLOG( "[SIPMXRESOLVER] -> CSipMXResolver::ResolveCPPluginUidL()" )
+    
+    CSipClientResolverUtils* resolver = CSipClientResolverUtils::NewLC();
+    resolver->GetImplementationUidWithUserL(
+    		aRequestUri.Uri().Extract( EUriUserinfo ), aUid );
+    CleanupStack::PopAndDestroy( resolver );
+    
+    SIPMXRLOGP( \
+    "[SIPMXRESOLVER] <- CSipMXResolver::ResolveCPPluginUidL(),uID:%d", aUid.iUid )
+    }
+
+
+//  End of File