Significantly improved database robustness
authorteknolog
Sun, 04 Apr 2010 15:54:17 +0100
changeset 109 223f270fa7ff
parent 108 554d9980157f
child 110 403412eb5292
Significantly improved database robustness
application/src/PodcastFeedView.cpp
engine/inc/FeedEngine.h
engine/inc/FeedInfo.h
engine/inc/PodcastModel.h
engine/inc/PodcastUtils.h
engine/src/FeedEngine.cpp
engine/src/FeedInfo.cpp
engine/src/OpmlParser.cpp
engine/src/PodcastModel.cpp
engine/src/ShowEngine.cpp
engine/src/ShowInfo.cpp
group/bld.inf
--- a/application/src/PodcastFeedView.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/application/src/PodcastFeedView.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -204,17 +204,12 @@
 
 	switch(aEventType)
 		{
-		case EEventPenDownOnItem:
-			DP("PEN DOWN");
-			break;
-			
 #ifndef SYMBIAN1_UI
 	case EEventItemClicked:
 #endif
 	case EEventEnterKeyPressed:
 	case EEventItemDoubleClicked:
 	case EEventItemActioned:
-		DP("DOUBLE TAP");
 			{
 			const RFeedInfoArray* sortedItems = NULL;
 			TInt index = iListContainer->Listbox()->CurrentItemIndex();
@@ -334,7 +329,8 @@
 		}
 	else
 		{
-		iPodcastModel.FeedEngine().GetStatsByFeed(aFeedInfo.Uid(), showCount, unplayedCount);	
+		// we will get a leave if there are no shows for this feed, for instance, which is fine
+		TRAP_IGNORE(iPodcastModel.FeedEngine().GetStatsByFeedL(aFeedInfo.Uid(), showCount, unplayedCount));	
 		
 		if (unplayedCount) {
 			unplayedShows.Format(*iFeedsFormat, unplayedCount);
@@ -370,7 +366,7 @@
 		}
 	CArrayPtr<CGulIcon>* icons = iListContainer->Listbox()->ItemDrawer()->FormattedCellData()->IconArray();
 	iconIndex = iFeedIdForIconArray.Find(aFeedInfo.Uid());
-	if(iconIndex == KErrNotFound && aFeedInfo.FeedIcon() != NULL && 
+	if(iconIndex == KErrNotFound && aFeedInfo.FeedIcon() != NULL && aFeedInfo.ImageFileName().Length() > 0 && 
 			aFeedInfo.FeedIcon()->SizeInPixels().iHeight > 0 &&
 			aFeedInfo.FeedIcon()->SizeInPixels().iWidth > 0)
 		{
--- a/engine/inc/FeedEngine.h	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/inc/FeedEngine.h	Sun Apr 04 15:54:17 2010 +0100
@@ -70,8 +70,7 @@
 	IMPORT_C void CancelUpdateAllFeeds();
 	IMPORT_C const RFeedInfoArray& GetSortedFeeds();
 	IMPORT_C CFeedInfo* GetFeedInfoByUid(TUint aFeedUid);	
-	IMPORT_C void GetStatsByFeed(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed);
-	IMPORT_C void GetDownloadedStats(TUint &aNumShows, TUint &aNumUnplayed);
+	IMPORT_C void GetStatsByFeedL(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed);
 
 	IMPORT_C void AddObserver(MFeedEngineObserver *observer);
 	IMPORT_C void RemoveObserver(MFeedEngineObserver *observer);
@@ -123,12 +122,12 @@
 	
 private:
 	void DBLoadFeedsL();
-	TBool DBRemoveFeed(TUint aUid);
-	TBool DBAddFeedL(const CFeedInfo& aTtem);
+	void DBRemoveFeedL(TUint aUid);
+	void DBAddFeedL(const CFeedInfo& aTtem);
 	CFeedInfo* DBGetFeedInfoByUidL(TUint aFeedUid);	
-	TUint DBGetFeedCount();
-	TBool DBUpdateFeedL(const CFeedInfo& aItem);
-	void DBGetStatsByFeed(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed);
+	TUint DBGetFeedCountL();
+	void DBUpdateFeedL(const CFeedInfo& aItem);
+	void DBGetStatsByFeedL(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed);
 
 		
 private:
--- a/engine/inc/FeedInfo.h	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/inc/FeedInfo.h	Sun Apr 04 15:54:17 2010 +0100
@@ -71,8 +71,6 @@
 		IMPORT_C CFbsBitmap* FeedIcon() const;
 		IMPORT_C void SetFeedIcon(CFbsBitmap* aBitmapToClone);
 		
-	//	IMPORT_C TInt FeedIconIndex() const;
-//		IMPORT_C void SetFeedIconIndex(TInt aIndex);
 	private:
 		CFeedInfo();
 		void ConstructL();
--- a/engine/inc/PodcastModel.h	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/inc/PodcastModel.h	Sun Apr 04 15:54:17 2010 +0100
@@ -85,6 +85,7 @@
 	TInt GetIapId();
 	
 	sqlite3* DB();
+	void ResetDB();
 	
 	IMPORT_C void GetAllShowsL();
 	IMPORT_C void GetNewShowsL();
@@ -99,6 +100,8 @@
 protected:
 	CPodcastModel();
 	void ConstructL();
+	
+	void OpenDBL();
 	// From ImageHandler
 	void ImageOperationCompleteL(TInt aError, TUint aHandle, CPodcastModel& aPodcastModel);
 private:	
--- a/engine/inc/PodcastUtils.h	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/inc/PodcastUtils.h	Sun Apr 04 15:54:17 2010 +0100
@@ -20,6 +20,14 @@
 #define PODCASTUTILS_H_
 
 #include <e32cmn.h>
+#include "sqlite3.h"
+// Cleanup stack macro for SQLite3
+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))
+
 
 _LIT(KURLPrefix, "http://");
 _LIT(KItpcPrefix, "itpc://");
--- a/engine/src/FeedEngine.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/FeedEngine.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -28,14 +28,6 @@
 #include <utf.h>
 
 _LIT(KFeedParseStorePath, "feeds\\");
-// 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))
-
 
 CFeedEngine* CFeedEngine::NewL(CPodcastModel& aPodcastModel)
 	{
@@ -53,36 +45,41 @@
 	iFeedClient = CHttpClient::NewL(iPodcastModel, *this);
 	iFeedTimer.ConstructL();
 	
-	RunFeedTimer();
+	TInt err = KErrNone;
+	TInt feedCount = 0;
 	
-    if (DBGetFeedCount() > 0) 
+	TRAP(err, feedCount = DBGetFeedCountL());
+    if (err == KErrNone && feedCount > 0)
     	{
 		DP("Loading feeds from DB");
-		DBLoadFeedsL();
-		} 
+		TRAP(err, DBLoadFeedsL());
+    	}		
+
     
-	if (iPodcastModel.IsFirstStartup()) {
+	if (err != KErrNone || iPodcastModel.IsFirstStartup()) {
 		TFileName defaultFile = iPodcastModel.SettingsEngine().DefaultFeedsFileName();
 		DP1("Loading default feeds from %S", &defaultFile);
 		if (BaflUtils::FileExists(iPodcastModel.FsSession(), defaultFile)) {
 			ImportFeedsL(defaultFile);
 		}
-	} else {
-		// clean out feeds temp directory
-		TFileName feedTempPath;
-		feedTempPath.Copy (iPodcastModel.SettingsEngine().PrivatePath ());
-		feedTempPath.Append(KFeedParseStorePath);
-		feedTempPath.Append(_L("*"));
+	} 
+	
+	// clean out feeds temp directory
+	TFileName feedTempPath;
+	feedTempPath.Copy (iPodcastModel.SettingsEngine().PrivatePath ());
+	feedTempPath.Append(KFeedParseStorePath);
+	feedTempPath.Append(_L("*"));
 
-		BaflUtils::EnsurePathExistsL(iPodcastModel.FsSession(), feedTempPath);
-		BaflUtils::DeleteFile(iPodcastModel.FsSession(),feedTempPath);
-	}
+	BaflUtils::EnsurePathExistsL(iPodcastModel.FsSession(), feedTempPath);
+	BaflUtils::DeleteFile(iPodcastModel.FsSession(),feedTempPath);
     
     TFileName importFile = iPodcastModel.SettingsEngine().ImportFeedsFileName();
     if (BaflUtils::FileExists(iPodcastModel.FsSession(), importFile)) {
     	DP("Importing feeds");
-    	ImportFeedsL(importFile);
+    	TRAP_IGNORE(ImportFeedsL(importFile));
 		}
+    
+	RunFeedTimer();
 	}
 
 CFeedEngine::CFeedEngine(CPodcastModel& aPodcastModel)
@@ -340,15 +337,17 @@
 	return ETrue;
 	}
 
