/*
* 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: A task to import Feeds.
*
*/
#include <S32Mem.h>
#include "ImportFeedsTask.h"
#include "FeedsDatabase.h"
#include "FeedsServer.h"
#include "feedsservermsg.h"
// Root folder related.
const TInt KRootFolderId = 0;
// -----------------------------------------------------------------------------
// CImportFeedsTask::NewL
//
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CImportFeedsTask* CImportFeedsTask::NewL(CFeedsServer& aFeedsServer,
MImportFeedsTaskObserver& aObserver, const RMessage2& aMessage)
{
CImportFeedsTask* self = new (ELeave) CImportFeedsTask(aFeedsServer, aObserver, aMessage);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::CImportFeedsTask
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CImportFeedsTask::CImportFeedsTask(CFeedsServer& aFeedsServer, MImportFeedsTaskObserver& aObserver, const RMessage2& aMessage):
CTask(aFeedsServer), iObserver(aObserver), iMessage(aMessage)
{
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::ConstructL()
{
BaseConstructL(ETrue);
iIdle = CIdle::NewL(CActive::EPriorityStandard);
iPackedFolder = NULL;
iMoreToAdd = ETrue;
iFeedsDatabase = &(iFeedsServer.Database());
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::CImportFeedsTask
// Deconstructor.
// -----------------------------------------------------------------------------
//
CImportFeedsTask::~CImportFeedsTask()
{
TRAP_IGNORE( CleanupImportTaskL() );
iImportFile.Close();
iRFs.Close();
delete iFullImportFileName;
delete iPackedFolder;
delete iIdle;
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::StartTaskL.
//
// Starts the task.
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::StartTaskL()
{
iImportState = EImportOpenOPMLFile;
iDBTransactInited = EFalse;
iFoundRootFolder = EFalse;
iParentStack.AppendL(KRootFolderId);
iSiblingIndexStack.AppendL(0);
iIdle->Start(TCallBack(StartImportStateMachine, this));
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::StartImportStateMachine.
//
// Starts the OPML import task
// -----------------------------------------------------------------------------
//
TBool CImportFeedsTask::StartImportStateMachine(TAny *aPtr)
{
TInt err(KErrNone);
CImportFeedsTask *self = static_cast<CImportFeedsTask *>(aPtr);
switch(self->iImportState)
{
case EImportOpenOPMLFile :
TRAP(err, self->OpenOPMLFileL());
if(err != KErrNone)
{
self->iObserver.ImportCompleted(err);
return EFalse;
}
self->iImportState = EImportPreparePackedFolder;
return ETrue;
case EImportPreparePackedFolder:
TRAP(err, self->PreparePackedFolderL());
if(err != KErrNone)
{
self->iObserver.ImportCompleted(err);
return EFalse;
}
self->iImportState = EImportIntoDB;
return ETrue;
case EImportIntoDB:
TRAP(err, self->ImportIntoDBL());
if(err != KErrNone)
{
self->iObserver.ImportCompleted(err);
return EFalse;
}
if(self->iMoreToAdd)
{
return ETrue;
}
self->iImportState = EImportDone;
self->iObserver.ImportCompleted(KErrNone);
return EFalse;
}
return EFalse;
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::CleanupImportTask.
//
// Cancel the ongoing OPML import task
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::CleanupImportTaskL()
{
if(iImportState == EImportIntoDB && iMoreToAdd)
{
iFeedsDatabase->CommitImportTransaction();
// Rollback didnt work with tables having index, so deleting all the added records :(
iFeedsDatabase->DeleteFeedTableRecordsL(iFeedIds);
iFeedsDatabase->DeleteFolderListTableRecordsL(iFolderItemIds);
if(iDBTransactInited)
ReleaseImportTables();
}
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ExtractClientImportMessageL.
//
// Extract the client passes message
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::OpenOPMLFileL()
{
User::LeaveIfError(iRFs.Connect());
User::LeaveIfError(iImportFile.Open(iRFs, *iFullImportFileName, EFileRead | EFileShareReadersOnly));
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::PreparePackedFolderL.
//
// Creates the packed folder by parsing the OPML file
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::PreparePackedFolderL()
{
iPackedFolder = iFeedsServer.ImportFolderL(iImportFile, iDispImportFileName);
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ReleaseImportTablesCallback.
//
// Callback function for import task completion
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::ReleaseImportTablesCallback(TAny *ptr)
{
CImportFeedsTask *self = static_cast<CImportFeedsTask *>(ptr);
self->iFeedsDatabase->CommitImportTransaction();
self->ReleaseImportTables();
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ReleaseImportTables.
//
// Closes all the OPML import related tables
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::ReleaseImportTables()
{
iFeedsDatabase->ReleaseImportTables();
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ImportIntoDBL.
//
// Starts importing the packed folder into DB
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::ImportIntoDBL()
{
CleanupStack::PushL(TCleanupItem(&ReleaseImportTablesCallback, this));
if(!iDBTransactInited)
{
iFeedsDatabase->PrepareImportTransationsL(); // Open tables, mark start of transactions
iDBTransactInited = ETrue;
}
ImportFoldersL(); // Import record by record
if(!iMoreToAdd)
{
CleanupStack::PopAndDestroy(/*ReleaseImportTablesCallback*/);
}
else
CleanupStack::Pop(/*ReleaseImportTablesCallback*/);
}
// -----------------------------------------------------------------------------
// CImportFeedsTask::ImportFoldersL.
//
// Imports the packed folder into DB
// -----------------------------------------------------------------------------
//
void CImportFeedsTask::ImportFoldersL()
{
TInt parent;
TInt siblingIndex;
TInt folderId;
TPtrC title;
TPtrC url;
TInt entryId;
TInt feedId;
TInt newfeedId;
TTime timestamp;
TInt unreadCount;
TInt statusCode;
TInt freq;
if(!iPackedFolder->HasNextToken())
{
iMoreToAdd = EFalse;
return;
}
iMoreToAdd = ETrue;
TUint token = iPackedFolder->NextToken();
switch (token)
{
case EFolderTokenFolderBegin:
// Extract the attributes.
iPackedFolder->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 (!iFoundRootFolder)
{
iFoundRootFolder = ETrue;
return;
}
// Determine the parent and its sibling index.
parent = iParentStack[iParentStack.Count() - 1];
siblingIndex = iSiblingIndexStack[iSiblingIndexStack.Count() - 1];
iSiblingIndexStack[iSiblingIndexStack.Count() - 1]++;
//create a sibling index hole
iFeedsDatabase->CreateSiblingIndexHoleL(parent, siblingIndex, 1);
// Add the folder.
iFeedsDatabase->FolderItemAddHelperL(iFolderListId, title, KNullDesC,
ETrue, siblingIndex, parent, folderId, newfeedId, freq);
// Push this folder on the stack as the active parent.
iParentStack.AppendL(folderId);
iSiblingIndexStack.AppendL(0);
iFolderItemIds.AppendL(folderId);
break;
case EFolderTokenFolderEnd:
// Pop this folder off of the stacks.
iParentStack.Remove(iParentStack.Count() - 1);
iSiblingIndexStack.Remove(iSiblingIndexStack.Count() - 1);
break;
case EFolderTokenFeed:
// Extract the attributes.
iPackedFolder->ExtractAttributes(title, url, entryId, feedId, timestamp, unreadCount, statusCode, freq);
// Determine the parent and its sibling index.
parent = iParentStack[iParentStack.Count() - 1];
siblingIndex = iSiblingIndexStack[iSiblingIndexStack.Count() - 1];
// Add the feed.
TRAPD( err, iFeedsDatabase->FolderItemAddHelperL(iFolderListId, title, url,
EFalse, siblingIndex, parent, folderId, newfeedId, freq) );
// Ignore problematic ones and continue to the next token
if( err == KErrNone && newfeedId >= 0)
{
iSiblingIndexStack[iSiblingIndexStack.Count() - 1]++;
iFolderItemIds.AppendL(folderId);
iFeedIds.AppendL(newfeedId);
}
break;
}
}