upnpavcontroller/upnpavcontrollerserver/src/upnpuploadsession.cpp
author samhuttu
Mon, 01 Nov 2010 12:37:49 +0200
branchnew development branch with rendering state machine and other goodies
changeset 38 5360b7ddc251
parent 32 3785f754ee62
permissions -rw-r--r--
New development branch with e.g. rendering state machine and a simple Qt example application using it.

/*
* 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:      server impl. of session against media server
*
*/

// INCLUDE FILES
// System
#include <mmf/common/mmfcontrollerpluginresolver.h>

// upnp stack api
#include <upnpstring.h>

// dlnasrv / mediaserver api
#include <upnpitem.h>
#include <upnpattribute.h>
#include <upnpdlnaprotocolinfo.h>

// dlnasrv / avcontroller helper api
#include "upnpconstantdefs.h" // for upnp-specific stuff
#include "upnpitemutility.h" // FindElementByNameL, GetResElements

// dlnasrv / xmlparser api
#include "upnpxmlparser.h"

// dlnasrv / internal api's
#include "upnpcdsreselementutility.h"
#include "httpuploader.h"
#include "upnpmetadatafetcher.h"
#include "upnpcommonutils.h"

// dlnasrv / avcontroller internal api's
#include "upnpuploadsession.h"
#include "upnpfiletransferitem.h"
#include "upnpavcontrollerserver.h"
#include "upnpfiletransferitem.h"
#include "upnpavdeviceextended.h"
#include "upnpavdispatcher.h"
#include "upnpaverrorhandler.h"
#include "upnpavcpstrings.h"
#include "upnpresourcehelper.h"
#include "upnpavcontrolpoint.h"

using namespace UpnpAVCPStrings;

_LIT( KComponentLogfile, "upnpavcontrollerserver.txt");
#include "upnplog.h"

// CONSTANTS
_LIT8( KImportUri,              "importUri" );
_LIT8( KAsterisk,               "*" );
const TUint32 KBufferSize       = 0x40000; // 256K
const TInt KParallerTransfers   = 1;

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