-TBool CFeedEngine::DBAddFeedL(const CFeedInfo& aItem)
+void CFeedEngine::DBAddFeedL(const CFeedInfo& aItem)
 	{
 	DP2("CFeedEngine::DBAddFeed, title=%S, URL=%S", &aItem.Title(), &aItem.Url());
 	
-	CFeedInfo *info = DBGetFeedInfoByUidL(aItem.Uid());
-	if (info) {
-		DP("Feed already exists!");
+	CFeedInfo *info;
+	
+	TRAPD(err, DBGetFeedInfoByUidL(aItem.Uid()));
+	
+	if (err == KErrNone && info) {
 		delete info;
-		return EFalse;
+		User::Leave(KErrAlreadyExists);
 	}
 
 	HBufC* titleBuf = HBufC::NewLC(KMaxLineLength);
@@ -372,24 +371,23 @@
 	
 	sqlite3_stmt *st;
 	 
-	//DP1("SQL statement length=%d", iSqlBuffer.Length());
 	int rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st, (const void**) NULL);
 	
 	if (rc==SQLITE_OK)
 		{
+		Cleanup_sqlite3_finalize_PushL(st);
 		rc = sqlite3_step(st);
 
-		if (rc == SQLITE_DONE)
+		if (rc != SQLITE_DONE)
 			{
-			sqlite3_finalize(st);
-			return ETrue;
+			User::Leave(KErrCorrupt);
 			}
-		else {
-			sqlite3_finalize(st);
+		CleanupStack::PopAndDestroy(); // st
 		}
-	}
-
-	return EFalse;
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
 	}
 
 EXPORT_C void CFeedEngine::RemoveFeedL(TUint aUid) 
