diff -r 000000000000 -r 96612d01cf9f videofeeds/mrssplugin/src/CIptvRssPlugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videofeeds/mrssplugin/src/CIptvRssPlugin.cpp Mon Jan 18 20:21:12 2010 +0200 @@ -0,0 +1,1509 @@ +/* +* Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: RSS plugin.* +*/ + + + + +#include +#include +#include +#include +#include + +#include "IptvDebug.h" +#include "MIptvEpgVodCallback.h" +#include "MIptvEpgLiveTvCallback.h" +#include "CIptvTimer.h" +#include + +#include "CIptvEpgService.h" +#include "iptvlastwatcheddata.h" +#include "iptvlastwatchedapi.h" + +#include "CIptvRssPlugin.h" +#include "CIptvRssDownload.h" +#include "CIptv3XmlContentHandler.h" + +_LIT8( KMimeType, "text/xml" ); + +_LIT( KIptvRssFileName, "rss." ); +_LIT( KIptvThumbnailExtension, ".jpg" ); +_LIT( KIptvVCFGExtension, ".vcfg" ); +_LIT( KIptvRssSearchFileName, "rsssearch." ); +_LIT( KIptvAllFiles, "*.*" ); +_LIT8( KIptvHexByteFormatStr, "%02x" ); + +const TInt64 KIptvRssUpdateSuccesInterval( 60 ); +const TInt64 KIptvRssUpdateFailedInterval( 0 ); +const TInt KIptvExtensionMaxSize( 5 ); + +const TInt KIptvRssPluginFreeSpace( 512000 ); // 500 KB + +static const TInt KReadAtOnceLength( 1000 ); + +const TInt KIptvTime_200_microsecond( 200 ); + +const TInt KIptvHexCharInByte( 2 ); +/** +* Enable this flag to update feed from local XML file. The path +* to XML file is defined with KIptvLocalTestFeed variable below. +*/ +//#define IPTV_RSS_LOCAL_TEST + +#ifdef IPTV_RSS_LOCAL_TEST +_LIT( KIptvLocalTestFeed, "C:\\videofeed.xml" ); +#warning Local feed test flag IPTV_RSS_LOCAL_TEST has been defined!!! +#endif + +// ======== MEMBER FUNCTIONS ======== + +// -------------------------------------------------------------------------- +// Symbian 2nd phase constructor can leave. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::ConstructL() + { + IPTVLOGSTRING_LOW_LEVEL( "RSS Plugin --- CIptvRssPlugin::ConstructL" ); + + User::LeaveIfError( iFs.Connect() ); + iDownload = CIptvRssDownload::NewL( *this, iFs, *iXmlContentHandler ); + iThumbnailDlAllowed = ThumbnailDlAllowedL(); + + if ( iThumbnailDlAllowed ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ConstructL --- Thumbnail downloading is allowed!" ); + } + else + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ConstructL --- Thumbnail downloading is not allowed!" ); + } + + iParserIdle = CIdle::NewL( CActive::EPriorityIdle ); + iXmlContentHandler = CIptvXmlContentHandler::NewL( *this ); + iParser = CParser::NewL( KMimeType, *iXmlContentHandler ); + } + +// -------------------------------------------------------------------------- +// Two-phased constructor. +// Create instance of concrete ECOM interface implementation +// -------------------------------------------------------------------------- +// +CIptvRssPlugin* CIptvRssPlugin::NewL() + { + IPTVLOGSTRING_LOW_LEVEL( "RSS Plugin --- CIptvRssPlugin::NewL" ); + + CIptvRssPlugin* self = new( ELeave ) CIptvRssPlugin(); + CleanupStack::PushL( self ); + + self->ConstructL(); + + CleanupStack::Pop( self ); + return self; + } + +// -------------------------------------------------------------------------- +// Destructor +// -------------------------------------------------------------------------- +// +CIptvRssPlugin::~CIptvRssPlugin() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::~CIptvRssPlugin" ); + + delete iItem; + delete iParser; + delete iDownload; + delete iParserIdle; + delete iXmlContentHandler; + delete iXmlFileContent; + delete iStartTimer; + delete iMD5Calculator; + iDlQueue.ResetAndDestroy(); + iIconList.ResetAndDestroy(); + iPreviouslyDownloadedAddresses.ResetAndDestroy(); + iPreviouslyDownloadedPaths.ResetAndDestroy(); + + iFs.Close(); + iVodCallback = NULL; + } + +// -------------------------------------------------------------------------- +// C++ default constructor +// -------------------------------------------------------------------------- +// +CIptvRssPlugin::CIptvRssPlugin() : + iXmlContentHandler( NULL ), + iParser( NULL ), + iParserIdle( NULL ), + iDownload( NULL ), + iVodCallback( NULL ), + iXmlFileContent( NULL ), + iStartTimer( NULL ), + iServiceId( 0 ), + iItem( NULL ), + iDlThumbnail( EFalse ), + iThumbnailDlAllowed( EFalse ), + iParsingFailed( EFalse ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::CIptvRssPlugin" ); + } + +// -------------------------------------------------------------------------- +// From CIptvEpgPluginInterface +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::RunPlugin() + { + IPTVLOGSTRING_LOW_LEVEL( "RSS Plugin --- CIptvRssPlugin::RunPlugin" ); + + // Timer removes UI jamming in update sequence. + if ( !iStartTimer ) + { + TRAP_IGNORE( iStartTimer = + CIptvTimer::NewL( CActive::EPriorityUserInput, *this ) ); + } + + if ( iStartTimer ) + { + if ( !iStartTimer->IsActive() ) + { + iStartTimer->After( KIptvTime_200_microsecond ); + } + } + } + +// -------------------------------------------------------------------------- +// Delayed plugin start. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::TimerExpired( CIptvTimer* /* aTimer */ ) + { + IPTVLOGSTRING_LOW_LEVEL( + "CIptvRssPlugin --- CIptvRssPlugin::TimerExpired" ); + + TRAPD( error, DoTimerExpiredL() ); + if ( error != KErrNone ) + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::TimerExpired --- Leave while DoTimerExpiredL() = %d", + error ); + TRAP( error, PluginFailedL( EIptvDlNoError ) ); + if ( error != KErrNone ) + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::TimerExpired --- Leave while PluginFailedL() = %d", + error ); + } + } + } + +// -------------------------------------------------------------------------- +// Delayed plugin start. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::DoTimerExpiredL() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DoTimerExpiredL" ); + + iDownload->InitializeL(); + RunPluginL(); + } + +// -------------------------------------------------------------------------- +// Start plugin. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::RunPluginL() + { + IPTVLOGSTRING_LOW_LEVEL( "RSS Plugin --- CIptvRssPlugin::RunPluginL" ); + + if ( ! iIsGroupOperation ) + { + // If exist, delete old rss file + if ( BaflUtils::FileExists( iFs, iRssPath ) ) + { + BaflUtils::DeleteFile( iFs, iRssPath ); + } + } + + // Clear obsolete thumbnail list. + iIconList.ResetAndDestroy(); + + // Clear already downloaded thumbnail list. + iPreviouslyDownloadedAddresses.ResetAndDestroy(); + iPreviouslyDownloadedPaths.ResetAndDestroy(); + + // Before we even start the download, we check that there is sensible + // amount of free disk space for content guide and thumbnail files. + TBool checkResult( EFalse ); + TRAPD( + checkError, + checkResult = SysUtil::DiskSpaceBelowCriticalLevelL( + &iFs, KIptvRssPluginFreeSpace, EDriveC ) ); + if ( checkError != KErrNone || checkResult ) + { + // Not enough space on disk, return immediately without any downloading. + if ( iIsSearchOperation ) + { + iVodCallback->ErrorL( KIptvErrorRssSearchFailed, EIptvDlDiskFull ); + } + else + { + iVodCallback->ErrorL( KIptvErrorEpgUpdateFailed, EIptvDlDiskFull ); + } + return; + } + + // Callback EPG manager that plugin is started + if ( iVodCallback ) + { + iVodCallback->StartedL(); + } + else + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RunPluginL --- iVodCallback is NULL" ); + } + +#ifndef IPTV_RSS_LOCAL_TEST + + if ( ( EIptvRssAddServiceThumbnailToDlQueue == iAction ) || + ( EIptvRssAddItemThumbnailToDlQueue == iAction ) ) + { + // Download only previously listed thumbnails. + iParsingFailed = EFalse; + DownloadThumbnailsL(); + } + else + { + // Download RSS-file. + iDownload->DownloadL( + iServiceAddress, + iRssPath, + EFalse, + KIptvEmptyDes, + iLastUpdated ); + } + +#else + + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RunPluginL --- Parsing XML from local filesystem!" ); + iRssPath.Copy( KIptvLocalTestFeed ); + DownloadFinishedL( EDownloadSucceeded, EIptvDlNoError ); + +#endif + } + +// -------------------------------------------------------------------------- +// Set callback pointer to MIptvEpgVodCallback. Plugin uses +// MIptvEpgVodCallback interface to supply Epg data to system. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetVodCallback( MIptvEpgVodCallback* aVodCallback ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetVodCallback" ); + + iXmlContentHandler->SetVodCallback( aVodCallback ); + iVodCallback = aVodCallback; + } + +// -------------------------------------------------------------------------- +// Set callback pointer to MIptvEpgLiveTvCallback. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetLiveTvCallback( + MIptvEpgLiveTvCallback* /*aLiveTvCallback*/ ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetLiveTvCallback" ); + } + +// -------------------------------------------------------------------------- +// From CIptvEpgPluginInterface interface +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetServiceInformation( + CIptvEpgService* aService, + TBool aUseSearchAddress ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetServiceInformation" ); + + TIptvRSSAction action( EIptvRssService ); + if ( aUseSearchAddress ) + { + action = EIptvRssSearch; + } + + TRAP_IGNORE( SetServiceInformationL( aService, action ) ); + } + +// -------------------------------------------------------------------------- +// From CIptvEpgPluginInterface interface +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetServiceInformationL( + CIptvEpgService* aService, + TIptvRSSAction aAction ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetServiceInformationL" ); + + if ( !aService ) + { + User::Leave( KErrArgument ); + } + + iAction = aAction; + iIsGroupOperation = + ( ( EIptvRssServiceGroup == iAction ) || + ( EIptvRssAddServiceThumbnailToDlQueue == iAction ) || + ( EIptvRssAddItemThumbnailToDlQueue == iAction ) ); + iIsSearchOperation = ( EIptvRssSearch == iAction ); + + if ( ( EIptvRssAddServiceThumbnailToDlQueue == iAction ) || + ( EIptvRssAddItemThumbnailToDlQueue == iAction ) ) + { + CIptvDownloadItem* item = CIptvDownloadItem::NewL(); + CleanupStack::PushL( item ); + item->iThumbnailUrl.Copy( aService->iAddress ); + item->iServiceThumbnail = ( EIptvRssAddServiceThumbnailToDlQueue == iAction ); + item->iId = aService->iServiceId; + AddToDlQueueL( item ); + CleanupStack::Pop( item ); + } + else + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetServiceInformationL --- USERNAME %S", + &aService->iUserName ); + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetServiceInformationL --- PASSWORD %S", + &aService->iPassword ); + + iServiceId = aService->iServiceId; + if ( iIsSearchOperation ) + { + iServiceAddress.Copy( aService->SearchUrl() ); + } + else + { + iServiceAddress.Copy( aService->iAddress ); + } + + iDownload->SetServiceInformation( aService ); + + if ( iIsGroupOperation ) + { + HBufC* path = HBufC::NewLC( KIptvMaxPath ); + TPtr16 pathPtr = path->Des(); + TBuf url; + url.Copy( iServiceAddress ); + + // Get pathname for vcfg file. + BuildUniqueuPathNameL( + url, + EIptvPathTmp, + KIptvVCFGExtension, + ETrue, + pathPtr ); + + iRssPath.Copy( *path ); + CleanupStack::PopAndDestroy( path ); + } + else + { + // Get RSS temp file path + TRAP_IGNORE( CIptvUtil::GetPathL( iFs, EIptvPathTmp, iRssPath ) ); + + if ( iIsSearchOperation ) + { + iRssPath.Append( KIptvRssSearchFileName ); + } + else + { + iRssPath.Append( KIptvRssFileName ); + } + + TBuf service; + service.Num( TInt64( iServiceId ) ); + iRssPath.Append( service ); + } + + iLastUpdated = aService->iLastUpdated; + + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetServiceInformation --- RSS temp file : %S", + &iRssPath ); + } + } + +// -------------------------------------------------------------------------- +// Handles download finished. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::DownloadFinishedL( TInt aState, TIptvDlError aError ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL" ); + + TBuf<1> empty; + + if ( !iDlThumbnail ) + { + switch ( aState ) + { + case EDownloadFailed: + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL --- EDownloadFailed" ); + PluginFailedL( aError ); + } + break; + + case EDownloadSucceeded: + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL --- EDownloadSucceeded" ); + if ( iIsGroupOperation ) + { + // This is used for group VCFG file download indication. + iVodCallback->UpdateServiceThumbnailL( iRssPath, ETrue ); + } + else + { + ParseL(); + } + } + break; + + case EDownloadNoNeed: + case EDownloadAlreadyDownloaded: + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL --- EDownloadNoNeed" ); + // When rss file has not been changed, also thumnails are + // assumed not having been changed. + if ( iIsGroupOperation ) + { + iVodCallback->ErrorL( + KIptvContentUpdateCompleted, + EIptvDlNoErrorUpToDate ); + iVodCallback->UpdateServiceThumbnailL( iRssPath, ETrue ); + } + else + { + PluginSucceededL(); + } + } + break; + + default: + break; + } + } + else + { + if ( iItem ) + { + if ( iItem->iServiceThumbnail ) + { + switch ( aState ) + { + case EDownloadFailed: + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL --- Service thumbnail download finished --- EDownloadFailed" ); + iVodCallback->UpdateServiceThumbnailL( empty, EFalse ); + + // Thumbnail file id is not used + TUint32 iconFileId( 0 ); + iVodCallback->UpdateCategoryIconL( + iItem->iId, iconFileId, empty, EFalse ); + } + break; + + case EDownloadSucceeded: + case EDownloadNoNeed: + // Set as already downloaded only first time, + // when really done it. + SetAlreadyDownloadedPathL(); + //lint -fallthrough intended here + case EDownloadAlreadyDownloaded: + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadFinishedL --- Service thumbnail %S", + &iDownloadPath ); + iVodCallback->UpdateServiceThumbnailL( + iDownloadPath, EFalse ); + + // Thumbnail file id is not used + TUint32 iconFileId( 0 ); + iVodCallback->UpdateCategoryIconL( + iItem->iId, + iconFileId, + iDownloadPath, + EFalse ); + iVodCallback->ErrorL( + KIptvServiceThumbnailDownloaded, + iServiceId ); + } + break; + + default: + break; + } + } + else + { + switch ( aState ) + { + case EDownloadFailed: + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin:: --- CIptvRssPlugin::DownloadFinishedL --- Content thumbnail download finished --- EDownloadFailed" ); + // Thumbnail file id is not used + TUint32 iconFileId( 0 ); + iVodCallback->UpdateContentIconL( + iItem->iId, + iconFileId, + empty, + EFalse ); + } + break; + + case EDownloadSucceeded: + case EDownloadNoNeed: + // Set as already downloaded only first time, + // when really done it. + SetAlreadyDownloadedPathL(); + //lint -fallthrough intended here + case EDownloadAlreadyDownloaded: + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin:: --- CIptvRssPlugin::DownloadFinishedL --- Content thumbnail %S", + &iDownloadPath ); + // Thumbnail file id is not used + TUint32 iconFileId( 0 ); + iVodCallback->UpdateContentIconL( + iItem->iId, + iconFileId, + iDownloadPath, + EFalse ); + if ( iIsSearchOperation ) + { + iVodCallback->ErrorL( + KIptvRssSearchContentThumbnailDownloaded, + iItem->iId ); + } + else + { + iVodCallback->ErrorL( + KIptvContentThumbnailDownloaded, + iItem->iId ); + } + } + break; + + default: + break; + } + } + } + + iDlThumbnail = EFalse; + DownloadThumbnailsL(); + } + } + +// -------------------------------------------------------------------------- +// Set plugin failed. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::PluginFailedL( TIptvDlError aError ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin:: --- CIptvRssPlugin::PluginFailedL" ); + + TTime valid( KIptvRssUpdateFailedInterval ); + + if ( iParsingFailed ) + { + if ( iIsSearchOperation ) + { + iVodCallback->ErrorL( + KIptvErrorRssSearchFailed, KIptvRssParserError ); + } + else + { + iVodCallback->ErrorL( + KIptvErrorEpgUpdateFailed, KIptvRssParserError ); + } + } + else + { + if ( iIsSearchOperation ) + { + iVodCallback->ErrorL( KIptvErrorRssSearchFailed, aError ); + } + else + { + iVodCallback->ErrorL( KIptvErrorEpgUpdateFailed, aError ); + } + } + + iVodCallback->FinishedL( valid ); + } + +// -------------------------------------------------------------------------- +// Set plugin succeeded. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::PluginSucceededL() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin:: --- CIptvRssPlugin::PluginSucceededL" ); + + TInt64 ms; + ms = KIptvMinuteAsMicrosecond * KIptvRssUpdateSuccesInterval; + TTime valid( ms ); + + if ( iIsSearchOperation ) + { + iVodCallback->ErrorL( KIptvErrorRssSearchSucceed, 0 ); + } + else + { + iVodCallback->ErrorL( KIptvErrorEpgUpdateSuccessed, 0 ); + } + + iVodCallback->FinishedL( valid ); + } + +// -------------------------------------------------------------------------- +// Parse EPG data. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::ParseL() + { + IPTVLOGSTRING_LOW_LEVEL( "RSS Plugin:: --- CIptvRssPlugin::ParseL" ); + + TRAPD( err, StartParsingXmlFileL( iRssPath ) ); + if ( err != KErrNone ) + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ParseL --- Leave while Parse() = %d", + err ); + PluginFailedL( EIptvDlNoError ); + } + +#ifndef IPTV_RSS_LOCAL_TEST + + // If exist, delete downloaded rss file. + if ( BaflUtils::FileExists( iFs, iRssPath ) ) + { + BaflUtils::DeleteFile( iFs, iRssPath ); + } + +#endif + + } + +// -------------------------------------------------------------------------- +// Parse EPG data. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::StartParsingXmlFileL( const TDesC& aFileName ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::StartParsingXmlFileL" ); + + RFile phile; + User::LeaveIfError( phile.Open( iFs, aFileName, EFileRead ) ); + CleanupClosePushL( phile ); + TInt size( 0 ); + User::LeaveIfError( phile.Size( size ) ); + delete iXmlFileContent; + iXmlFileContent = NULL; + if ( 0 < size ) + { + iXmlFileContent = HBufC8::NewL( size ); + TPtr8 fileContentPtr = iXmlFileContent->Des(); + User::LeaveIfError( phile.Read( fileContentPtr ) ); + size = iXmlFileContent->Length(); + } + CleanupStack::PopAndDestroy( &phile ); + + // There was at least some content in the file + if ( 0 < size ) + { + iCurrentParsePosition = 0; + iParser->ParseBeginL(); + if ( iParserIdle->IsActive() ) + { + iParserIdle->Cancel(); + } + TCallBack cb( ParseIdleCallback, this ); + iParserIdle->Start( cb ); + } + else + { + iParsingFailed = ETrue; + PluginFailedL( EIptvDlContentNotFound ); + } + } + +// -------------------------------------------------------------------------- +// Static entry point for CIdle callback. +// -------------------------------------------------------------------------- +// +TInt CIptvRssPlugin::ParseIdleCallback( TAny* aPluginImpl ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ParseIdleCallback" ); + + CIptvRssPlugin* self = static_cast ( aPluginImpl ); + if ( self ) + { + return self->HandleParseIdleCallback(); + } + else + { + return NULL; + } + } + +// -------------------------------------------------------------------------- +// Add thumbnail to download queue. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::AddToDlQueueL( const CIptvDownloadItem* aItem ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::AddToDlQueueL" ); + + iDlQueue.AppendL( aItem ); + } + +// -------------------------------------------------------------------------- +// Download thumbnails from download queue. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::DownloadThumbnailsL() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadThumbnailsL" ); + + if ( iParsingFailed ) + { + PluginFailedL( EIptvDlNoError ); + return; + } + + iDlThumbnail = ETrue; + TBool download( EFalse ); + TBool loop( ETrue ); + while ( loop ) + { + download = EFalse; + TInt count( iDlQueue.Count() ); + if ( count > 0 ) + { + delete iItem; + iItem = NULL; + iItem = iDlQueue[0]; + iDlQueue.Remove( 0 ); + + if ( iItem ) + { + iServiceAddress.Copy( iItem->iThumbnailUrl ); + + // Create variable for thumbnail path + HBufC* path = HBufC::NewLC( KIptvMaxPath ); + TPtr16 pathPtr = path->Des(); + + // If downloading service thumbnail + if ( iItem->iServiceThumbnail ) + { + TBool doDownload( EFalse ); + + if ( ! iIsSearchOperation ) + { + doDownload = ETrue; + } + else + { + // we do nothing here. We dont want to download service + // thumbnails for search results + } + + // Download service thumbnail only for "normal" vod. + // When doing search service thumbnail is not downloaded. + if ( doDownload ) + { + // Get pathname for service thumbnail. + BuildUniqueuPathNameL( + iItem->iThumbnailUrl, + EIptvPathService, + KIptvThumbnailExtension, + EFalse, + pathPtr ); + + // If exists, add it to thumbnail list. + if ( BaflUtils::FileExists( iFs, *path ) ) + { + HBufC* srvIcon = HBufC::NewLC( path->Length() ); + TPtr16 srvIconPtr = srvIcon->Des(); + srvIconPtr.Copy( *path ); + iIconList.AppendL( srvIcon ); + CleanupStack::Pop( srvIcon ); + } + + loop = EFalse; + download = ETrue; + iDownloadPath.Copy( *path ); + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadThumbnailsL --- Downloading service thumbnail -> %S", + &iDownloadPath ); + } + else + { + loop = ETrue; + download = EFalse; + } + } + else + { + if ( iThumbnailDlAllowed ) + { + if ( iIsSearchOperation ) + { + // Get pathname for search thumbnail. + BuildUniqueuPathNameL( + iItem->iThumbnailUrl, + EIptvPathRssSearchThumbnail, + KIptvThumbnailExtension, + ETrue, + pathPtr ); + } + else if ( iIsGroupOperation ) + { + // Get pathname for item thumbnail. + BuildUniqueuPathNameL( + iItem->iThumbnailUrl, + EIptvPathService, + KIptvThumbnailExtension, + ETrue, + pathPtr ); + } + else + { + // Get pathname for item thumbnail. + BuildUniqueuPathNameL( + iItem->iThumbnailUrl, + EIptvPathRssThumbnail, + KIptvThumbnailExtension, + ETrue, + pathPtr ); + } + + loop = EFalse; + download = ETrue; + iDownloadPath.Copy( *path ); + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::DownloadThumbnailsL --- Downloading content thumbnail -> %S", + &iDownloadPath ); + } + } + CleanupStack::PopAndDestroy( path ); + } + } + else + { + loop = EFalse; + PluginSucceededL(); + if ( EIptvRssService == iAction ) + { + RemoveObsoleteIconsL(); + } + + // Clear already downloaded thumbnail list. + iPreviouslyDownloadedAddresses.ResetAndDestroy(); + iPreviouslyDownloadedPaths.ResetAndDestroy(); + } + } + + if ( download ) + { + // Get address from possible previously downloaded. + HBufC* alreadyDownloaded = GetAlreadyDownloadedPath(); + if ( NULL == alreadyDownloaded ) + { + TRAPD( + dlError, + iDownload->DownloadL( + iServiceAddress, + iDownloadPath, + ETrue, + KIptvEmptyDes, + iLastUpdated ) ); + + // Starting of thumbnail download can fail for example because of + // invalid URL. + if ( dlError != KErrNone ) + { + DownloadFinishedL( EDownloadFailed, EIptvDlGeneral ); + } + } + else + { + // When already downloaded, use it. + if ( 0 != iDownloadPath.CompareF( *alreadyDownloaded ) ) + { + BaflUtils::CopyFile( iFs, *alreadyDownloaded, iDownloadPath ); + } + + // Retain old Thumbnail and remove it from list. + HBufC* fileName = HBufC::NewLC( iDownloadPath.Length() ); + fileName->Des().Copy( iDownloadPath ); + RemoveIconFromList( fileName, EFalse ); + CleanupStack::PopAndDestroy( fileName ); + + // Signaling must be done async to avoid recursive looping. + iDownload->SkipCurrentDownloadAsyncL(); + } + } + } + +// -------------------------------------------------------------------------- +// Keep track of already downloaded thumbnails to avoid to redownload. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetAlreadyDownloadedPathL() + { + +#ifdef _DEBUG + + // Debug print filename and url. + TBuf debugFileName; + debugFileName.Copy( iDownloadPath ); + + TBuf debugUrl; + debugUrl.Copy( iServiceAddress ); + + IPTVLOGSTRING3_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetAlreadyDownloadedPathL --- Set to already downloaded: %S From: %S", + &debugFileName, + &debugUrl ); + +#endif + + // Append new service address. + TInt len( iServiceAddress.Length() ); + HBufC8* addr = HBufC8::NewLC( len ); + TPtr8 addrPtr = addr->Des(); + addrPtr.Copy( iServiceAddress ); + iPreviouslyDownloadedAddresses.AppendL( addr ); + CleanupStack::Pop( addr ); + + // Append corresponding path. + len = iDownloadPath.Length(); + HBufC* path = HBufC::NewLC( len ); + TPtr16 pathPtr = path->Des(); + pathPtr.Copy( iDownloadPath ); + iPreviouslyDownloadedPaths.AppendL( path ); + CleanupStack::Pop( path ); + } + +// -------------------------------------------------------------------------- +// Keep track of already downloaded thumbnails to avoid to redownload. +// -------------------------------------------------------------------------- +// +HBufC* CIptvRssPlugin::GetAlreadyDownloadedPath() + { + HBufC* alreadyDownloaded( NULL ); + + TInt icon( -1 ); + + // Find address from list. + for ( TInt i = 0; + ( i < iPreviouslyDownloadedAddresses.Count() ) && ( -1 == icon ); + i++ ) + { + if ( 0 == iServiceAddress.CompareF( *iPreviouslyDownloadedAddresses[i] ) ) + { + icon = i; + } + } + + // When found, return it, otherwise append new one to the list. + if ( icon >= 0 ) + { + if ( iPreviouslyDownloadedPaths.Count() > icon ) + { + alreadyDownloaded = iPreviouslyDownloadedPaths[icon]; + +#ifdef _DEBUG + + // Debug print filename and url. + TBuf debugFileName; + debugFileName.Copy( *alreadyDownloaded ); + + TBuf debugUrl; + debugUrl.Copy( iServiceAddress ); + + IPTVLOGSTRING3_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::GetAlreadyDownloadedPathL --- Already downloaded: %S From: %S", + &debugFileName, + &debugUrl ); + +#endif + + } + } + + return alreadyDownloaded; + } + +// -------------------------------------------------------------------------- +// Handle idle callback functionality. +// -------------------------------------------------------------------------- +// +TInt CIptvRssPlugin::HandleParseIdleCallback() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::HandleParseIdleCallback" ); + + // By default add KReadAtOnceLength to current parse position + TInt lengthToBeExtracted( KReadAtOnceLength ); + TBool isLastPart( EFalse ); + + // Dealing with last part of the data in the buffer + if ( ( iCurrentParsePosition + lengthToBeExtracted ) > + iXmlFileContent->Length() ) + { + lengthToBeExtracted = + iXmlFileContent->Length() - iCurrentParsePosition; + isLastPart = ETrue; + } + + // Get next data part to be parsed + TPtr8 midPtr = iXmlFileContent->Des().MidTPtr( + iCurrentParsePosition, lengthToBeExtracted ); + TInt err( KErrNone ); + + // Trap possible leave. If there was something, wrong, just stop parsing + TRAP( err, iParser->ParseL( midPtr ) ); + + TInt retVal( 0 ); + // ParseL went just fine + if ( err == KErrNone ) + { + // We are dealing with last part of the data -> let's not call this + // callback again + if ( isLastPart ) + { + // If some leave occured, just ignore it + TRAP( err, iParser->ParseEndL() ); + iCurrentParsePosition = 0; + +#ifndef IPTV_RSS_LOCAL_TEST + + if ( iThumbnailDlAllowed && ( EIptvRssService == iAction ) ) + { + // We will start thumbnail downloading. Lets list + // current icons for comparing them with new available. + TRAP_IGNORE( ListCurrentIconsL() ) + } + + TRAP( err, DownloadThumbnailsL() ); + +#else + + TRAP_IGNORE( PluginSucceededL() ); + +#endif // IPTV_RSS_LOCAL_TEST + + } + // There will still be more data to be parsed in the buffer + else + { + iCurrentParsePosition += KReadAtOnceLength; + retVal = 1; + } + } + // ParseL leaved. Tell manager, that we have finished our job + else + { + TRAP( err, PluginFailedL( EIptvDlNoError ) ); + retVal = 0; + } + + return retVal; + } + +// -------------------------------------------------------------------------- +// Check is thumbnail download allowed. +// -------------------------------------------------------------------------- +// +TBool CIptvRssPlugin::ThumbnailDlAllowedL() const + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ThumbnailDlAllowedL" ); + + TBool allow( EFalse ); + CRepository* cenRep = CRepository::NewL( KIptvCenRepUid ); + if ( cenRep ) + { + CleanupStack::PushL( cenRep ); + TInt value; + TInt error = cenRep->Get( KIptvCenRepVoDThumbnailsKey, value ); + if ( error == KErrNone && value == 1 ) + { + allow = ETrue; + } + CleanupStack::PopAndDestroy( cenRep ); + } + + return allow; + } + +// -------------------------------------------------------------------------- +// XML parsing failed. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetParsingFailed() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetParsingFailed" ); + + iParsingFailed = ETrue; + } + +// -------------------------------------------------------------------------- +// Content update completed. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::ContentUpdateCompletedL() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ContentUpdateCompletedL" ); + + iVodCallback->ContentUpdateCompletedL(); + + if ( EIptvRssService == iAction ) + { + iVodCallback->ErrorL( KIptvThumbnailCount, iDlQueue.Count() ); + } + else if ( EIptvRssSearch == iAction ) + { + iVodCallback->ErrorL( KIptvRssSearchThumbnailCount, iDlQueue.Count() ); + } + } + +// -------------------------------------------------------------------------- +// Set first update. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::SetFirstUpdate( TBool /*aFirstUpdate*/ ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::SetFirstUpdate" ); + } + +// -------------------------------------------------------------------------- +// Build unique pathname for download object. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::BuildUniqueuPathNameL( + const TDesC& aUrl, + const TIptvPathSelection aPathSelection, + const TDesC& aDefaultExtension, + const TBool aGenerateName, + TPtr aPathName ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::BuildUniqueuPathNameL" ); + + // Lets get files type extension ex. .jpg, vcgf, ... + TInt urlLength( aUrl.Length() ); + TInt index( aUrl.LocateReverse( '.' ) ); + TInt extensionLength( 0 ); + + if ( ( urlLength - index ) < KIptvExtensionMaxSize ) + { + extensionLength = urlLength - index; + } + + // Get path for download object. + if ( ( EIptvPathService == aPathSelection ) || + ( EIptvPathTmp == aPathSelection ) ) + { + CIptvUtil::GetPathL( iFs, aPathSelection, aPathName ); + } + // Item thumbnail must be hashed to keep track on it. + else + { + CIptvUtil::GetPathL( iFs, aPathSelection, iServiceId, aPathName ); + } + + if ( aGenerateName ) + { + // Check whether md5 calculator is already constructed. + if ( !iMD5Calculator ) + { + iMD5Calculator = CMD5::NewL(); + } + + // Calculate the 128 bit, 16 byte hash + iMD5Calculator->Reset(); + TBuf8 buffer; + buffer.Copy( aUrl ); + + TPtrC8 hash = iMD5Calculator->Hash( buffer ); + + // Now print it as a 32 byte hex number + TBuf8 hexNumber; + for ( TInt i = 0; i < hash.Length(); i++ ) + { + hexNumber.Zero(); + hexNumber.Format( KIptvHexByteFormatStr, hash[i] ); + aPathName.Append( hexNumber[0] ); + aPathName.Append( hexNumber[1] ); + } + } + else + { + // Service thumbnail can be with service identifier. + aPathName.AppendNum( static_cast( iServiceId ) ); + } + + // Add thumbnail file extension. + if ( extensionLength > 0 ) + { + // If there was a extension for thumbnail use it + aPathName.Append( aUrl.Right( extensionLength ) ); + } + else + { + // By default add .jpg extension + aPathName.Append( aDefaultExtension ); + } + +#ifdef _DEBUG + + // Debug print filename. + TBuf debugFileName; + debugFileName.Copy( aPathName ); + + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::BuildUniqueuPathNameL Generated path name: %S", + &debugFileName ); + +#endif + + } + +// -------------------------------------------------------------------------- +// List current icons. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::ListCurrentIconsL() + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ListCurrentIconsL" ); + + CDir* iconList( NULL ); + + // Create mask path for thumbnail search + HBufC* mask = HBufC::NewLC( KIptvMaxPath ); + TPtr16 maskPtr = mask->Des(); + + // list item icons. + CIptvUtil::GetPathL( iFs, EIptvPathRssThumbnail, iServiceId, maskPtr ); + TInt dirLen( mask->Length() ); + maskPtr.Append( KIptvAllFiles ); + + if ( iFs.GetDir( maskPtr, + KEntryAttNormal, + ESortNone, + iconList ) == KErrNone ) + { + CleanupStack::PushL( iconList ); + + for ( TInt i = 0; i < iconList->Count(); i++ ) + { + TInt len( ( *iconList )[i].iName.Length() ); + HBufC* icon = HBufC::NewLC( dirLen + len ); + TPtr16 iconPtr = icon->Des(); + iconPtr.Copy( maskPtr.Mid( 0, dirLen ) ); + iconPtr.Append( ( *iconList )[i].iName.Mid( 0, len ) ); + iIconList.AppendL( icon ); + + CleanupStack::Pop( icon ); + } + + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::ListCurrentIconsL found: %d", + iIconList.Count() ); + + CleanupStack::PopAndDestroy( iconList ); + } + + CleanupStack::PopAndDestroy( mask ); + } + +// -------------------------------------------------------------------------- +// Remove icons stored to list. These icons are either from remove items or +// all icons are decided to be removed. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::RemoveObsoleteIconsL() + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RemoveObsoleteIconsL Count : %d", + iIconList.Count() ); + + HBufC* iconPath( NULL ); + + // Fetch thumbnail of last watched clip, when any. + CIptvLastWatchedApi* lastWatchedApi = CIptvLastWatchedApi::NewL(); + CleanupStack::PushL( lastWatchedApi ); + + CIptvLastWatchedData* lwData = CIptvLastWatchedData::NewL(); + if ( lwData ) + { + CleanupStack::PushL( lwData ); + TInt err( KErrNone ); + TRAPD( leaveErr, err = lastWatchedApi->GetLastWatchedDataL( *lwData ) ); + + if ( KErrNone == leaveErr && KErrNone == err ) + { + // Fetch thumbnail, no need to put it to cleanup stack. + iconPath = HBufC::NewL( lwData->IconPath().Length() ); + iconPath->Des().Copy( lwData->IconPath() ); + } + CleanupStack::PopAndDestroy( lwData ); + } + CleanupStack::PopAndDestroy( lastWatchedApi ); + + for ( TInt icon = 0; icon < iIconList.Count(); icon++ ) + { + TBool wasLastWatched( EFalse ); + + // Check whether thumbnail belongs to last watched clip. + if ( iconPath ) + { + if ( 0 == iIconList[icon]->Des().CompareF( *iconPath ) ) + { + wasLastWatched = ETrue; + } + } + +#ifdef _DEBUG + + // Debug print filename. + TBuf debugFileName; + debugFileName.Copy( iIconList[icon]->Des() ); + if ( wasLastWatched ) + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RemoveObsoleteIconsL Thumbnail of last watched clip saved: %S", + &debugFileName ); + } + else + { + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RemoveObsoleteIconsL Thumbnail deleted: %S", + &debugFileName ); + } + +#endif + + if ( !wasLastWatched ) + { + // Delete list thumbnail. + iFs.Delete( iIconList[icon]->Des() ); + } + } + + if ( iconPath ) + { + delete iconPath; + iconPath = NULL; + } + + // Remove all icons from list. + iIconList.ResetAndDestroy(); + } + +// -------------------------------------------------------------------------- +// Find thumbnail from list and delete it when found. +// -------------------------------------------------------------------------- +// +void CIptvRssPlugin::RemoveIconFromList( + const HBufC* aIconName, + TBool aDelete ) + { + IPTVLOGSTRING_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RemoveIconFromList" ); + + if ( aIconName && ( EIptvRssService == iAction ) ) + { + TInt icon( -1 ); + + // Find icon from list. + for ( TInt i = 0; ( i < iIconList.Count() ) && ( -1 == icon ); i++ ) + { + if ( 0 == iIconList[i]->Des().CompareF( *aIconName ) ) + { + icon = i; + } + } + + // When found, remove it. + if ( icon >= 0 ) + { + if ( aDelete ) + { + +#ifdef _DEBUG + + // Debug print filename. + TBuf debugFileName; + debugFileName.Copy( iIconList[icon]->Des() ); + IPTVLOGSTRING2_LOW_LEVEL( + "RSS Plugin --- CIptvRssPlugin::RemoveIconFromList --- Thumbnail deleted: %S", + &debugFileName ); + +#endif + + // Delete list thumbnail. + iFs.Delete( iIconList[icon]->Des() ); + } + + // Remove thumbnail from list. + delete iIconList[icon]; + iIconList.Remove( icon ); + } + } + }