diff -r 000000000000 -r dd21522fd290 browserutilities/feedsengine/FeedsServer/Server/src/FeedsDatabase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browserutilities/feedsengine/FeedsServer/Server/src/FeedsDatabase.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,4539 @@ +/* +* Copyright (c) 2005 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: The feeds server database. +* +*/ + + +#include +#include + +#include "FeedAttributes.h" +#include "FeedsDatabase.h" +#include "FolderAttributes.h" +#include "PackedAttributes.h" +#include "LeakTracker.h" +#include "Logger.h" +#include "PackedFeed.h" +#include "PackedFolder.h" +#include "FeedsServer.h" + +// Constants +// Database file name. +const TUid KSecureUid = {0x10281F95}; +_LIT(KSecure, "SECURE"); +_LIT(KDatabaseFileName, "FeedsDatabase"); +_LIT(KDbExtension, ".db"); + +// Table names. +_LIT(KVersionTable, "VersionTable"); +_LIT(KFolderListTable, "FolderListTable"); +_LIT(KFeedTable, "FeedTable"); +_LIT(KItemTable, "ItemTable"); +_LIT(KEnclosureTable, "EnclosureTable"); +_LIT(KSettingsTable, "SettingsTable"); + +// Table index names. +_LIT(KFolderListTableIndex, "FolderListTableIndex"); +_LIT(KFeedTableIndex, "FeedTableIndex"); +_LIT(KItemTableIndex, "ItemTableIndex"); +_LIT(KEnclosureTableIndex, "EnclosureTableIndex"); +_LIT(KSettingsTableIndex, "SettingsTableIndex"); + +// Table field names. +_LIT(KFolderListId, "FolderListId"); +_LIT(KFolderItemId, "FolderItemId"); +_LIT(KIsFolder, "IsFolder"); +_LIT(KItemId, "ItemId"); +_LIT(KParentId, "ParentId"); +_LIT(KSiblingOrder, "SiblingOrder"); +_LIT(KStatus,"Status"); +_LIT(KVersion, "Version"); +_LIT(KVersionId, "VersionID"); +_LIT(KTitle_100MaxLen, "Title"); +_LIT(KFeedId, "FeedId"); +_LIT(KDate, "Date"); +_LIT(KFeedUrl, "FeedUrl"); +_LIT(KWebUrl, "WebUrl"); +_LIT(KDescription, "Description"); +_LIT(KItemStatus, "ItemStatus"); +_LIT(KEnclosureId, "EnclosureId"); +_LIT(KLength_100MaxLen, "Length"); +_LIT(KContentType_100MaxLen, "ContentType"); +_LIT(KItemIdStr, "ItemIdStr"); +_LIT(KUnreadCount, "UnreadCount"); +_LIT(KAccessPoint, "AccessPoint"); +_LIT(KAutoUpdate, "AutoUpdate"); +_LIT(KAutoUpdateWhileRoaming, "AutoUpdateWhileRoaming"); +_LIT(KAutoUpdateFreq, "AutoUpdateFreq"); +_LIT(KLastAutoUpdate, "LastAutoUpdate"); + +// Misc string consts. +_LIT(KSpace, " "); +_LIT(KNew, "new"); +_LIT(KUnread, "unread"); +_LIT(KRead, "read"); + +// Root folder related. +const TInt KRootFolderId = 0; +_LIT(KRootFolder, "Root Folder"); + +// Misc consts. +const TInt K100MaxLen = 100; +const TInt KIntLength = 15; +const TInt KInt64Length = 25; +const TInt KVersion31 = 1; +//const TInt KVersion32 = 2; +const TInt KVersion50 = 3; +const TInt KVersion71 = 4; + +const TInt KResvSpaceForDupTitles = 6; //Space should be left in feed/folder title to append number in case of duplicate titles. +const TInt KAutoUpdatingOff = 0; + +// DATA TYPES +struct TAttribute + { + TUint token; + TPtrC value; + }; + + +// TODO: RDbDatabase::Begin/Commit/RollBack and RDbRowSet::Cancel needs to be +// used to guard the consistancy of the databse. See CMidRecordStoreDb +// (CMidRecordStoreDb.cpp) for a good example. + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::NewL +// +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CFeedsDatabase* CFeedsDatabase::NewL(CFeedsServer* aFeedsServer, TBool &aDatabaseCreated) + { + CFeedsDatabase* self = new (ELeave) CFeedsDatabase(aFeedsServer); + + aDatabaseCreated = EFalse; + + CleanupStack::PushL(self); + self->ConstructL(aDatabaseCreated); + CleanupStack::Pop(); + + return self; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::NewL +// +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ConstructL(TBool &aDatabaseCreated) + { + TInt err; + User::LeaveIfError( iDBs.Connect() ); + + // Create the path to the database file. + TParse aParse; + TDriveName cDrive = TDriveUnit( EDriveC ).Name(); + User::LeaveIfError( aParse.SetNoWild( KDatabaseFileName, &cDrive, &KDbExtension() ) ); + + + // Determine if the database exists. + TBool isDbExists = EFalse; + CDbDatabaseNames *dbNames = iDBs.DatabaseNamesL(EDriveC, KSecureUid); + for(int i = 0; i < dbNames->Count(); i++) + { + if( (*dbNames)[i] == aParse.NameAndExt() ) + { + isDbExists = ETrue; + break; + } + } + delete dbNames; + + iDatabasePath = aParse.FullName(); + // If the database file doesn't exit create it and create the tables. + if ( !isDbExists ) + { + TRAP( err, ResetDatabaseL() ); + + // Ensure that the database isn't partially initialized. + if ( err != KErrNone ) + { + iDBs.DeleteDatabase( iDatabasePath, KSecureUid ); + User::Leave( err ); + } + + aDatabaseCreated = ETrue; + } + + // Otherwise, just open the database. + else + { + TBuf<32> format; + format.Copy(KSecure); + format.Append(KSecureUid.Name()); + + User::LeaveIfError(iDatabase.Open(iDBs, iDatabasePath, format)); + + // check version + UseVersionTableLC( RDbTable::EReadOnly ); + // Get the row. + iVersionTable.FirstL(); + iVersionTable.GetL(); + // Get version + TInt version = iVersionTable.ColUint16(iVersionColSet->ColNo(KVersionId)); + // + CleanupStack::PopAndDestroy(/*version Table*/); + // If version is lower than 5.0, add a new column into old database, then update the version table. + if ( version < KVersion50 ) + { + + UseFolderListTableLC(RDbTable::EUpdatable); + + // get the exiting col set + CDbColSet* colSet = iDatabase.ColSetL(KFolderListTable); + + colSet->AddL(TDbCol(KStatus, EDbColInt32)); + iDatabase.AlterTable(KFolderListTable, *colSet); + + CleanupStack::PopAndDestroy(/* FolderListTable */); + + // Set the status as KErrorNone + // Prep the item table. + UseFolderListTableLC(RDbTable::EUpdatable); + + while( iFolderListTable.NextL() ) + { + // Get the row. and add the default value. + iFolderListTable.GetL(); + iFolderListTable.UpdateL(); + + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), KErrNone); + + iFolderListTable.PutL(); + + } + + CleanupStack::PopAndDestroy(/* FolderListTable */); + + //Add a new colum KAutoUpdateFreq to FeedTable + AlterFeedTableWithAutoFequencyL(); + // Add the version as 7.1 + UseVersionTableLC(RDbTable::EUpdatable); + + // Update the version table.There is only one row in this table. + iVersionTable.FirstL(); + + if (iVersionTable.AtRow()) + { + iVersionTable.GetL(); + iVersionTable.UpdateL(); + } + else + { + iVersionTable.Reset(); + iVersionTable.InsertL(); + } + + // Add the version as 7.1 + iVersionTable.SetColL(iVersionColSet->ColNo(KVersionId), KVersion71); + iVersionTable.PutL(); + CleanupStack::PopAndDestroy(/* version table */); + + } + else if( version < KVersion71 ) + { + //Add a new colum KAutoUpdateFreq to FeedTable + AlterFeedTableWithAutoFequencyL(); + // Add the version as 7.1 in DB + UseVersionTableLC(RDbTable::EUpdatable); + + // Update the database. There is only one row in this table... + iVersionTable.FirstL(); + + if (iVersionTable.AtRow()) + { + iVersionTable.GetL(); + iVersionTable.UpdateL(); + } + else + { + iVersionTable.Reset(); + iVersionTable.InsertL(); + } + + // Add the version as 7.1 + iVersionTable.SetColL(iVersionColSet->ColNo(KVersionId), KVersion71); + iVersionTable.PutL(); + CleanupStack::PopAndDestroy(/* version table */); + + } + else if ( version == KVersion31 ) + { + // JH todo: transform here! + } + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CFeedsDatabase +// +// C++ default constructor can NOT contain any code that +// might leave. +// ----------------------------------------------------------------------------- +// +CFeedsDatabase::CFeedsDatabase(CFeedsServer* aFeedsServer): + iLeakTracker(CLeakTracker::EFeedsDatabase),iFeedsServer(aFeedsServer) + { + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::~CFeedsDatabase +// +// Destructor +// ----------------------------------------------------------------------------- +// +CFeedsDatabase::~CFeedsDatabase() + { + delete iFolderListColSet; + iFolderListTable.Close(); + + delete iFeedColSet; + iFeedTable.Close(); + + delete iItemColSet; + iItemTable.Close(); + + delete iEnclosureColSet; + iEnclosureTable.Close(); + + delete iVersionColSet; + iVersionTable.Close(); + + delete iSettingsColSet; + iSettingsTable.Close(); + + iDatabase.Close(); + iDBs.Close(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FeedIdFromUrlL +// +// Returns the feed if of the feed with the given url. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::FeedIdFromUrlL(const TDesC& aFeedUrl, TInt aFolderListId, TInt& aFeedId) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FeedId FROM FeedTable WHERE FeedUrl = 'aFeedUrl' AND FolderListId = aFolderListId + _LIT(KQuery, "SELECT FeedId FROM FeedTable WHERE FeedUrl = \'%S\' AND FolderListId = %d"); + + query = HBufC::NewLC( KQuery().Length() + aFeedUrl.Length() + KIntLength ); + + query->Des().Format( KQuery, &aFeedUrl, aFolderListId ); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + aFeedId = view.ColUint16(colSet->ColNo(KFeedId)); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + + return found; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderListIdFromFeedIdL +// +// Returns the feed if of the feed with the given url. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderListIdFromFeedIdL( TInt aFeedId, TInt& aFolderListId ) + { + TDbSeekKey seekKey((TUint16) aFeedId); + + // Prep the feed table. + UseFeedTableLC(RDbTable::EReadOnly); + + // Get the information about the feed. + if (iFeedTable.SeekL(seekKey)) + { + // Get the row. + iFeedTable.GetL(); + + // Extract the fields. + aFolderListId = iFeedTable.ColInt32(iFeedColSet->ColNo(KFolderListId)); + } + else + { + User::Leave(KErrCorrupt); + } + + CleanupStack::PopAndDestroy(/*Feed Table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FeedIdFromFolderItemIdL +// +// Return the feed-id of the given folder-item-id. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::FeedIdFromFolderItemIdL(TInt aFolderItemId, TInt& aFeedId) + { + TDbSeekKey seekKey((TUint16) aFolderItemId); + TBool found = EFalse; + + // Prep the FolderList table. + UseFolderListTableLC(RDbTable::EReadOnly); + + // Get the folder item. + if (iFolderListTable.SeekL(seekKey)) + { + TBool isFolder; + + // Get the row. + iFolderListTable.GetL(); + + isFolder = iFolderListTable.ColUint8(iFolderListColSet->ColNo(KIsFolder)); + + if (!isFolder) + { + aFeedId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFeedId)); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(/*folder list Table*/); + + return found; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemInfoL +// +// Return the folder item info from folder-item-id. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemInfoL(TInt aFolderItemId, TBool &aIsFolder, HBufC*& aTitle, HBufC*& aFeedUrl) + { + TDbSeekKey seekKey((TUint16) aFolderItemId); + + // Prep the FolderList table. + UseFolderListTableLC(RDbTable::EReadOnly); + + // Get the folder item. + if (iFolderListTable.SeekL(seekKey)) + { + // Get the row. + iFolderListTable.GetL(); + + aIsFolder = iFolderListTable.ColUint8(iFolderListColSet->ColNo(KIsFolder)); + + *aTitle = iFolderListTable.ColDes16(iFolderListColSet->ColNo(KTitle_100MaxLen)); + + TInt FeedId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFeedId)); + + if(!aIsFolder) + { + + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FeedUrl FROM FeedTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT FeedUrl FROM FeedTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, FeedId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + ReadLongTextL(view, colSet->ColNo(KFeedUrl), aFeedUrl); + } + } + + CleanupStack::PopAndDestroy(/*colSet*/); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(/*query*/); + } + } + + CleanupStack::PopAndDestroy(/*folder list Table*/); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UrlFromFeedIdL +// +// Return the url of the feed with the given feed-id. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::UrlFromFeedIdL(TInt aFeedId, HBufC*& aFeedUrl) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FeedUrl FROM FeedTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT FeedUrl FROM FeedTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + ReadLongTextL(view, colSet->ColNo(KFeedUrl), aFeedUrl); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + + return found; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FindItemL +// +// Finds the item with the given item-id-str and returns its id. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::FindItemL(TInt aFeedId, const TDesC& aItemIdStr, TInt& aItemId) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT ItemId FROM ItemTable WHERE FeedId = aFeedId AND ItemIdStr = 'aItemIdStr' + _LIT(KQuery, "SELECT ItemId FROM ItemTable WHERE FeedId = %d AND ItemIdStr = \'%S\'"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + aItemIdStr.Length()); + + query->Des().Format(KQuery, aFeedId, &aItemIdStr); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Find the item. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the item id. + view.GetL(); + aItemId = view.ColUint16(colSet->ColNo(KItemId)); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + return found; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FindFolderItemL +// +// Finds the folder item with the given name. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::FindFolderItemL(TInt& aFolderListId, const TDesC& aName, + TInt& aFolderItemId) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FolderItemId FROM FolderListTable WHERE FolderListId = aFolderListId + // AND Title = 'aName' + _LIT(KQuery, "SELECT FolderItemId FROM FolderListTable WHERE FolderListId = %d AND Title = '%S'"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + aName.Length()); + + query->Des().Format(KQuery, aFolderListId, &aName); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + aFolderItemId = view.ColUint16(colSet->ColNo(KFolderItemId)); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + + return found; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::GetDuplicateFolderCounter +// +// Parses the Folder/Feed name to get the postfix integer for duplicated names +// (ex Folder, Folder (1), Folder (2) ...) +// ----------------------------------------------------------------------------- +// +//TBool CFeedsDatabase::GetDuplicateFolderCounter(const TDesC& aFolderTitle, TInt &aCounterVal) +TBool CFeedsDatabase::GetDuplicateFolderCounter(const TDesC& aFolderToBeAdded, const TDesC& aFolderTitle, TInt &aCounterVal) + { + + if(aFolderToBeAdded == aFolderTitle) + return ETrue; + + // return EFalse if FolderTitle is empty + if(aFolderTitle.Length()<=0) + return EFalse; + + // Use a lexical parser to parse the FolderTitle ( FolderName (%d)) + TLex parser(aFolderTitle); + + // Go til first '(' + while(!parser.Eos()) + { + TChar c(parser.Peek()); + if( c != '(') + parser.Get(); + else + break; + } + + // If end of string return EFalse + if(parser.Eos()) + return EFalse; + + // skip '(' + parser.Get(); + + // Get postfix integer value + if(parser.Val(aCounterVal) != KErrNone) + return EFalse; + + // If not ending with ')' return EFalse + if(parser.Get() != ')') + return EFalse; + + // If end of string return ETrue + if(parser.Eos()) + return ETrue; + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ValidateFeedURLL +// +// Checks for the FeedURL's existance +// Returns EFalse if the specified URL exists else ETrue +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::ValidateFeedURLL(const TInt &aFolderListId, const TDesC& aUrl) + { + + RDbView view; + HBufC* query = NULL; + TBool IsValid = ETrue; + + // If URL is empty return EFalse + if(aUrl.Length() <= 0) + return EFalse; + + // Check for the URL duplicate + _LIT(KQuery, "SELECT FeedId FROM FeedTable WHERE FeedUrl = \'%S\' AND FolderListId = %d"); + query = HBufC::NewLC(KQuery().Length() + KIntLength + aUrl.Length()); + + query->Des().Format(KQuery, &aUrl, aFolderListId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // If there exists atleast one record we are not suppose to add the feed again + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // FeedURL aleady exists, no need to process this feed + IsValid = EFalse; + } + } + + CleanupStack::PopAndDestroy(/*colSet*/); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(/*query*/); + + return IsValid; + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::GenerateNewFolderTitleL +// +// This will check for the duplicate folder names and suggest a new folder title if duplicated +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::GenerateNewFeedFolderTitleL( + const TInt &aFolderListId, + const TInt &aParentEntryId, + const TDesC& aTitle, + TDes& aNewFeedFolderTitle + ) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + _LIT(KQuery, "SELECT Title FROM FolderListTable WHERE FolderListId = %d AND ParentId = %d AND Title LIKE '%S*'"); + + if(aTitle.Length() <= 0) + return; + + query = HBufC::NewLC(KQuery().Length() + KIntLength + aTitle.Length()); + + query->Des().Format(KQuery, aFolderListId, aParentEntryId, &aTitle); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.EvaluateAll() >= 0) + { + + if(view.CountL() <= 0) + { + // Name doesnt exist, so no problem adding this name + aNewFeedFolderTitle = aTitle; + } + else + { + RArray FolderPostfixArray; + CleanupClosePushL(FolderPostfixArray); + + // Store all folder name extensions ('FolderName (%d)') in an array + for (view.FirstL(); view.AtRow(); view.NextL()) + { + // Get the current row. + view.GetL(); + + HBufC *FolderTitle = NULL; + ReadLongTextL(view, colSet->ColNo(KTitle_100MaxLen), FolderTitle); + CleanupStack::PushL(FolderTitle); + + TInt PostfixVal=0; + if(GetDuplicateFolderCounter(aTitle, FolderTitle->Des(), PostfixVal)) + FolderPostfixArray.Append(PostfixVal); + + CleanupStack::PopAndDestroy(/*FolderTitle*/); + } + + // Search for a free postfix counter for duplicated folder/feed title + TInt PostfixVal = 1; + TInt length = FolderPostfixArray.Count(); + if(length <= 0) + { + aNewFeedFolderTitle = aTitle; + } + else + { + do + { + TInt index = 0; + for (index = 0 ; index < length ; index++) + { + if(FolderPostfixArray[index] == PostfixVal) + break; + } + + if(index >= length) + break; + + PostfixVal++; + } + while(ETrue); + // Generate a new folder/feed title by appending the new counter + _LIT(KFolderNameFormat, "%S (%d)"); + aNewFeedFolderTitle.Format(KFolderNameFormat, &aTitle, PostfixVal); + } + + CleanupStack::PopAndDestroy(/*FolderPostfixArray*/); + } + } + else + { + aNewFeedFolderTitle = aTitle; + } + + CleanupStack::PopAndDestroy(/*colSet*/); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(/*query*/); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ValidateFeedFolderTitleL +// +// This will check for the duplicate folder names and feed URLs and suggest the next title +// Returns ETrue if the Feed/Folder can be added to database else EFalse +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::ValidateFeedFolderTitleL( + const TInt &aFolderListId, + const TInt &aParentEntryId, + const TDesC& aTitle, + const TBool aIsFolder, + TDes& aNewFeedTitle + ) + { + if(!aIsFolder) + { + + // If Feed URL is duplicated return EFalse + //if(!ValidateFeedURLL(aFolderListId, aUrl)) + // return EFalse; + + } + + if(aTitle.Length() <=0) + return EFalse; + + GenerateNewFeedFolderTitleL(aFolderListId, aParentEntryId, aTitle, aNewFeedTitle); + + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::AllFeedIds +// +// Extract all of the feed-ids. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::AllFeedIdsL( RArray& aFeedIds, TInt aFolderListId ) + { + RDbView view; + HBufC* query = NULL; + + if( aFolderListId == KAllFolderListId ) + { + // Create a view given this select... + // SELECT FeedId FROM FeedTable + _LIT(KQuery, "SELECT FeedId FROM FeedTable"); + + query = HBufC::NewLC( KQuery().Length() ); + } + else + { + // Create a view given this select... + // SELECT FeedId FROM FeedTable WHERE FolderListId = aFolderListId + _LIT(KQuery, "SELECT FeedId FROM FeedTable WHERE FolderListId = %d"); + + query = HBufC::NewLC( KQuery().Length() + KIntLength ); + query->Des().Format( KQuery, aFolderListId ); + } + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Find the item. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + // Get the current row. + view.GetL(); + + aFeedIds.AppendL(view.ColUint16(colSet->ColNo(KFeedId))); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::IsFreshL +// +// Determines if the given feed is newly created (not ok to read from the database). +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::IsNewlyCreatedL(TInt aFeedId) + { + TDbSeekKey seekKey((TUint16) aFeedId); + TBool isNewlyCreated = EFalse; + TTime now; + + // Prep the feed table. + UseFeedTableLC(RDbTable::EReadOnly); + + // Get the information about the feed. + if (iFeedTable.SeekL(seekKey)) + { + // Get the row. + iFeedTable.GetL(); + + // Extract the fields. + TTime date = iFeedTable.ColTime(iFeedColSet->ColNo(KDate)); + + // Determine if the feed is fresh. + if (date == 0) + { + isNewlyCreated = ETrue; + } + } + else + { + User::Leave(KErrCorrupt); + } + + CleanupStack::PopAndDestroy(/*Feed Table*/); + + return isNewlyCreated; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ExtractFeedL +// +// Extracts the feed from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ExtractFeedL(TInt aFeedId, CPackedFeed& aFeed) + { + // Pack the feed. + PackFeedL(aFeedId, aFeed); + + // Pack the feed's items. + PackItemsL(aFeedId, aFeed); + + // Signal the end of the feed. + aFeed.FeedEndsL(); + aFeed.Trim(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ExtractRootFolderL +// +// Extracts the folder from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ExtractRootFolderL( TInt aFolderListId, CPackedFolder& aPackedFolder, TBool aItemTitleNeed ) + { + // Use the tables. + UseFeedTableLC(RDbTable::EReadOnly); + + // Extract the root folder and all of its children. + aPackedFolder.FolderBeginsL(KRootFolder, KRootFolderId); + PackFolderL( aFolderListId, KRootFolderId, aPackedFolder, aItemTitleNeed ); + aPackedFolder.FolderEndsL(); + aPackedFolder.DoneL(); + + // Clean up. + CleanupStack::PopAndDestroy(/*feed table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UpdateFeedL +// +// Update the database given the packed feed. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UpdateFeedL(const CPackedFeed& aPackedFeed, const TDesC& /* aFeedUrl */,TInt aFeedId, + TInt aFolderListId, TBool aPurgeOldItems) + { + RArray itemIds; + RArray feedAttributes; + RArray itemAttributes; + RArray enclosureAttributes; + TBool isFeed = EFalse; + TBool isItem = EFalse; + TBool isEnclosure = EFalse; + TInt feedId = 0; + TInt itemId = 0; + TInt enclosureId = 0; + TAttribute attribute; + TUint attributeToken; + TPtrC attributeValue; + TBool isNewFeed = EFalse; + TInt newItemCount = 0; + TBool newItem = EFalse; + feedId = aFeedId; + + // This array holds the ids of the items found in the feed. The array is then + // used to remove items from the database that aren't in the updated feed. + CleanupClosePushL(itemIds); + + CleanupClosePushL(feedAttributes); + CleanupClosePushL(itemAttributes); + CleanupClosePushL(enclosureAttributes); + + // Use the various tables + UseFeedTableLC(RDbTable::EUpdatable); + UseItemTableLC(RDbTable::EUpdatable); + UseEnclosureTableLC(RDbTable::EUpdatable); + + // Unpack the packed feed. + while (aPackedFeed.HasNextToken()) + { + TUint token; + + token = aPackedFeed.NextToken(); + + switch (token) + { + case EFeedTokenFeedBegin: + isFeed = ETrue; + //isNewFeed = ETrue; + // Resolve the url to determine if this feed is already in the database. + //if (FeedIdFromUrlL(aFeedUrl, aFolderListId, feedId)) + // { + // isNewFeed = EFalse; + // } + + // Otherwise lookup a new feed id to use. + //else + // { + // // Get a new id for the feed. + // feedId = NextFeedIdL(); + // } + break; + + case EFeedTokenFeedEnd: + { + // TODO: Track whether or not any new item were added. The feed's timestamp + // should only be updated if this happened. So rather than updating the + // timestamp in CommitFeedL it should be updated here. + // + // Or prehaps this shouldn't be done. If this is done the user's "last update" + // timestamp won't be updated - so they may _feel_ the update didn't happen. + + // Remove any items that weren't in the packed feed (this removes old items). + TInt purgedUnreadNewCount = 0; + if (aPurgeOldItems) + { + purgedUnreadNewCount = PurgeOtherItemsL(feedId, itemIds); + } + newItemCount -= purgedUnreadNewCount; + + TTime now; + + // Commit the feed to the database. + now.UniversalTime(); + CommitFeedL(aFolderListId, isNewFeed, feedId, feedAttributes, now, newItemCount); + + feedAttributes.Reset(); + isFeed = EFalse; + } + break; + + case EFeedTokenItemBegin: + isItem = ETrue; + itemId = NextItemIdL(); + enclosureId = 0; + break; + + case EFeedTokenItemEnd: + // Commit the item to the database. + newItem = CommitItemL(itemId, feedId, itemAttributes, itemIds); + + itemAttributes.Reset(); + isItem = EFalse; + if( newItem ) + { + newItemCount++; + } + break; + + case EFeedTokenEnclosureBegin: + isEnclosure = ETrue; + break; + + case EFeedTokenEnclosureEnd: + // Commit the enclosure to the database. + CommitEnclosureL(enclosureId++, itemId, feedId, enclosureAttributes); + + enclosureAttributes.Reset(); + isEnclosure = EFalse; + break; + + case EPackedTokenAttribute: + // Apply the given attribute to the current object (enclosure, item, or feed). + aPackedFeed.ExtractAttributeValue(attributeToken, attributeValue); + + attribute.token = attributeToken; + attribute.value.Set(attributeValue); + + if (isEnclosure) + { + enclosureAttributes.AppendL(attribute); + } + else if (isItem) + { + itemAttributes.AppendL(attribute); + } + else if (isFeed) + { + feedAttributes.AppendL(attribute); + } + break; + } + } + + // Clean up. + CleanupStack::PopAndDestroy(/*enclosure table*/); + CleanupStack::PopAndDestroy(/*item table*/); + CleanupStack::PopAndDestroy(/*feed table*/); + + CleanupStack::PopAndDestroy(/*enclosureAttributes*/); + CleanupStack::PopAndDestroy(/*attributeValue*/); + CleanupStack::PopAndDestroy(/*feedAttributes*/); + + CleanupStack::PopAndDestroy(/*itemIds*/); + iDatabase.Compact(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ImportFolderL +// +// Update the database given the packed folder. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ImportFolderL(TInt aFolderListId, const CPackedFolder& aPackedFolder) + { + RArray parentStack; + RArray siblingIndexStack; + TInt parent; + TInt siblingIndex; + TInt folderId; + TBool foundRootFolder = EFalse; + TPtrC title; + TPtrC url; + TInt entryId; + TInt feedId; + TTime timestamp; + TInt unreadCount; + TInt statusCode; + TInt freq; + + // Open the various tables + UseFolderListTableLC(RDbTable::EUpdatable); + UseFeedTableLC(RDbTable::EUpdatable); + + // A simple stack is used to track the folder-nesting. Start with the root-folder. + CleanupClosePushL(parentStack); + CleanupClosePushL(siblingIndexStack); + + parentStack.AppendL(KRootFolderId); + siblingIndexStack.AppendL(0); + + // Unpack the packed folder. + while (aPackedFolder.HasNextToken()) + { + TUint token; + + token = aPackedFolder.NextToken(); + + switch (token) + { + case EFolderTokenFolderBegin: + // Extract the attributes. + aPackedFolder.ExtractAttributes(title, url, entryId, feedId, timestamp, unreadCount, statusCode, freq); + + // The first folder in the PackedFolder is the root-folder. There is no + // reason to store this folder in the database, as such this folder is skipped. + if (!foundRootFolder) + { + foundRootFolder = ETrue; + continue; + } + + // Determine the parent and its sibling index. + parent = parentStack[parentStack.Count() - 1]; + siblingIndex = siblingIndexStack[siblingIndexStack.Count() - 1]; + siblingIndexStack[siblingIndexStack.Count() - 1]++; + + // Add the folder. + TInt feedId; + FolderItemAddHelperL(aFolderListId, title, KNullDesC, + ETrue, siblingIndex, parent, folderId, feedId, freq); + + // Push this folder on the stack as the active parent. + parentStack.AppendL(folderId); + siblingIndexStack.AppendL(0); + break; + + case EFolderTokenFolderEnd: + // Pop this folder off of the stacks. + parentStack.Remove(parentStack.Count() - 1); + siblingIndexStack.Remove(siblingIndexStack.Count() - 1); + break; + + case EFolderTokenFeed: + // Extract the attributes. + aPackedFolder.ExtractAttributes(title, url, entryId, feedId, timestamp, unreadCount, statusCode, freq); + + // Determine the parent and its sibling index. + parent = parentStack[parentStack.Count() - 1]; + siblingIndex = siblingIndexStack[siblingIndexStack.Count() - 1]; + + // Add the feed. + + TInt folderId, newfeedId; + TRAPD( err, FolderItemAddHelperL(aFolderListId, title, url, + EFalse, siblingIndex, parent, folderId, newfeedId, freq) ); + + // Ignore problematic ones and continue to the next token + if( err == KErrNone ) + { + siblingIndexStack[siblingIndexStack.Count() - 1]++; + } + break; + } + } + + CleanupStack::PopAndDestroy(/*siblingIndexStack*/); + CleanupStack::PopAndDestroy(/*parentStack*/); + CleanupStack::PopAndDestroy(/*feed table*/); + CleanupStack::PopAndDestroy(/*folder list table*/); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemAddL +// +// Add a new entry. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::FolderItemAddL(TInt aFolderListId, const TDesC& aTitle, + const TDesC& aUrl, TBool aIsFolder, TInt aParentEntryId, TInt aFreq) + { + TInt entryId = 0; + + // Open the various tables + UseFolderListTableLC(RDbTable::EUpdatable); + UseFeedTableLC(RDbTable::EUpdatable); + + // Adjust the sibling indexes of the existing folder items such that this + // item can be inserted at index zero. + CreateSiblingIndexHoleL(aParentEntryId, 0, 1); + + // Add the folder item at sibling index 0. + TInt feedId = 0; + TRAPD( err, FolderItemAddHelperL(aFolderListId, aTitle, aUrl, aIsFolder, + 0, aParentEntryId, entryId, feedId, aFreq) ); + User::LeaveIfError( err ); + + // Clean up. + CleanupStack::PopAndDestroy(/*feed table*/); + CleanupStack::PopAndDestroy(/*folder list table*/); + if(feedId != KUnassignedId) + { + iFeedsServer->UpdateFeedL(aFolderListId,feedId,EFalse); + } + return entryId; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemAddHelperL +// +// Add a new entry. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemAddHelperL(TInt aFolderListId, const TDesC& aTitle, + const TDesC& aUrl, TBool aIsFolder, TInt aSiblingIndex, TInt aParentEntryId, + TInt& aOutFolderId, TInt& aOutFeedId, TInt aFreq) + { + + HBufC* safeTitle = NULL; + TBool found(ETrue); + TBuf NewTitle; + + aOutFeedId = KUnassignedId; + + // Get a unique id for this new folder item. + aOutFolderId = NextFolderItemIdL(); + + // Remove any chars that may not be database safe. + safeTitle = aTitle.AllocLC(); + + do + { + TInt pos(0); + if ((pos = safeTitle->Locate('\'')) != KErrNotFound) + { + safeTitle->Des().Delete(pos, 1); + } + else + { + found = EFalse; + } + } + while (found); + + if(safeTitle->Des().Length()>NewTitle.MaxLength()-KResvSpaceForDupTitles) + { + safeTitle->Des().SetLength(NewTitle.MaxLength()-KResvSpaceForDupTitles); + } + + // Fixed for Bug id - JJUN-78VES7 (FeedsServer crashes under IPC attack) + // It is a common mistake to use Des() to create a TDesC16& reference. + // While not incorrect, it is simpler and much more efficient to simply dereference + // the heap descriptor. + + if( ValidateFeedFolderTitleL(aFolderListId, aParentEntryId, *safeTitle, aIsFolder, NewTitle) ) + { + // Add it to the feed table if its a new feed. + if (!aIsFolder) + { + aOutFeedId = CommitFeedL(aFolderListId, NewTitle, aUrl, aFreq); + } + // Add it to the folder list table. + CommitFolderListL(aFolderListId, aOutFolderId, aParentEntryId, aSiblingIndex, + aIsFolder, aOutFeedId, NewTitle); + } + + CleanupStack::PopAndDestroy(safeTitle); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemUpdateL +// +// Update an entry. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemUpdateL(TInt aFolderItemId, + const TDesC& aTitle, const TDesC& aUrl, TInt aFreq) + { + TDbSeekKey folderListKey(aFolderItemId); + + // Open the various tables + UseFolderListTableLC(RDbTable::EUpdatable); + TInt feedId = KUnassignedId; + TInt folderListId = 0; + if (iFolderListTable.SeekL(folderListKey)) + { + TBool isFolder; + // TInt folderListId; + + // Update the title in the folder list table. + iFolderListTable.GetL(); + iFolderListTable.UpdateL(); + + isFolder = iFolderListTable.ColUint8(iFolderListColSet->ColNo(KIsFolder)); + // folderListId = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KFolderListId)); + + iFolderListTable.SetColL(iFolderListColSet->ColNo(KTitle_100MaxLen), + aTitle.Left(K100MaxLen)); + + // If the entry is a feed then make sure the feed id is still valid. + if (!isFolder) + { + feedId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFeedId)); + folderListId = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KFolderListId)); + // Resolve the url to determine if this feed is already subscribed to. If it's + // a new feed it is added to the database. + //if (!FeedIdFromUrlL(aUrl, folderListId, feedId)) + // { + // feedId = CommitFeedL(folderListId, aTitle, aUrl); + // } + + + UseFeedTableLC(RDbTable::EUpdatable); + TDbSeekKey seekKey((TUint16) feedId); + + if (iFeedTable.SeekL(seekKey)) + { + iFeedTable.GetL(); + iFeedTable.UpdateL(); + } + else + { + User::Leave(KErrCorrupt); + } + iFeedTable.SetColL(iFeedColSet->ColNo(KTitle_100MaxLen), aTitle.Left(K100MaxLen)); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KFeedUrl), aUrl); + iFeedTable.SetColL(iFeedColSet->ColNo(KAutoUpdateFreq), aFreq); + iFeedTable.PutL(); + CleanupStack::PopAndDestroy(/*feed table*/); + // Set the feed id. + //iFolderListTable.SetColL(iFolderListColSet->ColNo(KFeedId), feedId); + } + + iFolderListTable.PutL(); + if(feedId != KUnassignedId) + { + iFeedsServer->UpdateFeedL(folderListId,feedId,EFalse); + } + } + + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemDeleteL +// +// Delete the given folder items and any newly unreferenced feeds. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemDeleteL(const RArray& aFolderItemIds, TBool aSessionCalled) + { + RArray feedIds; + + CleanupClosePushL(feedIds); + if(aSessionCalled) + { + iDeleteFolderArray.Reset(); + for(TInt i = 0; i < aFolderItemIds.Count(); i++) + { + iDeleteFolderArray.AppendL(aFolderItemIds[i]); + } + } + // Delete the items, including all the children of any folders. + FolderItemDeleteHelperL(aFolderItemIds, feedIds); + + // Purge unreferenced feeds. + for (TInt i = 0; i < feedIds.Count(); i++) + { + PurgeFeedIfNotReferencedL(feedIds[i]); + } + + CleanupStack::PopAndDestroy(/*feedIds*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderListDeleteL +// +// Delete anything under the folder list. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderListDeleteL( TInt aFolderListId ) + { + HBufC* query = NULL; + RArray feedIds; + + // Purge the feeds and their items, enclosures. + CleanupClosePushL(feedIds); + AllFeedIdsL( feedIds, aFolderListId ); + for (TInt i = 0; i < feedIds.Count(); i++) + { + FeedPurgeL(feedIds[i], ETrue); + } + CleanupStack::PopAndDestroy(/*feedIds*/); + + // Delete the folder items from the FolderListTable. + // DELETE FROM FolderListTable WHERE FolderListId = aFolderListId + _LIT(KQuery, "DELETE FROM FolderListTable WHERE FolderListId = %d"); + query = HBufC::NewLC(KQuery().Length() + KIntLength); + query->Des().Format(KQuery, aFolderListId); + // err is KErrNone even multiple records are deleted + TInt err = iDatabase.Execute(*query); + CleanupStack::PopAndDestroy(query); + iFeedsServer->ScheduleUpdateManagerL(aFolderListId); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemDeleteHelperL +// +// Delete the given folder items and store the feedIds in aFeedIds. aFeedIds +// can then be used to delete any newly unreferenced feeds. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemDeleteHelperL(const RArray& aFolderItemIds, + RArray& aFeedIds) + { + TInt parentId = 0; + TInt err; + TInt statusCode; + + if (aFolderItemIds.Count() == 0) + { + return; + } + + // Use the table. + UseFolderListTableLC(RDbTable::EUpdatable); + + // Delete each of the entries. + for (TInt i = 0; i < aFolderItemIds.Count(); i++) + { + // Find the entry. + TDbSeekKey seekKey(aFolderItemIds[i]); + + if (iFolderListTable.SeekL(seekKey)) + { + TInt folderItemId; + TInt feedId; + TBool isFolder; + + iFolderListTable.GetL(); + + // Get the parent, so it can adjust the sibling order. This only + // needs to be done once -- on the first iter... + if (i == 0) + { + parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + } + + folderItemId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFolderItemId)); + feedId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFeedId)); + isFolder = iFolderListTable.ColUint8(iFolderListColSet->ColNo(KIsFolder)); + statusCode = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + // Delete it. + iFolderListTable.DeleteL(); + + // If this is a folder then all of the children need to be deleted too. + if (isFolder) + { + RArray children; + + // Get the children. + CleanupClosePushL(children); + FolderItemGetChildrenL(folderItemId, children); + + // Delete the children. + FolderItemDeleteL(children); + CleanupStack::PopAndDestroy(/*children*/); + } + + // Otherwise add the feed-id to the array of potentially unreferenced feeds. + else + { + err = aFeedIds.InsertInOrder(feedId); + if ((err != KErrNone) && (err != KErrAlreadyExists)) + { + User::Leave(err); + } + } + if(statusCode != KErrNone && iDeleteFolderArray.Find(folderItemId) != KErrNotFound) + { + TInt parent = parentId; + TInt previousStatus = KErrNone; + while(parent != KRootFolderId) + { + TDbSeekKey folderListKey(parent); + if(iFolderListTable.SeekL(folderListKey)) + { + iFolderListTable.GetL(); + parent = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + previousStatus = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + iFolderListTable.UpdateL(); + // Folder status value should be -ve of total errorneous folder/feeds contained by it. + TInt status = previousStatus + 1; + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), status); + iFolderListTable.PutL(); + + if(status != KErrNone) + { + break; + } + } + } + + } + } + } + + // Fix up the sibling indexes. + AdjustSiblingIndexesL(parentId); + + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemMoveL +// +// Move the folder items within their parent. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemMoveL(const RArray& aFolderItemIds, + TInt aNewIndex) + { + TInt parentId = 0; + TInt count; + + if (aFolderItemIds.Count() == 0) + { + return; + } + + // Use the table. + UseFolderListTableLC(RDbTable::EUpdatable); + count = iFolderListTable.CountL(); + + // 1) Move the entries to the end, by changing there sibling indexes. + for (TInt i = 0; i < aFolderItemIds.Count(); i++) + { + // Find the entry. + TDbSeekKey seekKey(aFolderItemIds[i]); + + if (iFolderListTable.SeekL(seekKey)) + { + iFolderListTable.GetL(); + + // Get the parent This only needs to be done once -- on the first iter... + if (i == 0) + { + parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + } + + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KSiblingOrder), count + i); + iFolderListTable.PutL(); + } + } + + // 2) Create a hole for the entries to be moved to, this also adjusts all of the + // indexes to remove any holes that may have been created by the move. + CreateSiblingIndexHoleL(parentId, aNewIndex, aFolderItemIds.Count()); + + // 3) Move the entries into the newly created hole by changing their sibling indexes. + for (TInt i = 0; i < aFolderItemIds.Count(); i++) + { + // Find the entry. + TDbSeekKey seekKey(aFolderItemIds[i]); + + if (iFolderListTable.SeekL(seekKey)) + { + iFolderListTable.GetL(); + + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KSiblingOrder), aNewIndex + i); + iFolderListTable.PutL(); + } + } + + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemMoveToL +// +// Move the entries to another parent. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemMoveToL(const RArray& aFolderItemIds, + TInt aNewParent) + { + TInt parentId = 0; + TInt statusCode = KErrNone; + + if (aFolderItemIds.Count() == 0) + { + return; + } + + // Use the table. + UseFolderListTableLC(RDbTable::EUpdatable); + + // Move each of the entries. + for (TInt i = 0; i < aFolderItemIds.Count(); i++) + { + // Find the entry. + TDbSeekKey seekKey(aFolderItemIds[i]); + + if (iFolderListTable.SeekL(seekKey)) + { + iFolderListTable.GetL(); + + // Create a hole in the new parent folder for the items to be moved. This only + // needs to be done once -- on the first iter... + if (i == 0) + { + parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + CreateSiblingIndexHoleL(aNewParent, 0, aFolderItemIds.Count()); + } + statusCode = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + // Change the new parent and sibling index. The moved folder items are placed + // at the beginning of the new parent. + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KParentId), aNewParent); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KSiblingOrder), i); + iFolderListTable.PutL(); + + if(statusCode != KErrNone) + { + TInt parent = parentId; + TInt previousStatus = KErrNone; + while(parent != KRootFolderId) + { + TDbSeekKey folderListKey(parent); + if(iFolderListTable.SeekL(folderListKey)) + { + iFolderListTable.GetL(); + parent = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + previousStatus = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + iFolderListTable.UpdateL(); + TInt status = previousStatus + 1; + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), status); + iFolderListTable.PutL(); + + if(status != KErrNone) + { + break; + } + } + } + parent = aNewParent; + while(parent != KRootFolderId) + { + TDbSeekKey folderListKey(parent); + if(iFolderListTable.SeekL(folderListKey)) + { + iFolderListTable.GetL(); + parent = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + previousStatus = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), previousStatus - 1); + iFolderListTable.PutL(); + + if(previousStatus != KErrNone) + { + break; + } + } + } + + } + } + } + + // Fix up the sibling indexes of the old parent. + AdjustSiblingIndexesL(parentId); + + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::AdjustSiblingIndexesL +// +// Reorders the sibling indexes. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::AdjustSiblingIndexesL(TInt aParentId) + { + RDbView view; + HBufC* query = NULL; + TInt siblingIndex = 0; + + // Create a view given this select... + // SELECT SiblingOrder FROM FolderListTable WHERE ParentId = aParentId ORDER BY SiblingOrder + _LIT(KQuery, "SELECT SiblingOrder FROM FolderListTable WHERE ParentId = %d ORDER BY SiblingOrder"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aParentId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Reorder each entry in the given folder-list and parent folder. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + // Get the current row. + view.GetL(); + + // Update the order. + view.UpdateL(); + view.SetColL(colSet->ColNo(KSiblingOrder), siblingIndex++); + view.PutL(); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateSiblingIndexHoleL +// +// Creates a hole in the sibling index. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateSiblingIndexHoleL(TInt aParentId, TInt aNewIndex, TInt aHoleSize) + { + RDbView view; + HBufC* query = NULL; + TInt siblingIndex = 0; + + // Create a view given this select... + // SELECT SiblingOrder FROM FolderListTable + // WHERE ParentId = aParentId + // ORDER BY SiblingOrder + _LIT(KQuery, "SELECT SiblingOrder FROM FolderListTable WHERE ParentId = %d ORDER BY SiblingOrder"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aParentId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Reorder each entry in the given folder-list and parent folder. + if (view.EvaluateAll() >= 0) + { + TInt index = 0; + + for (view.FirstL(); view.AtRow(); view.NextL()) + { + // Get the current row. + view.GetL(); + + siblingIndex = view.ColUint16(colSet->ColNo(KSiblingOrder)); + + if (index == aNewIndex) + { + index += aHoleSize; + } + + // Update the order. + if (index != siblingIndex) + { + view.UpdateL(); + view.SetColL(colSet->ColNo(KSiblingOrder), index); + view.PutL(); + } + + index++; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FolderItemGetChildrenL +// +// Extract the folder-item-ids of the children of the given parent. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FolderItemGetChildrenL(TInt aFolderItemId, RArray& aChildren) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FolderItemId FROM FolderListTable WHERE ParentId = aFolderItemId + _LIT(KQuery, "SELECT FolderItemId FROM FolderListTable WHERE ParentId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFolderItemId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Extract and add the children's folder-item-id to aChildren. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + TInt folderItemId; + + // Get the current row. + view.GetL(); + + // Get the fields + folderItemId = view.ColUint16(colSet->ColNo(KFolderItemId)); + + // Append it. + aChildren.AppendL(folderItemId); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FeedUpdateItemStatusL +// +// Update the status of each of the items in the given feed. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FeedUpdateItemStatusL(TInt aFeedId, + const RArray& aItemIds, const RArray& aItemStatus, TInt aUnreadCount) + { + HBufC* query = NULL; + RDbView view; + + if (aItemIds.Count() == 0) + { + return; + } + + // Perpare the query. + // SELECT ItemId, ItemStatus FROM ItemTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT ItemId, ItemStatus FROM ItemTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + // Execute the query. + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Purge the old items. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + TInt itemId; + TInt itemStatus; + TInt pos; + + // Get the current row. + view.GetL(); + + // Get the itemId and current Status. + itemId = view.ColUint16(colSet->ColNo(KItemId)); + itemStatus = view.ColUint16(colSet->ColNo(KItemStatus)); + + // If found in aItemIds update its status. + if ((pos = aItemIds.Find(itemId)) != KErrNotFound) + { + if (aItemStatus[pos] != itemStatus) + { + view.UpdateL(); + view.SetColL(colSet->ColNo(KItemStatus), aItemStatus[pos]); + view.PutL(); + } + } + } // for loop + + // Prep the feed table. + UseFeedTableLC(RDbTable::EUpdatable); + // update the unread count for the feed + TDbSeekKey seekKey((TUint16) aFeedId); + if (iFeedTable.SeekL(seekKey)) + { + // Write the count + iFeedTable.GetL(); + iFeedTable.UpdateL(); + iFeedTable.SetColL(iFeedColSet->ColNo(KUnreadCount), aUnreadCount); + iFeedTable.PutL(); + } + CleanupStack::PopAndDestroy(/*Feed Table*/); + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PurgeFeedIfNotReferencedL +// +// Deletes the feed if the feedId isn't referenced in the folder-list table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PurgeFeedIfNotReferencedL(TInt aFeedId) + { + RDbView view; + HBufC* query = NULL; + TBool deleted = EFalse; + + // Create a view given this select... + // SELECT FolderItemId FROM FolderListTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT FolderItemId FROM FolderListTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Evalulate the query if no rows are returned then purge the feed. + if (view.Evaluate() >= 0) + { + view.FirstL(); + if (!view.AtRow()) + { + FeedPurgeL(aFeedId, ETrue); + deleted = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + if(deleted) + { + iFeedsServer->UpdateFeedL(KNoFolderListId,aFeedId,ETrue); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FeedPurgeL +// +// Removes the feed's items also deletes the feed if aDeleteFeed is ETrue. +// It is only safe to call this method with aDeleteFeed set to ETrue if +// aFeedId is not found in the FolderListTable. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::FeedPurgeL(TInt aFeedId, TBool aDeleteFeed) + { + HBufC* query = NULL; + + // Delete the enclosures from the Enclosure Table. This is done first to + // Ensure that enclosures don't get ophaned if the delete-items query leaves. + // DELETE FROM EnclosureTable WHERE FeedId = aFeedId + _LIT(KQueryE, "DELETE FROM EnclosureTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQueryE().Length() + KIntLength); + query->Des().Format(KQueryE, aFeedId); + + // err is KErrNone even multiple records are deleted + TInt err = iDatabase.Execute(*query); + CleanupStack::PopAndDestroy(query); + + // Delete the items from the Item Table + // DELETE FROM ItemTable WHERE FeedId = aFeedId + _LIT(KQueryI, "DELETE FROM ItemTable WHERE FeedId = %d"); + query = HBufC::NewLC(KQueryI().Length() + KIntLength); + query->Des().Format(KQueryI, aFeedId); + + err = iDatabase.Execute(*query); + CleanupStack::PopAndDestroy(query); + + // Delete the feed from the Feed Table + if (aDeleteFeed) + { + // DELETE FROM FeedTable WHERE FeedId = aFeedId + _LIT(KQueryF, "DELETE FROM FeedTable WHERE FeedId = %d"); + query = HBufC::NewLC(KQueryF().Length() + KIntLength); + query->Des().Format(KQueryF, aFeedId); + + err = iDatabase.Execute(*query); + CleanupStack::PopAndDestroy(query); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PurgeOldItemsL +// +// Purge any old items in the given feed. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PurgeOldItemsL(TInt aFeedId, const TTime& aTimestamp) + { + HBufC* query = NULL; + TBuf tsStr; + TBuf temp; + RDbView view; + // Convert aTimestamp to the query form -- i.e #1997-12-31 23:59:59#. + aTimestamp.FormatL(tsStr, TShortDateFormatSpec()); + tsStr.Append(KSpace); + aTimestamp.FormatL(temp, TTimeFormatSpec()); + tsStr.Append(temp); + + // Perpare the query. + // SELECT ItemId, Date FROM ItemTable WHERE FeedId = aFeedId AND Date < #tsStr# + _LIT(KQuery, "SELECT ItemId, Date FROM ItemTable WHERE FeedId = %d AND Date < #%S#"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + tsStr.Length()); + + query->Des().Format(KQuery, aFeedId, &tsStr); + + // Execute the query. + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Purge the old items. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + TInt itemId; + + // Get the current row. + view.GetL(); + + // Get the itemId and date. + itemId = view.ColUint16(colSet->ColNo(KItemId)); + + // Purge the associated enclosures. This is done first to ensure that + // enclosures don't get ophaned if the delete-item statement leaves. + PurgeEnclosuresL(aFeedId, itemId); + + // Delete the item. + view.DeleteL(); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PurgeEnclosuresL +// +// Purge the associated enclosures +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PurgeEnclosuresL(TInt aFeedId, TInt aItemId) + { + HBufC* query = NULL; + + // DELETE FROM EnclosureTable WHERE FeedId = aFeedId AND ItemId = aItemId + _LIT(KQuery, "DELETE FROM EnclosureTable WHERE FeedId = %d AND ItemId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + KIntLength); + + query->Des().Format(KQuery, aFeedId, aItemId); + + User::LeaveIfError(iDatabase.Execute(*query)); + CleanupStack::PopAndDestroy(query); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PurgeOtherItemsL +// +// Purge all items not found in the given array. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::PurgeOtherItemsL(TInt aFeedId, const RArray& aItemIds) + { + HBufC* query = NULL; + RDbView view; + TInt purgedUnreadNewCount = 0; + + // SELECT ItemId, ItemStatus FROM ItemTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT ItemId, ItemStatus FROM ItemTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + // Execute the query. + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Purge the old items. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + TInt itemId; + + // Get the current row. + view.GetL(); + + itemId = view.ColUint16(colSet->ColNo(KItemId)); + + // If this item isn't in aItemIds then delete the item and + // its enclosures. + if (aItemIds.Find(itemId) == KErrNotFound) + { + TInt itemStatus = view.ColUint8(colSet->ColNo(KItemStatus)); + if( itemStatus == EUnreadItem || itemStatus == ENewItem ) + { + purgedUnreadNewCount++; + } + // Purge the associated enclosures. This is done first to ensure that + // enclosures don't get ophaned if the delete-item statement leaves. + PurgeEnclosuresL(aFeedId, itemId); + + // Delete the item. + view.DeleteL(); + } + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + + return purgedUnreadNewCount; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ResetDatabaseL +// +// Reset the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ResetDatabaseL() + { + TBuf<32> format; + format.Copy(KSecure); + format.Append(KSecureUid.Name()); + + // Create the database file. + TInt err = iDatabase.Create( iDBs, iDatabasePath, format); + User::LeaveIfError( err ); + + // Create the tables. + CreateVersionTableL(); + CreateFolderListTableL(); + CreateFeedTableL(); + CreateFeedItemTableL(); + CreateItemEnclosureTableL(); + CreateSettingsTableL(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateVersionTableL +// +// Creates the version table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateVersionTableL() + { + CDbColSet* colSet = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + colSet->AddL(TDbCol(KVersion, EDbColText16)); + colSet->AddL(TDbCol(KVersionId, EDbColUint16)); + + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KVersionTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Prep the settings table. + UseVersionTableLC(RDbTable::EUpdatable); + + // Update the database. There is only one row in this table... + iVersionTable.FirstL(); + + if (iVersionTable.AtRow()) + { + iVersionTable.GetL(); + iVersionTable.UpdateL(); + } + else + { + iVersionTable.Reset(); + iVersionTable.InsertL(); + } + + iVersionTable.SetColL(iVersionColSet->ColNo(KVersionId), KVersion71); + + iVersionTable.PutL(); + CleanupStack::PopAndDestroy(/* version table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateFolderListTableL +// +// Creates the folder-list table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateFolderListTableL() + { + CDbColSet* colSet = NULL; + TDbKeyCol folderItemIdCol(KFolderItemId); + CDbKey* indexKey = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + colSet->AddL(TDbCol(KFolderListId, EDbColInt32)); + colSet->AddL(TDbCol(KFolderItemId, EDbColUint16)); + colSet->AddL(TDbCol(KParentId, EDbColUint16)); + colSet->AddL(TDbCol(KSiblingOrder, EDbColUint16)); + colSet->AddL(TDbCol(KIsFolder, EDbColUint8)); + colSet->AddL(TDbCol(KFeedId, EDbColUint16)); + colSet->AddL(TDbCol(KTitle_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KStatus, EDbColInt32)); + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KFolderListTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Index the table. + indexKey = CDbKey::NewLC(); + + indexKey->AddL(folderItemIdCol); + User::LeaveIfError(iDatabase.CreateIndex(KFolderListTableIndex, + KFolderListTable, *indexKey)); + CleanupStack::PopAndDestroy(indexKey); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateFeedTableL +// +// Creates the feed table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateFeedTableL() + { + CDbColSet* colSet = NULL; + TDbKeyCol feedIdCol(KFeedId); + CDbKey* indexKey = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + + colSet->AddL(TDbCol(KFolderListId, EDbColInt32)); + colSet->AddL(TDbCol(KFeedId, EDbColUint16)); + colSet->AddL(TDbCol(KDate, EDbColDateTime)); + colSet->AddL(TDbCol(KTitle_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KFeedUrl, EDbColLongText16)); + colSet->AddL(TDbCol(KDescription, EDbColLongText16)); + colSet->AddL(TDbCol(KWebUrl, EDbColLongText16)); + colSet->AddL(TDbCol(KUnreadCount, EDbColUint16)); + colSet->AddL(TDbCol(KAutoUpdateFreq, EDbColUint32)); + + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KFeedTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Index the table. + indexKey = CDbKey::NewLC(); + + indexKey->AddL(feedIdCol); + User::LeaveIfError(iDatabase.CreateIndex(KFeedTableIndex, KFeedTable, *indexKey)); + CleanupStack::PopAndDestroy(indexKey); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateFeedItemTableL +// +// Creates the feed-list table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateFeedItemTableL() + { + CDbColSet* colSet = NULL; + TDbKeyCol feedIdCol(KFeedId); + TDbKeyCol itemIdCol(KItemId); + CDbKey* indexKey = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + + colSet->AddL(TDbCol(KItemId, EDbColUint16)); + colSet->AddL(TDbCol(KFeedId, EDbColUint16)); + colSet->AddL(TDbCol(KDate, EDbColDateTime)); + colSet->AddL(TDbCol(KItemStatus, EDbColUint8)); + colSet->AddL(TDbCol(KTitle_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KDescription, EDbColLongText16)); + colSet->AddL(TDbCol(KWebUrl, EDbColLongText16)); + colSet->AddL(TDbCol(KItemIdStr, EDbColLongText16)); + + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KItemTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Index the table. + indexKey = CDbKey::NewLC(); + + indexKey->AddL(itemIdCol); + User::LeaveIfError(iDatabase.CreateIndex(KItemTableIndex, KItemTable, *indexKey)); + CleanupStack::PopAndDestroy(indexKey); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateItemEnclosureTableL +// +// Creates the item-enclosure table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateItemEnclosureTableL() + { + CDbColSet* colSet = NULL; + TDbKeyCol feedIdCol(KFeedId); + TDbKeyCol itemIdCol(KItemId); + TDbKeyCol enclosureIdCol(KEnclosureId); + CDbKey* indexKey = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + + colSet->AddL(TDbCol(KEnclosureId, EDbColUint16)); + colSet->AddL(TDbCol(KItemId, EDbColUint16)); + colSet->AddL(TDbCol(KFeedId, EDbColUint16)); + colSet->AddL(TDbCol(KLength_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KTitle_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KContentType_100MaxLen, EDbColText16, K100MaxLen)); + colSet->AddL(TDbCol(KWebUrl, EDbColLongText16)); + + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KEnclosureTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Index the table. + indexKey = CDbKey::NewLC(); + + indexKey->AddL(feedIdCol); + indexKey->AddL(itemIdCol); + indexKey->AddL(enclosureIdCol); + User::LeaveIfError(iDatabase.CreateIndex(KEnclosureTableIndex, KEnclosureTable, *indexKey)); + CleanupStack::PopAndDestroy(indexKey); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CreateSettingsTableL +// +// Creates the settings table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CreateSettingsTableL() + { + CDbColSet* colSet = NULL; + TDbKeyCol folderListIdCol( KFolderListId ); + CDbKey* indexKey = NULL; + + // Create the table's column set. + colSet = CDbColSet::NewLC(); + colSet->AddL(TDbCol(KFolderListId, EDbColInt32)); + colSet->AddL(TDbCol(KAutoUpdate, EDbColUint8)); + colSet->AddL(TDbCol(KAutoUpdateWhileRoaming, EDbColUint8)); + colSet->AddL(TDbCol(KAccessPoint, EDbColUint32)); + colSet->AddL(TDbCol(KAutoUpdateFreq, EDbColUint32)); + colSet->AddL(TDbCol(KLastAutoUpdate, EDbColDateTime)); + + // Create the table. + User::LeaveIfError(iDatabase.CreateTable(KSettingsTable, *colSet)); + CleanupStack::PopAndDestroy(colSet); + + // Index the table. + indexKey = CDbKey::NewLC(); + + indexKey->AddL( folderListIdCol ); + User::LeaveIfError(iDatabase.CreateIndex(KSettingsTableIndex, + KSettingsTable, *indexKey)); + CleanupStack::PopAndDestroy(indexKey); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::NextFolderItemIdL +// +// Returns an available folder-item id. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::NextFolderItemIdL() + { + TBool found; + TUint16 id; + + // Prep the folder table. + UseFolderListTableLC(RDbTable::EReadOnly); + + // Search for a unquie id. + do + { + id = (TUint16) Math::Random(); + TDbSeekKey seekKey(id); + + found = iFolderListTable.SeekL(seekKey); + + // Don't allow the root folder id to be picked. + if (id == KRootFolderId) + { + found = ETrue; + } + } + while (found); + + CleanupStack::PopAndDestroy(/*Folder list Table*/); + return id; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::NextFeedIdL +// +// Returns an available feed id. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::NextFeedIdL() + { + TBool found = ETrue; + TUint16 id; + + // Prep the folder table. + UseFeedTableLC(RDbTable::EReadOnly); + + // Search for a unquie id. + do + { + id = (TUint16) Math::Random(); + + // A feed id of 0 is special (meaning unassigned). + if (id != 0) + { + TDbSeekKey seekKey(id); + + found = iFeedTable.SeekL(seekKey); + } + } + while (found); + + CleanupStack::PopAndDestroy(/*Feed Table*/); + return id; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::NextItemIdL +// +// Returns an available item id. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::NextItemIdL() + { + TBool found = ETrue; + TUint16 id; + + // Prep the folder table. + UseItemTableLC(RDbTable::EReadOnly); + + // Search for a unquie id. + do + { + id = (TUint16) Math::Random(); + + // A item id of 0 is special (meaning unassigned). + if (id != 0) + { + TDbSeekKey seekKey(id); + + found = iItemTable.SeekL(seekKey); + } + } + while (found); + + CleanupStack::PopAndDestroy(/*item Table*/); + return id; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitFolderListL +// +// Commit the folder entry to the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitFolderListL(TInt aFolderListId, TInt aFolderItemId, + TInt aParentId, TInt aSiblingIndex, TBool aIsFolder, TInt aFeedId, + const TDesC& aTitle) + { + if (aFeedId == KUnassignedId) + { + aFeedId = 0; + } + + // Update the database. + iFolderListTable.Reset(); + iFolderListTable.InsertL(); + + iFolderListTable.SetColL(iFolderListColSet->ColNo(KFolderListId), aFolderListId); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KFolderItemId), aFolderItemId); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KParentId), aParentId); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KSiblingOrder), aSiblingIndex); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KIsFolder), aIsFolder); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KFeedId), aFeedId); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KTitle_100MaxLen), aTitle.Left(K100MaxLen)); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), KErrNone); + + iFolderListTable.PutL(); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitFeedL +// +// Commit the feed to the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitFeedL(TInt aFolderListId, TBool aIsNewFeed, TInt aFeedId, + const RArray& aAttributes, const TTime& aDefaultTime, TInt aUnreadCount) + { + TPtrC title(KNullDesC); + TPtrC description(KNullDesC); + TPtrC link(KNullDesC); + TPtrC timeStamp(KNullDesC); + TPtrC feedUrl(KNullDesC); + TInt unreadCount = aUnreadCount; + + // Get the values. + for (TInt i = 0; i < aAttributes.Count(); i++) + { + switch (aAttributes[i].token) + { + case EFeedAttributeTitle: + title.Set(aAttributes[i].value); + break; + + case EFeedAttributeLink: + link.Set(aAttributes[i].value); + break; + + case EFeedAttributeDescription: + description.Set(aAttributes[i].value); + break; + + case EFeedAttributeFeedUrl: + feedUrl.Set(aAttributes[i].value); + break; + + case EFeedAttributeTimestamp: + timeStamp.Set(aAttributes[i].value); + break; + } + } + + // If timeStamp was provided convert it into a TTime otherwise just + // use the default time. + TTime date = aDefaultTime; + + // TODO: Two timestamps are needed -- one for tracking when the + // author changed their feed and one for the last time the + // feed was updated. +#if 0 + if (timeStamp.Length() > 0) + { + TLex16 lex(timeStamp); + TInt64 ts; + + User::LeaveIfError(lex.Val(ts)); + date = ts; + } +#endif + + // If this is a new feed then get ready to insert a new entry. + if (aIsNewFeed) + { + + iFeedTable.Reset(); + iFeedTable.InsertL(); + + } + + // Otherwise get ready to update the existing entry. + else + { + TDbSeekKey seekKey((TUint16) aFeedId); + + if (iFeedTable.SeekL(seekKey)) + { + iFeedTable.GetL(); + iFeedTable.UpdateL(); + } + else + { + User::Leave(KErrCorrupt); + } + + unreadCount = iFeedTable.ColUint16(iFeedColSet->ColNo(KUnreadCount)); + unreadCount += aUnreadCount; + } + // Write the entry. aFolderListId + iFeedTable.SetColL(iFeedColSet->ColNo(KFolderListId), aFolderListId); + iFeedTable.SetColL(iFeedColSet->ColNo(KFeedId), aFeedId); + iFeedTable.SetColL(iFeedColSet->ColNo(KDate), date); + iFeedTable.SetColL(iFeedColSet->ColNo(KTitle_100MaxLen), title.Left(K100MaxLen)); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KFeedUrl), feedUrl); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KDescription), description); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KWebUrl), link); + iFeedTable.SetColL(iFeedColSet->ColNo(KUnreadCount), unreadCount); + + iFeedTable.PutL(); + + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitFeedL +// +// Commit a new feed to the database. +// ----------------------------------------------------------------------------- +// +TInt CFeedsDatabase::CommitFeedL(TInt aFolderListId, const TDesC& aTitle, const TDesC& aUrl, TInt aFreq) + { + RArray attributes; + TAttribute attribute; + TTime zero(0); + TInt feedId; + TInt zeroCount = 0; + + UseFeedTableLC(RDbTable::EUpdatable); + + CleanupClosePushL(attributes); + attributes.Reset(); + + // Add the title to the attribute list. + attribute.token = EFeedAttributeTitle; + attribute.value.Set(aTitle); + attributes.AppendL(attribute); + + // Add the url to the attribute list. + attribute.token = EFeedAttributeFeedUrl; + attribute.value.Set(aUrl); + attributes.AppendL(attribute); + + // Get a id for the feed. + feedId = NextFeedIdL(); + + // Add an entry for the feed in the feed table. + CommitFeedL(aFolderListId, ETrue, feedId, attributes, zero, zeroCount, aFreq); + + // Clean up. + CleanupStack::PopAndDestroy(/*attributes*/); + CleanupStack::PopAndDestroy(/*feed table*/); + + return feedId; + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitFeedL +// +// Commit the feed to the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitFeedL(TInt aFolderListId, TBool aIsNewFeed, TInt aFeedId, + const RArray& aAttributes, const TTime& aDefaultTime, TInt aUnreadCount,TInt aFreq) + { + TPtrC title(KNullDesC); + TPtrC description(KNullDesC); + TPtrC link(KNullDesC); + TPtrC timeStamp(KNullDesC); + TPtrC feedUrl(KNullDesC); + TInt unreadCount = aUnreadCount; + + // Get the values. + for (TInt i = 0; i < aAttributes.Count(); i++) + { + switch (aAttributes[i].token) + { + case EFeedAttributeTitle: + title.Set(aAttributes[i].value); + break; + + case EFeedAttributeLink: + link.Set(aAttributes[i].value); + break; + + case EFeedAttributeDescription: + description.Set(aAttributes[i].value); + break; + + case EFeedAttributeFeedUrl: + feedUrl.Set(aAttributes[i].value); + break; + + case EFeedAttributeTimestamp: + timeStamp.Set(aAttributes[i].value); + break; + } + } + + // If timeStamp was provided convert it into a TTime otherwise just + // use the default time. + TTime date = aDefaultTime; + + // TODO: Two timestamps are needed -- one for tracking when the + // author changed their feed and one for the last time the + // feed was updated. +#if 0 + if (timeStamp.Length() > 0) + { + TLex16 lex(timeStamp); + TInt64 ts; + + User::LeaveIfError(lex.Val(ts)); + date = ts; + } +#endif + + // If this is a new feed then get ready to insert a new entry. + if (aIsNewFeed) + { + iFeedTable.Reset(); + iFeedTable.InsertL(); + } + + // Otherwise get ready to update the existing entry. + else + { + TDbSeekKey seekKey((TUint16) aFeedId); + + if (iFeedTable.SeekL(seekKey)) + { + iFeedTable.GetL(); + iFeedTable.UpdateL(); + } + else + { + User::Leave(KErrCorrupt); + } + + unreadCount = iFeedTable.ColUint16(iFeedColSet->ColNo(KUnreadCount)); + unreadCount += aUnreadCount; + } + // Write the entry. aFolderListId + iFeedTable.SetColL(iFeedColSet->ColNo(KFolderListId), aFolderListId); + iFeedTable.SetColL(iFeedColSet->ColNo(KFeedId), aFeedId); + iFeedTable.SetColL(iFeedColSet->ColNo(KDate), date); + iFeedTable.SetColL(iFeedColSet->ColNo(KTitle_100MaxLen), title.Left(K100MaxLen)); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KFeedUrl), feedUrl); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KDescription), description); + WriteLongTextL(iFeedTable, iFeedColSet->ColNo(KWebUrl), link); + iFeedTable.SetColL(iFeedColSet->ColNo(KUnreadCount), unreadCount); + iFeedTable.SetColL(iFeedColSet->ColNo(KAutoUpdateFreq), aFreq); + + iFeedTable.PutL(); + + } +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitItemL +// +// Commit the item to the database. The itemIdStr is also appended to aItemIdStrs. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::CommitItemL(TInt aItemId, TInt aFeedId, + const RArray& aAttributes, RArray& aItemIds) + { + TPtrC timeStamp(KNullDesC); + TPtrC title(KNullDesC); + TPtrC description(KNullDesC); + TPtrC link(KNullDesC); + TPtrC itemIdStr(KNullDesC); + + // Get the values. + for (TInt i = 0; i < aAttributes.Count(); i++) + { + switch (aAttributes[i].token) + { + case EItemAttributeIdStr: + itemIdStr.Set(aAttributes[i].value); + break; + + case EItemAttributeTitle: + title.Set(aAttributes[i].value); + break; + + case EItemAttributeDescription: + description.Set(aAttributes[i].value); + break; + + case EItemAttributeLink: + link.Set(aAttributes[i].value); + break; + + case EItemAttributeTimestamp: + timeStamp.Set(aAttributes[i].value); + break; + } + } + + // Ignore the item if it is already in the database. + // TODO: Don't ignore it if the timestamp changes. In this case + // the item needs to be updated below rather than inserted. + TInt id; + + if (FindItemL(aFeedId, itemIdStr, id)) + { + // If the item is found then append it's id to aItemIds. + aItemIds.AppendL(id); + + return EFalse; + } + + // Otherwise this is a new item so append the provided id to aItemIds. + else + { + aItemIds.AppendL(aItemId); + } + + // If timeStamp was provided convert it into a TTime otherwise just + // use the current time. + TTime date; + + if (timeStamp.Length() > 0) + { + TLex16 lex(timeStamp); + TInt64 ts; + + User::LeaveIfError(lex.Val(ts)); + date = ts; + } + else + { + date.UniversalTime(); + } + + // Update the database. + iItemTable.Reset(); + iItemTable.InsertL(); + + iItemTable.SetColL(iItemColSet->ColNo(KItemId), aItemId); + iItemTable.SetColL(iItemColSet->ColNo(KFeedId), aFeedId); + iItemTable.SetColL(iItemColSet->ColNo(KDate), date); + iItemTable.SetColL(iItemColSet->ColNo(KItemStatus), ENewItem); + iItemTable.SetColL(iItemColSet->ColNo(KTitle_100MaxLen), title.Left(K100MaxLen)); + WriteLongTextL(iItemTable, iItemColSet->ColNo(KDescription), description); + WriteLongTextL(iItemTable, iItemColSet->ColNo(KWebUrl), link); + WriteLongTextL(iItemTable, iItemColSet->ColNo(KItemIdStr), itemIdStr); + + iItemTable.PutL(); + + return ETrue; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitEnclosureL +// +// Commit the enclosure to the database +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitEnclosureL(TInt aEnclosureId, TInt aItemId, + TInt aFeedId, const RArray& aAttributes) + { + TPtrC title(KNullDesC); + TPtrC length(KNullDesC); + TPtrC contentType(KNullDesC); + TPtrC link(KNullDesC); + + // Get the values. + for (TInt i = 0; i < aAttributes.Count(); i++) + { + switch (aAttributes[i].token) + { + case EEnclosureAttributeTitle: + title.Set(aAttributes[i].value); + break; + + case EEnclosureAttributeSize: + length.Set(aAttributes[i].value); + break; + + case EEnclosureAttributeContentType: + contentType.Set(aAttributes[i].value); + break; + + case EEnclosureAttributeLink: + link.Set(aAttributes[i].value); + break; + } + } + + // Update the database. + iEnclosureTable.Reset(); + iEnclosureTable.InsertL(); + + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KTitle_100MaxLen), title.Left(K100MaxLen)); + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KEnclosureId), aEnclosureId); + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KItemId), aItemId); + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KFeedId), aFeedId); + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KLength_100MaxLen), length.Left(K100MaxLen)); + iEnclosureTable.SetColL(iEnclosureColSet->ColNo(KContentType_100MaxLen), contentType.Left(K100MaxLen)); + WriteLongTextL(iEnclosureTable, iEnclosureColSet->ColNo(KWebUrl), link); + + iEnclosureTable.PutL(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ExtractFolderListIdInSettingsL +// +// Get the folder list Ids from the settings table from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ExtractFolderListIdInSettingsL( RArray& aFolderListIds ) + { + TInt folderListId; + + // Prep the settings table. + UseSettingsTableLC(RDbTable::EReadOnly); + + while( iSettingsTable.NextL() ) + { + iSettingsTable.GetL(); + folderListId = iSettingsTable.ColInt32(iSettingsColSet->ColNo(KFolderListId)); + aFolderListIds.AppendL( folderListId ); + } + + CleanupStack::PopAndDestroy(/* settings table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ExtractAutoUpdateSettingsL +// +// Get the settings from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ExtractAutoUpdateSettingsL( TInt aFolderListId, TBool& aAutoUpdate, TInt& aAutoUpdateFreq, + TUint32& aAutoUpdateAP, TBool &autoUpdateWhileRoaming ) + { + // Prep the settings table. + UseSettingsTableLC(RDbTable::EReadOnly); + + TDbSeekKey seekKey( aFolderListId ); + // Extract the values. + if (iSettingsTable.SeekL(seekKey)) + { + iSettingsTable.GetL(); + + aAutoUpdate = iSettingsTable.ColUint8(iSettingsColSet->ColNo(KAutoUpdate)); + aAutoUpdateAP = iSettingsTable.ColUint32(iSettingsColSet->ColNo(KAccessPoint)); + aAutoUpdateFreq = iSettingsTable.ColUint32(iSettingsColSet->ColNo(KAutoUpdateFreq)); + autoUpdateWhileRoaming = iSettingsTable.ColUint8(iSettingsColSet->ColNo(KAutoUpdateWhileRoaming)); + } + else + { + User::Leave(KErrNotFound); + } + + CleanupStack::PopAndDestroy(/* settings table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitAutoUpdateSettingsL +// +// Commit the settings to the database +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitAutoUpdateSettingsL( TInt aFolderListId, TBool aAutoUpdate, TInt aAutoUpdateFreq, + TUint32 aAutoUpdateAP, TBool aAutoUpdateWhileRoaming ) + { + TTime never(0); + + // Prep the settings table. + UseSettingsTableLC(RDbTable::EUpdatable); + + TDbSeekKey seekKey( aFolderListId ); + // Update the database. + if (iSettingsTable.SeekL(seekKey)) + { + iSettingsTable.GetL(); + iSettingsTable.UpdateL(); + + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdate), aAutoUpdate); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAccessPoint), aAutoUpdateAP); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdateFreq), aAutoUpdateFreq); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdateWhileRoaming), aAutoUpdateWhileRoaming); + } + else + { + iSettingsTable.Reset(); + iSettingsTable.InsertL(); + + // initiate last auto update to 0 + iSettingsTable.SetColL(iSettingsColSet->ColNo(KFolderListId), aFolderListId); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdate), aAutoUpdate); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAccessPoint), aAutoUpdateAP); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdateFreq), aAutoUpdateFreq); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KAutoUpdateWhileRoaming), aAutoUpdateWhileRoaming); + iSettingsTable.SetColL(iSettingsColSet->ColNo(KLastAutoUpdate), never); + } + + iSettingsTable.PutL(); + + CleanupStack::PopAndDestroy(/* settings table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ExtractLastAutoUpdateSettingsL +// +// Get the last auto update settings from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ExtractLastAutoUpdateSettingsL( TInt aFolderListId, TTime& aLastAutoUpdate ) + { + // Prep the settings table. + UseSettingsTableLC(RDbTable::EReadOnly); + + TDbSeekKey seekKey( aFolderListId ); + // Extract the values. + if (iSettingsTable.SeekL(seekKey)) + { + iSettingsTable.GetL(); + + aLastAutoUpdate = iSettingsTable.ColTime(iSettingsColSet->ColNo(KLastAutoUpdate)); + } + else + { + User::Leave(KErrNotFound); + } + + CleanupStack::PopAndDestroy(/* settings table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitLastAutoUpdateSettingsL +// +// Commit the last auto update settings to the database +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitLastAutoUpdateSettingsL( TInt aFolderListId, TTime aLastAutoUpdate ) + { + // Prep the settings table. + UseSettingsTableLC(RDbTable::EUpdatable); + + TDbSeekKey seekKey( aFolderListId ); + // Update the database. + if (iSettingsTable.SeekL(seekKey)) + { + iSettingsTable.GetL(); + iSettingsTable.UpdateL(); + + iSettingsTable.SetColL(iSettingsColSet->ColNo(KLastAutoUpdate), aLastAutoUpdate); + + iSettingsTable.PutL(); + } + else + { + User::Leave(KErrNotFound); + } + + CleanupStack::PopAndDestroy(/* settings table */); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::Compact +// +// Compacts the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::Compact() + { + iDatabase.Compact(); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PackFolderL +// +// Extracts and pack the folder. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PackFolderL( TInt aFolderListId, TInt aFolderId, + CPackedFolder& aPackedFolder, TBool aItemTitleNeed ) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT FolderItemId, SiblingOrder, IsFolder, FeedId, Title FROM FolderListTable + // WHERE FolderListId = aFolderListId AND ParentId = aFolderId + // ORDER BY SiblingOrder + _LIT(KQuery, "SELECT FolderItemId, SiblingOrder, IsFolder, FeedId, Title, Status FROM FolderListTable WHERE FolderListId = %d AND ParentId = %d ORDER BY SiblingOrder"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + KIntLength); + + query->Des().Format(KQuery, aFolderListId, aFolderId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + + CleanupStack::PopAndDestroy(query); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // For each entry either write the feed or folder to aPackedFolder (where folders + // are written recursively. + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + TInt folderItemId; + TInt isFolder; + TPtrC title; + TInt statusCode; + // Get the current row. + view.GetL(); + + // Get the fields + folderItemId = view.ColUint16(colSet->ColNo(KFolderItemId)); + isFolder = view.ColUint8(colSet->ColNo(KIsFolder)); + title.Set(view.ColDes16(colSet->ColNo(KTitle_100MaxLen))); + statusCode = view.ColInt32(colSet->ColNo(KStatus)); + + // Process the folder. + if (isFolder) + { + // Recursively pack the folder. + aPackedFolder.FolderBeginsL(title, folderItemId, statusCode); + PackFolderL( aFolderListId, folderItemId, aPackedFolder, aItemTitleNeed ); + aPackedFolder.FolderEndsL(); + } + + // Otherwise append the feed. + else + { + TDbSeekKey seekKey; + TInt feedId; + + // Init the key to the feedId of this folder item. + feedId = view.ColUint16(colSet->ColNo(KFeedId)); + seekKey.Add(feedId); + + if(iFeedTable.SeekL(seekKey)) + { + HBufC* url; + TTime lastUpdate; + + iFeedTable.GetL(); + + // Get the feed's feed url. + ReadLongTextL(iFeedTable, iFeedColSet->ColNo(KFeedUrl), url); + CleanupStack::PushL(url); + + // Get the feed's feed last update timestamp. + lastUpdate = iFeedTable.ColTime(iFeedColSet->ColNo(KDate)); + + TInt unreadCount = iFeedTable.ColUint16(iFeedColSet->ColNo(KUnreadCount)); + TInt freq = iFeedTable.ColUint32(iFeedColSet->ColNo(KAutoUpdateFreq)); + + // Pack the feed. + if (aItemTitleNeed) + { + aPackedFolder.AddFeedL( title, *url, lastUpdate, freq, statusCode, unreadCount, folderItemId, feedId ); + SelectMiniItemsL( feedId, ENewItem, aPackedFolder ); + } + else + { + aPackedFolder.AddFeedL( title, *url, lastUpdate, freq, statusCode, unreadCount, folderItemId, feedId ); + } + + CleanupStack::PopAndDestroy(url); + } + } + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PackFeedL +// +// Extracts and pack the feed. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PackFeedL(TInt aFeedId, CPackedFeed& aFeed) + { + TDbSeekKey seekKey((TUint16) aFeedId); + + // Prep the feed table. + UseFeedTableLC(RDbTable::EReadOnly); + + // Get the information about the feed. + if (iFeedTable.SeekL(seekKey)) + { + HBufC* feedUrl = NULL; + HBufC* description = NULL; + HBufC* webUrl = NULL; + + // Get the row. + iFeedTable.GetL(); + + // Extract the fields. + TTime date = iFeedTable.ColTime(iFeedColSet->ColNo(KDate)); + TPtrC16 title(iFeedTable.ColDes16(iFeedColSet->ColNo(KTitle_100MaxLen))); + + ReadLongTextL(iFeedTable, iFeedColSet->ColNo(KFeedUrl), feedUrl); + CleanupStack::PushL(feedUrl); + ReadLongTextL(iFeedTable, iFeedColSet->ColNo(KDescription), description); + CleanupStack::PushL(description); + ReadLongTextL(iFeedTable, iFeedColSet->ColNo(KWebUrl), webUrl); + CleanupStack::PushL(webUrl); + + // Copy the data into the packed feed. + aFeed.FeedBeginsL(); + + aFeed.AddAttributeL(EFeedAttributeFeedId, aFeedId); + + if (title.Length() > 0) + { + aFeed.AddAttributeL(EFeedAttributeTitle, title); + } + if (feedUrl->Length() > 0) + { + aFeed.AddAttributeL(EFeedAttributeFeedUrl, *feedUrl); + } + if (description->Length() > 0) + { + aFeed.AddAttributeL(EFeedAttributeDescription, *description); + } + if (webUrl->Length() > 0) + { + aFeed.AddAttributeL(EFeedAttributeLink, *webUrl); + } + + // Add the timestamp. + TBuf16 dateStr; + + dateStr.Format(_L("%Ld"), date.Int64()); + aFeed.AddAttributeL(EFeedAttributeTimestamp, dateStr); + + CleanupStack::PopAndDestroy(webUrl); + CleanupStack::PopAndDestroy(description); + CleanupStack::PopAndDestroy(feedUrl); + } + else + { + User::Leave(KErrCorrupt); + } + + CleanupStack::PopAndDestroy(/*Feed Table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PackItemsL +// +// Extracts and pack the items. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PackItemsL(TInt aFeedId, CPackedFeed& aFeed) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT * FROM ItemTable WHERE FeedId = aFeedId ORDER BY Date DESC + _LIT(KQuery, "SELECT * FROM ItemTable WHERE FeedId = %d ORDER BY Date DESC"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), + RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + HBufC* description = NULL; + HBufC* webUrl = NULL; + + // Get the row. + view.GetL(); + + // Extract the fields. + TInt itemId = view.ColUint16(colSet->ColNo(KItemId)); + TTime date = view.ColTime(colSet->ColNo(KDate)); + TInt itemStatus = view.ColUint8(colSet->ColNo(KItemStatus)); + TPtrC16 title(view.ColDes16(colSet->ColNo(KTitle_100MaxLen))); + + ReadLongTextL(view, colSet->ColNo(KDescription), description); + CleanupStack::PushL(description); + ReadLongTextL(view, colSet->ColNo(KWebUrl), webUrl); + CleanupStack::PushL(webUrl); + + // Copy the data into the packed feed. + aFeed.ItemBeginsL(); + + if (title.Length() > 0) + { + aFeed.AddAttributeL(EItemAttributeTitle, title); + } + if (description->Length() > 0) + { + aFeed.AddAttributeL(EItemAttributeDescription, *description); + } + if (webUrl->Length() > 0) + { + aFeed.AddAttributeL(EItemAttributeLink, *webUrl); + } + + aFeed.AddAttributeL(EItemAttributeItemId, itemId); + + // Add the read status. + switch( itemStatus ) + { + case EUnreadItem: + { + aFeed.AddAttributeL(EItemAttributeStatus, KUnread); + } + break; + case EReadItem: + { + aFeed.AddAttributeL(EItemAttributeStatus, KRead); + } + break; + case ENewItem: + { + aFeed.AddAttributeL(EItemAttributeStatus, KNew); + } + break; + } + + // Add the timestamp. + TBuf16 dateStr; + + dateStr.Format(_L("%Ld"), date.Int64()); + aFeed.AddAttributeL(EItemAttributeTimestamp, dateStr); + + CleanupStack::PopAndDestroy(webUrl); + CleanupStack::PopAndDestroy(description); + + // Pack the enclosures. + PackEnclosuresL(aFeedId, itemId, aFeed); + + // Signal the end of the item. + aFeed.ItemEndsL(); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PackEnclosuresL +// +// Extracts and pack the enclosure information. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PackEnclosuresL(TInt aFeedId, TInt aItemId, CPackedFeed& aFeed) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT * FROM EnclosureTable WHERE FeedId = aFeedId AND ItemId = aItemId + _LIT(KQuery, "SELECT * FROM EnclosureTable WHERE FeedId = %d AND ItemId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength + KIntLength); + + query->Des().Format(KQuery, aFeedId, aItemId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + HBufC* webUrl = NULL; + + // Get the row. + view.GetL(); + + // Extract the fields. + TPtrC16 title(view.ColDes16(colSet->ColNo(KTitle_100MaxLen))); + TPtrC16 length(view.ColDes16(colSet->ColNo(KLength_100MaxLen))); + TPtrC16 contentType(view.ColDes16(colSet->ColNo(KContentType_100MaxLen))); + + ReadLongTextL(view, colSet->ColNo(KWebUrl), webUrl); + CleanupStack::PushL(webUrl); + + // Copy the data into the packed feed. + aFeed.EnclosureBeginsL(); + + if (title.Length() > 0) + { + aFeed.AddAttributeL(EEnclosureAttributeTitle, title); + } + if (length.Length() > 0) + { + aFeed.AddAttributeL(EEnclosureAttributeSize, length); + } + if (contentType.Length() > 0) + { + aFeed.AddAttributeL(EEnclosureAttributeContentType, contentType); + } + if (webUrl->Length() > 0) + { + aFeed.AddAttributeL(EEnclosureAttributeLink, *webUrl); + } + + // Signal the end of the enclosure. + aFeed.EnclosureEndsL(); + + CleanupStack::PopAndDestroy(webUrl); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::SelectMiniItemsL +// +// Select the minimum items information with the desired status. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::SelectMiniItemsL( TInt aFeedId, TInt aStatus, CPackedFolder& aFolder ) + { + RDbView view; + HBufC* query = NULL; + + // Create a view given this select... + _LIT(KQuery, "SELECT Title, ItemId FROM ItemTable WHERE FeedId = %d AND ItemStatus = %d"); + + query = HBufC::NewLC( KQuery().Length() + KIntLength + KIntLength ); + + query->Des().Format( KQuery, aFeedId, aStatus ); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), + RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + if (view.EvaluateAll() >= 0) + { + for (view.FirstL(); view.AtRow(); view.NextL()) + { + // Get the row. + view.GetL(); + + // Extract the fields. + TPtrC title( view.ColDes16(colSet->ColNo(KTitle_100MaxLen)) ); + TInt itemId = view.ColUint16(colSet->ColNo(KItemId)); + + // Copy the data into the packed folder. + aFolder.ItemBeginsL(); + + if (title.Length() > 0) + { + aFolder.AddAttributeL( EFolderAttributeMiniItemTitle, title ); + aFolder.AddAttributeL( EFolderAttributeMiniItemId, itemId ); + } + + // Signal the end of the item. + aFolder.ItemEndsL(); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::WriteLongTextL +// +// Writes "long" text to the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::WriteLongTextL(RDbRowSet& aTable, TInt aColumnIndex, + const TDesC& aValue) + { + RDbColWriteStream stream; + + stream.OpenLC(aTable, aColumnIndex); + stream.WriteL(aValue); + stream.Close(); + CleanupStack::Pop(/*stream*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReadLongTextL +// +// Reads "long" text from the database. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReadLongTextL(RDbRowSet& aTable, TInt aColumnIndex, + HBufC*& aValue) + { + RDbColReadStream stream; + HBufC* value = NULL; + TInt length; + + length = aTable.ColLength(aColumnIndex); + value = HBufC::NewLC(length); + TPtr v(value->Des()); + + if (length > 0) + { + stream.OpenLC(aTable, aColumnIndex); + stream.ReadL(v, length); + stream.Close(); + CleanupStack::Pop(/*stream*/); + } + + CleanupStack::Pop(value); + aValue = value; + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseFolderListTableLC +// +// Pushes the release table function onto cleanup stack +// and opens the FolderList table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseFolderListTableLC(RDbRowSet::TAccess aAccess) + { + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseFolderListTable, this)); + + OpenFolderListTableL(aAccess); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::OpenFolderListTableL +// +// Closes the Feed table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::OpenFolderListTableL(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iFolderListTableRefCount++; + + // If need be open the table. + if (iFolderListTableRefCount == 1) + { + // Open the database a get the colSet. + User::LeaveIfError(iFolderListTable.Open(iDatabase, KFolderListTable, aAccess)); + iFolderListColSet = iFolderListTable.ColSetL(); + + User::LeaveIfError(iFolderListTable.SetIndex(KFolderListTableIndex)); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseFolderListTable +// +// Closes the Folder List table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseFolderListTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iFolderListTableRefCount--; + + // If need be close the table. + if (self->iFolderListTableRefCount == 0) + { + delete self->iFolderListColSet; + self->iFolderListColSet = NULL; + self->iFolderListTable.Close(); + } + else if (self->iFolderListTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseFeedTableLC +// +// Pushes the release table function onto cleanup stack +// and opens the Feed table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseFeedTableLC(RDbRowSet::TAccess aAccess) + { + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseFeedTable, this)); + + OpenFeedTableL(aAccess); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::OpenFeedTableL +// +// Opens the Feed table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::OpenFeedTableL(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iFeedTableRefCount++; + + // If need be open the table. + if (iFeedTableRefCount == 1) + { + User::LeaveIfError(iFeedTable.Open(iDatabase, KFeedTable, aAccess)); + iFeedColSet = iFeedTable.ColSetL(); + + User::LeaveIfError(iFeedTable.SetIndex(KFeedTableIndex)); + } + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseFeedTable +// +// Closes the Feed table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseFeedTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iFeedTableRefCount--; + + // If need be close the table. + if (self->iFeedTableRefCount == 0) + { + delete self->iFeedColSet; + self->iFeedColSet = NULL; + self->iFeedTable.Close(); + } + else if (self->iFeedTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::PrepareImportTransationsL +// +// Opens the OPML import related tables (FeedTable and FolderListTable) +// and starts a transaction +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::PrepareImportTransationsL() + { + + OpenFeedTableL(RDbTable::EUpdatable); + OpenFolderListTableL(RDbTable::EUpdatable); + + // Start transaction + iDatabase.Begin(); + + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseImportTables +// +// Closes the OPML import related tables (FeedTable and FolderListTable) +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseImportTables() + { + ReleaseFolderListTable(this); + ReleaseFeedTable(this); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CommitImportTransaction +// +// Commits current database transaction +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CommitImportTransaction() + { + if(iDatabase.InTransaction()) + iDatabase.Commit(); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::CancelImportTransaction +// +// Cancels/Rollbacks current database transaction +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::CancelImportTransaction() + { + if(iDatabase.InTransaction()) + iDatabase.Rollback(); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DeleteFeedTableRecordsL +// +// Deletes records from a FeedTable +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DeleteFeedTableRecordsL(RArray& aFeedIds) + { + if(aFeedIds.Count() <= 0) + return; + + DeleteRecordsFromTableL(KFeedTable, KFeedId, aFeedIds); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DeleteFolderListTableRecordsL +// +// Deletes records from a FolderListTable +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DeleteFolderListTableRecordsL(RArray& aFolderItemIds) + { + if(aFolderItemIds.Count() <= 0) + return; + + DeleteRecordsFromTableL(KFolderListTable, KFolderItemId, aFolderItemIds); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DeleteRecordsFromTableL +// +// Deletes records from a given table +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DeleteRecordsFromTableL(const TDesC& aTableName, const TDesC& aColumnName, RArray& aIds) + { + _LIT( KSQLDeleteFormat, "DELETE FROM %S WHERE %S = %d"); + + TInt numIds = aIds.Count(); + if(numIds <= 0) + { + return; + } + + HBufC* query = NULL; + query = HBufC::NewLC( + KSQLDeleteFormat().Length() + + aTableName.Length() + + aColumnName.Length() + + KIntLength + ); + + for(TInt i=0; iDes().Format(KSQLDeleteFormat, &aTableName, &aColumnName, aIds[i]); + iDatabase.Execute(*query); + } + + CleanupStack::PopAndDestroy(query); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseItemTableLC +// +// Opens the Item table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseItemTableLC(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iItemTableRefCount++; + + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseItemTable, this)); + + // If need be open the table. + if (iItemTableRefCount == 1) + { + User::LeaveIfError(iItemTable.Open(iDatabase, KItemTable, aAccess)); + iItemColSet = iItemTable.ColSetL(); + + User::LeaveIfError(iItemTable.SetIndex(KItemTableIndex)); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseItemTable +// +// Closes the Item table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseItemTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iItemTableRefCount--; + + // If need be close the table. + if (self->iItemTableRefCount == 0) + { + delete self->iItemColSet; + self->iItemColSet = NULL; + self->iItemTable.Close(); + } + else if (self->iItemTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseEnclosureTableLC +// +// Opens the Enclosure table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseEnclosureTableLC(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iEnclosureTableRefCount++; + + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseEnclosureTable, this)); + + // If need be open the table. + if (iEnclosureTableRefCount == 1) + { + User::LeaveIfError(iEnclosureTable.Open(iDatabase, KEnclosureTable, aAccess)); + iEnclosureColSet = iEnclosureTable.ColSetL(); + + User::LeaveIfError(iEnclosureTable.SetIndex(KEnclosureTableIndex)); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseEnclosureTable +// +// Closes the Enclosure table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseEnclosureTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iEnclosureTableRefCount--; + + // If need be close the table. + if (self->iEnclosureTableRefCount == 0) + { + delete self->iEnclosureColSet; + self->iEnclosureColSet = NULL; + self->iEnclosureTable.Close(); + } + else if (self->iEnclosureTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseVersionTableLC +// +// Opens the Version table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseVersionTableLC(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iVersionTableRefCount++; + + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseVersionTable, this)); + + // If need be open the table. + if (iVersionTableRefCount == 1) + { + User::LeaveIfError(iVersionTable.Open(iDatabase, KVersionTable, aAccess)); + iVersionColSet = iVersionTable.ColSetL(); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseVersionTable +// +// Closes the Version table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseVersionTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iVersionTableRefCount--; + + // If need be close the table. + if (self->iVersionTableRefCount == 0) + { + delete self->iVersionColSet; + self->iVersionColSet = NULL; + self->iVersionTable.Close(); + } + else if (self->iVersionTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UseSettingsTableLC +// +// Opens the Settings table for use. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UseSettingsTableLC(RDbRowSet::TAccess aAccess) + { + // Inc the ref count. + iSettingsTableRefCount++; + + // Push the clean up function on the stack. + CleanupStack::PushL(TCleanupItem(&ReleaseSettingsTable, this)); + + // If need be open the table. + if (iSettingsTableRefCount == 1) + { + User::LeaveIfError(iSettingsTable.Open(iDatabase, KSettingsTable, aAccess)); + iSettingsColSet = iSettingsTable.ColSetL(); + + User::LeaveIfError(iSettingsTable.SetIndex( KSettingsTableIndex )); + } + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::ReleaseSettingsTable +// +// Closes the Settings table. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::ReleaseSettingsTable(TAny *aPtr) + { + CFeedsDatabase* self = static_cast(aPtr); + + // Dec the ref count. + self->iSettingsTableRefCount--; + + // If need be close the table. + if (self->iSettingsTableRefCount == 0) + { + delete self->iSettingsColSet; + self->iSettingsColSet = NULL; + self->iSettingsTable.Close(); + } + else if (self->iSettingsTableRefCount < 0) + { + User::Panic(_L("Feeds Server"), KErrArgument); + } + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::UpdateFeedStatus +// +// Update feed with status Codes +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::UpdateFeedStatusL(TInt aFeedId, TInt aFeedStatus) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + TInt previousStatus = KErrNone; + TInt parentId = KRootFolderId; + + // Create a view given this select... + _LIT(KQuery, "SELECT ParentId,Status FROM FolderListTable WHERE FeedId = %d AND IsFolder = %d"); + query = HBufC::NewLC( KQuery().Length() + KIntLength + KIntLength ); + + query->Des().Format( KQuery, aFeedId, 0 ); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EUpdatable)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + view.UpdateL(); + previousStatus = view.ColInt32(colSet->ColNo(KStatus)); + parentId = view.ColUint16(colSet->ColNo(KParentId)); + view.SetColL(colSet->ColNo(KStatus),aFeedStatus); + view.PutL(); + found = ETrue; + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + if(!found) + { + return; + } + + if(previousStatus == KErrNone && aFeedStatus == KErrNone) + { + return; + } + else if(previousStatus != KErrNone && aFeedStatus != KErrNone) + { + return; + } + else if(previousStatus == KErrNone && aFeedStatus != KErrNone) + { + // Open the various tables + UseFolderListTableLC(RDbTable::EUpdatable); + while(parentId != KRootFolderId) + { + TDbSeekKey folderListKey(parentId); + if(iFolderListTable.SeekL(folderListKey)) + { + iFolderListTable.GetL(); + parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + previousStatus = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), previousStatus-1); + iFolderListTable.PutL(); + if(previousStatus != KErrNone) + { + break; + } + } + } + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + else if(previousStatus != KErrNone && aFeedStatus == KErrNone) + { + // Open the various tables + UseFolderListTableLC(RDbTable::EUpdatable); + while(parentId != KRootFolderId) + { + TDbSeekKey folderListKey(parentId); + if(iFolderListTable.SeekL(folderListKey)) + { + iFolderListTable.GetL(); + parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + previousStatus = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KStatus)); + iFolderListTable.UpdateL(); + iFolderListTable.SetColL(iFolderListColSet->ColNo(KStatus), previousStatus+1); + iFolderListTable.PutL(); + + if(previousStatus+1 != KErrNone) + { + break; + } + } + } + // Clean up. + CleanupStack::PopAndDestroy(/*folder list table*/); + } + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::FreqFromFeedIdL +// +// Return the auto update freq of the feed with the given feed-id. +// ----------------------------------------------------------------------------- +// +TBool CFeedsDatabase::FreqFromFeedIdL(TInt aFeedId, TInt& aFreq) + { + RDbView view; + TBool found = EFalse; + HBufC* query = NULL; + + // Create a view given this select... + // SELECT AutoUpdateFreq FROM FeedTable WHERE FeedId = aFeedId + _LIT(KQuery, "SELECT AutoUpdateFreq FROM FeedTable WHERE FeedId = %d"); + + query = HBufC::NewLC(KQuery().Length() + KIntLength); + + query->Des().Format(KQuery, aFeedId); + + User::LeaveIfError(view.Prepare(iDatabase, TDbQuery(*query), RDbView::EReadOnly)); + CleanupClosePushL(view); + + CDbColSet* colSet = view.ColSetL(); + CleanupStack::PushL(colSet); + + // Search for the feed. + if (view.Evaluate() >= 0) + { + if (view.FirstL()) + { + // Get the feed id. + view.GetL(); + aFreq = view.ColUint32(colSet->ColNo(KAutoUpdateFreq)); + } + } + + CleanupStack::PopAndDestroy(colSet); + CleanupStack::PopAndDestroy(/*view*/); + CleanupStack::PopAndDestroy(query); + + return found; + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::AlterFeedTableWithAutoFequencyL +// +// Adds a new column AutoUpdateFreq to FeedTable in the case of versions less +// than 7.1. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::AlterFeedTableWithAutoFequencyL() + { + UseFeedTableLC(RDbTable::EUpdatable); + + // get the exiting col set + CDbColSet* colSet = iDatabase.ColSetL(KFeedTable); + + colSet->AddL(TDbCol(KAutoUpdateFreq, EDbColUint32)); + iDatabase.AlterTable(KFeedTable, *colSet); + + CleanupStack::PopAndDestroy(/* FeedTable */); + + // Set the auto update frequency as KErrorNotSet + // Prep the item table. + UseFeedTableLC(RDbTable::EUpdatable); + + while( iFeedTable.NextL() ) + { + // Get the row. and add the default value. + iFeedTable.GetL(); + iFeedTable.UpdateL(); + + iFeedTable.SetColL(iFeedColSet->ColNo(KAutoUpdateFreq), KAutoUpdatingOff); + + iFeedTable.PutL(); + } + + CleanupStack::PopAndDestroy(/* iFeedTable */); + } + +#if defined(_DEBUG) +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DebugPrintTables +// +// Prints the tables to the log file. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DebugPrintTablesL() + { + DebugPrintFolderListTableL(); + DebugPrintItemTableL(); + } + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DebugPrintFolderListTableL +// +// Prints the folder list table to the log file. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DebugPrintFolderListTableL() + { + // Prep the FolderList table. + UseFolderListTableLC(RDbTable::EReadOnly); + + // column names + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, + _L("=============================================================================================================")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("FolderListTable")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("ListId\t\tItemId\tParent\tSiblin\tType\tFeedId\tTitle")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, + _L("=============================================================================================================")); + + while( iFolderListTable.NextL() ) + { + // Get the row. + iFolderListTable.GetL(); + + TInt folderListId = iFolderListTable.ColInt32(iFolderListColSet->ColNo(KFolderListId)); + TInt folderItemId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFolderItemId)); + TInt parentId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KParentId)); + TInt SiblingOrder = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KSiblingOrder)); + TBool isFolder = iFolderListTable.ColUint8(iFolderListColSet->ColNo(KIsFolder)); + TInt feedId = iFolderListTable.ColUint16(iFolderListColSet->ColNo(KFeedId)); + if( isFolder ) + { + feedId = KUnassignedId; + } + TPtrC title( KNullDesC ); + title.Set(iFolderListTable.ColDes16(iFolderListColSet->ColNo(KTitle_100MaxLen))); + + // folder or feed + if( isFolder ) + { + if( folderListId == 0 ) + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t\t%d\t%d\t%d\tfolder\t%d\t%S"), + folderListId, folderItemId, parentId, SiblingOrder, feedId, &title); + } + else + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t%d\t%d\t%d\tfolder\t%d\t%S"), + folderListId, folderItemId, parentId, SiblingOrder, feedId, &title); + } + } + else + { + if( folderListId == 0 ) + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t\t%d\t%d\t%d\tfeed\t%d\t%S"), + folderListId, folderItemId, parentId, SiblingOrder, feedId, &title); + } + else + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t%d\t%d\t%d\tfeed\t%d\t%S"), + folderListId, folderItemId, parentId, SiblingOrder, feedId, &title); + } + } + } + + CleanupStack::PopAndDestroy(/*folder list Table*/); + } + + +// ----------------------------------------------------------------------------- +// CFeedsDatabase::DebugPrintItemTableL +// +// Prints the item table to the log file. +// ----------------------------------------------------------------------------- +// +void CFeedsDatabase::DebugPrintItemTableL() + { + // Prep the item table. + UseItemTableLC(RDbTable::EReadOnly); + + // column names + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, + _L("=============================================================================================================")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("ItemTable")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("ItemId\tFeedId\tStatus\tTitle\tIdStr")); + FEED_LOG(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, + _L("=============================================================================================================")); + + while( iItemTable.NextL() ) + { + // Get the row. + iItemTable.GetL(); + + TInt itemId = iItemTable.ColUint16(iItemColSet->ColNo(KItemId)); + TInt feedId = iItemTable.ColUint16(iItemColSet->ColNo(KFeedId)); + + TBuf<(KMaxTimeFormatSpec + KMaxShortDateFormatSpec) * 2> timestamp; + //TBuf temp; + TTime date = iItemTable.ColTime(iItemColSet->ColNo(KDate)); + date.FormatL(timestamp, TTimeFormatSpec()); + //date.FormatL(temp, TShortDateFormatSpec()); + //timestamp.Append(_L(" ")); + //timestamp.Append(temp); + // JH TO DO: why timestamp not shown up in the log + + TInt itemStatus = iItemTable.ColUint16(iItemColSet->ColNo(KItemStatus)); + TPtrC title( KNullDesC ); + title.Set(iItemTable.ColDes16(iItemColSet->ColNo(KTitle_100MaxLen))); + HBufC* idStr = NULL; + ReadLongTextL(iItemTable, iItemColSet->ColNo(KItemIdStr), idStr); + CleanupStack::PushL(idStr); + + switch( itemStatus ) + { + case EUnreadItem: + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t%d\t%S\t%S\t%S\t%S"), + itemId, feedId, &KUnread(), &idStr->Des(), &title, ×tamp); + } + break; + case EReadItem: + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t%d\t%S\t%S\t%S\t%S"), + itemId, feedId, &KRead(), &idStr->Des(), &title, ×tamp); + } + break; + case ENewItem: + { + FEED_LOG6(_L("Feeds"), _L("Feeds_DB.log"), + EFileLoggingModeAppend, _L("%d\t%d\t%S\t%S\t%S\t%S"), + itemId, feedId, &KNew(), &idStr->Des(), &title, ×tamp); + } + break; + } + + CleanupStack::PopAndDestroy(/*idStr*/); + } + + CleanupStack::PopAndDestroy(/*item Table*/); + } +#endif