@@ -427,15 +425,13 @@
 			DP("Removed feed from array");
 			
 			// now remove it from DB
-			DBRemoveFeed(aUid);
-
-			return;
+			DBRemoveFeedL(aUid);
 		}
 	}
 }
 
 
-TBool CFeedEngine::DBRemoveFeed(TUint aUid)
+void CFeedEngine::DBRemoveFeedL(TUint aUid)
 	{
 	DP("CFeedEngine::DBRemoveFeed");
 	_LIT(KSqlStatement, "delete from feeds where uid=%u");
@@ -447,23 +443,23 @@
 	
 	if (rc==SQLITE_OK)
 		{
+		Cleanup_sqlite3_finalize_PushL(st);
 		rc = sqlite3_step(st);
-		sqlite3_finalize(st);
 
-		if (rc == SQLITE_DONE)
+		if (rc != SQLITE_DONE)
 			{
-			DP("Feed removed from DB");
-			return ETrue;
+			User::Leave(KErrNotFound);
 			}
-		else
-			{
-			DP("Error when removing feed from DB");
-			}
+		
+		CleanupStack::PopAndDestroy(); //st
 		}
-	return EFalse;	
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
 	}
 
-TBool CFeedEngine::DBUpdateFeedL(const CFeedInfo &aItem)
+void CFeedEngine::DBUpdateFeedL(const CFeedInfo &aItem)
 	{
 	DP2("CFeedEngine::DBUpdateFeed, title=%S, URL=%S", &aItem.Title(), &aItem.Url());
 	
@@ -488,25 +484,23 @@
 	
 	sqlite3_stmt *st;
 	 
-	//DP1("SQL statement length=%d", iSqlBuffer.Length());
 	int rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st, (const void**) NULL);
 	
 	if (rc==SQLITE_OK)
 		{
+		Cleanup_sqlite3_finalize_PushL(st);
 		rc = sqlite3_step(st);
-		sqlite3_finalize(st);
 		
-		if (rc == SQLITE_DONE)
+		if (rc != SQLITE_DONE)
 			{
-			return ETrue;
+			User::Leave(KErrNotFound);
 			}
+		CleanupStack::PopAndDestroy(); //st
 		}
 	else
 		{
-		DP1("SQLite rc=%d", rc);
+		User::Leave(KErrCorrupt);
 		}
