engine/src/ShowEngine.cpp
changeset 2 29cda98b007e
child 6 e211a78d3037
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/engine/src/ShowEngine.cpp	Thu Feb 25 14:29:19 2010 +0000
@@ -0,0 +1,1263 @@
+/*
+* Copyright (c) 2007-2010 Sebastian Brannstrom, Lars Persson, EmbedDev AB
+*
+* 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:
+* EmbedDev AB - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include "ShowEngine.h"
+#include "FeedEngine.h"
+#include "FeedInfo.h"
+#include <bautils.h>
+#include <s32file.h>
+#include "SettingsEngine.h"
+#include <e32hashtab.h>
+#include <httperr.h>
+#include "SoundEngine.h"
+#include "debug.h"
+#include "PodcastUtils.h"
+
+//#include <mpxmedia.h>
+//#include <mpxattribute.h>
+//#include <mpxmediageneraldefs.h>
+
+const TUint KMaxDownloadErrors = 3;
+const TInt KMimeBufLength = 100;
+
+// Cleanup stack macro for SQLite3
+// TODO Move this to some common place.
+static void Cleanup_sqlite3_finalize_wrapper(TAny* handle)
+	{
+	sqlite3_finalize(static_cast<sqlite3_stmt*>(handle));
+	}
+#define Cleanup_sqlite3_finalize_PushL(__handle) CleanupStack::PushL(TCleanupItem(&Cleanup_sqlite3_finalize_wrapper, __handle))
+
+
+CShowEngine::CShowEngine(CPodcastModel& aPodcastModel) :
+	iPodcastModel(aPodcastModel),
+	iDB(*aPodcastModel.DB())
+	{
+	}
+
+EXPORT_C CShowEngine::~CShowEngine()
+	{	
+	delete iShowClient;
+	iObservers.Close();
+	delete iShowDownloading;
+	delete iMetaDataReader;
+	iApaSession.Close();
+	}
+
+EXPORT_C CShowEngine* CShowEngine::NewL(CPodcastModel& aPodcastModel)
+	{
+	CShowEngine* self = new (ELeave) CShowEngine(aPodcastModel);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+EXPORT_C void CShowEngine::GetMimeType(const TDesC& aFileName, TDes& aMimeType)
+	{
+	aMimeType.Zero();
+	RFile file;
+	if (file.Open(iPodcastModel.FsSession(), aFileName, 0) == KErrNone)
+		{
+		if (file.Read(iRecogBuffer) == KErrNone)
+			{
+			TDataRecognitionResult result;
+			if (iApaSession.RecognizeData(aFileName, iRecogBuffer, result)
+					== KErrNone)
+				{
+				aMimeType.Copy(result.iDataType.Des());
+				}
+
+			}
+		}
+	file.Close();
+	}
+
+void CShowEngine::ConstructL()
+	{	
+	iShowClient = CHttpClient::NewL(iPodcastModel, *this);
+	iShowClient->SetResumeEnabled(ETrue);
+	iMetaDataReader = new (ELeave) CMetaDataReader(*this, iPodcastModel.FsSession());
+	iMetaDataReader->ConstructL();
+	User::LeaveIfError(iApaSession.Connect());
+	}
+
+EXPORT_C void CShowEngine::SuspendDownloads()
+	{
+	iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+	iShowClient->Stop();
+	}
+
+EXPORT_C void CShowEngine::ResumeDownloadsL()
+	{
+	DP("CShowEngine::ResumeDownloadsL BEGIN");
+	if (iPodcastModel.SettingsEngine().DownloadSuspended())
+		{
+		iPodcastModel.SettingsEngine().SetDownloadSuspended(EFalse);
+		iDownloadErrors = 0;
+		DownloadNextShowL();
+		}
+	DP("CShowEngine::ResumeDownloadsL END");
+	}
+
+EXPORT_C void CShowEngine::RemoveAllDownloads()
+	{
+	if (!iPodcastModel.SettingsEngine().DownloadSuspended())
+		{
+		SuspendDownloads();
+		}
+
+	DBRemoveAllDownloads();
+	}
+
+EXPORT_C TBool CShowEngine::RemoveDownloadL(TUint aUid)
+	{
+	DP("CShowEngine::RemoveDownload\t Trying to remove download");
+
+	TBool retVal = EFalse;
+	TBool resumeAfterRemove = EFalse;
+	// if trying to remove the present download, we first stop it
+	if (!iPodcastModel.SettingsEngine().DownloadSuspended() && iShowDownloading != NULL
+			&& iShowDownloading->Uid() == aUid)
+		{
+		DP("CShowEngine::RemoveDownload\t This is the active download, we suspend downloading");
+		SuspendDownloads();
+		resumeAfterRemove = ETrue;
+		}
+
+	CShowInfo *info = DBGetShowByUidL(aUid);
+	if (info != NULL)
+		{
+		info->SetDownloadState(ENotDownloaded);
+		DBUpdateShow(*info);
+		delete info;
+		}
+	DBRemoveDownload(aUid);
+
+	// partial downloads should be removed
+	if (iShowDownloading)
+		{
+		BaflUtils::DeleteFile(iPodcastModel.FsSession(), iShowDownloading->FileName());
+		}
+
+	NotifyShowDownloadUpdatedL(-1, -1);
+	NotifyDownloadQueueUpdatedL();
+	
+	if (resumeAfterRemove) {
+		ResumeDownloadsL();
+	}
+	
+	DownloadNextShowL();
+	retVal = ETrue;
+
+	return retVal;
+	}
+
+void CShowEngine::Connected(CHttpClient* /*aClient*/)
+	{
+
+	}
+
+void CShowEngine::Progress(CHttpClient* /*aHttpClient */, TInt aBytes,
+		TInt aTotalBytes)
+	{	
+	iShowDownloading->SetShowSize(aTotalBytes);
+	TRAP_IGNORE(NotifyShowDownloadUpdatedL(aBytes, aTotalBytes));
+	}
+
+void CShowEngine::Disconnected(CHttpClient* /*aClient */)
+	{
+	}
+
+void CShowEngine::DownloadInfo(CHttpClient* aHttpClient, TInt aTotalBytes)
+	{
+	DP1("About to download %d bytes", aTotalBytes);
+	if (aHttpClient == iShowClient && iShowDownloading != NULL
+			&& aTotalBytes != -1)
+		{
+		iShowDownloading->SetShowSize(aTotalBytes);
+		}
+	}
+
+TBool CShowEngine::GetShowL(CShowInfo *info)
+	{
+	CFeedInfo *feedInfo = iPodcastModel.FeedEngine().GetFeedInfoByUid(
+			info->FeedUid());
+	if (feedInfo == NULL)
+		{
+		DP("Feed not found for this show!");
+		return EFalse;
+		}
+
+	TFileName filePath;
+	filePath.Copy(iPodcastModel.SettingsEngine().BaseDir());
+	
+	TFileName relPath;
+	relPath.Copy(feedInfo->Title());
+	relPath.Append('\\');
+
+	TFileName fileName;
+	PodcastUtils::FileNameFromUrl(info->Url(), fileName);
+	relPath.Append(fileName);
+	PodcastUtils::EnsureProperPathName(relPath);
+
+	// complete file path is base dir + rel path
+	filePath.Append(relPath);
+	info->SetFileNameL(filePath);
+
+	return iShowClient->GetL(info->Url(), filePath);
+	}
+
+EXPORT_C TBool CShowEngine::AddShowL(const CShowInfo& aItem)
+	{
+	DP1("CShowEngine::AddShowL, title=%S", &aItem.Title());
+	CShowInfo *showInfo = DBGetShowByUidL(aItem.Uid());
+
+	if (showInfo == NULL)
+		{
+		DBAddShow(aItem);
+		return ETrue;
+		}
+	else
+		{
+		delete showInfo;	
+		return EFalse;
+		}	
+	}
+
+EXPORT_C void CShowEngine::AddObserver(MShowEngineObserver *observer)
+	{
+	iObservers.Append(observer);
+	}
+
+EXPORT_C void CShowEngine::RemoveObserver(MShowEngineObserver *observer)
+	{
+	TInt index = iObservers.Find(observer);
+
+	if (index > KErrNotFound)
+		{
+		iObservers.Remove(index);
+		}
+	}
+
+void CShowEngine::AddShowToMpxCollection(CShowInfo &/*aShowInfo*/)
+	{
+/*	RArray<TInt> contentIDs;
+	contentIDs.AppendL( KMPXMediaIdGeneral );
+	
+	CMPXMedia* media = CMPXMedia::NewL( contentIDs.Array() );
+	CleanupStack::PushL( media );
+	contentIDs.Close();
+	CleanupStack::PopAndDestroy(media);   */
+	}
+
+void CShowEngine::CompleteL(CHttpClient* /*aHttpClient*/, TInt aError)
+	{
+	if (iShowDownloading != NULL)
+		{
+		DP1("CShowEngine::Complete\tDownload of file: %S is complete", &iShowDownloading->FileName());		
+		// decide what kind of file this is		
+		if(aError != KErrCouldNotConnect)
+			{
+			if(aError == KErrDisconnected && !iPodcastModel.SettingsEngine().DownloadSuspended()) {
+				// no error if disconnect happened because of suspended downloading
+				iShowDownloading->SetLastError(aError);
+			}
+
+			if (aError == KErrNone)
+				{
+				TBuf<KMimeBufLength> mimeType;
+				GetMimeType(iShowDownloading->FileName(), mimeType);
+				_LIT(KMimeAudio,"audio");
+				_LIT(KMimeVideo,"video");
+				if (mimeType.Left(5) == KMimeAudio)
+					{
+					iShowDownloading->SetShowType(EAudioPodcast);
+					}
+				else if (mimeType.Left(5) == KMimeVideo)
+					{
+					iShowDownloading->SetShowType(EVideoPodcast);
+					}
+
+				iShowDownloading->SetDownloadState(EDownloaded);
+				DBUpdateShow(*iShowDownloading);
+				DBRemoveDownload(iShowDownloading->Uid());
+				AddShowToMpxCollection(*iShowDownloading);				
+				NotifyShowFinishedL(aError);
+
+				delete iShowDownloading;
+				iShowDownloading = NULL;
+				}
+			else
+				{
+				// 400 and 500 series errors are serious errors on which probably another download will fail
+				if(aError >= HTTPStatus::EBadRequest && aError <= HTTPStatus::EBadRequest+200)
+					{
+					iShowDownloading->SetDownloadState(EFailedDownload);
+					DBUpdateShow(*iShowDownloading);
+					DBRemoveDownload(iShowDownloading->Uid());
+					NotifyShowFinishedL(aError);
+
+					delete iShowDownloading;
+					iShowDownloading = NULL;
+					}
+				else // other kind of error, missing network etc, reque this show
+					{
+					iShowDownloading->SetDownloadState(EQueued);
+					DBUpdateShow(*iShowDownloading);
+					}
+
+				iDownloadErrors++;
+				if (iDownloadErrors > KMaxDownloadErrors)
+					{
+					DP("Too many downloading errors, suspending downloads");
+					iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+					NotifyShowFinishedL(aError);
+					}
+				}
+			DownloadNextShowL();
+			}		
+
+		else
+			{
+			// Connection error
+			if(iShowDownloading)
+				{
+				iShowDownloading->SetDownloadState(EQueued);
+				DBUpdateShow(*iShowDownloading);
+				}
+			iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+			NotifyShowFinishedL(aError);
+			}
+		}
+	}
+
+EXPORT_C CShowInfo* CShowEngine::ShowDownloading()
+	{
+	return iShowDownloading;
+	}
+
+EXPORT_C CShowInfo* CShowEngine::GetShowByUidL(TUint aShowUid)
+	{
+	return DBGetShowByUidL(aShowUid);
+	}
+CShowInfo* CShowEngine::DBGetShowByUidL(TUint aUid)
+	{
+	DP("CShowEngine::DBGetShowByUid");
+	CShowInfo *showInfo = NULL;
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype from shows where uid=%u");
+	iSqlBuffer.Format(KSqlStatement, aUid);
+
+	sqlite3_stmt *st;
+
+	//DP1("SQL: %S", &iSqlBuffer.Left(KSqlDPLen));
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		if (rc == SQLITE_ROW)
+			{
+			showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			CleanupStack::Pop(showInfo);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+
+	return showInfo;
+	}
+
+EXPORT_C CShowInfo* CShowEngine::DBGetShowByFileNameL(TFileName aFileName)
+	{
+	DP("CShowEngine::DBGetShowByUid");
+	CShowInfo *showInfo = NULL;
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype from shows where filename=\"%S\"");
+	iSqlBuffer.Format(KSqlStatement, &aFileName);
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		if (rc == SQLITE_ROW)
+			{
+			showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			CleanupStack::Pop(showInfo);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+
+	return showInfo;
+	}
+
+void CShowEngine::DBGetAllShowsL(RShowInfoArray& aShowArray)
+	{
+	DP("CShowEngine::DBGetAllShows");
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype from shows");
+	iSqlBuffer.Format(KSqlStatement);
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		while (rc == SQLITE_ROW)
+			{
+			CShowInfo* showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			aShowArray.Append(showInfo);
+			CleanupStack::Pop(showInfo);
+			rc = sqlite3_step(st);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+
+	}
+
+void CShowEngine::DBGetAllDownloadsL(RShowInfoArray& aShowArray)
+	{
+	DP("CShowEngine::DBGetAllDownloads");
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, shows.uid, showsize, trackno, pubdate, showtype, lasterror from downloads, shows where downloads.uid=shows.uid");
+	iSqlBuffer.Format(KSqlStatement);
+
+#ifndef DONT_SORT_SQL
+	_LIT(KSqlSort, " order by dl_index");
+	iSqlBuffer.Append(KSqlSort);
+#endif
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		while (rc == SQLITE_ROW)
+			{
+			CShowInfo* showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			aShowArray.Append(showInfo);
+			CleanupStack::Pop(showInfo);
+			rc = sqlite3_step(st);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+
+	// delete downloads that don't have a show
+	
+	_LIT(KSqlStatement2, "delete from downloads where uid not in (select downloads.uid from shows, downloads where shows.uid=downloads.uid)");
+	iSqlBuffer.Format(KSqlStatement2);
+
+	rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,	&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+	}
+
+CShowInfo* CShowEngine::DBGetNextDownloadL()
+	{
+	DP("CShowEngine::DBGetNextDownload");
+	CShowInfo *showInfo = NULL;
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, shows.uid, showsize, trackno, pubdate, showtype, lasterror from downloads, shows where downloads.uid=shows.uid");
+	iSqlBuffer.Format(KSqlStatement);
+
+#ifdef DONT_SORT_SQL
+	_LIT(KSqlSort, " limit 1");
+	iSqlBuffer.Append(KSqlSort);
+#else
+	_LIT(KSqlNoSort, " order by dl_index limit 1");
+	iSqlBuffer.Append(KSqlNoSort);
+#endif
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		if (rc == SQLITE_ROW)
+			{
+			showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			CleanupStack::Pop(showInfo);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+
+	return showInfo;
+	}
+
+void CShowEngine::DBGetShowsByFeedL(RShowInfoArray& aShowArray, TUint aFeedUid)
+	{
+	DP1("CShowEngine::DBGetShowsByFeed BEGIN, feedUid=%u", aFeedUid);
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype, lasterror from shows where feeduid=%u");
+	iSqlBuffer.Format(KSqlStatement, aFeedUid);
+
+#ifndef DONT_SORT_SQL	
+	_LIT(KSqlOrderByDate, " order by pubdate desc");
+	iSqlBuffer.Append(KSqlOrderByDate);
+#endif
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		while (rc == SQLITE_ROW)
+			{
+			CShowInfo* showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			aShowArray.Append(showInfo);
+			CleanupStack::Pop(showInfo);
+			rc = sqlite3_step(st);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+	DP("CShowEngine::DBGetShowsByFeed END");
+	}
+
+TUint CShowEngine::DBGetDownloadsCount()
+	{
+	DP("CShowEngine::DBGetDownloadsCount");
+
+	_LIT(KSqlStatement, "select count(*) from downloads");
+	iSqlBuffer.Format(KSqlStatement);
+
+	sqlite3_stmt *st;
+	TUint count = 0;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+
+		if (rc == SQLITE_ROW)
+			{
+			count = sqlite3_column_int(st, 0);
+			}
+		sqlite3_finalize(st);
+		}
+	return count;
+	}
+
+void CShowEngine::DBGetDownloadedShowsL(RShowInfoArray& aShowArray)
+	{
+	DP("CShowEngine::DBGetDownloadedShows");
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype, lasterror from shows where downloadstate=%u");
+	iSqlBuffer.Format(KSqlStatement, EDownloaded);
+
+#ifndef DONT_SORT_SQL
+	_LIT(KSqlSort, " order by title");
+	iSqlBuffer.Append(KSqlSort);
+#endif	
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		while (rc == SQLITE_ROW)
+			{
+			CShowInfo* showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			aShowArray.Append(showInfo);
+			CleanupStack::Pop(showInfo);
+			rc = sqlite3_step(st);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+	}
+
+void CShowEngine::DBGetNewShowsL(RShowInfoArray& aShowArray)
+	{
+	DP("CShowEngine::DBGetNewShows");
+	_LIT(KSqlStatement, "select url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype, lasterror from shows where playstate=%u");
+	iSqlBuffer.Format(KSqlStatement, ENeverPlayed);
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		Cleanup_sqlite3_finalize_PushL(st);
+		while (rc == SQLITE_ROW)
+			{
+			CShowInfo* showInfo = CShowInfo::NewLC();
+			DBFillShowInfoFromStmtL(st, showInfo);
+			aShowArray.Append(showInfo);
+			CleanupStack::Pop(showInfo);
+			rc = sqlite3_step(st);
+			}
+		CleanupStack::PopAndDestroy();//st
+		}
+	}
+
+void CShowEngine::DBDeleteOldShowsByFeed(TUint aFeedUid)
+	{
+	DP("CShowEngine::DBDeleteOldShows");
+	
+	// what we do:
+	// 1. sort shows by pubdate
+	// 2. select the first MaxListItems shows
+	// 3. delete the rest if downloadstate is ENotDownloaded
+	
+	_LIT(KSqlStatement,"delete from shows where feeduid=%u and downloadstate=0 and uid not in " \
+			"(select uid from shows where feeduid=%u order by pubdate desc limit %u)");
+	iSqlBuffer.Format(KSqlStatement, aFeedUid, aFeedUid, iPodcastModel.SettingsEngine().MaxListItems());
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+	
+	_LIT(KSqlStatement2, "delete from downloads where uid not in (select downloads.uid from shows, downloads where shows.uid=downloads.uid)");
+	iSqlBuffer.Format(KSqlStatement2);
+
+	rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,	&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+	}
+
+void CShowEngine::DBFillShowInfoFromStmtL(sqlite3_stmt *st, CShowInfo* showInfo)
+	{
+	const void *urlz = sqlite3_column_text16(st, 0);
+	TPtrC16 url((const TUint16*) urlz);
+	showInfo->SetUrlL(url);
+
+	const void *titlez = sqlite3_column_text16(st, 1);
+	TPtrC16 title((const TUint16*) titlez);
+	showInfo->SetTitleL(title);
+
+	const void *descz = sqlite3_column_text16(st, 2);
+	TPtrC16 desc((const TUint16*) descz);
+	showInfo->SetDescriptionL(desc);
+
+	const void *filez = sqlite3_column_text16(st, 3);
+	TPtrC16 file((const TUint16*) filez);
+	showInfo->SetFileNameL(file);
+
+	sqlite3_int64 pos = sqlite3_column_int64(st, 4);
+	TTimeIntervalMicroSeconds position(pos);
+	showInfo->SetPosition(position);
+
+	TUint playtime = sqlite3_column_int(st, 5);
+	showInfo->SetPlayTime(playtime);
+
+	TUint playstate = sqlite3_column_int(st, 6);
+	showInfo->SetPlayState((TPlayState) playstate);
+
+	TUint downloadstate = sqlite3_column_int(st, 7);
+	showInfo->SetDownloadState((TDownloadState) downloadstate);
+
+	TUint feeduid = sqlite3_column_int(st, 8);
+	showInfo->SetFeedUid(feeduid);
+
+	TUint uid = sqlite3_column_int(st, 9);
+	showInfo->SetUid(uid);
+
+	TUint showsize = sqlite3_column_int(st, 10);
+	showInfo->SetShowSize(showsize);
+
+	TUint trackno = sqlite3_column_int(st, 11);
+	showInfo->SetTrackNo((TShowType) trackno);
+
+	sqlite3_int64 pubdate = sqlite3_column_int64(st, 12);
+	TTime timepubdate(pubdate);
+	showInfo->SetPubDate(timepubdate);
+
+	TUint showtype = sqlite3_column_int(st, 13);
+	showInfo->SetShowType((TShowType) showtype);
+	
+	TInt lasterror = sqlite3_column_int(st, 14);
+	showInfo->SetLastError(lasterror);
+	}
+
+TBool CShowEngine::DBAddShow(const CShowInfo& aItem)
+	{
+	DP2("CShowEngine::DBAddShow, title=%S, URL=%S", &aItem.Title(), &aItem.Url());
+
+	_LIT(KSqlStatement, "insert into shows (url, title, description, filename, position, playtime, playstate, downloadstate, feeduid, uid, showsize, trackno, pubdate, showtype)"
+			" values (\"%S\",\"%S\", \"%S\", \"%S\", \"%Lu\", \"%u\", \"%u\", \"%u\", \"%u\", \"%u\", \"%u\", \"%u\", \"%Lu\", \"%d\")");
+	iSqlBuffer.Format(KSqlStatement, &aItem.Url(), &aItem.Title(), &aItem.Description(),
+			&aItem.FileName(), aItem.Position().Int64(), aItem.PlayTime(),
+			aItem.PlayState(), aItem.DownloadState(), aItem.FeedUid(),
+			aItem.Uid(), aItem.ShowSize(), aItem.TrackNo(),
+			aItem.PubDate().Int64(), aItem.ShowType());
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		if (rc == SQLITE_DONE)
+			{
+			sqlite3_finalize(st);
+			return ETrue;
+			}
+		else
+			{
+			sqlite3_finalize(st);
+			}
+		}
+	else
+		{
+		DP1("SQLite rc=%d", rc);
+		}
+
+	return EFalse;
+	}
+
+void CShowEngine::DBAddDownload(TUint aUid)
+	{
+	DP1("CShowEngine::DBAddDownload, aUid=%u", aUid);
+
+	_LIT(KSqlStatement, "insert into downloads (uid) values (%u)");
+	iSqlBuffer.Format(KSqlStatement, aUid);
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		}
+
+	sqlite3_finalize(st);
+	}
+
+TBool CShowEngine::DBUpdateShow(CShowInfo& aItem)
+	{
+	DP1("CShowEngine::DBUpdateShow, title='%S'", &aItem.Title());
+
+	_LIT(KSqlStatement, "update shows set url=\"%S\", title=\"%S\", description=\"%S\", filename=\"%S\", position=\"%Lu\","
+			"playtime=\"%u\", playstate=\"%u\", downloadstate=\"%u\", feeduid=\"%u\", showsize=\"%u\", trackno=\"%u\","
+			"pubdate=\"%Lu\", showtype=\"%d\", lasterror=\"%d\" where uid=\"%u\"");
+	iSqlBuffer.Format(KSqlStatement, &aItem.Url(), &aItem.Title(), &aItem.Description(),
+			&aItem.FileName(), aItem.Position().Int64(), aItem.PlayTime(),
+			aItem.PlayState(), aItem.DownloadState(), aItem.FeedUid(),
+			aItem.ShowSize(), aItem.TrackNo(), aItem.PubDate().Int64(),
+			aItem.ShowType(), aItem.LastError(), aItem.Uid());
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+
+		if (rc == SQLITE_DONE)
+			{
+			sqlite3_finalize(st);
+			return ETrue;
+			}
+		else
+			{
+			sqlite3_finalize(st);
+			}
+		}
+	else
+		{
+		DP1("SQLite rc=%d", rc);
+		}
+
+	return EFalse;
+	}
+
+TBool CShowEngine::DBDeleteShow(TUint aUid)
+	{
+	DP("CShowEngine::DBDeleteShow");
+
+	_LIT(KSqlStatement, "delete from shows where uid=%u");
+	iSqlBuffer.Format(KSqlStatement, aUid);
+
+	sqlite3_stmt *st;
+
+	//DP1("SQL: %S", &iSqlBuffer.Left(KSqlDPLen));
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+
+		if (rc == SQLITE_DONE)
+			{
+			sqlite3_finalize(st);
+			return ETrue;
+			}
+		else
+			{
+			sqlite3_finalize(st);
+			}
+		}
+	else
+		{
+		DP1("SQLite rc=%d", rc);
+		}
+
+	return EFalse;
+	}
+
+TBool CShowEngine::DBDeleteAllShowsByFeed(TUint aFeedUid)
+	{
+	DP("CShowEngine::DBDeleteAllShowsByFeed");
+
+	_LIT(KSqlStatement, "delete from shows where feeduid=%u");
+	iSqlBuffer.Format(KSqlStatement, aFeedUid);
+
+	sqlite3_stmt *st;
+
+	//DP1("SQL: %S", &iSqlBuffer.Left(KSqlDPLen));
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+
+		if (rc == SQLITE_DONE)
+			{
+			sqlite3_finalize(st);
+			return ETrue;
+			}
+		else
+			{
+			sqlite3_finalize(st);
+			}
+		}
+	else
+		{
+		DP1("SQLite rc=%d", rc);
+		}
+
+	return EFalse;
+	}
+
+void CShowEngine::DBRemoveAllDownloads()
+	{
+	DP("CShowEngine::DBRemoveAllDownloads");
+
+	_LIT(KSqlStatement, "delete from downloads");
+	iSqlBuffer.Format(KSqlStatement);
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+
+	_LIT(KSqlStatement2, "update shows set downloadstate=0 where downloadstate=1");
+	iSqlBuffer.Format(KSqlStatement2);
+
+	rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1, &st,
+			(const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+
+	}
+
+void CShowEngine::DBRemoveDownload(TUint aUid)
+	{
+	DP("CShowEngine::DBRemoveDownload");
+
+	_LIT(KSqlStatement, "delete from downloads where uid=%u");
+	iSqlBuffer.Format(KSqlStatement, aUid);
+
+	sqlite3_stmt *st;
+
+	int rc = sqlite3_prepare16_v2(&iDB, (const void*) iSqlBuffer.PtrZ(), -1,
+			&st, (const void**) NULL);
+
+	if (rc == SQLITE_OK)
+		{
+		rc = sqlite3_step(st);
+		sqlite3_finalize(st);
+		}
+	}
+
+EXPORT_C CShowInfo* CShowEngine::GetNextShowByTrackL(CShowInfo* aShowInfo)
+	{
+	CShowInfo* nextShow = NULL;
+	RShowInfoArray array;
+	DBGetShowsByFeedL(array, aShowInfo->FeedUid());
+	TUint diff = KMaxTInt;
+	for (TInt loop = 0; loop < array.Count(); loop++)
+		{
+		if (aShowInfo->TrackNo() < array[loop]->TrackNo())
+			{
+			if ((array[loop]->TrackNo() - aShowInfo->TrackNo()) < diff)
+				{
+				diff = array[loop]->TrackNo() - aShowInfo->TrackNo();
+				nextShow = array[loop];
+				}
+			}
+		}
+	array.ResetAndDestroy();
+	return nextShow;
+	}
+
+TBool CShowEngine::CompareShowsByUid(const CShowInfo &a, const CShowInfo &b)
+	{
+	return a.Uid() == b.Uid();
+	}
+
+TInt CShowEngine::CompareShowsByDate(const CShowInfo &a, const CShowInfo &b)
+	{
+	if (a.PubDate() > b.PubDate())
+		{
+		//		DP2("Sorting %S less than %S", &a.iTitle, &b.iTitle);
+		return -1;
+		}
+	else if (a.PubDate() == b.PubDate())
+		{
+		//		DP2("Sorting %S equal to %S", &a.iTitle, &b.iTitle);
+		return 0;
+		}
+	else
+		{
+		//		DP2("Sorting %S greater than %S", &a.iTitle, &b.iTitle);
+		return 1;
+		}
+	}
+
+TInt CShowEngine::CompareShowsByTrackNo(const CShowInfo &a, const CShowInfo &b)
+	{
+	if (a.TrackNo() < b.TrackNo())
+		{
+		return -1;
+		}
+	else if (a.TrackNo() == b.TrackNo())
+		{
+		return 0;
+		}
+	else
+		{
+		return 1;
+		}
+	}
+
+TInt CShowEngine::CompareShowsByTitle(const CShowInfo &a, const CShowInfo &b)
+	{
+	if (a.Title() < b.Title())
+		{
+		//		DP2("Sorting %S less than %S", &a.iTitle, &b.iTitle);
+		return -1;
+		}
+	else if (a.Title() == b.Title())
+		{
+		//		DP2("Sorting %S equal to %S", &a.iTitle, &b.iTitle);
+		return 0;
+		}
+	else
+		{
+		//		DP2("Sorting %S greater than %S", &a.iTitle, &b.iTitle);
+		return 1;
+		}
+	}
+
+EXPORT_C void CShowEngine::DeletePlayedShows(RShowInfoArray &aShowInfoArray)
+	{
+	for (TInt i = 0; i < aShowInfoArray.Count(); i++)
+		{
+		if (aShowInfoArray[i]->PlayState() == EPlayed
+				&& aShowInfoArray[i]->FileName().Length() > 0)
+			{
+			if (CompareShowsByUid(*(iPodcastModel.PlayingPodcast()), *(aShowInfoArray[i]))
+					&& iPodcastModel.SoundEngine().State() != ESoundEngineNotInitialized)
+				{
+				iPodcastModel.SoundEngine().Stop();
+				}
+			BaflUtils::DeleteFile(iPodcastModel.FsSession(), aShowInfoArray[i]->FileName());
+			aShowInfoArray[i]->SetDownloadState(ENotDownloaded);
+			DBUpdateShow(*aShowInfoArray[i]);
+			}
+		}
+	}
+
+EXPORT_C void CShowEngine::DeleteAllShowsByFeedL(TUint aFeedUid, TBool aDeleteFiles)
+	{
+	RShowInfoArray array;
+	DBGetShowsByFeedL(array, aFeedUid);
+
+	const TInt count = array.Count();
+
+	for (TInt i = count - 1; i >= 0; i--)
+		{
+		if (array[i]->FileName().Length() > 0)
+			{
+			if (aDeleteFiles)
+				{
+				BaflUtils::DeleteFile(iPodcastModel.FsSession(), array[i]->FileName());
+				}
+			}
+		}
+	array.ResetAndDestroy();
+	DBDeleteAllShowsByFeed(aFeedUid);
+	}
+
+EXPORT_C void CShowEngine::DeleteOldShowsByFeed(TUint aFeedUid)
+	{
+		DBDeleteOldShowsByFeed(aFeedUid);
+	}
+
+EXPORT_C void CShowEngine::DeleteShowL(TUint aShowUid, TBool aRemoveFile)
+	{
+
+	CShowInfo *info = DBGetShowByUidL(aShowUid);
+
+	if (info != NULL)
+		{
+		if (info->FileName().Length() > 0 && aRemoveFile)
+			{
+			BaflUtils::DeleteFile(iPodcastModel.FsSession(), info->FileName());
+			}
+		
+		info->SetDownloadState(ENotDownloaded);
+		DBUpdateShow(*info);
+		delete info;
+		}
+	}
+
+EXPORT_C void CShowEngine::GetShowsByFeedL(RShowInfoArray& aShowArray, TUint aFeedUid)
+	{
+	DP("CShowEngine::GetShowsByFeed");
+	DBGetShowsByFeedL(aShowArray, aFeedUid);
+	}
+
+EXPORT_C void CShowEngine::GetAllShowsL(RShowInfoArray &aArray)
+	{
+	DP("CShowEngine::GetAllShows");
+	DBGetAllShowsL(aArray);
+	}
+
+EXPORT_C void CShowEngine::GetShowsDownloadedL(RShowInfoArray &aArray)
+	{
+	DP("CShowEngine::GetShowsDownloaded");
+	DBGetDownloadedShowsL(aArray);
+	}
+
+EXPORT_C void CShowEngine::GetNewShowsL(RShowInfoArray &aArray)
+	{
+	DP("CShowEngine::GetNewShows");
+	DBGetNewShowsL(aArray);
+	}
+
+EXPORT_C void CShowEngine::GetShowsDownloadingL(RShowInfoArray &aArray)
+	{
+	DP("CShowEngine::GetShowsDownloading");
+	DBGetAllDownloadsL(aArray);
+	}
+
+EXPORT_C TInt CShowEngine::GetNumDownloadingShows()
+	{
+	return (const TInt) DBGetDownloadsCount();
+	}
+
+EXPORT_C void CShowEngine::AddDownloadL(CShowInfo& aInfo)
+	{
+	aInfo.SetDownloadState(EQueued);
+	DBUpdateShow(aInfo);
+	DBAddDownload(aInfo.Uid());
+	DownloadNextShowL();
+	}
+
+void CShowEngine::DownloadNextShowL()
+	{
+	DP("CShowEngine::DownloadNextShowL BEGIN");
+	// Check if we have anything in the download queue
+	const TInt count = DBGetDownloadsCount();
+	DP("CShowEngine::DownloadNextShow\tTrying to start new download");DP1("CShowEngine::DownloadNextShow\tShows in download queue %d", count);
+
+	// Inform the observers
+	NotifyDownloadQueueUpdatedL();
+
+	if (count > 0)
+		{
+		if (iPodcastModel.SettingsEngine().DownloadSuspended())
+			{
+			DP("CShowEngine::DownloadNextShow\tDownload process is suspended, ABORTING");
+			return;
+			}
+		else if (iShowClient->IsActive())
+			{
+			DP("CShowEngine::DownloadNextShow\tDownload process is already active.");
+			return;
+			}
+		else
+			{
+
+			// Start the download
+			
+			CShowInfo *info = DBGetNextDownloadL();
+			
+			while(info != NULL)
+				{
+				TBool getOk = EFalse;
+				DP1("CShowEngine::DownloadNextShow\tDownloading: %S", &(info->Title()));
+				info->SetDownloadState(EDownloading);
+				info->SetLastError(KErrNone);
+				DBUpdateShow(*info);
+				iShowDownloading = info;
+				TRAPD(error,getOk = GetShowL(info));
+				if (error != KErrNone || !getOk)
+					{
+					info->SetDownloadState(EFailedDownload);
+					DBRemoveDownload(info->Uid());
+					DBUpdateShow(*info);
+					info = DBGetNextDownloadL();
+					
+					if(info == NULL)
+						{
+						iPodcastModel.SettingsEngine().SetDownloadSuspended(ETrue);
+						iShowDownloading = NULL;
+						}
+					}				
+				else
+					{
+					break;
+					}
+				}
+			}
+		}
+	else
+		{
+		iShowDownloading = NULL;DP("CShowEngine::DownloadNextShow\tNothing to download");
+		}
+	DP("CShowEngine::DownloadNextShowL END");
+	}
+
+void CShowEngine::NotifyDownloadQueueUpdatedL()
+	{
+	const TInt count = iObservers.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		iObservers[i]->DownloadQueueUpdatedL(1, DBGetDownloadsCount() - 1);
+		}
+	}
+
+void CShowEngine::NotifyShowDownloadUpdatedL(TInt aBytesOfCurrentDownload, TInt aBytesTotal)
+	{
+	const TInt count = iObservers.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+			iObservers[i]->ShowDownloadUpdatedL(aBytesOfCurrentDownload, aBytesTotal);
+		}
+	}
+
+void CShowEngine::NotifyShowFinishedL(TInt aError)
+	{
+	const TInt count = iObservers.Count();
+		for (TInt i = 0; i < count; i++)
+			{
+				iObservers[i]->ShowDownloadFinishedL(iShowDownloading?iShowDownloading->Uid():0, aError);
+			}
+	}
+
+EXPORT_C void CShowEngine::NotifyShowListUpdatedL()
+	{
+	for (TInt i = 0; i < iObservers.Count(); i++)
+		{
+		iObservers[i]->ShowListUpdatedL();
+		}
+	}
+
+void CShowEngine::ReadMetaData(CShowInfo& aShowInfo)
+	{
+	//DP1("Read %S", &(aShowInfo->Title()));
+	DBUpdateShow(aShowInfo);
+	}
+
+void CShowEngine::ReadMetaDataCompleteL()
+	{
+	NotifyShowListUpdatedL();
+	MetaDataReader().SetIgnoreTrackNo(EFalse);
+	}
+
+EXPORT_C void CShowEngine::UpdateShow(CShowInfo& aInfo)
+	{
+	DBUpdateShow(aInfo);
+	}
+
+EXPORT_C CMetaDataReader& CShowEngine::MetaDataReader()
+	{
+	return *iMetaDataReader;
+	}
+
+void CShowEngine::FileError(TUint /*aError*/)
+	{
+	//TODO: Error dialog
+	//StopDownloads();
+	iDownloadErrors = KMaxDownloadErrors;
+	}