/*
* 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 <badesca.h>
#include <e32math.h>
#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),iIsFolderTableUpdateNeeded(EFalse)
{
}
// -----------------------------------------------------------------------------
// 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<TInt> 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<TInt>& 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<TInt> itemIds;
RArray<TAttribute> feedAttributes;
RArray<TAttribute> itemAttributes;
RArray<TAttribute> 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<TInt> parentStack;
RArray<TInt> 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<K100MaxLen> 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));
if (aUrl.Length() > 0)
{
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<TInt>& aFolderItemIds, TBool aSessionCalled)
{
RArray<TInt> 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<TInt> 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<TInt>& aFolderItemIds,
RArray<TInt>& 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<TInt> 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<TInt>& 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<TInt>& 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<TInt>& 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<TInt>& aItemIds, const RArray<TInt>& 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<KMaxTimeFormatSpec * 2> tsStr;
TBuf<KMaxTimeFormatSpec * 2> 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<TInt>& 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<TAttribute>& 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();
if (iIsFolderTableUpdateNeeded)
{
//update the folder table.
TInt entryId;
EntryIdFromFeedIdL(aFeedId, aFolderListId, entryId);
FolderItemUpdateL(entryId, title, KNullDesC, KAutoUpdatingOff);
}
}
// -----------------------------------------------------------------------------
// CFeedsDatabase::CommitFeedL
//
// Commit a new feed to the database.
// -----------------------------------------------------------------------------
//
TInt CFeedsDatabase::CommitFeedL(TInt aFolderListId, const TDesC& aTitle, const TDesC& aUrl, TInt aFreq)
{
RArray<TAttribute> 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<TAttribute>& 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<TAttribute>& aAttributes, RArray<TInt>& aItemIds)
{
TPtrC timeStamp(KNullDesC);
TPtrC title(KNullDesC);
TPtrC description(KNullDesC);
TPtrC link(KNullDesC);
TPtrC itemIdStr(KNullDesC);
TBool isNewItem(EFalse);
// 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;
}
}
// 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();
}
// Ignore the item if it is already in the database.
// If the timestamp chnages the item needs to be updated
// rather than inserted.
TInt id;
if (FindItemL(aFeedId, itemIdStr, id))
{
TDbSeekKey seekKey( id );
// Update the database.
iItemTable.SeekL(seekKey);
iItemTable.GetL();
TBuf<(KMaxTimeFormatSpec + KMaxShortDateFormatSpec) * 2> previousTimestamp;
TTime previousDate = iItemTable.ColTime(iItemColSet->ColNo(KDate));
previousDate.FormatL(previousTimestamp, TTimeFormatSpec());
if (date == previousDate)
{
// If the item is found and timestamp remains same then just
// append it's id to aItemIds.
aItemIds.AppendL(id);
return isNewItem;
}
else
{
// If the item is found and the timestamp has changed then make sure that
// the new itemId is appened to aItemIds.
aItemIds.AppendL(aItemId);
iItemTable.GetL();
iItemTable.UpdateL();
}
}
// Otherwise this is a new item so append the provided id to aItemIds.
else
{
aItemIds.AppendL(aItemId);
// Update the database.
iItemTable.Reset();
iItemTable.InsertL();
isNewItem = ETrue;
}
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 isNewItem;
}
// -----------------------------------------------------------------------------
// CFeedsDatabase::CommitEnclosureL
//
// Commit the enclosure to the database
// -----------------------------------------------------------------------------
//
void CFeedsDatabase::CommitEnclosureL(TInt aEnclosureId, TInt aItemId,
TInt aFeedId, const RArray<TAttribute>& 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<TInt>& 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<KInt64Length> 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<KInt64Length> 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<CFeedsDatabase*>(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<CFeedsDatabase*>(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<TInt>& aFeedIds)
{
if(aFeedIds.Count() <= 0)
return;
DeleteRecordsFromTableL(KFeedTable, KFeedId, aFeedIds);
}
// -----------------------------------------------------------------------------
// CFeedsDatabase::DeleteFolderListTableRecordsL
//
// Deletes records from a FolderListTable
// -----------------------------------------------------------------------------
//
void CFeedsDatabase::DeleteFolderListTableRecordsL(RArray<TInt>& 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<TInt>& 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; i<numIds; i++)
{
query->Des().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<CFeedsDatabase*>(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<CFeedsDatabase*>(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<CFeedsDatabase*>(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<CFeedsDatabase*>(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 */);
}
// -----------------------------------------------------------------------------
// CFeedsDatabase::FeedIdFromEntryIdL
//
// Returns the feed id of the feed with the given entry id.
// -----------------------------------------------------------------------------
//
TBool CFeedsDatabase::FeedIdFromEntryIdL(const TInt& aEntryId, 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 FolderListTable WHERE FolderItemId = %d AND FolderListId = %d");
query = HBufC::NewLC( KQuery().Length() + KIntLength + KIntLength );
query->Des().Format( KQuery, aEntryId, 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::EntryIdFromFeedIdL
//
// Returns the feed id of the feed with the given entry id.
// -----------------------------------------------------------------------------
//
TBool CFeedsDatabase::EntryIdFromFeedIdL(const TInt& aFeedId, TInt aFolderListId, TInt& aEntryId)
{
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 FolderItemId FROM FolderListTable WHERE FeedId = %d AND FolderListId = %d");
query = HBufC::NewLC( KQuery().Length() + KIntLength + KIntLength );
query->Des().Format( KQuery, aFeedId, 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();
aEntryId = view.ColUint16(colSet->ColNo(KFolderItemId));
found = ETrue;
}
}
CleanupStack::PopAndDestroy(colSet);
CleanupStack::PopAndDestroy(/*view*/);
CleanupStack::PopAndDestroy(query);
return found;
}
#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<KMaxTimeFormatSpec * 2> 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);
TPtrC idStrPtr(idStr->Des());
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(), &idStrPtr, &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(), &idStrPtr, &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(), &idStrPtr, &title, ×tamp);
}
break;
}
CleanupStack::PopAndDestroy(/*idStr*/);
}
CleanupStack::PopAndDestroy(/*item Table*/);
}
#endif