-
-	return EFalse;
 	}
 
 void CFeedEngine::ParsingCompleteL(CFeedInfo *item)
@@ -627,11 +621,9 @@
 			iClientState = EIdle;
 			if(aError == KErrNone)
 				{
-				if( BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), iActiveFeed->ImageFileName() ))
-					{
-						// If this fails, no reason to worry
-					TRAP_IGNORE(iPodcastModel.ImageHandler().LoadFileAndScaleL(iActiveFeed->FeedIcon(), iActiveFeed->ImageFileName(), TSize(64,56), *iActiveFeed, iActiveFeed->Uid()));
-					}				
+				// now the image has been downloaded, so we set it again in the FeedInfo to start
+				// converting it
+				TRAP_IGNORE(iActiveFeed->SetImageFileNameL(iActiveFeed->ImageFileName(), &iPodcastModel));
 				}
 			DBUpdateFeedL(*iActiveFeed);
 			NotifyFeedUpdateComplete(iActiveFeed->Uid(), aError);
@@ -808,49 +800,13 @@
 		return a.Title().CompareF(b.Title());
 	}
 
-EXPORT_C void CFeedEngine::GetDownloadedStats(TUint &aNumShows, TUint &aNumUnplayed)
+EXPORT_C void CFeedEngine::GetStatsByFeedL(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed)
 	{
-	DP("CFeedEngine::GetDownloadedStats");
-	_LIT(KSqlStatement, "select count(*) from shows where downloadstate=%u");
-	iSqlBuffer.Format(KSqlStatement, EDownloaded);
-
-	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_ROW) {
-	  		aNumShows = sqlite3_column_int(st, 0);
-	  	}
-	}
-		  
-	sqlite3_finalize(st);
-
-	_LIT(KSqlStatement2, "select count(*) from shows where downloadstate=%u and playstate=%u");
-	iSqlBuffer.Format(KSqlStatement2, EDownloaded, ENeverPlayed);
-
-	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) {
-	  		aNumUnplayed = sqlite3_column_int(st, 0);
-	  	}
-	}
-		  
-	sqlite3_finalize(st);
+	//DP1("CFeedEngine::GetStatsByFeed, aFeedUid=%u", aFeedUid);
+	DBGetStatsByFeedL(aFeedUid, aNumShows, aNumUnplayed);
 	}
 
-EXPORT_C void CFeedEngine::GetStatsByFeed(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed)
-	{
-	//DP1("CFeedEngine::GetStatsByFeed, aFeedUid=%u", aFeedUid);
-	DBGetStatsByFeed(aFeedUid, aNumShows, aNumUnplayed);
-	}
-
-void CFeedEngine::DBGetStatsByFeed(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed)
+void CFeedEngine::DBGetStatsByFeedL(TUint aFeedUid, TUint &aNumShows, TUint &aNumUnplayed)
 	{
 	//DP1("CFeedEngine::DBGetStatsByFeed, feedUid=%u", aFeedUid);
 	_LIT(KSqlStatement, "select count(*) from shows where feeduid=%u");
@@ -860,50 +816,77 @@
 	 
 	int rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st,	(const void**) NULL);
 	
-	if( rc==SQLITE_OK ){
+	if( rc==SQLITE_OK)
+		{
+		Cleanup_sqlite3_finalize_PushL(st);
 	  	rc = sqlite3_step(st);
 	  	
-	  	if (rc == SQLITE_ROW) {
+	  	if (rc == SQLITE_ROW)
+	  		{
 	  		aNumShows = sqlite3_column_int(st, 0);
-	  	}
-	}
+	  		}
+	  	else
+	  		{
+			User::Leave(KErrNotFound);
+	  		}
+	  	CleanupStack::PopAndDestroy(); // st
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
 		  
-	sqlite3_finalize(st);
-
 	_LIT(KSqlStatement2, "select count(*) from shows where feeduid=%u and playstate=0");
 	iSqlBuffer.Format(KSqlStatement2, aFeedUid);
 
 	rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st,	(const void**) NULL);
 		
