upnpavcontroller/upnpavcontrollerserver/src/upnpuploadsession.cpp
author Sampo Huttunen <sampo.huttunen@nokia.com>
Thu, 18 Nov 2010 15:46:57 +0200
branchIOP_Improvements
changeset 44 97caed2372ca
parent 38 5360b7ddc251
permissions -rw-r--r--
Fixed AVController, it was accidentally set to search only for renderers. Now also servers are added to device list. Also some minor changes in package definition xml and platform API xml definition files.

/*
* 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