upnpavcontroller/upnpavcontrollerhelper/src/upnpdownloaditemresolver.cpp
changeset 0 7f85d04be362
child 34 eab116a48b80
child 38 5360b7ddc251
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpavcontroller/upnpavcontrollerhelper/src/upnpdownloaditemresolver.cpp	Thu Dec 17 08:52:00 2009 +0200
@@ -0,0 +1,596 @@
+/*
+* 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:      Resolver for downloading remote items
+*
+*/
+
+
+
+
+
+
+// INCLUDE FILES
+// System
+#include <pathinfo.h>
+#include <bautils.h>
+
+// upnp stack api's
+#include <upnpobject.h>
+#include <upnpitem.h>
+#include <upnpelement.h>
+#include <upnpattribute.h> // for getting resource protocol info
+#include <upnpdlnaprotocolinfo.h> // for resolving object mimetype
+
+// upnpframework / avcontroller api
+#include "upnpavcontroller.h" // avcontrol services
+#include "upnpavdevice.h" // avcontroller device class
+#include "upnpavbrowsingsession.h" // avcontrol browsing session
+#include "upnpfiledownloadsession.h" // avcontrol download session
+
+// upnpframework / avcontroller helper api
+#include "upnpconstantdefs.h" // for element names
+#include "upnpitemutility.h" // for FindAttributeByName
+#include "upnpresourceselector.h" // MUPnPResourceSelector
+#include "upnpitemresolverobserver.h" // observer for this class
+#include "upnpdlnautility.h"  // IsSupportedDlnaProfile
+
+// upnpframework / internal api's
+#include "upnpcommonutils.h" // for FileExtensionByMimeTypeL
+#include "upnpsettingsengine.h" // get selected download location
+
+// avcontroller helper internal
+#include "upnpremoteitemresolver.h" // remote item resolver impl.
+#include "upnpdownloaditemresolver.h" // download item resolver impl.
+
+_LIT( KComponentLogfile, "upnpavcontrollerhelper.txt");
+#include "upnplog.h"
+
+// CONSTANTS
+_LIT( KTempPrefix, "upnpfwtemp");
+
+// METHODS
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::NewL
+//---------------------------------------------------------------------------
+CUPnPDownloadItemResolver* CUPnPDownloadItemResolver::NewL(
+    const TDesC8& aItemId,
+    MUPnPAVController& aAvController,
+    MUPnPAVBrowsingSession& aHostSession,
+    MUPnPResourceSelector& aSelector,
+    const TDesC8& aBrowseFilter )
+    {
+    CUPnPDownloadItemResolver* self = new (ELeave) CUPnPDownloadItemResolver(
+        aItemId, aAvController, aHostSession, aSelector, aBrowseFilter );
+    CleanupStack::PushL( self );
+    self->ConstructL(
+        aItemId, aAvController, aHostSession, aSelector, aBrowseFilter );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::CUPnPDownloadItemResolver
+//---------------------------------------------------------------------------
+CUPnPDownloadItemResolver::CUPnPDownloadItemResolver(
+    const TDesC8& /*aItemId*/,
+    MUPnPAVController& aAvController,
+    MUPnPAVBrowsingSession& /*aHostSession*/,
+    MUPnPResourceSelector& aSelector,
+    const TDesC8& /*aBrowseFilter*/ )
+    : iAvController( aAvController ),
+      iState( EStateIdle ),iSelector(aSelector)
+    {
+
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::ConstructL
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::ConstructL(
+    const TDesC8& aItemId,
+    MUPnPAVController& /*aAvController*/,
+    MUPnPAVBrowsingSession& aHostSession,
+    MUPnPResourceSelector& aSelector,
+    const TDesC8& aBrowseFilter )
+    {
+    iRemoteResolver = CUPnPRemoteItemResolver::NewL(
+        aItemId, aHostSession, aSelector, aBrowseFilter );
+    iRemoteDevice = CUpnpAVDevice::NewL( aHostSession.Device() );
+    iSettingsEngine = CUPnPSettingsEngine::NewL();
+    
+    // Open File Server session
+    User::LeaveIfError( iFsSession.Connect() );
+    User::LeaveIfError( iFsSession.ShareProtected() );   
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::~CUPnPDownloadItemResolver
+//---------------------------------------------------------------------------
+CUPnPDownloadItemResolver::~CUPnPDownloadItemResolver()
+    {        
+    Cleanup();
+    delete iRemoteResolver;
+    iRemoteResolver = 0;
+    delete iRemoteDevice;
+    iRemoteDevice= 0;
+    delete iSettingsEngine;
+    iSettingsEngine = 0;
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::ResolveL
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::ResolveL(
+    MUPnPItemResolverObserver& aObserver )
+    {
+    __LOG( "DownloadItemResolver:Resolve()" );
+    __ASSERTD( iState == EStateIdle, __FILE__, __LINE__ );
+
+    // change state
+    iObserver = &aObserver;
+
+    // first resolve the item
+    iRemoteResolver->ResolveL( *this );
+    iState = EStateResolving;
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::ResolveComplete
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::ResolveComplete(
+    const MUPnPItemResolver& /*aResolver*/, TInt aError )
+    {
+    __LOG1( "DownloadItemResolver:ResolveComplete(%d)", aError );
+    __ASSERTD( iState == EStateResolving, __FILE__, __LINE__ );
+
+    if ( aError == KErrNone )
+        {
+        TRAP( aError, 
+                const CUpnpElement& res =
+                        iSelector.SelectResourceL( iRemoteResolver->Item() );
+                IsLocallySupportedL( res );
+                );
+        if( aError )
+            {
+            Complete( aError );
+            }
+        else
+            {
+            TRAPD( err, InitiateDownloadL() );
+            if ( err != KErrNone )
+                {
+                Complete( err );
+                }
+            }
+        }
+    else
+        {
+        Complete( aError );
+        }
+
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::InitiateDownloadL
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::InitiateDownloadL()
+    {
+    __LOG( "CUPnPDownloadItemResolver::InitiateDownloadL");
+    // start a download session if not already started
+    if( !iDownloadSession )
+        {
+        iDownloadSession =
+            &iAvController.StartDownloadSessionL( *iRemoteDevice );
+        }
+    iDownloadSession->SetObserver( *this );
+
+    // Get selected download location.
+    HBufC* copyLocation = GetSelectedDownloadLocationL();
+    CleanupStack::PushL( copyLocation );
+    _LIT(KTempFolder, "temp\\");
+    // Create temp file name
+    HBufC* tempFileName = CreateTmpFileNameL();
+    CleanupStack::PushL( tempFileName );
+
+    // Create and save full file path.
+    if( iLocalFile )
+        {
+        // delete if already allocated.
+        delete iLocalFile;
+        iLocalFile = 0;
+        }
+    
+    iLocalFile = HBufC::NewL( copyLocation->Length() +
+                              KTempFolder().Length() );
+    iLocalFile->Des().Append( *copyLocation );
+    iLocalFile->Des().Append( KTempFolder );
+    //check the existence of the target folder
+    if( !BaflUtils::FolderExists( iFsSession, *iLocalFile ) )
+        {
+        User::LeaveIfError( iFsSession.MkDirAll( *iLocalFile ) );
+        }
+        
+    User::LeaveIfError( iFsSession.SetAtt( *iLocalFile, 
+                                    KEntryAttHidden, 
+                                    KEntryAttNormal ) );
+                                        
+    iLocalFile = iLocalFile->ReAllocL( 
+        iLocalFile->Length() + tempFileName->Length() );
+    
+    iLocalFile->Des().Append( *tempFileName );
+
+    // write the file path into the item
+    CUpnpElement& writableRes =
+        const_cast<CUpnpElement&>( iRemoteResolver->Resource() );
+    writableRes.SetFilePathL( *iLocalFile );
+    CleanupStack::PopAndDestroy( tempFileName );
+    CleanupStack::PopAndDestroy( copyLocation );
+    
+    // Create local target file for dowload item
+    TInt err = CreateRFile( *iLocalFile );
+
+    if( err == KErrNone )
+        {
+        __LOG( "StartDownloading...");
+        // initiate download
+        
+        iDownloadSession->StartDownloadL( writableRes, 
+                                      iRemoteResolver->Item(), 
+                                      iFile,
+                                      (TInt)this );
+                                      
+        iState = EStateDownloading;
+        }
+    else // Create download target failed!
+        {
+        __LOG( "Create download target failed!");
+        User::Leave( err );
+        }
+    __LOG( "CUPnPDownloadItemResolver::InitiateDownloadL -End");
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::TransferStarted
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::TransferStarted( TInt /*aKey*/,
+    TInt /*aStatus*/ )
+    {
+    __LOG( "DownloadItemResolver:TransferStarted");
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::TransferCompleted
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::TransferCompleted( TInt /*aKey*/,
+    TInt aStatus, const TDesC& /*aFilePath*/ )
+    {
+    __LOG1( "DownloadItemResolver:TransferCompleted(%d)", aStatus );
+    iFile.Close();
+    Complete( aStatus );
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::TransferProgress
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::TransferProgress( TInt /*aKey*/,
+    TInt /*aBytes*/, TInt /*aTotalBytes*/ )
+    {
+    __LOG( "DownloadItemResolver:TransferProgress");
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::MediaServerDisappeared
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::MediaServerDisappeared(
+    TUPnPDeviceDisconnectedReason /*aReason*/ )
+    {
+    __LOG( "DownloadItemResolver:MediaServerDisappeared" );
+    Complete( KErrDisconnected );
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::Item
+//---------------------------------------------------------------------------
+const CUpnpItem& CUPnPDownloadItemResolver::Item() const
+    {
+    __ASSERTD( iState == EStateReady, __FILE__, __LINE__ );
+
+    return iRemoteResolver->Item();
+    }
+
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::Resource
+//---------------------------------------------------------------------------
+const CUpnpElement& CUPnPDownloadItemResolver::Resource() const
+    {
+    __ASSERTD( iState == EStateReady, __FILE__, __LINE__ );
+
+    return iRemoteResolver->Resource();
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::DeleteTempFilesL
+// --------------------------------------------------------------------------
+EXPORT_C void CUPnPDownloadItemResolver::DeleteTempDownloadFilesL()
+    {
+    __LOG("CUPnPDownloadItemResolver::DeleteTempDownloadFilesL begin");
+
+    RFs fs;
+    User::LeaveIfError( fs.Connect() );
+    CleanupClosePushL( fs );
+
+    CFileMan* fileMan = CFileMan::NewL( fs );
+    CleanupStack::PushL( fileMan );
+    _LIT( KAnyChar, "*");
+    _LIT( KAnyExtension, "*.*");
+    _LIT( KUpnpUploadTempDirectory, "temp\\" );
+
+    // clean selected download directory
+    HBufC* path = HBufC::NewLC( KMaxFileName );
+    CUPnPSettingsEngine* settingsEngine = CUPnPSettingsEngine::NewL();
+    CleanupStack::PushL( settingsEngine );
+    HBufC* copyLocation = HBufC::NewL( KMaxFileName );
+    CleanupStack::PushL( copyLocation );
+    TBool copyLocationIsPhoneMemory = 0; // not used in this case
+    TPtr copyLocationPtr( copyLocation->Des() );
+    settingsEngine->GetCopyLocationL( copyLocationPtr,
+        copyLocationIsPhoneMemory );
+    path->Des().Append( *copyLocation );
+    path->Des().Append( KAnyChar );
+    path->Des().Append( KTempPrefix );
+    path->Des().Append( KAnyExtension );
+    fileMan->Delete( *path );
+    
+    path->Des().Zero();
+    path->Des().Append( *copyLocation );
+    path->Des().Append( KUpnpUploadTempDirectory );
+    path->Des().Append( KAnyExtension );
+    fileMan->Delete( *path );
+
+    CleanupStack::PopAndDestroy( copyLocation );
+    CleanupStack::PopAndDestroy( settingsEngine );
+    CleanupStack::PopAndDestroy( path );
+
+    CleanupStack::PopAndDestroy( fileMan );
+    CleanupStack::PopAndDestroy( &fs );
+
+    __LOG("CUPnPDownloadItemResolver::DeleteTempDownloadFilesL End");
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::Complete
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::Complete( TInt aError )
+    {
+    __ASSERTD( iState == EStateResolving || iState == EStateDownloading,
+        __FILE__, __LINE__ );
+
+    if ( iDownloadSession != 0 )
+        {
+        iAvController.StopDownloadSession( *iDownloadSession );
+        iDownloadSession = 0;
+        }
+
+    MUPnPItemResolverObserver& observer = *iObserver;
+    iObserver = 0;
+    if ( aError == KErrNone )
+        {
+        iState = EStateReady;
+        }
+    else
+        {
+        iState = EStateIdle;
+        Cleanup();
+        }
+
+    observer.ResolveComplete( *this, aError );
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::Cleanup
+//---------------------------------------------------------------------------
+void CUPnPDownloadItemResolver::Cleanup()
+    {
+    iObserver = 0;
+    iFile.Close();
+    
+    if ( iDownloadSession != 0 )
+        {
+        iAvController.StopDownloadSession( *iDownloadSession );
+        iDownloadSession = 0;
+        }
+        
+    if ( iLocalFile )
+        {
+        // delete the local file
+        iFsSession.Delete( iLocalFile->Des() );       
+        __LOG1( "DownloadItemResolver: deleted local file(%d)", iLocalFile );
+        delete iLocalFile;
+        iLocalFile = 0;
+        }
+        
+    iFsSession.Close();
+
+    iState = EStateIdle;
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::CreateTmpFileNameL
+//---------------------------------------------------------------------------
+HBufC* CUPnPDownloadItemResolver::CreateTmpFileNameL()
+    {
+    __LOG( "DownloadItemResolver::CreateTmpFileName" );
+    __ASSERTD( iState == EStateResolving, __FILE__, __LINE__ );
+
+    HBufC* tempfilename = NULL;
+    HBufC* fileExt = NULL;
+    
+    // Get file extension
+    const CUpnpAttribute* attr = UPnPItemUtility
+        ::FindAttributeByName( iRemoteResolver->Resource(), 
+        KAttributeProtocolInfo );
+    if ( attr != 0 )
+        {
+        CUpnpDlnaProtocolInfo* pInfo =
+            CUpnpDlnaProtocolInfo::NewL( attr->Value() );
+        CleanupStack::PushL( pInfo );
+        fileExt = UPnPCommonUtils::FileExtensionByMimeTypeL(
+            pInfo->ThirdField() );
+        CleanupStack::PopAndDestroy( pInfo );
+        pInfo = NULL;
+        }
+
+    // If file extension exist create whole file name.
+    if( fileExt )
+        {
+        CleanupStack::PushL( fileExt );
+        tempfilename = HBufC::NewL( 
+            KTempPrefix().Length() + 
+            iRemoteResolver->Item().Id().Length() + 
+            fileExt->Length() );
+        CleanupStack::PushL( tempfilename );
+        // Add prefix
+        tempfilename->Des().Append( KTempPrefix ); 
+        // Add item name. Convert 8 to 16 and replace illeagal characters.
+        HBufC8* tmpItemName8 = 
+            UPnPCommonUtils::ReplaceIllegalFilenameCharactersL( 
+            iRemoteResolver->Item().Id() );
+        CleanupStack::PushL( tmpItemName8 );
+        HBufC* itemname = HBufC::NewL( tmpItemName8->Length() );
+        CleanupStack::PushL( itemname );
+        itemname->Des().Copy( *tmpItemName8 );
+        tempfilename->Des().Append( *itemname );
+        CleanupStack::PopAndDestroy( itemname );
+        CleanupStack::PopAndDestroy( tmpItemName8 );
+        // Add file extension
+        tempfilename->Des().Append( *fileExt );
+
+        CleanupStack::Pop( tempfilename );
+        CleanupStack::PopAndDestroy( fileExt );
+        }
+    else // Create without file extension
+        {
+        tempfilename = HBufC::NewL( 
+            KTempPrefix().Length() + iRemoteResolver->Item().Id().Length() );
+        CleanupStack::PushL( tempfilename );
+        // Add prefix
+        tempfilename->Des().Append( KTempPrefix ); 
+        // Add item name. Convert 8 to 16 and replace illeagal characters.
+        HBufC8* tmpItemName8 = 
+            UPnPCommonUtils::ReplaceIllegalFilenameCharactersL( 
+            iRemoteResolver->Item().Id() );
+        CleanupStack::PushL( tmpItemName8 );
+        HBufC* itemname = HBufC::NewL( tmpItemName8->Length() );
+        CleanupStack::PushL( itemname );
+        itemname->Des().Copy( *tmpItemName8 );
+        tempfilename->Des().Append( *itemname );
+        CleanupStack::PopAndDestroy( itemname );
+        CleanupStack::PopAndDestroy( tmpItemName8 );
+
+        CleanupStack::Pop( tempfilename );
+        }
+
+    return tempfilename; //transfer ownership
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::GetSelectedDownloadLocationL
+//---------------------------------------------------------------------------
+HBufC* CUPnPDownloadItemResolver::GetSelectedDownloadLocationL()
+    {
+    __LOG( "DownloadItemResolver::GetSelectedDownloadLocationL" );
+
+    HBufC* copyLocation = HBufC::NewL( KMaxFileName );
+    CleanupStack::PushL( copyLocation );
+    TBool copyLocationIsPhoneMemory = 0;
+    TPtr copyLocationPtr( copyLocation->Des() );
+    TRAPD( error, iSettingsEngine->GetCopyLocationL( 
+        copyLocationPtr, copyLocationIsPhoneMemory ) )
+    
+    // Something wrong in getting copy location. Default to 
+    // phone memory.
+    if( error != KErrNone )
+        {
+        TPtrC phoneDrive( PathInfo::PhoneMemoryRootPath() );
+        copyLocation->Des().Append( phoneDrive );
+        }
+    
+    CleanupStack::Pop( copyLocation );
+    return copyLocation;
+    }
+
+// -----------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::CreateRFile
+// -----------------------------------------------------------------------------
+// 
+TInt CUPnPDownloadItemResolver::CreateRFile( const TDesC& aFilePath )
+    {
+    __LOG( "DownloadItemResolver::CreateRFile" );
+    iFile.Close();
+
+    // In some special case, the function Replace() will fail
+    // with error -14(KErrInUse) by using 'EFileWrite' mode.
+    // Maybe some other handler does not close the file. 
+    TInt err = iFile.Replace(
+                iFsSession,
+                aFilePath,
+                EFileShareReadersOrWriters );
+                
+    if( KErrPathNotFound == err )
+        {
+        __LOG( "Directory not available -> create new" );
+        iFsSession.MkDirAll( aFilePath );
+        err = iFile.Create( iFsSession, aFilePath, EFileWrite );
+        }
+    return err;
+    }
+
+// --------------------------------------------------------------------------
+// CUPnPDownloadItemResolver::IsLocallySupportedL()
+// Check if the audio is DLNA supported in remote to local playback 
+// --------------------------------------------------------------------------
+//
+void CUPnPDownloadItemResolver::IsLocallySupportedL( const CUpnpElement& aRes )
+    {
+    const CUpnpAttribute* attr = 
+                       &UPnPItemUtility::FindAttributeByNameL( 
+                                              aRes, KAttributeProtocolInfo );
+    // parse protocol info
+    CUpnpDlnaProtocolInfo* pInfo = NULL;
+    pInfo = CUpnpDlnaProtocolInfo::NewL( attr->Value() );
+    
+    //if DLNA compliant item
+    if ( pInfo->PnParameter() != KNullDesC8() )
+        {
+        if( !UPnPDlnaUtility::IsSupportedDlnaProfile( 
+                                              pInfo->PnParameter() ) )
+            {
+            User::Leave(KErrNotSupported);
+            }
+        }
+    else //if not, check MIME type
+        {
+        if( !UPnPDlnaUtility::IsSupportedMimeType( pInfo->ThirdField() ) )
+            {
+            User::Leave(KErrNotSupported);
+            }
+        
+        }
+    }
+
+
+