-	if( rc==SQLITE_OK ){
+	if(rc==SQLITE_OK)
+		{
+		Cleanup_sqlite3_finalize_PushL(st);
 	  	rc = sqlite3_step(st);
 	  	
-	  	if (rc == SQLITE_ROW) {
+	  	if (rc == SQLITE_ROW)
+	  		{
 	  		aNumUnplayed = sqlite3_column_int(st, 0);
-	  	}
+	  		}
+	  	else
+	  		{
+			User::Leave(KErrNotFound);
+	  		}
+	  	CleanupStack::PopAndDestroy(); // st
 	}
-		  
-	sqlite3_finalize(st);
 }
 
-TUint CFeedEngine::DBGetFeedCount()
+TUint CFeedEngine::DBGetFeedCountL()
 	{
-	 DP("DBGetFeedCount BEGIN");
-	 sqlite3_stmt *st;
-	 int rc = sqlite3_prepare_v2(&iDB,"select count(*) from feeds" , -1, &st, (const char**) NULL);
-	 TUint size = 0;
+	DP("DBGetFeedCount BEGIN");
+	sqlite3_stmt *st;
+	int rc = sqlite3_prepare_v2(&iDB,"select count(*) from feeds" , -1, &st, (const char**) NULL);
+	TUint size = 0;
 	 
-	 if( rc==SQLITE_OK ){
-	  	rc = sqlite3_step(st);
-	  	
-	  	if (rc == SQLITE_ROW) {
+	if( rc==SQLITE_OK )
+		{
+		Cleanup_sqlite3_finalize_PushL(st);
+		rc = sqlite3_step(st);
+			
+		if (rc == SQLITE_ROW)
+			{
 	  		size = sqlite3_column_int(st, 0);
-	  	}
-	  }
-	  
-	  sqlite3_finalize(st);
-	  DP1("DBGetFeedCount END=%d", size);
-	  return size;
+	  		}
+		else
+			{
+	  		User::Leave(KErrCorrupt);
+	  		}
+		CleanupStack::PopAndDestroy(); // st
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	DP1("DBGetFeedCount END=%d", size);
+	return size;
 }
 
 void CFeedEngine::DBLoadFeedsL()
@@ -920,11 +903,13 @@
 	TLinearOrder<CFeedInfo> sortOrder( CFeedEngine::CompareFeedsByTitle);
 
 	int rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st,	(const void**) NULL);
-	Cleanup_sqlite3_finalize_PushL(st);
 	
-	if (rc==SQLITE_OK) {
+	if (rc==SQLITE_OK)
+		{
+		Cleanup_sqlite3_finalize_PushL(st);
 		rc = sqlite3_step(st);
-		while(rc == SQLITE_ROW) {
+		while(rc == SQLITE_ROW) 
+			{
 			feedInfo = CFeedInfo::NewLC();
 			
 			const void *urlz = sqlite3_column_text16(st, 0);
@@ -945,8 +930,11 @@
 
 			const void *imagefilez = sqlite3_column_text16(st, 4);
 			TPtrC16 imagefile((const TUint16*)imagefilez);
-			feedInfo->SetImageFileNameL(imagefile, &iPodcastModel);
-						
+			if (imagefile.Length() > 0)
+				{
+				feedInfo->SetImageFileNameL(imagefile, &iPodcastModel);
+				}
+			
 			const void *linkz = sqlite3_column_text16(st, 5);
 			TPtrC16 link((const TUint16*)linkz);
 			feedInfo->SetDescriptionL(link);
@@ -960,9 +948,10 @@
 			feedInfo->SetLastUpdated(lastupdatedtime);
 			
 			sqlite3_int64 customtitle = sqlite3_column_int64(st, 10);
-			if (customtitle) {
+			if (customtitle)
+				{
 				feedInfo->SetCustomTitle();
-			}
+				}
 			
 			TInt lasterror = sqlite3_column_int(st, 11);
 			feedInfo->SetLastError(lasterror);
@@ -974,10 +963,13 @@
 			CleanupStack::Pop(feedInfo);
 				
 			rc = sqlite3_step(st);
+			}	
+		CleanupStack::PopAndDestroy();//st
 		}
-	}
-
-	CleanupStack::PopAndDestroy();//st
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
 
 	DP("DBLoadFeeds END");
 	}
