mmsharing/mmshavailability/src/musavaterminal.cpp
changeset 22 496ad160a278
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsharing/mmshavailability/src/musavaterminal.cpp	Fri Jun 11 13:36:18 2010 +0300
@@ -0,0 +1,616 @@
+/*
+* Copyright (c) 2005-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:   Discovered terminal
+*
+*/
+
+
+#include "musavaterminal.h"
+
+#include <escapeutils.h>
+#include <uri8.h>
+#include <sip.h>
+#include <sipconnection.h>
+#include <sipservertransaction.h>
+#include <sipclienttransaction.h>
+#include <sipheaderbase.h>
+#include <sipextensionheader.h>
+#include <sdpdocument.h>
+#include <sipcontenttypeheader.h>
+#include <sipmessageelements.h>
+#include <sipresponseelements.h>
+#include <siprequestelements.h>
+#include <sipstrings.h>
+#include <sipstrconsts.h>
+#include <sipcontactheader.h>
+#include <sipaddress.h>
+
+#include "muslogger.h"
+#include "musavacapabilityexchange.h"
+#include "musavacapability.h"
+#include "musavacapabilityquerybase.h"
+#include "musavacapabilitycontext.h"
+#include "mmusavacapabilityqueryobserver.h"
+#include "mussettings.h"
+#include "mussettingskeys.h"
+#include "musavasipheaderutil.h"
+
+// --------------------------------------------------------------------------
+// Symbian two-phase constructor
+// --------------------------------------------------------------------------
+//
+CMusAvaTerminal* CMusAvaTerminal::NewL( CMusAvaCapabilityExchange& aExchange,
+                                    const TDesC8& aTerminalUri,
+                                    const TDesC8& aTerminalId )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::NewL" )
+    CMusAvaTerminal* self = new (ELeave) CMusAvaTerminal( aExchange );
+    CleanupStack::PushL( self );
+    self->ConstructL( aTerminalUri, aTerminalId );
+    CleanupStack::Pop( self );
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::NewL" )
+    return self;
+    }
+
+
+// --------------------------------------------------------------------------
+// C++ destructor
+// --------------------------------------------------------------------------
+//
+CMusAvaTerminal::~CMusAvaTerminal()
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::~CMusAvaTerminal" )
+
+    ResetAndDestroyQuery();
+    
+    delete iUri;
+    delete iTerminalId;
+    iRequestedQuery = NULL;
+    
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::~CMusAvaTerminal" )
+    }
+
+// --------------------------------------------------------------------------
+// C++ constructor
+// --------------------------------------------------------------------------
+//
+CMusAvaTerminal::CMusAvaTerminal( CMusAvaCapabilityExchange& aExchange )
+    : iExchange( aExchange )
+    {
+    }
+
+
+// --------------------------------------------------------------------------
+// Symbian second-phase constructor
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::ConstructL( const TDesC8& aTerminalUri,
+                                const TDesC8& aTerminalId )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::ConstructL" )
+
+    MUS_LOG_TDESC8( "mus: [MUSAVA] - CMusAvaTerminal::Id ",aTerminalId)
+    MUS_LOG_TDESC8( "mus: [MUSAVA] - CMusAvaTerminal::MatchL Uri",aTerminalUri )
+    iUri = aTerminalUri.AllocL();
+    iTerminalId = aTerminalId.AllocL();
+
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::ConstructL" )
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::Id
+// --------------------------------------------------------------------------
+//
+const TDesC8& CMusAvaTerminal::Id() const
+    {
+    return *iTerminalId;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::ToUriL
+// --------------------------------------------------------------------------
+//
+const TDesC8& CMusAvaTerminal::Uri() const
+    {
+    return *iUri;
+    }
+    
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::MacthL
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::MatchL( const TDesC8& aTerminalUri, 
+                             const TDesC8& aTerminalId )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::MatchL" )
+    TBool match = EFalse;
+    TBool useDoubleKeyMatch = Id().Length() > 0 && aTerminalId.Length() > 0;
+    
+    MUS_LOG_TDESC8( "mus: [MUSAVA] - CMusAvaTerminal::MatchL aTerminalId ",aTerminalId )
+    MUS_LOG_TDESC8( "mus: [MUSAVA] - CMusAvaTerminal::MatchL aTerminalUri ",aTerminalUri )    
+    if ( useDoubleKeyMatch )
+        {
+        match = Uri().Compare( aTerminalUri ) == 0 && 
+                Id().CompareF( aTerminalId ) == 0;
+        }
+    else //not known yet or no terminal id in request i.e. best guess
+        {
+        match = Uri().Compare( aTerminalUri ) == 0;
+        }
+        
+    if ( match )
+        {
+        AttachUriL( aTerminalUri );
+        AttachIdL( aTerminalId );
+        }
+
+    MUS_LOG1( "mus: [MUSAVA] <- CMusAvaTerminal::MatchL = %d",match )
+    return match;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::RequestedQuery
+// --------------------------------------------------------------------------
+//
+const CMusAvaCapability* CMusAvaTerminal::RequestedQuery() const
+    {
+    return iRequestedQuery;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::ExecuteQueryL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::ExecuteQueryL( CMusAvaCapabilityQueryBase* aQuery )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::ExecuteQueryL" )
+    
+    __ASSERT_ALWAYS( aQuery , User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( 
+        aQuery->State() == CMusAvaCapabilityQueryBase::ECapabilityQueryCreated,
+        User::Leave( KErrArgument ) );
+    __ASSERT_ALWAYS( !iQuery, User::Leave( KErrAlreadyExists ) );
+
+    ResetAndDestroyQuery();
+                  
+    aQuery->ExecuteL();
+    
+    iQuery = aQuery;                           
+        
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::ExecuteQueryL" )
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::QueryCompletedL
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::QueryCompletedL( const CSIPClientTransaction& aResponse )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::QueryCompletedL" )
+    TBool consumed = EFalse;
+    
+    if ( iQuery && iQuery->State() != 
+        CMusAvaCapabilityQueryBase::ECapabilityQueryCompleted )
+        {
+        iQuery->CompletedL( aResponse );
+        consumed = iQuery->State() == 
+            CMusAvaCapabilityQueryBase::ECapabilityQueryCompleted;
+        
+        if ( consumed )
+            {
+            const CSIPExtensionHeader* userAgent = 
+                MusAvaCapabilityContext::UserAgentHeaderL( aResponse );
+            if ( userAgent )
+                {
+                AttachIdL( userAgent->Value() );
+                }
+            }
+        }
+        
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::QueryCompletedL" )
+    
+    return consumed;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::QueryCanceled
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::QueryCanceled( 
+                                const CSIPClientTransaction& aTransaction )
+    {
+    TBool consumed = EFalse;
+    if ( iQuery && iQuery->State() != 
+            CMusAvaCapabilityQueryBase::ECapabilityQueryCompleted )
+        {
+        iQuery->Canceled( aTransaction );
+        consumed = iQuery->State() == 
+            CMusAvaCapabilityQueryBase::ECapabilityQueryCompleted;
+        }
+    return consumed;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::QueryExecuting
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::QueryExecuting()
+    {
+    TBool executing = EFalse;
+    if ( iQuery && iQuery->State() == 
+            CMusAvaCapabilityQueryBase::ECapabilityQueryExecuting )
+        {
+        executing = ETrue;
+        }
+    return executing;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::QueryRequestedL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::QueryRequestedL( CSIPServerTransaction& aQuery )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::QueryRequestedL" )
+
+    CSIPResponseElements* response = 
+          CSIPResponseElements::NewLC( 
+                      KMUSAVASIP200, 
+                      SIPStrings::StringF( SipStrConsts::EPhraseOk ) );
+    
+    CSdpDocument* sdpContent = 
+        CMusAvaCapability::ResponseContentLC( aQuery );
+
+    RPointerArray<CSIPHeaderBase> headers;
+    CSIPHeaderBase::PushLC( &headers );
+    
+    if ( PopulateResponseL( aQuery, headers, *sdpContent ) )
+        {
+        RStringF feature = 
+                 MusAvaCapabilityContext::SIPStringL( KCapabilitySwisFeature );
+        CleanupClosePushL( feature );
+        CMusAvaSipheaderUtil::AddAcceptContactHeaderL( headers,
+                                                        feature );
+        CleanupStack::PopAndDestroy(); //feature
+        MUS_LOG( "mus: [MUSAVA]  AddAcceptContactHeaderL -> Success ")            
+
+        MUS_LOG( "mus: [MUSAVA]  AddAcceptEncodingHeaderL -> Success ")                        
+   
+        MUS_LOG( "mus: [MUSAVA]  AddAcceptLanguageHeaderL -> Success ")                        
+        CMusAvaSipheaderUtil::AddAcceptSdpHeaderL(headers); 
+        MUS_LOG( "mus: [MUSAVA]  AddAcceptSDPHeaderL -> Success ")                                    
+        AddResponseHeadersL( *response, headers );
+        CleanupStack::Pop( &headers );        
+        AddResponseContentL( *response, *sdpContent );        
+        }
+    else
+        {
+        CleanupStack::PopAndDestroy( &headers );
+        response->SetStatusCodeL( KMUSAVASIPNotImplemented );
+        response->SetReasonPhraseL( 
+            SIPStrings::StringF( SipStrConsts::EPhraseNotImplemented ) );
+        }
+    CleanupStack::PopAndDestroy( sdpContent );
+
+    MUS_LOG( "mus: [MUSAVA] -> Sending Response For Options Request ..." )    
+    aQuery.SendResponseL( response );
+    CleanupStack::Pop( response );
+    
+    iExchange.QueryObserver().CapabilityQueryAnswered( ETrue );
+    
+    // Add sipaddress proposal
+    if ( response->StatusCode( ) == KMUSAVASIP200 )
+        {
+                                             
+        const CSIPContactHeader* contact = 
+            MusAvaCapabilityContext::ContactHeaderL( aQuery );
+                                             
+        if ( !contact )
+            {
+            MUS_LOG( "mus: [MUSAVA] => FAILED due lack of contact header" )
+            }
+        else
+            {
+    /*
+           	const TDesC8& uriInContact =
+    		    contact->SIPAddress()->Uri8().Uri().UriDes();
+    		if ( uriInContact.Length() > 0 )
+    		    {
+    		    HBufC* uri = 
+    		        EscapeUtils::ConvertToUnicodeFromUtf8L( uriInContact );
+    		    CleanupStack::PushL( uri );   
+    		    iExchange.QueryObserver().CapabilitiesResolvedL( *uri );
+    		    CleanupStack::PopAndDestroy( uri );
+    		    }
+    */
+
+            // If there is P-Asserted-Identity header then send the OPTIONS
+            // to this. Store it in settings data as To header so then future
+            // request can be sent there.
+            
+            CDesCArrayFlat* pAssertedIdentityHeaders =
+                     MusAvaCapabilityContext::PAssertedIdentityHeaderL(  
+                                 MusAvaCapabilityContext::MessageElementsL(aQuery));
+            CleanupStack::PushL( pAssertedIdentityHeaders );
+            __ASSERT_ALWAYS(pAssertedIdentityHeaders,User::Leave(KErrArgument));
+            if(pAssertedIdentityHeaders->Count()>0)
+                {
+                iExchange.QueryObserver().SipHeadersL(*pAssertedIdentityHeaders,
+                                                      SipStrConsts::EToHeader);
+                }
+            else
+                {
+                // P-Asserted-Identity header not exist. So rely on other contacts
+                // read from phone book or Tel URI to send request.
+                }
+            pAssertedIdentityHeaders->Reset();
+            CleanupStack::PopAndDestroy( pAssertedIdentityHeaders ); 
+
+   		    TBool sequential = 
+                  MultimediaSharingSettings::OperatorVariantSettingL() ==
+                  	MusSettingsKeys::EOperatorSpecific || 
+                  MusSettingsKeys::ESequential ==  
+     	        	MultimediaSharingSettings::CapabilityQuerySettingL();
+         
+            TBool alreadyRequested = iExchange.QueryObserver().
+                   CapabilitiesResolvedForCingular();
+
+            if ( sequential && !alreadyRequested )
+  		        {
+   		        iExchange.QueryObserver().SetCapabilitiesResolvedForCingular();
+   		        }
+            }
+        }
+    
+    
+    //if pending query
+    if ( iQuery )
+        {
+        MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::QueryRequestedL Executing Pending Query" )
+        iQuery->ExecuteL();
+        }
+
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::QueryRequestedL" )
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::AttachQuery
+// --------------------------------------------------------------------------
+//
+TInt CMusAvaTerminal::AttachQuery( CMusAvaCapabilityQueryBase& /*aQuery*/ )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::AttachQuery" )
+    iQueries++; 
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::AttachQuery" )
+    return iQueries;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::DetachQuery
+// --------------------------------------------------------------------------
+//
+TInt CMusAvaTerminal::DetachQuery( CMusAvaCapabilityQueryBase& /*aQuery*/ )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::DetachQuery" )
+    iQueries--;
+    __ASSERT_ALWAYS( iQueries >= 0, 
+                        User::Panic( _L("CMusAvaTerminal"), KErrGeneral ) );
+    
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::DetachQuery" )
+    
+    return iQueries;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::AttachIdL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::AttachIdL( const TDesC8& aTerminalId )
+    {
+    if ( aTerminalId.Length() > 0 )
+        {
+        //terminal id might change                                
+        HBufC8* tmpTerminalId = aTerminalId.AllocL();
+        delete iTerminalId;
+        iTerminalId = tmpTerminalId;
+        }
+    }
+    
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::AttachUriL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::AttachUriL( const TDesC8& aUri )
+    {
+    if ( aUri.Length() > 0 )
+        {
+        delete iUri;
+        iUri = NULL;
+        iUri = aUri.AllocL();
+        }
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::ResetAndDestroyQuery
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::ResetAndDestroyQuery()
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::ResetAndDestroyQuery" )
+    CMusAvaCapabilityQueryBase* query = iQuery;
+    iQuery = NULL;
+    delete query;
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::ResetAndDestroyQuery" )
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::PopulateResponseL
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::PopulateResponseL( CSIPServerTransaction& aQuery,
+                            RPointerArray<CSIPHeaderBase>& aResponseHeaders,
+                            CSdpDocument& aSdpContent )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::PopulateResponseL" )
+    
+    TBool supported = EFalse;
+    
+    const CSIPAcceptContactHeader* featureSet = 
+        MusAvaCapabilityContext::AcceptContactHeaderL( aQuery );
+    
+    User::LeaveIfError( !featureSet ? KErrGeneral : KErrNone );
+    
+    for( TInt i = 0; i < iExchange.Capabilities().Count();i++ )
+        {
+        CMusAvaCapability* capability = iExchange.Capabilities()[ i ];
+        TBool containsFeature = capability->Supports( *featureSet );
+        supported = containsFeature ? ETrue : supported;
+                           
+        if ( containsFeature )
+            {
+            const CSIPMessageElements& elements = 
+                    MusAvaCapabilityContext::MessageElementsL( aQuery );
+            const TDesC8& content = elements.Content();
+            CSdpDocument* sdp = NULL;
+            
+            if ( content.Length() > 0 )
+                {
+                sdp = CSdpDocument::DecodeLC( content );                
+                }
+            else
+                {
+                sdp = CSdpDocument::NewLC();
+                }
+
+            //store video codecs that came from the other terminal
+            CDesCArrayFlat* videoCodecs = CMusAvaCapability::ResolveCodecsL( *sdp );
+            CleanupStack::PushL( videoCodecs );
+            capability->Exchange().QueryObserver().VideoCodecsResolvedL( *videoCodecs );
+            CleanupStack::PopAndDestroy( videoCodecs );                    
+            
+            //store fast startup mode if present
+            MusSettingsKeys::TFastMode mode = 
+                CMusAvaCapability::ResolveFastModeL( *sdp );
+            capability->Exchange().QueryObserver().FastModeResolved( mode );
+            
+            CleanupStack::PopAndDestroy( sdp );
+            
+            capability->PopulateResponseL( aQuery,
+                                           aResponseHeaders,
+                                           aSdpContent );
+            iRequestedQuery = capability;
+            }
+        }
+        
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::PopulateResponseL" )
+        
+    return supported;
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::AddResponseHeadersL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::AddResponseHeadersL( CSIPResponseElements& aResponse,
+                            RPointerArray<CSIPHeaderBase>& aResponseHeaders )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::AddResponseHeadersL" )
+
+    CSIPMessageElements& message = aResponse.MessageElements();
+
+    if ( iExchange.TerminalId().Length() > 0 )
+        {
+        //terminal id
+    	CSIPHeaderBase* userAgent = 
+    	    MusAvaCapabilityContext::UserAgentHeaderLC( 
+    	        iExchange.TerminalId() );
+        aResponseHeaders.AppendL( userAgent );
+        CleanupStack::Pop( userAgent );
+        }
+        
+    //Set user headers
+    message.SetUserHeadersL( aResponseHeaders );
+    
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::AddResponseHeadersL" )
+    }
+
+
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::AddResponseContentL
+// --------------------------------------------------------------------------
+//
+void CMusAvaTerminal::AddResponseContentL( CSIPResponseElements& aResponse,
+                                        CSdpDocument& aSdpContent )
+    {
+    MUS_LOG( "mus: [MUSAVA] -> CMusAvaTerminal::AddResponseContentL" )
+
+    CSIPMessageElements& message = aResponse.MessageElements();
+
+    //create content from SDP document
+    HBufC8* content = MusAvaCapabilityContext::ToTextL( aSdpContent );
+    CleanupStack::PushL( content );
+    
+    //create content type
+    CSIPContentTypeHeader* contentTypeHeader = NULL;
+    contentTypeHeader =
+        CSIPContentTypeHeader::NewLC( KMUSAVASIPMediaTypeApplication,
+                                      KMUSAVASIPMediaSubTypeSDP );
+    
+    //set content
+    message.SetContentL( content, contentTypeHeader );
+    CleanupStack::Pop( contentTypeHeader );
+    CleanupStack::Pop( content );
+
+    MUS_LOG( "mus: [MUSAVA] <- CMusAvaTerminal::AddResponseContentL" )
+    }
+// --------------------------------------------------------------------------
+// CMusAvaTerminal::IsDiscovered
+// --------------------------------------------------------------------------
+//
+TBool CMusAvaTerminal::IsDiscovered()
+    {
+    TBool isDiscovered = EFalse;
+    TBool isGarbage = !iQueries && !RequestedQuery();
+    
+    if ( !isGarbage )
+        {
+        isDiscovered = 
+            iQueries == 1 &&
+            iQuery && 
+            iQuery->State() == CMusAvaCapabilityQueryBase::ECapabilityQueryCompleted;
+        }
+    else
+        {
+        isDiscovered = ETrue;
+        }
+        
+    return isDiscovered;
+    
+    }