// --------------------------------------------------------------------------
// CUPnPUploadSession::NewL
// See upnpuploadsession.h
// --------------------------------------------------------------------------
CUPnPUploadSession* CUPnPUploadSession::NewL( CUpnpAVControllerServer&
    aServer, TInt aSessionId, const TDesC8& aUuid )
    {
    CUPnPUploadSession* self = new (ELeave) CUPnPUploadSession(
        aServer, aSessionId );
    CleanupStack::PushL( self );    
    self->ConstructL( aUuid );
    CleanupStack::Pop( self );
    return self;
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::CUPnPUploadSession
// See upnpuploadsession.h
// --------------------------------------------------------------------------
CUPnPUploadSession::CUPnPUploadSession( CUpnpAVControllerServer& aServer,
    TInt aSessionId ) :
    CUPnPFileTransferSessionBase( aServer, aSessionId ),
    iResourceIndex( KErrNotFound ),
    iAsyncError( KErrNone ),
    iIPSessionId( KErrNotFound ),
    iSchedulerStopped( ETrue )
    {
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::~CUPnPUploadSession
// See upnpuploadsession.h
// --------------------------------------------------------------------------
CUPnPUploadSession::~CUPnPUploadSession()
    {
    __LOG( "CUPnPUploadSession::~CUPnPUploadSession" );

    delete iUploader;
    iResources.ResetAndDestroy();
    
    __LOG( "CUPnPUploadSession::~CUPnPUploadSession - end" );
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ConstructL
// See upnpuploadsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::ConstructL( const TDesC8& aUuid )
    {
    __LOG( "CUPnPUploadSession::ConstructL" );
    
    CUPnPFileTransferSessionBase::ConstructL( aUuid );

    iUploader = CHttpUploader::NewL( *this, (TUint32)iServer.IAP(),
        KBufferSize, KParallerTransfers );
    
    // Gets related ControlPoint device (CUpnpDevice).
    // It is needed for CUpnpAVControlPoint.
    iCpDevice = iServer.ControlPoint().Device( aUuid );
    if ( !iCpDevice ) 
        {
        User::Leave( KErrNotFound );
        }
    
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUPnPUploadSession::ActionResponseL( CUpnpAction* aAction )
    {
    if (aAction->Name().Compare(KCreateObject) == 0)
        {
        __ASSERT( iIPSessionId == aAction->SessionId(),
            __FILE__, __LINE__ );
        CdsCreateObjectResponse(
            aAction->Error(),
            aAction->ArgumentValue(KObjectID), 
            aAction->ArgumentValue(KResult)
            );
        }
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUPnPUploadSession::StateUpdatedL( CUpnpService* /*aService*/ )
    {
    // No implementation required
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUPnPUploadSession::HttpResponseL( CUpnpHttpMessage* /*aMessage*/ )
    {
    // No implementation required
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUPnPUploadSession::DeviceDiscoveredL( CUpnpDevice* /*aDevice*/ )
    {
    // No implementation required
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ActionResponseL
// From MUpnpAVControlPointObserver
// --------------------------------------------------------------------------
void CUPnPUploadSession::DeviceDisappearedL( CUpnpDevice* /*aDevice*/ )
    {
    // No implementation required
    }

// --------------------------------------------------------------------------
// CUPnPDownloadSession::TransferProgress
// See upnpdownloadsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::TransferProgress( TAny* aKey, TInt aBytes,
    TInt aTotalBytes )
    {
    __LOG( "CUPnPUploadSession::TransferProgress" );
    
    if( iProgressTrackingEnabled )
        {
        TUpnpFileTransferEvent item;
        TInt err = FindItemByKey( item, (TInt)aKey );
        if( err == KErrNone )
            {
            item.iStatus = KErrNone;
            item.iParam2 = aTotalBytes;
            item.iParam1 = aBytes;
            item.iEvent = TUpnpFileTransferEvent::ETransferProgress;

            Complete( item );
            }
        else
            {
            __LOG( "TransferProgress - Not enabled!" );
            }
        }
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ReadyForTransfer
// See upnpdownloadsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::ReadyForTransferL( TAny* aKey )
    {
    __LOG( "CUPnPUploadSession::ReadyForTransferL" );
    
    TUpnpFileTransferEvent event;
    if( FindItemByKey( event, (TInt)aKey, iResourceIndex ) == KErrNone )
        {
        ReadyForTransferL( event );
        
        event.iEvent = TUpnpFileTransferEvent::ETransferStarted;
        Complete( event );
        }
    else
        {
        __LOG( "ReadyForTransfer - Key not found" );
        
        // Not found
        event.iStatus = KErrGeneral;
        event.iParam2 = 0;
        event.iEvent = TUpnpFileTransferEvent::ETransferCompleted;
        
        Complete( event );
        }
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::TransferCompleted
// See upnpdownloadsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::TransferCompleted( TAny* aKey, TInt aStatus )
    {
    __LOG2( "CUPnPUploadSession::TransferCompleted, key = %d, status = %d",
            (TInt)aKey, aStatus );
    
    TUpnpFileTransferEvent item;
    TInt index;
    TInt err = FindItemByKey( item, (TInt)aKey, index );
    if( err == KErrNone )
        {
        item.iStatus = UPnPAVErrorHandler::ConvertToSymbianErrorCode( aStatus,
        EUPnPHTTPError );
        
        item.iEvent = TUpnpFileTransferEvent::ETransferCompleted;
        Complete( item );
                
        iTransferItems.Remove( index );
        delete iResources[ index ];
        iResources.Remove( index );
        }
    else
        {
        __LOG( "TransferCompleted - Key not found" );
        
        // Not found
        if( aStatus == KErrCancel )
            {
            item.iStatus = aStatus;
            }
        else
            {
            item.iStatus = KErrGeneral;    
            }    
        
        item.iParam2 = 0;
        item.iEvent = TUpnpFileTransferEvent::ETransferCompleted;
        
        Complete( item );
        } 
    
    if( aStatus == KErrDisconnected )
        {
        __LOG( "TransferCompleted - Target device lost" );
        
        TInt count = iTransferItems.Count();
        for( TInt i = 0; i < count; i++ )
            {
            iUploader->CancelTransfer( (TAny*)iTransferItems[i].iKey );

            if( iResources[ i ]->ItemId() )
                {
                // Send destroyobject
                __LOG( "CancelAllUploadsL - sending destroyobject" );
                TRAP_IGNORE( DestroyObjectL( *iResources[ i ]->ItemId() ) );
                }
            }
        iResources.ResetAndDestroy();    
        iTransferItems.Reset();
        }      
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::CdsCreateObjectResponse
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::CdsCreateObjectResponse(
    TInt aErr,
    const TDesC8& aObjectID, 
    const TDesC8& aResult )
    {
    __LOG1( "CUPnPUploadSession::CdsCreateObjectResponse: %d" , aErr );

    __ASSERTD( iTransferItems.Count() == iResources.Count(), __FILE__, 
               __LINE__ );
    
    iServer.Dispatcher().UnRegister( iIPSessionId );
    iIPSessionId = KErrNotFound;
    
    aErr = UPnPAVErrorHandler::ConvertToSymbianErrorCode( aErr,
        EUPnPContentDirectoryError );

    if( aErr == KErrNone )
        {
        TRAP( aErr, HandleObjectResponseL( aObjectID, aResult ) );
        }        
    
    iAsyncError = aErr;
    StopWait();
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::StartUploadL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::StartUploadL( const RMessage2& aMessage )
    {
    __LOG( "CUPnPUploadSession::StartUploadL" );
    
    __ASSERTD( iTransferItems.Count() == iResources.Count(), __FILE__, 
               __LINE__ );
    
    CUpnpFileTransferItem* tmpTransferItem = CUpnpFileTransferItem::NewLC();
        
    ReadTransferItemFromMessageL( aMessage, 1 ,tmpTransferItem );
        
    if( CheckIfKeyExists( tmpTransferItem->Key() ) )
        {
        User::Leave( KErrInUse );
        }
    
    TUpnpFileTransferEvent transferItem;        
    transferItem.iKey = tmpTransferItem->Key();
            
    CUpnpItem* tmpUpnpItem = UPnPMetadataFetcher::CreateItemFromFileLC( 
        tmpTransferItem->Path() );
        
    tmpUpnpItem->SetIdL( KNullDesC8 );
    tmpUpnpItem->SetParentIdL( KContainerIdAny );
    tmpUpnpItem->SetRestricted( EFalse );

    const CUpnpElement& resEl = UPnPItemUtility::FindElementByNameL(
        *tmpUpnpItem, KElementRes );

    const CUpnpAttribute* pInfo = UPnPItemUtility::FindAttributeByName(
        resEl, KAttributeProtocolInfo );  
      
    if( iDevice->DlnaCompatible() )
        {
        // Dlna device, additional checks required
        __LOG( "StartUploadL - DLNA device" );
        
        TPtrC8 objectClass = tmpUpnpItem->ObjectClass(); 
        if( objectClass.Find( KClassAudio ) != KErrNotFound &&
            iDevice->AudioUpload() )
            {
            // Trying to upload audio and it's supported
            }
        else if( objectClass.Find( KClassImage ) != KErrNotFound &&
            iDevice->ImageUpload() )
            {
            // Trying to upload images and it's supported
            }
        else if(  objectClass.Find( KClassVideo ) != KErrNotFound &&
            iDevice->VideoUpload() )
            {
            // Trying to upload video and it's supported
            }
        else
            {
            // Unknown media type, or copy not supported
            __LOG( "StartUploadL - Unknown media type, or copy not \
supported" );
            User::Leave( KErrNotSupported );
            }    

            if( iDevice->ValidateTransfer( pInfo->Value() ) )
                {
                __LOG( "StartUploadL - Match by protocolInfo succeeded" );
                // Continue with DLNA upload
                // ProtocolInfo is in DLNA format
                }
            else
                {
                __LOG( "StartUploadL - Match by protocolInfo failed, upload \
as UPnP content" );
                // Continue with UPnP upload
                // Check the protocolInfo
                ProtocolInfoToUPnPL( pInfo );
                }        
        }
    else
        {
        __LOG( "StartUploadL - UPnP Device -> UPnP upload" );
        // Continue with UPnP upload
        // Check the protocolInfo
        ProtocolInfoToUPnPL( pInfo );        
        }
        
    iUploader->InsertFileIntoWaitQueueL( (TAny*)transferItem.iKey,
        tmpTransferItem->Path(), KNullDesC8 );
    
    SetHeadersL( pInfo->Value(), (TAny*)transferItem.iKey );
    
    iTransferItems.Append( transferItem );
    
    CUPnPResourceHelper* helper = CUPnPResourceHelper::NewL();
    CleanupStack::Pop( tmpUpnpItem );
    CleanupStack::PushL( helper );
    helper->SetItem( tmpUpnpItem ); // Transfer ownership
    if( iResources.Append( helper )!= KErrNone  )
        {
        CleanupStack::PopAndDestroy( helper );
        }
    CleanupStack::Pop( helper );
    
    iUploader->MoveToTransferQueueL( (TAny*)transferItem.iKey );
    
    CleanupStack::PopAndDestroy( tmpTransferItem );
    
    aMessage.Complete( KErrNone );
    
    __LOG( "CUPnPUploadSession::StartUploadL - end " );    
    }
    
// --------------------------------------------------------------------------
// CUPnPUploadSession::CancelUploadL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::CancelUploadL( const RMessage2& aMessage )
    {
    __LOG( "CUPnPUploadSession::CancelUploadL" );          
    
    __ASSERTD( iTransferItems.Count() == iResources.Count(), __FILE__,
               __LINE__ );
    
    TInt key = aMessage.Int1();

    TInt index;
    if( CheckIfKeyExists( key, index ) )
        {
        iUploader->CancelTransfer( (TAny*)key );
        aMessage.Complete( KErrNone );
        iTransferItems.Remove( index );
        if( iResources[ index ]->ItemId() )
            {
            // Send destroyobject
            DestroyObjectL( *iResources[ index ]->ItemId() );
            }
        delete iResources[index ];
        iResources.Remove( index );   
        }
    else
        {
        aMessage.Complete( KErrNotFound );
        }        
    
    __LOG( "CUPnPUploadSession::CancelUploadL - end" );
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::CancelAllUploadsL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::CancelAllUploadsL( const RMessage2& aMessage )
    {
    __LOG( "CUPnPUploadSession::CancelAllUploadsL" );          
    
    __ASSERTD( iTransferItems.Count() == iResources.Count(), __FILE__,
               __LINE__ );
        
    TInt count = iTransferItems.Count();
    for( TInt i = 0; i < count; i++ )
        {
        iUploader->CancelTransfer( (TAny*)iTransferItems[i].iKey );

        if( iResources[ i ]->ItemId() )
            {
            // Send destroyobject
            __LOG( "CancelAllUploadsL - sending destroyobject" );
            DestroyObjectL( *iResources[ i ]->ItemId() );
            }
        }
    iResources.ResetAndDestroy();
    iTransferItems.Reset();
    iEventQueu.Reset();

    // Scheduler loop started, stop it and ignore createobject-resp
    __LOG( "CancelAllUploadsL - Un register" );
    iServer.Dispatcher().UnRegister( iIPSessionId );
    iIPSessionId = KErrNotFound;
    iAsyncError = KErrCancel;

    __LOG( "CancelAllUploadsL - Stop scheduler loop" );
    StopWait();

    aMessage.Complete( KErrNone );

    __LOG( "CUPnPUploadSession::CancelAllUploadsL - end" );
    }
    
// --------------------------------------------------------------------------
// CUPnPUploadSession::StartTrackingUploadProgressL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::StartTrackingUploadProgressL( const RMessage2&
    aMessage )
    {
    __LOG( "CUPnPUploadSession::StartTrackingUploadProgressL" );
    
    TInt key = aMessage.Int1();
    if( CheckIfKeyExists( key ) )
        {
        iUploader->TrackProgress( (TAny*)key, ETrue );
        iProgressTrackingEnabled = ETrue;
        aMessage.Complete( KErrNone );
        }
    else
        {
        aMessage.Complete( KErrNotFound );
        }    
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::StopTrackingUploadProgressL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::StopTrackingUploadProgressL( const RMessage2&
    aMessage )
    {
    __LOG( "CUPnPUploadSession::StopTrackingUploadProgressL" );
    
    TInt key = aMessage.Int1();
    if( CheckIfKeyExists( key ) )
        {
        iUploader->TrackProgress( (TAny*)key, EFalse );
        iProgressTrackingEnabled = EFalse;        
        aMessage.Complete( KErrNone );
        }
    else
        {
        aMessage.Complete( KErrNotFound );
        }
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::GetUploadEventL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::GetUploadEventL( const RMessage2& aMessage )
    {
    __LOG( "CUPnPUploadSession::GetUploadEventL" );
    
    if( iEventQueu.Count() )
        {
        // There are events in the queu, write the first queued event back
        // to client
        __LOG1( "GetUploadEventL - events in queu, count = %d",
            iEventQueu.Count() );
        TPckg<TUpnpFileTransferEvent> resp1( iEventQueu[0] );
        aMessage.Write( 1, resp1  ); // Write response using slot 1
        aMessage.Complete( KErrNone );
        
        iEventQueu.Remove( 0 );
        }
    else
        {
        __ASSERTD( !iEventMsg, __FILE__, __LINE__ );
        __LOG( "GetUploadEventL - Store msg" );
        iEventMsg = new (ELeave) RMessage2( aMessage );
        } 
    __LOG( "CUPnPUploadSession::GetUploadEventL - end" );
    }
    
// --------------------------------------------------------------------------
// CUPnPUploadSession::CancelGetUploadEventL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::CancelGetUploadEventL( const RMessage2& aMessage )
    {
    __LOG( "CUPnPUploadSession::CancelGetUploadEventL" );          
    
    if( iEventMsg )
        {
        iEventMsg->Complete( KErrCancel );
        delete iEventMsg; iEventMsg = NULL;
        }
    aMessage.Complete( KErrNone );    
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::DeviceDisappearedL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::DeviceDisappearedL(
    CUpnpAVDeviceExtended& aDevice )
    {
    __LOG( "CUPnPUploadSession::DeviceDisappearedL" );

    if( aDevice.Uuid().Compare( iDevice->Uuid() ) == 0 )
        {
        TUpnpFileTransferEvent event;
        event.iEvent = TUpnpFileTransferEvent::EDeviceDisconnected;

        Complete( event );
        }
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::SetHeadersL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::SetHeadersL( const TDesC8& aInfo, TAny* aKey )
    {
    CUpnpDlnaProtocolInfo* tmpInfo = CUpnpDlnaProtocolInfo::NewL( aInfo );
    CleanupStack::PushL( tmpInfo );

    // Set the content-type header
    iUploader->SetHeaderL( aKey, KContentType,
        tmpInfo->ThirdField() );
    
    // Set the expect header
    iUploader->SetHeaderL( aKey, KExpectHeader, K100Continue );

    CleanupStack::PopAndDestroy( tmpInfo );            
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ReadyForTransferL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::ReadyForTransferL( TUpnpFileTransferEvent& aEvent )
    {
    __LOG( "CUPnPUploadSession::ReadyForTransferL" );
    
    if ( !iSchedulerStopped || iWait.IsStarted() )
        {
        __LOG1( "CUPnPUploadSession::ReadyForTransferL\
        IsStarted = %d", (TInt)iWait.IsStarted() );
        __LOG1( "CUPnPUploadSession::ReadyForTransferL\
        iSchedulerStopped = %d", (TInt)iSchedulerStopped );
        User::Leave( KErrNotReady );
        }

    __ASSERTD( iTransferItems.Count() == iResources.Count(), __FILE__, 
               __LINE__ );
    
    CUpnpItem* tmpUpnpItem = iResources[ iResourceIndex ]->Item();
    if( !tmpUpnpItem )
        {
        User::Leave( KErrCorrupt );
        }
    
    HBufC8* xmlDoc = CUPnPXMLParser::XmlForCreateObjectLC(
        *tmpUpnpItem );

    iIPSessionId = CreateObjectL( KContainerIdAny, *xmlDoc );

    // Register
    iServer.Dispatcher().RegisterL( iIPSessionId, *this );
    
    CleanupStack::PopAndDestroy( xmlDoc );
    
    iWait.Start();
    
    __LOG1( "CUPnPUploadSession::ReadyForTransferL\
        iAsyncError = %d", iAsyncError );

    User::LeaveIfError( iAsyncError );

    const CUpnpElement& resEl = UPnPItemUtility::FindElementByNameL(
        *iResources[ iResourceIndex ]->Item(), KElementRes );

    const CUpnpAttribute* pInfo = UPnPItemUtility::FindAttributeByName(
        resEl, KAttributeProtocolInfo );  

    CUpnpDlnaProtocolInfo* tmpInfo = CUpnpDlnaProtocolInfo::NewL(
        pInfo->Value() );
    CleanupStack::PushL( tmpInfo );      
    
    // Set DLNA specific headers    
    if( tmpInfo->PnParameter().Length() )
        {
        // DLNA content, set the content-features header
        iUploader->SetHeaderL( (TAny*)aEvent.iKey, KContentFeatures,
            tmpInfo->FourthField() );        

        // Check if background mode is available and use it if it is
        if( tmpInfo->DlnaFlag( UpnpDlnaProtocolInfo::TM_B_FLAG ) )
            {
            __LOG( "ReadyForTransferL - Use background mode" );
            
            iUploader->SetHeaderL( (TAny*)aEvent.iKey, KTransferMode,
                KBackgroundMode );  
            }
        else
            {
            // Background is not available for some reason.
            // Check if media specific transfer mode is available
            if( UPnPCommonUtils::IsImageSupported( 
                    tmpInfo->ProtocolInfoL() ) )
                {
                // Uploading image, alternative for background is interactive
                if( tmpInfo->DlnaFlag( UpnpDlnaProtocolInfo::TM_I_FLAG ) )
                    {
                    __LOG( "ReadyForTransferL - Use interactive mode" );
                    iUploader->SetHeaderL( (TAny*)aEvent.iKey, KTransferMode,
                        KInteractiveMode );
                    }
                else
                    {
                    // Target DMS does not support appropriate transfer mode
                    __LOG( "ReadyForTransferL - No appropriate mode" );
                    // Still, give a try and use background
                    iUploader->SetHeaderL( (TAny*)aEvent.iKey, KTransferMode,
                        KBackgroundMode );  
                    }            
                }
            else if( UPnPCommonUtils::IsAudioSupported(
                        tmpInfo->ProtocolInfoL() ) ||
                    UPnPCommonUtils::IsVideoSupported(
                        tmpInfo->ProtocolInfoL() ) )
                {
                // Uploading A/V, alternative for background is streaming
                if( tmpInfo->DlnaFlag( UpnpDlnaProtocolInfo::TM_S_FLAG ) )
                    {
                    __LOG( "ReadyForTransferL - Use streaming mode" );
                    iUploader->SetHeaderL( (TAny*)aEvent.iKey, KTransferMode,
                    KStreamingMode );
                    }
                else
                    {
                    // Target DMS does not support appropriate transfer mode
                    __LOG( "ReadyForTransferL - No appropriate mode" );
                    // Still, give a try and use background
                    iUploader->SetHeaderL( (TAny*)aEvent.iKey, KTransferMode,
                        KBackgroundMode );  
                    }                 
                }
            else
                {
                __LOG( "ReadyForTransferL - Unknown media type" );
                }    
                        
            }            

        }                
    
    CleanupStack::PopAndDestroy( tmpInfo ); 
    
    iUploader->SetPropertyL( (TAny*)aEvent.iKey,
        CHttpTransferBase::ETargetURI,
        *iResources[ iResourceIndex ]->Resource() );
            
    iUploader->StartTransferL( (TAny*)aEvent.iKey );
        
    __LOG( "CUPnPUploadSession::ReadyForTransferL - end" );
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ParseCreateObjectResponseL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::HandleObjectResponseL( const TDesC8& aObjectID,
    const TDesC8& aResult )
    {
    __LOG( "CUPnPUploadSession::HandleObjectResponseL" );          
    
    HBufC8* importUri = ParseCreateObjectResponseL( aResult );
    CleanupStack::PushL( importUri );

    HBufC8* tmpUri = UpnpString::EncodeXmlStringL( importUri );
    CleanupStack::PopAndDestroy( importUri );
    CleanupStack::PushL( tmpUri );
        
    HBufC* tmpUri16 = UpnpString::ToUnicodeL( *tmpUri );
    CleanupStack::PopAndDestroy( tmpUri );
          
    iResources[ iResourceIndex ]->SetResource( tmpUri16 );
        
    HBufC8* tmpID = aObjectID.AllocL();
    iResources[ iResourceIndex ]->SetItemId( tmpID );
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ParseCreateObjectResponseL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
HBufC8* CUPnPUploadSession::ParseCreateObjectResponseL(
    const TDesC8& aResponse )
    {
    __LOG( "CUPnPUploadSession::ParseCreateObjectResponseL" );          
    
    HBufC8* importURI = NULL;
    
    CUPnPXMLParser* parser = CUPnPXMLParser::NewL();
    CleanupStack::PushL( parser );
    
    RPointerArray<CUpnpObject> array;
    CleanupResetAndDestroyPushL( array );
    
    parser->ParseResultDataL( array, aResponse );
    
    TInt count = array.Count();
    
    // Lets find the first item with an import URI and use that
    for( TInt i = 0; i < count; i++ )
        {
        importURI = ImportURIFromItemL( *array[ i ] );
        if( importURI )
            {
             // Transfer ownership, casting is safe
             // (array[ 0 ]->ObjectType() == EUPnPItem)
            CUpnpItem* item = static_cast<CUpnpItem*>( array[ i ] );
            iResources[ iResourceIndex ]->SetItem( item );
            array.Remove( i );
            i = count;
            }
        }
    if( !importURI ) // no suitable items, leave
        {
        User::Leave( KErrGeneral );
        }
            
    CleanupStack::PopAndDestroy( &array );
    CleanupStack::PopAndDestroy( parser );  
              
    if( !UpnpCdsResElementUtility::IsUriAbsolute( *importURI ) )
        {
        // Import uri is not absolute, upload not supported. leave.
        delete importURI; importURI = NULL;
        User::Leave( KErrGeneral );
        }
      
    return importURI;
    }       

// --------------------------------------------------------------------------
// CUPnPUploadSession::ImportURIFromItemL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
HBufC8* CUPnPUploadSession::ImportURIFromItemL( const CUpnpObject& aObject )
    {
    HBufC8* importURI = NULL;
    if( aObject.ObjectType() == EUPnPItem )
        {
        // Get the res-elements
        RUPnPElementsArray elArray;
        CleanupClosePushL( elArray );
        UPnPItemUtility::GetResElements( aObject, elArray );
        
        // Find the import uri 
        TInt count = elArray.Count();           
        for( TInt i = 0; i < count; i++ )
            {
            const CUpnpAttribute* attribute = NULL;
            attribute = &UPnPItemUtility::FindAttributeByNameL(
                *elArray[ i ], KImportUri );
            if( attribute )
                {
                // import uri found
                i = count;
                importURI = attribute->Value().AllocL();
                }
            }            
        CleanupStack::PopAndDestroy( &elArray );        
        }
    return importURI;
    }

// --------------------------------------------------------------------------
// CUPnPUploadSession::ProtocolInfoToUPnPL
// See upnpbrowsingsession.h
// --------------------------------------------------------------------------
void CUPnPUploadSession::ProtocolInfoToUPnPL( const CUpnpAttribute* aInfo )
    {
    __LOG( "CUPnPUploadSession::ProtocolInfoToUPnPL" );
    
    CUpnpDlnaProtocolInfo* destInfo =
        CUpnpDlnaProtocolInfo::NewL( aInfo->Value() );
    CleanupStack::PushL( destInfo );
    
    if( destInfo->PnParameter().Length() )
        {
        __LOG( "ProtocolInfoToUPnPL - Convert to UPnP" );
        
        CUpnpProtocolInfo* targetInfo = CUpnpProtocolInfo::NewL();
        CleanupStack::PushL( targetInfo );
        
        targetInfo->SetFirstFieldL( destInfo->FirstField() );
        targetInfo->SetSecondFieldL( KAsterisk );
        targetInfo->SetThirdFieldL( destInfo->ThirdField() );
        targetInfo->SetFourthFieldL( KAsterisk );
        
        // A bit dirty const cast.. but makes implementation much easier
        CUpnpAttribute* bute = const_cast<CUpnpAttribute*>( aInfo );
        bute->SetValueL( targetInfo->ProtocolInfoL() );
        
        CleanupStack::PopAndDestroy( targetInfo );
        }
    else
        {
        __LOG( "ProtocolInfoToUPnPL - UPnP content -> do nothing" );
        // Not DLNA content, do nothing
        }    
        
    CleanupStack::PopAndDestroy( destInfo );
    }

//---------------------------------------------------------------------------
// CUPnPUploadSession::StopWait()
// See upnpbrowsingsession.h
//---------------------------------------------------------------------------
//
void CUPnPUploadSession::StopWait()
    {
    __LOG( "ProtocolInfoToUPnPL::StopWait" );
    if ( iWait.IsStarted() )
        {
        if ( iWait.CanStopNow() )
            {
            __LOG( "ProtocolInfoToUPnPL::StopWait - stop" );
            iWait.AsyncStop();
            iSchedulerStopped = ETrue;
            }
        else
            {
            __LOG( "CUPnPUploadSession::StopWait\
- not able to stop now, use callback" );
            iSchedulerStopped = EFalse;
            iWait.AsyncStop( TCallBack(
                                SchedulerStoppedCallBack,
                                this ) );
            }
        }
    }

//---------------------------------------------------------------------------
// CUPnPUploadSession::SchedulerStoppedCallBack()
// See upnpbrowsingsession.h
//---------------------------------------------------------------------------
//
TInt CUPnPUploadSession::SchedulerStoppedCallBack( TAny* aPtr )
    {
    CUPnPUploadSession* self = 
        static_cast<CUPnPUploadSession*>( aPtr );
    self->DoSchedulerStoppedCallBack();
    return 0;
    }

//---------------------------------------------------------------------------
// CUPnPUploadSession::DoSchedulerStoppedCallBack()
// See upnpbrowsingsession.h
//---------------------------------------------------------------------------
//
void CUPnPUploadSession::DoSchedulerStoppedCallBack()
    {
    __LOG( "ProtocolInfoToUPnPL::DoSchedulerStoppedCallBack" );
    iSchedulerStopped = ETrue;
    }

//---------------------------------------------------------------------------
// CUPnPUploadSession::CreateObjectL()
//---------------------------------------------------------------------------
//
int CUPnPUploadSession::CreateObjectL( const TDesC8& aContainerId,
    const TDesC8& aElements )
    {
    CUpnpAction* action = iServer.ControlPoint().CreateActionLC( 
            iCpDevice, KContentDirectory, KCreateObject );
    
    action->SetArgumentL( KContainerID, aContainerId );
    action->SetArgumentL( KElements, aElements );

    iServer.ControlPoint().SendL( action );
    CleanupStack::Pop( action );
    if (action->SessionId() < 0)
        {
        User::Leave( action->SessionId() );    
        }
    return action->SessionId();
    }

//---------------------------------------------------------------------------
// CUPnPUploadSession::DestroyObjectL()
//---------------------------------------------------------------------------
//
int CUPnPUploadSession::DestroyObjectL( const TDesC8& aObjectId )
    {
    CUpnpAction* action = iServer.ControlPoint().CreateActionLC( 
            iCpDevice, KContentDirectory, KDestroyObject );
    
    action->SetArgumentL( KObjectID, aObjectId );

    iServer.ControlPoint().SendL( action );
    CleanupStack::Pop( action );
    if (action->SessionId() < 0)
        {
        User::Leave( action->SessionId() );    
        }
    return action->SessionId();
    }

// End of file