@@ -990,15 +982,15 @@
 	iSqlBuffer.Format(KSqlStatement, aFeedUid);
 
 	sqlite3_stmt *st;
-	 
-	//DP1("SQL statement length=%d", iSqlBuffer.Length());
-
+	
 	int rc = sqlite3_prepare16_v2(&iDB, (const void*)iSqlBuffer.PtrZ() , -1, &st,	(const void**) NULL);
 	
-	if (rc==SQLITE_OK) {
+	if (rc==SQLITE_OK)
+		{
 		Cleanup_sqlite3_finalize_PushL(st);
 		rc = sqlite3_step(st);
-		if (rc == SQLITE_ROW) {
+		if (rc == SQLITE_ROW)
+			{
 			feedInfo = CFeedInfo::NewLC();
 			
 			const void *urlz = sqlite3_column_text16(st, 0);
@@ -1042,9 +1034,17 @@
 			feedInfo->SetLastError(lasterror);
 						
 			CleanupStack::Pop(feedInfo);
-		}
+			}
+		else
+			{
+			User::Leave(KErrNotFound);
+			}
 		CleanupStack::PopAndDestroy();//st	
-	}
+		}
+	else
+		{
+		User::Leave(KErrNotFound);
+		}
 	
 	return feedInfo;
 }
--- a/engine/src/FeedInfo.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/FeedInfo.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -52,7 +52,9 @@
 	copy->SetLinkL(Link());
 	copy->SetBuildDate(BuildDate());
 	copy->SetLastUpdated(LastUpdated());
-	copy->iFeedIcon->Duplicate(iFeedIcon->Handle());
+	if (iFeedIcon) {
+		copy->SetFeedIcon(iFeedIcon);
+	}
 	copy->SetImageFileNameL(ImageFileName(), NULL);
 	if(CustomTitle())
 		{
@@ -64,6 +66,7 @@
 	CleanupStack::Pop(copy);
 	return copy;
 	}
+
 CFeedInfo::CFeedInfo()
 	{
 	iCustomTitle = EFalse;
@@ -82,7 +85,7 @@
 
 void CFeedInfo::ConstructL()
 	{
-	iFeedIcon = new (ELeave) CFbsBitmap;
+	//iFeedIcon = new (ELeave) CFbsBitmap;
 	}
 
 EXPORT_C const TDesC& CFeedInfo::Url() const
@@ -195,6 +198,7 @@
 
 EXPORT_C void CFeedInfo::SetImageFileNameL(const TDesC& aFileName, CPodcastModel* aPodcastModel)
 	{
+	DP1("CFeedInfo::SetImageFileNameL BEGIN, aFileName=%S", &aFileName);
 	TFileName cacheFileName;
 	
 	if (iImageFileName)
@@ -209,15 +213,21 @@
 	cacheFileName.Append(parser.Name());
 	cacheFileName.Append(KMbmExtension());
 	
-	if( iFeedIcon->SizeInPixels() == TSize(0,0) && BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), cacheFileName) )
+	if (iFeedIcon) {
+		delete iFeedIcon;
+	}
+	
+	if( BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), cacheFileName) )
 		{
 		iFeedIcon = CEikonEnv::Static()->CreateBitmapL(cacheFileName, 0);
 		}
 	else if(aPodcastModel &&  BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), ImageFileName() ))
 		{
 		// If this fails, no reason to worry
+		iFeedIcon = new CFbsBitmap();
 		TRAP_IGNORE(aPodcastModel->ImageHandler().LoadFileAndScaleL(FeedIcon(), ImageFileName(), TSize(64,56), *this, Uid()));
-		}		
+		}	
+	DP("CFeedInfo::SetImageFileNameL END");
 	} 
 
 EXPORT_C TBool CFeedInfo::CustomTitle() const
--- a/engine/src/OpmlParser.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/OpmlParser.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -130,18 +130,17 @@
 				} else if (attr16.Compare(KTagHtmlUrl) == 0) {
 					newFeed->SetLinkL(*val16);
 					hasUrl = ETrue;
-				// text=...
+				// title=...
 				} else if (attr16.Compare(KTagTitle) == 0) {
 					newFeed->SetTitleL(*val16);
-					newFeed->SetCustomTitle();
 					hasTitle = ETrue;
 				// description=
 				} else if (attr16.Compare(KTagDescription) == 0) {
 					newFeed->SetDescriptionL(*val16);
+				// text=
 				} else if (attr16.Compare(KTagText) == 0) {
 					if (!hasTitle) {
 						newFeed->SetTitleL(*val16);
-						newFeed->SetCustomTitle();
 						hasTitle = ETrue;
 					}
 				} 
@@ -156,6 +155,14 @@
 				newFeed->SetTitleL(newFeed->Url());
 			}
 			
+			// if the title is the same as the URL, it is hardly a custom
+			// title, so let's replace it on update
+			if (newFeed->Title().Length() &&
+					newFeed->Url().Length() &&
+					newFeed->Title().Compare(newFeed->Url()) != 0) {
+				newFeed->SetCustomTitle();
+			}
+			
 			if (iSearching) {
 				iFeedEngine.AddSearchResultL(newFeed);
 				CleanupStack::Pop(newFeed);
--- a/engine/src/PodcastModel.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/PodcastModel.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -22,6 +22,7 @@
 #include "SettingsEngine.h"
 #include "ShowEngine.h"
 #include "connectionengine.h"
+#include "podcastutils.h"
 
 #include <cmdestination.h>
 #include <cmmanager.h>
@@ -84,6 +85,21 @@
 	iSettingsEngine = CSettingsEngine::NewL(*this);
 	iConnectionEngine = CConnectionEngine::NewL(*this);	
 	
+	TRAPD(err, OpenDBL());
+	
+	if (err != KErrNone)
+		{
+		ResetDB();
+		
+		TRAP(err, OpenDBL());
+		
+		if (err != KErrNone)
+			{
+			User::Panic(_L("Podcatcher"), 1);
+			}
+		
+		}
+	
 	iFeedEngine = CFeedEngine::NewL(*this);
 	iShowEngine = CShowEngine::NewL(*this);
 
@@ -237,38 +253,90 @@
 	}
 }
 
+void CPodcastModel::ResetDB()
+	{
+	DP("CPodcastModel::ResetDB BEGIN");
+	
+	if (iDB != NULL)
+		{
+		sqlite3_close(iDB);
+		iDB = NULL;
+		}
+	
+	TFileName dbFileName;
+	dbFileName.Copy(iSettingsEngine->PrivatePath());
+	dbFileName.Append(KDBFileName);
+
+	// remove the old DB file
+	if (BaflUtils::FileExists(iFsSession, dbFileName))
+		{
+		BaflUtils::DeleteFile(iFsSession, dbFileName);
+		}
+
+	// copy template to new DB
+	TFileName dbTemplate;
+	dbTemplate.Copy(iSettingsEngine->PrivatePath());
+	dbTemplate.Append(KDBTemplateFileName);
+
+	BaflUtils::CopyFile(iFsSession, dbTemplate,dbFileName);
+	iIsFirstStartup = ETrue;
+	DP("CPodcastModel::ResetDB END");
+	}
+
+
+void CPodcastModel::OpenDBL()
+	{
+	DP("CPodcastModel::OpenDBL BEGIN");
+	
+	if (iDB != NULL)
+		{
+		sqlite3_close(iDB);
+		iDB = NULL;
+		}
+	
+	TFileName dbFileName;
+	dbFileName.Copy(iSettingsEngine->PrivatePath());
+	dbFileName.Append(KDBFileName);
+		
+	if (!BaflUtils::FileExists(iFsSession, dbFileName))
+		{
+		User::Leave(KErrNotFound);
+		}
+	
+	if (iDB == NULL) {	
+		// open DB
+		TBuf8<KMaxFileName> filename8;
+		filename8.Copy(dbFileName);
+		int rc = sqlite3_open((const char*) filename8.PtrZ(), &iDB);
+		if(rc != SQLITE_OK){
+			User::Leave(KErrCorrupt);
+		}
+
+		// do a test query 
+		sqlite3_stmt *st;
+		rc = sqlite3_prepare_v2(iDB,"select count(*) from feeds" , -1, &st, (const char**) NULL);
+		if( rc==SQLITE_OK )
+			{
+			Cleanup_sqlite3_finalize_PushL(st);
+			rc = sqlite3_step(st);
+					
+			if (rc != SQLITE_ROW)
+				{
+				User::Leave(KErrCorrupt);
+				}
+			CleanupStack::PopAndDestroy(); // st
+			}
+		else
+			{
+			User::Leave(KErrCorrupt);
+			}
+		}
+
+	DP("CPodcastModel::OpenDBL END");	
+	}
+
 sqlite3* CPodcastModel::DB()
 {
-	DP("CPodcastModel::DB BEGIN");
-	if (iDB == NULL) {		
-		TFileName dbFileName;
-		dbFileName.Copy(iSettingsEngine->PrivatePath());
-		//iFsSession.PrivatePath(dbFileName);
-		dbFileName.Append(KDBFileName);
-		DP1("DB is at %S", &dbFileName);
-
-		if (!BaflUtils::FileExists(iFsSession, dbFileName)) {
-			TFileName dbTemplate;
-			dbTemplate.Copy(iSettingsEngine->PrivatePath());
-			//iFsSession.PrivatePath(dbTemplate);
-			dbTemplate.Append(KDBTemplateFileName);
-			DP1("No DB found, copying template from %S", &dbTemplate);
-			BaflUtils::CopyFile(iFsSession, dbTemplate,dbFileName);
-			iIsFirstStartup = ETrue;
-		}
-		
-		TBuf8<KMaxFileName> filename8;
-		filename8.Copy(dbFileName);
-		DP("Before sqlite3_open");
-		int rc = sqlite3_open((const char*) filename8.PtrZ(), &iDB);
-		if( rc != SQLITE_OK){
-			DP("Error loading DB");
-			User::Panic(_L("Podcatcher"), 10);
-		}
-
-
-	}
-	DP("CPodcastModel::DB END");
 	return iDB;
 }
 
--- a/engine/src/ShowEngine.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/ShowEngine.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -34,15 +34,6 @@
 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())
--- a/engine/src/ShowInfo.cpp	Sun Apr 04 00:21:57 2010 +0100
+++ b/engine/src/ShowInfo.cpp	Sun Apr 04 15:54:17 2010 +0100
@@ -217,10 +217,22 @@
 
 EXPORT_C CShowInfo::CShowInfo(CShowInfo *aInfo)
 	{
+	if (iTitle)
+		delete iTitle;
 	iTitle = aInfo->Title().Alloc();
+	
+	if(iUrl)
+		delete iUrl;
 	iUrl = aInfo->Url().Alloc();
+	
+	if (iDescription)
+		delete iDescription;
 	iDescription = aInfo->Description().Alloc();
+	
+	if (iFileName)
+		delete iFileName;
 	iFileName = aInfo->FileName().Alloc();
+	
 	iPosition = aInfo->Position();
 	iPlayTime = aInfo->PlayTime();
 	iPlayState = aInfo->PlayState();
--- a/group/bld.inf	Sun Apr 04 00:21:57 2010 +0100
+++ b/group/bld.inf	Sun Apr 04 15:54:17 2010 +0100
@@ -22,9 +22,9 @@
 
 PRJ_MMPFILES
 
-//#ifdef SQLITE_INCLUDED
+#ifdef SQLITE_INCLUDED
 ..\engine\sqlite\group\sqlite.mmp
-//#endif
+#endif
 
 PRJ_MMPFILES
 ..\engine\group\engine.mmp
@@ -33,6 +33,7 @@
 ..\application\group\Podcast.mmp
 
 PRJ_EXPORTS
+..\engine\config\podcatcher.sqlite \epoc32\winscw\c\private\A0009D00\podcatcher.sqlite.template
 ..\engine\config\defaultfeeds.xml \epoc32\winscw\c\private\A0009D00\defaultfeeds.xml
 ..\engine\config\testfeeds.xml \epoc32\winscw\c\data\testfeeds.xml
 ..\application\help\podcatcher.hlp \epoc32\winscw\c\resource\help\podcatcher.hlp