diff -r 9905f7d46607 -r b63e67867dcd omads/omadsextensions/adapters/bookmark/src/bookmarkdatastore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omads/omadsextensions/adapters/bookmark/src/bookmarkdatastore.cpp Tue Jul 13 03:39:25 2010 +0530 @@ -0,0 +1,2117 @@ +/* +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: Part of SyncML Data Synchronization Plug In Adapter +* +*/ + + +#include +#include +#include + +#include +#include +#include + +#include "bookmarkdatastore.h" +#include "vbookmarkconverter.h" +#include "omadsfolderobject.h" +#include "bookmarkdataproviderdefs.h" +#include "conversionutil.h" +#include "changefinder.h" +#include "logger.h" + + +_LIT8( KBookmarkFolderMimeType, "application/vnd.omads-folder+xml" ); +_LIT8( KBookmarkFolderMimeVersion, "" ); +_LIT8( KBookmarkItemMimeType, "text/x-vbookmark" ); +_LIT8( KBookmarkItemMimeVersion, "" ); +_LIT( KRSSRootFolderName, "Web Feeds" ); + +const TInt KDefaultBufferSize = 1024; +const TInt KDataBufferNotReady = -1; +const TInt KRssFeedsOffset = 50000; +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::CBookmarkDataStore +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +CBookmarkDataStore::CBookmarkDataStore() : + iDataBaseOpened( EFalse ), iFeedsServer(*this), iRootFolder(*this), + iKey( TKeyArrayFix( _FOFF( TNSmlSnapshotItem, ItemId() ), ECmpTInt ) ), + iHasHistory( EFalse ) + { + LOGGER_ENTERFN( "CBookmarkDataStore" ); + LOGGER_LEAVEFN( "CBookmarkDataStore" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::ConstructL +// Symbian 2nd phase constructor, can leave. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::ConstructL() + { + LOGGER_ENTERFN( "CBookmarkDataStore::ConstructL" ); + + User::LeaveIfError( iRfs.Connect() ); + User::LeaveIfError( iSession.Connect() ); + + iNewItems = new ( ELeave ) CNSmlDataItemUidSet; + iDeletedItems = new ( ELeave ) CNSmlDataItemUidSet; + iSoftDeletedItems = new ( ELeave ) CNSmlDataItemUidSet; + iUpdatedItems = new ( ELeave ) CNSmlDataItemUidSet; + iMovedItems = new ( ELeave ) CNSmlDataItemUidSet; + + LOGGER_LEAVEFN( "CBookmarkDataStore::ConstructL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::~CBookmarkDataStore +// Destructor +// ----------------------------------------------------------------------------- +CBookmarkDataStore::~CBookmarkDataStore() + { + LOGGER_ENTERFN( "~CBookmarkDataStore" ); + + delete iDataBuffer; + delete iNewItems; + delete iDeletedItems; + delete iSoftDeletedItems; + delete iUpdatedItems; + delete iMovedItems; + delete iItemToBeReplaced; + + if ( iChangeFinder ) + { + TRAPD( error, iChangeFinder->CloseL() ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1( "iChangeFinder->CloseL() leaved with %d", error ); + } + } + delete iChangeFinder; + + delete iConverter; + + if ( iDataBaseOpened ) + { + iDb.Close(); + iRootFolder.Close(); + iFeedsServer.Close(); + } + + iSession.Close(); + iRfs.Close(); + LOGGER_LEAVEFN( "~CBookmarkDataStore" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +CBookmarkDataStore* CBookmarkDataStore::NewL() + { + LOGGER_ENTERFN( "CBookmarkDataStore::NewL" ); + CBookmarkDataStore* self = CBookmarkDataStore::NewLC(); + CleanupStack::Pop( self ); + LOGGER_LEAVEFN( "CBookmarkDataStore::NewL" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::NewLC +// Two-phased constructor. +// ----------------------------------------------------------------------------- +CBookmarkDataStore* CBookmarkDataStore::NewLC() + { + LOGGER_ENTERFN( "CBookmarkDataStore::NewLC" ); + CBookmarkDataStore* self = new ( ELeave ) CBookmarkDataStore(); + CleanupStack::PushL( self ); + self->ConstructL(); + LOGGER_LEAVEFN( "CBookmarkDataStore::NewLC" ); + return self; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoOpenL +// Opens database. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoOpenL( const TDesC& /*aStoreName*/, + MSmlSyncRelationship& aContext, TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoOpenL" ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + if ( iDataBaseOpened ) + { + User::RequestComplete( iCallerStatus, KErrInUse ); + LOGGER_WRITE( "CBookmarkDataStore::DoOpenL failed with KErrInUse." ); + return; + } + + // Create ChangeFinder + if ( iChangeFinder ) + { + delete iChangeFinder; + iChangeFinder = NULL; + } + iChangeFinder = CChangeFinder::NewL( aContext, iKey, iHasHistory ); + + // Create converter object + if ( iConverter ) + { + delete iConverter; + iConverter = NULL; + } + iConverter = CBookmarkConversionUtil::NewL(); + + + TInt err( KErrNone ); + err = iDb.Open( iSession, KBrowserBookmarks ); + if ( err ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoOpenL iDb.Open err: %d.", err ); + User::RequestComplete( iCallerStatus, err ); + return; + } + err = iFeedsServer.Connect(); + if ( err ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoOpenL iFeedsServer.Connect err: %d.", err ); + User::RequestComplete( iCallerStatus, err ); + return; + } + err = iRootFolder.Open( iFeedsServer ); + if ( err ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoOpenL iRootFolder.Open err: %d.", err ); + User::RequestComplete( iCallerStatus, err ); + return; + } + + iRootFolder.FetchRootFolderItemL(); // calls FolderItemRequestCompleted when completed + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoOpenL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::FolderItemRequestCompleted +// RSS item database request is completed +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::FolderItemRequestCompleted( TInt aStatus, + CRequestHandler::TRequestHandlerType ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::FolderItemRequestCompleted" ); + + TRAPD( err, DoFolderItemRequestCompletedL( aStatus ) ); + + if ( err != KErrNone ) + { + LOGGER_WRITE_1( "DoFolderItemRequestCompletedL leaved with err: %d", err ); + User::RequestComplete( iCallerStatus, err ); + } + + LOGGER_LEAVEFN( "CBookmarkDataStore::FolderItemRequestCompleted" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoFolderItemRequestCompletedL +// RSS item database request is completed +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoFolderItemRequestCompletedL( TInt aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoFolderItemRequestCompletedL" ); + switch ( iCurrentState ) + { + case EClosed : + { + LOGGER_WRITE("Database ready"); + iDataBaseOpened = ETrue; + iCurrentState = EOpenAndWaiting; + RegisterSnapshotL(); + break; + } + + // bookmark is added (Add command) + case EBookmarkCreating : + { + // RSS Item has been created. + LOGGER_WRITE_1("RSS item created, err %d", aStatus); + // Restore state + iCurrentState = EOpenAndWaiting; + if ( aStatus == KErrNone ) + { + RssItemCreatedL(); + } + break; + } + + // bookmark is updated (Replace command) + case EBookmarkUpdating : + { + LOGGER_WRITE("RSS item replaced"); + if ( aStatus == KErrNone ) + { + TBool moveNeeded(EFalse); + RssItemReplacedL( moveNeeded ); + + if ( moveNeeded ) + { + // Moving is still ongoing, don't complete request yet. + return; + } + + LOGGER_WRITE_1("Item ID: %d", *iCurrentItem); + LOGGER_WRITE_1("Parent ID: %d", iParentFolder); + } + // Restore state + iCurrentState = EOpenAndWaiting; + break; + } + + // bookmark is updated and moved (Replace command, 2nd phase) + case EBookmarkUpdatedAndMoving: + { + LOGGER_WRITE_1( "RSS item moved (replaced), err: %d", aStatus ); + if ( aStatus == KErrNone ) + { + // Inform ChangeFinder of updated item + iChangeFinder->ItemUpdatedL( *iMovedItem ); // ownership transferred + iMovedItem = NULL; + LOGGER_WRITE( "ItemReplacedL" ); + } + else + { + delete iMovedItem; + iMovedItem = NULL; + } + // Restore state + iCurrentState = EOpenAndWaiting; + break; + } + + // bookmark is moved (Move command) + case EBookmarkMoving: + { + LOGGER_WRITE_1( "RSS item moved, err: %d", aStatus ); + if ( aStatus == KErrNone ) + { + iChangeFinder->ItemMovedL( *iMovedItem ); // ownership transferred + iMovedItem = NULL; + } + else + { + delete iMovedItem; + iMovedItem = NULL; + } + // Restore state + iCurrentState = EOpenAndWaiting; + break; + } + + case EBookmarkDeleting: + { + LOGGER_WRITE_1( "RSS item removed, err: %d", aStatus ); + if ( aStatus == KErrNone ) + { + // Inform ChangeFinder of the removed item + TSnapshotItem item( iReplaceItem ); + iChangeFinder->ItemDeletedL( item ); + } + // Restore state + iCurrentState = EOpenAndWaiting; + break; + } + case EBookmarkDeletingAll: + { + LOGGER_WRITE_1( "all RSS items removed, err: %d", aStatus ); + break; + } + + default : + LOGGER_WRITE_1( "Invalid state: %d", iCurrentState ); + return; + } + User::RequestComplete( iCallerStatus, aStatus ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoFolderItemRequestCompletedL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::RssItemCreatedL +// Rss item has been created, add item to changefinder +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::RssItemCreatedL() + { + TRACE_FUNC_ENTRY; + if ( !iRootFolder.HasRootFolderItem() ) + { + LOGGER_WRITE( "rss root folder not found" ); + User::Leave( KErrNotFound ); + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* parent = rootFolder.Search( iParentFolder - KRssFeedsOffset ); + if ( !parent ) + { + LOGGER_WRITE( "parent folder not found" ); + User::Leave( KErrNotFound ); + } + LOGGER_WRITE_1("parent->Id(): %d", parent->Id()); + LOGGER_WRITE_1( "Name: %S", &iNewItemName ); + const CFolderItem* addedItem = parent->Search( iNewItemName ); + iNewItemName.Zero(); + if ( addedItem ) + { + LOGGER_WRITE_1("addedItem found, id: %d", addedItem->Id()); + + // Output the uid value of new item + *iCurrentItem = addedItem->Id() + KRssFeedsOffset; + + // Inform ChangeFinder of the added item + TSnapshotItem snapshotItem( *iCurrentItem ); + snapshotItem.SetParentId( iParentFolder ); + snapshotItem.CreateHashL( addedItem->Name(), addedItem->SourceUrl() ); + iChangeFinder->ItemAddedL( snapshotItem ); + LOGGER_WRITE( "ItemAddedL" ); + } + else + { + LOGGER_WRITE( "Added item not found" ); + User::Leave( KErrNotFound ); + } + LOGGER_WRITE_1("Item ID: %d", *iCurrentItem); + LOGGER_WRITE_1("Parent ID: %d", iParentFolder); + TRACE_FUNC_EXIT; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::RssItemReplacedL +// Rss item has been replaced, update changefinder +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::RssItemReplacedL( TBool& aMoveNeeded ) + { + TRACE_FUNC_ENTRY; + aMoveNeeded = EFalse; + if ( !iRootFolder.HasRootFolderItem() ) + { + LOGGER_WRITE( "rss root folder not found" ); + User::Leave( KErrNotFound ); + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + LOGGER_WRITE_1( "rootFolder.Search %d", iReplaceItem - KRssFeedsOffset ); + const CFolderItem* modItem = rootFolder.Search( iReplaceItem - KRssFeedsOffset ); + if ( modItem ) + { + LOGGER_WRITE_1("Item found, id: %d", modItem->Id()); + + const CFolderItem* parent = modItem->Parent(); + if ( parent ) + { + TInt currentParent = parent->Id() + KRssFeedsOffset; + if ( iParentFolder != parent->Id() + KRssFeedsOffset ) + { + // move to another folder + const CFolderItem* newParent = rootFolder.Search( + iParentFolder - KRssFeedsOffset ); + if ( !newParent ) + { + // new parent not found + LOGGER_WRITE( "new parent not found" ); + User::Leave( KErrPathNotFound ); + } + else if ( !newParent->IsFolder() ) + { + // not a folder + LOGGER_WRITE( "parent is not a folder" ); + User::Leave( KErrPathNotFound ); + } + else + { + // Output the uid value of new item + *iCurrentItem = modItem->Id() + KRssFeedsOffset; + + iCurrentState = EBookmarkUpdatedAndMoving; + RPointerArray movedItems; + CleanupClosePushL( movedItems ); + movedItems.Append( modItem ); + // FolderItemRequestCompleted is called when ready + iRootFolder.MoveFolderItemsToL( movedItems, *newParent); + CleanupStack::PopAndDestroy( &movedItems ); + aMoveNeeded = ETrue; + + delete iMovedItem; + iMovedItem = NULL; + iMovedItem = new (ELeave) TSnapshotItem( *iCurrentItem , + iParentFolder ); + iMovedItem->CreateHashL( modItem->Name(), modItem->SourceUrl() ); + LOGGER_WRITE( "ItemReplacedL,waiting to move item.." ); + return; + } + + } + } + else + { + //parent not found + LOGGER_WRITE( "rss parent not defined" ); + } + + // Output the uid value of new item + *iCurrentItem = modItem->Id() + KRssFeedsOffset; + + // Inform ChangeFinder of updated item + TSnapshotItem snapshotItem( *iCurrentItem, iParentFolder ); + snapshotItem.CreateHashL( modItem->Name(), modItem->SourceUrl() ); + iChangeFinder->ItemUpdatedL( snapshotItem ); + LOGGER_WRITE( "ItemReplacedL" ); + } + else + { + LOGGER_WRITE_1( "Replaced item %d not found",iReplaceItem - KRssFeedsOffset ); + User::Leave( KErrNotFound ); + } + TRACE_FUNC_EXIT; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCancelRequest +// Not supported, does nothing. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCancelRequest() + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCancelRequest" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCancelRequest" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoStoreName +// Returns the name of the DataStore +// ----------------------------------------------------------------------------- +const TDesC& CBookmarkDataStore::DoStoreName() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoStoreName" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoStoreName" ); + + if ( iDataBaseOpened ) + { + return KBrowserBookmarks; + } + else + { + return KNullDesC; + } + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoBeginTransactionL +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoBeginTransactionL() + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoBeginTransactionL" ); + LOGGER_WRITE( "CBookmarkDataStore::DoBeginTransactionL leaved with KErrNotSupported." ) + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCommitTransactionL +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCommitTransactionL( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCommitTransactionL" ); + LOGGER_WRITE( "CBookmarkDataStore::DoCommitTransactionL failed with KErrNotSupported." ); + + iCallerStatus = &aStatus; + User::RequestComplete( iCallerStatus, KErrNotSupported ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCommitTransactionL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoRevertTransaction +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoRevertTransaction( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoRevertTransaction" ); + iCallerStatus = &aStatus; + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoRevertTransaction" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoBeginBatchL +// Batching is not supported. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoBeginBatchL() + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoBeginBatchL" ); + LOGGER_WRITE( "CBookmarkDataStore::DoBeginBatchL leaved with KErrNotSupported." ); + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCommitBatchL +// Batching is not supported +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCommitBatchL( RArray& /*aResultArray*/, TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCommitBatchL" ); + LOGGER_WRITE( "CBookmarkDataStore::DoCommitBatchL failed with KErrNotSupported" ); + + iCallerStatus = &aStatus; + User::RequestComplete( iCallerStatus, KErrNotSupported ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCommitBatchL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCancelBatch +// Batching is not supported +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCancelBatch() + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCancelBatch" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCancelBatch" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoSetRemoteStoreFormatL +// Not supported +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoSetRemoteStoreFormatL( const CSmlDataStoreFormat& /*aServerDataStoreFormat*/ ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoSetRemoteStoreFormatL" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoSetRemoteStoreFormatL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoSetRemoteMaxObjectSize +// Not supported +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoSetRemoteMaxObjectSize( TInt /*aServerMaxObjectSize*/ ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoSetRemoteMaxObjectSize" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoSetRemoteMaxObjectSize" ); + } + + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoMaxObjectSize +// Reads the maximum object size from the central repository +// ----------------------------------------------------------------------------- +TInt CBookmarkDataStore::DoMaxObjectSize() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoMaxObjectSize" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoMaxObjectSize" ); + return 0; // no limit + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoOpenItemL +// Opens item in the DataStore, reads it (either completely or partially) +// to the temporary buffer where it can be later read to the remote database. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoOpenItemL( + TSmlDbItemUid aUid, + TBool& aFieldChange, + TInt& aSize, + TSmlDbItemUid& aParent, + TDes8& aMimeType, + TDes8& aMimeVer, + TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoOpenItemL" ); + LOGGER_WRITE_1( "Item: %d", aUid ); + + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + aFieldChange = EFalse; + + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "Warning: Unexpected current state: %d", iCurrentState ); + } + + SAFEDELETE( iDataBuffer ); + iDataBuffer = CBufFlat::NewL( KDefaultBufferSize ); + iReaderPosition = 0; + if ( aUid < KRssFeedsOffset ) + { + LOGGER_WRITE( "Handle id as bookmark item " ); + TInt err( KErrNone ); + CFavouritesItem* item = CFavouritesItem::NewLC(); + err = iDb.Get( aUid, *item ); + if (err) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE_1( "RFavouritesDb::Get failed with %d", err ); + CleanupStack::PopAndDestroy( item ); + return; + } + + + + iConverter->FavouritesItemToBufferL( *item, *iDataBuffer ); + aSize = iDataBuffer->Size(); + aParent = item->ParentFolder(); + + // Set mime type according to item type + // The following code handles also the case, where the receiving + // buffer doesn't contain enough space for the type (truncated) + if ( item->Type() == CFavouritesItem::EItem ) + { + LOGGER_WRITE("item type: EItem"); + AssignString( aMimeType, KBookmarkItemMimeType ); + AssignString( aMimeVer, KBookmarkItemMimeVersion ); + } + else + { + LOGGER_WRITE("item type: EFolder"); + AssignString( aMimeType, KBookmarkFolderMimeType ); + AssignString( aMimeVer, KBookmarkFolderMimeVersion ); + } + + CleanupStack::PopAndDestroy( item ); + } + else + { + LOGGER_WRITE( "Handle id as rssFeed item " ); + + TInt rssId = aUid - KRssFeedsOffset; + LOGGER_WRITE_1( "rssId: %d", rssId ); + + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + return; + } + + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* founded = rootFolder.Search( rssId ); + if ( founded ) + { + LOGGER_WRITE( "Item found" ); + const CFolderItem* parent = founded->Parent(); + if ( parent ) + { + LOGGER_WRITE( "parent found" ); + aParent = parent->Id() + KRssFeedsOffset; + } + else + { + LOGGER_WRITE( "no parent (root)" ); + aParent = KErrNotFound;// rootFolder.Id() + KRssFeedsOffset; + } + + if ( !founded->IsFolder() ) + { + LOGGER_WRITE("item type: EItem"); + AssignString( aMimeType, KBookmarkItemMimeType ); + AssignString( aMimeVer, KBookmarkItemMimeVersion ); + } + else + { + LOGGER_WRITE("item type: EFolder"); + AssignString( aMimeType, KBookmarkFolderMimeType ); + AssignString( aMimeVer, KBookmarkFolderMimeVersion ); + } + iConverter->RssItemToBufferL( *founded, *iDataBuffer ); + aSize = iDataBuffer->Size(); + + } + else + { + LOGGER_WRITE( "Item not found" ); + User::RequestComplete( iCallerStatus, KErrNotFound ); + return; + } + + } + + User::RequestComplete( iCallerStatus, KErrNone ); + iCurrentState = EBookmarkOpen; + +#ifdef _DEBUG + LOGGER_WRITE_1( "aFieldChange: %d", (TInt)aFieldChange ); + LOGGER_WRITE_1( "aSize: %d", aSize ); + LOGGER_WRITE_1( "aParent: %d", aParent ); + TPtr8 bufPtr = iDataBuffer->Ptr(0); + LOGGER_WRITE8_1( "iDataBuffer: %S", &bufPtr); +#endif + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoOpenItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCreateItemL +// Create new item to the message store. +// Return the id number of the newly created item +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCreateItemL( + TSmlDbItemUid& aUid, + TInt aSize, + TSmlDbItemUid aParent, + const TDesC8& aMimeType, + const TDesC8& /*aMimeVer*/, + TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCreateItemL" ); + LOGGER_WRITE_1( "aParent: %d", aParent ); + LOGGER_WRITE8_1( "aMimeType: %S", &aMimeType ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + delete iItemToBeReplaced; + iItemToBeReplaced = NULL; + + // Check MIME type + if ( aMimeType.Compare( KBookmarkFolderMimeType() ) == 0 ) + { + LOGGER_WRITE("item type: EFolder"); + iMimeType = CFavouritesItem::EFolder; + } + else if ( aMimeType.Compare( KBookmarkItemMimeType() ) == 0 ) + { + LOGGER_WRITE("item type: EItem"); + iMimeType = CFavouritesItem::EItem; + } + else + { + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_WRITE( "Unexpected mime type" ); + return; + } + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "Warning: Unexpected current state: %d", iCurrentState ); + } + + // Ensure that we've got enough disk space for the item + if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iRfs, aSize, EDriveC ) ) + { + User::RequestComplete( iCallerStatus, KErrDiskFull ); + LOGGER_WRITE( "SysUtil::DiskSpaceBelowCriticalLevelL failed with KErrDiskFull." ); + return; + } + + if ( aParent < KRssFeedsOffset ) + { + LOGGER_WRITE( "Handle id as bookmark item" ); + // Ensure that parent folder exists + TBool folderExists( EFalse ); + TInt err = iDb.FolderExists( aParent, folderExists ); + if ( err || !folderExists ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE_1( "iDb.FolderExist returned %d, folder not found", err ); + return; + } + + } + else + { + LOGGER_WRITE( "Handle id as rssFeed item " ); + + TInt rssId = aParent - KRssFeedsOffset; + LOGGER_WRITE_1( "parentRssId: %d", rssId ); + + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + return; + } + + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* founded = rootFolder.Search( rssId ); + TBool folderExists( EFalse ); + if ( founded ) + { + if ( founded->IsFolder() ) + { + folderExists = ETrue; + } + } + if ( !folderExists ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE( "Folder does not exist" ); + return; + } + } + + iCurrentState = EBookmarkCreating; + // Store parent for further use + iParentFolder = aParent; + + SAFEDELETE( iDataBuffer ); + iDataBuffer = CBufFlat::NewL( KDefaultBufferSize ); + iWriterPosition = 0; + + iCurrentItem = &aUid; + + + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCreateItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoReplaceItemL +// Begin the replace operation, ensure that the item really exists +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoReplaceItemL( + TSmlDbItemUid aUid, + TInt aSize, + TSmlDbItemUid aParent, + TBool /*aFieldChange*/, + TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoReplaceItemL" ); + LOGGER_WRITE_1("aUid: %d", aUid); + LOGGER_WRITE_1("aParent: %d", aParent); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + delete iItemToBeReplaced; + iItemToBeReplaced = NULL; + + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "Warning: Unexpected current state: %d", iCurrentState ); + } + + // Ensure that we've got enough disk space for the item + if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iRfs, aSize, EDriveC ) ) + { + User::RequestComplete( iCallerStatus, KErrDiskFull ); + LOGGER_WRITE( "SysUtil::DiskSpaceBelowCriticalLevelL failed with KErrDiskFull." ); + return; + } + + if ( aUid < KRssFeedsOffset ) + { + LOGGER_WRITE( "Bookmark item" ); + iItemToBeReplaced = CFavouritesItem::NewL(); + // Check that item exists + TInt err = iDb.Get( aUid, *iItemToBeReplaced ); + if ( err != KErrNone ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE_1( "iDb.Get failed with %d", err ); + SAFEDELETE(iItemToBeReplaced); + return; + } + + // is parent changed + if ( aParent != iItemToBeReplaced->ParentFolder() ) + { + if ( aParent >= KRssFeedsOffset ) + { + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_WRITE( "cannot move to RSS items folder" ); + SAFEDELETE(iItemToBeReplaced); + return; + } + // parent is changed, ensure that new parent folder exists + TBool folderExists( EFalse ); + err = iDb.FolderExists( aParent, folderExists ); + if ( err || !folderExists ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE_1( "iDb.FolderExist returned %d, new parent folder not found", err ); + SAFEDELETE(iItemToBeReplaced); + return; + } + } + + + // Store some variables to be used later in commit + iMimeType = iItemToBeReplaced->Type(); + iItemToBeReplaced->SetParentFolder( aParent ); + iParentFolder = aParent; + iReplaceItem = aUid; + } + else + { + LOGGER_WRITE( "RSS item" ); + if ( aParent < KRssFeedsOffset ) + { + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_WRITE( "cannot move RSS item to normal folder" ); + return; + } + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + return; + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* rssItem = rootFolder.Search( aUid - KRssFeedsOffset ); + if ( !rssItem ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss item not found" ); + return; + } + if ( rssItem->IsFolder() ) + { + iMimeType = CFavouritesItem::EFolder; + } + else + { + iMimeType = CFavouritesItem::EItem; + } + const CFolderItem* parent = rssItem->Parent(); + if ( parent ) + { + TInt currentParent = parent->Id() + KRssFeedsOffset; + + const CFolderItem* newParent = rootFolder.Search( aParent - KRssFeedsOffset ); + if ( !newParent ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE( "new parent not found" ); + return; + } + else if ( !newParent->IsFolder() ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE( "new parent must be folder" ); + return; + } + else + { + iParentFolder = aParent; + } + + } + else + { + iParentFolder = KErrNotFound; + } + iReplaceItem = aUid; + } + + + + SAFEDELETE(iDataBuffer); + iDataBuffer = CBufFlat::NewL( KDefaultBufferSize ); + iWriterPosition = 0; + + iCurrentItem = &aUid; + iCurrentState = EBookmarkUpdating; + + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoReplaceItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoReadItemL +// Read specified amount of data from the temporary buffer +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoReadItemL( TDes8& aBuffer ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoReadItemL" ); + + if (iCurrentState != EBookmarkOpen || !iDataBuffer) + { + LOGGER_WRITE_1( "Unexpected state %d", iCurrentState ); + User::Leave( KErrNotReady ); + } + + if (iReaderPosition == KDataBufferNotReady) + { + LOGGER_WRITE( "No data to read" ); + User::Leave( KErrEof ); + } + + // Thiw is how much data there is left in the buffer + TInt left = iDataBuffer->Size() - iReaderPosition; + + if ( left > 0 ) + { + // This is how much there's space in the destination buffer + TInt destSize = aBuffer.MaxSize(); + + // This is how much we can read + TInt toRead = destSize < left ? destSize : left; + + // Read the data from the buffer, then update the position + iDataBuffer->Read( iReaderPosition, aBuffer, toRead ); + iReaderPosition += toRead; + } + else + { + iReaderPosition = KDataBufferNotReady; + LOGGER_WRITE( "No data to read" ); + User::Leave( KErrEof ); + } + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoReadItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoWriteItemL +// Write specified amount of data to the temporary buffer +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoWriteItemL( const TDesC8& aData ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoWriteItemL" ); + + if ( iCurrentState != EBookmarkCreating && iCurrentState != EBookmarkUpdating ) + { + LOGGER_WRITE_1( "Unexpected current state: %d", iCurrentState ); + User::Leave( KErrNotReady ); + } + + // Calculate total size + TInt totalSize = aData.Size() + iDataBuffer->Size(); + + // Ensure that we've got enough disk space for the item + if ( SysUtil::DiskSpaceBelowCriticalLevelL( &iRfs, totalSize, EDriveC ) ) + { + User::RequestComplete( iCallerStatus, KErrDiskFull ); + LOGGER_WRITE("SysUtil::DiskSpaceBelowCriticalLevelL failed with KErrDiskFull."); + return; + } + + // Add data to buffer + iDataBuffer->InsertL( iWriterPosition, aData ); + iWriterPosition += aData.Size(); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoWriteItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCommitItemL +// Commits item from temporary buffer to the message store +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCommitItemL( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCommitItemL" ); + LOGGER_WRITE_1("iParentFolder: %d", iParentFolder); + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if ( iCurrentState != EBookmarkCreating && iCurrentState != EBookmarkUpdating ) + { + User::RequestComplete( iCallerStatus, KErrNotReady ); + LOGGER_WRITE_1( "Unexpected current state: %d", iCurrentState ); + return; + } + + if ( iDataBuffer->Size() <= 0 ) + { + User::RequestComplete( iCallerStatus, KErrNotReady ); + LOGGER_WRITE_1( "Data buffer has no data (%d)", iDataBuffer->Size() ); + return; + } + + + + // If iItemToBeReplaced exist, bookmark item is going to be replaced. + // iItemToBeReplaced contains original bookmark and only some of it's data is replaced. + CFavouritesItem* item(NULL); + if ( iItemToBeReplaced ) + { + // Change object ownership to "item"-object, and push to cleanupStack + item = iItemToBeReplaced; + CleanupStack::PushL( item ); + iItemToBeReplaced = NULL; + } + else + { + // Create new object. + item = CFavouritesItem::NewLC(); + } + + iDataBuffer->Compress(); + TInt err = iConverter->BufferToFavouritesItemL( iMimeType, *iDataBuffer, *item ); + + if ( iParentFolder == KErrNotFound ) + { + if ( item->Name().Compare( KRSSRootFolderName ) == 0 ) + { + LOGGER_WRITE( "Was RSS Rootfolder" ); + // Remove from cleanup stack + CleanupStack::PopAndDestroy( item ); + + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + return; + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + + *iCurrentItem = rootFolder.Id() + KRssFeedsOffset; + + // Inform ChangeFinder of updated item + TSnapshotItem snapshotItem( rootFolder.Id() + KRssFeedsOffset ); + snapshotItem.SetParentId( iParentFolder ); + snapshotItem.CreateHashL( KRSSRootFolderName, KNullDesC ); + iChangeFinder->ItemUpdatedL( snapshotItem ); + + // Destroy buffer + SAFEDELETE( iDataBuffer ); + iWriterPosition = 0; + + // Restore state and signal we're done + LOGGER_WRITE( "Signal KErrNone" ); + iCurrentState = EOpenAndWaiting; + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_WRITE_1("Item ID: %d", *iCurrentItem); + LOGGER_WRITE_1("Parent ID: %d", iParentFolder); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCommitItemL" ); + return; + } + } + + if ( iParentFolder < KRssFeedsOffset ) + { + // Convert buffer to favourites item + LOGGER_WRITE( "BookmarkItem" ); + + if ( err == KErrNone ) + { + LOGGER_WRITE_1 ( "ParentFolder: %d", iParentFolder ) + // Creating new item + if ( iCurrentState == EBookmarkCreating ) + { +#ifdef _DEBUG + LOGGER_WRITE( "Create new bookmark item" ); + TPtrC namePtr = item->Name(); + LOGGER_WRITE_1( "name: %S", &namePtr ); +#endif + // Set parent folder + item->SetParentFolder( iParentFolder ); + + // Add to database + err = iDb.Add( *item, EFalse ); + LOGGER_WRITE_1("iDb.Add return: %d", err); + if ( err == KErrNone ) + { + // Output the uid value of new item + *iCurrentItem = item->Uid(); + LOGGER_WRITE_1("New item Uid: %d", *iCurrentItem); + // Inform ChangeFinder of the added item + TSnapshotItem snapshotItem( *iCurrentItem ); + snapshotItem.SetParentId( iParentFolder ); + snapshotItem.CreateHashL( item->Name(), item->Url() ); + iChangeFinder->ItemAddedL( snapshotItem ); + } + else + { + LOGGER_WRITE_1( "RFavouritesDb::Add failed: %d", err ); + } + } + // Updating existing item + else + { + LOGGER_WRITE( "Update existing item" ); + item->SetParentFolder(iParentFolder); + err = iDb.Update( *item, iReplaceItem, EFalse ); + if ( err == KErrNone ) + { + // Inform ChangeFinder of updated item + TSnapshotItem snapshotItem( iReplaceItem ); + snapshotItem.SetParentId( iParentFolder ); + snapshotItem.CreateHashL( item->Name(), item->Url() ); + iChangeFinder->ItemUpdatedL( snapshotItem ); + } + else + { + LOGGER_WRITE_1( "RFavouritesDb::Update failed: %d", err ); + } + } + } + else + { + LOGGER_WRITE_1( "Failed to create db item (%d)", err ); + } + + } + else + { + LOGGER_WRITE( "RSS item" ); + err = iConverter->BufferToFavouritesItemL( iMimeType, *iDataBuffer, *item ); + // Destroy buffer + SAFEDELETE( iDataBuffer ); + iWriterPosition = 0; + if ( err == KErrNone ) + { + if ( iCurrentState == EBookmarkCreating ) + { + TBool isFolder = ( iMimeType == CFavouritesItem::EFolder ); + CreateRssItemL( iParentFolder - KRssFeedsOffset, item->Name(), item->Url(), isFolder ); + + CleanupStack::PopAndDestroy( item ); + LOGGER_WRITE( "waiting FolderItemRequestCompleted..." ); + return; + } + else + { + LOGGER_WRITE( "Replace RSS item" ); + ReplaceRssItemL( iReplaceItem - KRssFeedsOffset, item->Name(), item->Url()); + + CleanupStack::PopAndDestroy( item ); + LOGGER_WRITE( "waiting FolderItemRequestCompleted..." ); + return; + } + } + else + { + // Data was corrupted + LOGGER_WRITE_1( " iConverter->BufferToFavouritesItemL err: %d", err ); + err = KErrCorrupt; + } + } + + + // Remove from cleanup stack + CleanupStack::PopAndDestroy( item ); + + // Destroy buffer + SAFEDELETE( iDataBuffer ); + iWriterPosition = 0; + + // Restore state and signal we're done + iCurrentState = EOpenAndWaiting; + User::RequestComplete( iCallerStatus, err ); + + LOGGER_WRITE_1("Item ID: %d", iReplaceItem); + LOGGER_WRITE_1("Parent ID: %d", iParentFolder); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCommitItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::CreateRssItemL +// Creates new Rss item, FolderItemRequestCompleted is called when done +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::CreateRssItemL( TInt aRssParentUid, const TDesC& aName, const TDesC& aUrl, TBool aIsFolder ) + { + TRACE_FUNC_ENTRY; + LOGGER_WRITE_1("aRssParentUid: %d", aRssParentUid); + LOGGER_WRITE_1("aName: %S", &aName); + + if ( !iRootFolder.HasRootFolderItem() ) + { + LOGGER_WRITE( "rss root folder not found" ); + User::Leave( KErrNotFound ); + } + + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + + // check that parent folder exists + const CFolderItem* parent = rootFolder.Search( aRssParentUid ); + if ( !parent ) + { + LOGGER_WRITE( "parent folder not found" ); + User::Leave( KErrNotFound ); + } + + // check that folder does not already exists + const CFolderItem* existingItem = parent->Search( aName ); + if ( existingItem ) + { + LOGGER_WRITE("Same name already exist, return KErrAlreadyExists"); + User::Leave( KErrAlreadyExists ); + } + + TInt err(KErrNone); + // async func. FolderItemRequestCompleted is called when completed + TRAP( err, iRootFolder.AddFolderItemL( + aName, + aUrl, + aIsFolder, + *parent ) ); + LOGGER_WRITE_1( "iRootFolder.AddFolderItemL err: %d", err ); + + iNewItemName.Copy( aName ); + + TRACE_FUNC_EXIT; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::ReplaceRssItemL +// Replaces rss item, FolderItemRequestCompleted is called when done +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::ReplaceRssItemL( TInt aRssItemUid, const TDesC& aNewName, const TDesC& aNewUrl ) + { + TRACE_FUNC_ENTRY; + LOGGER_WRITE_1("aRssItemUid: %d", aRssItemUid); + LOGGER_WRITE_1("aNewName: %S", &aNewName); + LOGGER_WRITE_1("aNewUrl: %S", &aNewUrl); + + if ( !iRootFolder.HasRootFolderItem() ) + { + LOGGER_WRITE( "rss root folder not found" ); + User::Leave( KErrNotFound ); + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + LOGGER_WRITE_1( "rootFolder.Search %d", aRssItemUid ); + const CFolderItem* rssItem = rootFolder.Search( aRssItemUid ); + if ( !rssItem ) + { + LOGGER_WRITE( "rssItem not found" ); + User::Leave( KErrNotFound ); + } + + // async func. FolderItemRequestCompleted is called when completed + if ( rssItem->IsFolder() ) + { + iRootFolder.ChangeFolderItemL( + *rssItem, + aNewName, + KNullDesC ); + } + else + { + iRootFolder.ChangeFolderItemL( + *rssItem, + aNewName, + aNewUrl ); + } + + TRACE_FUNC_EXIT; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCloseItem +// Closes open item in the data store +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCloseItem() + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCloseItem" ); + + // Make sure that we're opened an item + if ( iCurrentState == EBookmarkOpen ) + { + // Reset read buffer + iReaderPosition = KDataBufferNotReady; + SAFEDELETE( iDataBuffer ); + + // Start to wait for the next operation + iCurrentState = EOpenAndWaiting; + } + else + { + LOGGER_WRITE_1( "Invalid state %d.", iCurrentState ); + } + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCloseItem" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoMoveItemL +// Moves item from one bookmark folder to another +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoMoveItemL( TSmlDbItemUid aUid, + TSmlDbItemUid aNewParent, TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoMoveItemL" ); + LOGGER_WRITE_1("aUid: %d", aUid); + LOGGER_WRITE_1("new parent: %d", aNewParent); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + TInt err( KErrNone ); + + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "WARNING! Invalid state: %d", iCurrentState ); + } + + if ( aUid < KRssFeedsOffset ) + { + // Bookmark item + LOGGER_WRITE( "Bookmark item" ); + // Ensure that new parent folder exists + TBool folderExists( EFalse ); + err = iDb.FolderExists( aNewParent, folderExists ); + if ( err || !folderExists ) + { + User::RequestComplete( iCallerStatus, KErrPathNotFound ); + LOGGER_WRITE_1( "iDb.FolderExist returned %d, new parent folder not found", err ); + return; + } + + CFavouritesItem* item = CFavouritesItem::NewLC(); + + err = iDb.Get( aUid, *item ); + if ( err == KErrNone ) + { + if ( item->ParentFolder() != aNewParent ) + { + TTime time = item->Modified(); + + // Parent was changed, set new + item->SetParentFolder( aNewParent ); + + // Update, this'll move the item + err = iDb.Update( *item, aUid, ETrue ); + + if ( err == KErrNone ) + { + // Do not change the timestamp, otherwise this will be + // considered to be 'updated' item instead of moved one + err = iDb.SetModified(aUid, time); + if ( err != KErrNone ) + { + LOGGER_WRITE_1( "iDb.SetModified(aUid, time) failed (%d).", err ); + } + + // Inform ChangeFinder of updated item + TSnapshotItem snapshotItem( aUid ); + snapshotItem.SetParentId( iParentFolder ); + snapshotItem.CreateHashL( item->Name(), item->Url() ); + iChangeFinder->ItemMovedL( snapshotItem ); + } + else + { + LOGGER_WRITE_1( "iDb.Update(*item, aUid, ETrue) failed (%d).", err ); + } + } + else + { + LOGGER_WRITE( "Ignoring move (parent was already correct)." ); + } + } + else + { + LOGGER_WRITE_1( "RFavouritesDb::Get failed with %d", err ); + err = KErrNotFound; + } + + CleanupStack::PopAndDestroy( item ); + User::RequestComplete( iCallerStatus, err ); + } + else + { + // RRS item + LOGGER_WRITE( "RSS item" ); + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + return; + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* rssItem = rootFolder.Search( aUid - KRssFeedsOffset ); + if ( !rssItem ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rssItem not found" ); + return; + } + LOGGER_WRITE_1("rssItem->Id(): %d", rssItem->Id()); + if ( !rssItem->Parent() ) + { + // this is "RSS Root" folder, can't move + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "RSS Root folder, can't move" ); + return; + } + const CFolderItem* parent = rootFolder.Search( aNewParent - KRssFeedsOffset ); + if ( !parent ) + { + // new parent not found + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "new parent not found" ); + return; + } + if ( !parent->IsFolder() ) + { + // not a folder + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "parent is not a folder" ); + return; + } + RPointerArray movedItems; + CleanupClosePushL( movedItems ); + movedItems.Append( rssItem ); + // FolderItemRequestCompleted is called when ready + iRootFolder.MoveFolderItemsToL( movedItems, *parent); + CleanupStack::PopAndDestroy( &movedItems ); + + delete iMovedItem; + iMovedItem = NULL; + iMovedItem = new (ELeave) TSnapshotItem( aUid, aNewParent ); + + iCurrentState = EBookmarkMoving; + LOGGER_WRITE( "Wait for FolderItemRequestCompleted.." ); + } + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoMoveItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoDeleteItemL +// Removes item from the message store +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoDeleteItemL( TSmlDbItemUid aUid, TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoDeleteItemL" ); + LOGGER_WRITE_1( "aUid: %d", aUid ); + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1("CBookmarkDataStore::DoDeleteItemL, Incorrect state: %d", iCurrentState); + } + + TInt error( KErrNone ); + if ( aUid < KRssFeedsOffset ) + { + LOGGER_WRITE( "Delete Bookmark item" ); + // Delete item from db and return the error code + error = iDb.Delete( aUid ); + + if ( error == KErrNone ) + { + // Inform ChangeFinder of the removed item + TSnapshotItem item( aUid ); + iChangeFinder->ItemDeletedL( item ); + } + else + { + LOGGER_WRITE_1("CBookmarkDataStore::DoDeleteItemL, iDb.Delete failed: %d", error); + } + + User::RequestComplete( iCallerStatus, error ); + } + else + { + LOGGER_WRITE( "Delete RSS item" ); + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "rss root folder not found" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeleteItemL" ); + return; + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + const CFolderItem* item = rootFolder.Search( aUid - KRssFeedsOffset ); + if ( !item ) + { + User::RequestComplete( iCallerStatus, KErrNotFound ); + LOGGER_WRITE( "item not found" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeleteItemL" ); + return; + } + + LOGGER_WRITE_1("founded. item->Id(): %d", item->Id()); + if ( !item->Parent() ) + { + LOGGER_WRITE_1( + "Item parent not found, this is root folder. Return error: %d", KErrAccessDenied); + User::RequestComplete( iCallerStatus, KErrAccessDenied ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeleteItemL" ); + return; + } + else + { + LOGGER_WRITE( "parent found" ); + } + + RPointerArray folderItems; + CleanupClosePushL( folderItems ); + error = folderItems.Append( item ); + LOGGER_WRITE_1( "folderItems.Append error: %d", error ); + TRAP( error, iRootFolder.DeleteFolderItemsL( folderItems ) ); + CleanupStack::PopAndDestroy( &folderItems ); + LOGGER_WRITE_1( "Trap error: %d", error ); + + iReplaceItem = aUid; + iCurrentState = EBookmarkDeleting; + LOGGER_WRITE( "Wait for FolderItemRequestCompleted.." ); + } + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeleteItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoSoftDeleteItemL +// Soft delete isn't supported. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoSoftDeleteItemL(TSmlDbItemUid /*aUid*/, TRequestStatus& aStatus) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoSoftDeleteItemL" ); + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + User::RequestComplete(iCallerStatus, KErrNotSupported); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoSoftDeleteItemL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoDeleteAllItemsL +// Deletes all items in the standard folders of bookmark store +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoDeleteAllItemsL( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoDeleteAllItemsL" ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if (iCurrentState != EOpenAndWaiting) + { + LOGGER_WRITE_1( "CSmsDataStore::DoDeleteAllItemsL, Incorrect state: %d", iCurrentState ); + } + + // Reset the whole change finder + iChangeFinder->ResetL(); + + // Delete all Bookmark items + LOGGER_WRITE( "Delete Bookmark items" ); + // Loop through all items at root, and delete everything + CFavouritesItemList* list = new ( ELeave ) CFavouritesItemList(); + TInt error = iDb.GetAll( *list, KFavouritesRootUid ); + if ( error == KErrNone ) + { + // Loop through the list and delete all items + TInt count = list->Count(); + LOGGER_WRITE_1("list->Count(): %d", count); + for ( TInt i = 0; i < count; ++i ) + { + CFavouritesItem* item = (*list)[i]; + + // Don't bother try to erase items, which are read only + if ( !item->IsFactoryItem() ) + { + TInt deleted = iDb.Delete( item->Uid() ); + if ( deleted != KErrNone ) + { + // In the case of error, store the error value + error = deleted; + LOGGER_WRITE_1("CBookmarkDataStore::DoDeleteAllItemsL, iDb.Delete failed: %d", error); + } + + LOGGER_WRITE_1("item->Uid(): %d", item->Uid()) + LOGGER_WRITE_1("iDb.Delete ret: %d", error) + + } + else + { + LOGGER_WRITE_1("item->IsFactoryItem(): id: %d", item->Uid()); + } + } + } + else + { + LOGGER_WRITE_1("CBookmarkDataStore::DoDeleteAllItemsL, iDb.GetAll failed: %d", error); + } + delete list; + + // Delete all WebFeeds + LOGGER_WRITE( "Delete RSS items" ); + if ( !iRootFolder.HasRootFolderItem() ) + { + User::RequestComplete( iCallerStatus, error ); + LOGGER_WRITE( "no RSS items" ); + return; + } + const CFolderItem& rootFolder = iRootFolder.RootFolderItem(); + // add subfolders + RPointerArray folderItems; + CleanupClosePushL( folderItems ); + for ( TInt i = 0; i < rootFolder.FolderItemCount(); i++) + { + error = folderItems.Append( rootFolder.FolderItemAt( i ) ); + LOGGER_WRITE_1( "folderItems.Append error: %d", error ); + } + + if ( folderItems.Count() > 0 ) + { + TRAP( error, iRootFolder.DeleteFolderItemsL( folderItems ) ); + + LOGGER_WRITE_1( "Trap error: %d", error ); + + iCurrentState = EBookmarkDeletingAll; + LOGGER_WRITE( "Wait for FolderItemRequestCompleted.." ); + } + else + { + LOGGER_WRITE( "RSS items not found" ); + User::RequestComplete( iCallerStatus, KErrNone ); + } + CleanupStack::PopAndDestroy( &folderItems ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeleteAllItemsL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoHasSyncHistory +// This method returns ETrue if Data Store has history information. +// Slow-sync will be used if Data Store does not have history information. +// ----------------------------------------------------------------------------- +TBool CBookmarkDataStore::DoHasSyncHistory() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoHasSyncHistory" ); + LOGGER_WRITE_1( "iHasHistory: %d", iHasHistory ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoHasSyncHistory" ); + return iHasHistory; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoAddedItems +// This method returns UIDs of added items. Those items are added after previous +// synchronization with current synchronization relationship. +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CBookmarkDataStore::DoAddedItems() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoAddedItems" ); + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoAddedItems, invalid state %d.", iCurrentState ); + } + + TInt error(KErrNone); + + // Clear new-items array + iNewItems->Reset(); + + // Search for new items + TRAP( error, iChangeFinder->FindNewItemsL( *iNewItems ) ) + if ( error != KErrNone ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoAddedItems, iChangeFinder->FindNewItemsL leaved with %d.", error ); + } + + LOGGER_WRITE_1( "New item count: %d.", iNewItems->ItemCount() ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoAddedItems" ); + + return *iNewItems; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoDeletedItems +// Returns ids of items, which are deleted after previous synchronization +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CBookmarkDataStore::DoDeletedItems() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoDeletedItemsL" ); + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoDeletedItems, invalid state %d.", iCurrentState ); + } + + TInt error( KErrNone ); + + // Clear deleted-items array + iDeletedItems->Reset(); + + // Search for deleted items + TRAP( error, iChangeFinder->FindDeletedItemsL( *iDeletedItems ) ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoDeletedItems, iChangeFinder->FindDeletedItemsL leaved with %d.", error ); + } + + LOGGER_WRITE_1( "Deleted item count: %d.", iDeletedItems->ItemCount() ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoDeletedItemsL" ); + return *iDeletedItems; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoSoftDeletedItems +// Not directly supported, empty list returned +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CBookmarkDataStore::DoSoftDeletedItems() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoSoftDeletedItems" ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoSoftDeletedItems" ); + + // Return empty array as a result + iSoftDeletedItems->Reset(); + return *iSoftDeletedItems; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoModifiedItems +// Finds all modified items in the data store +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CBookmarkDataStore::DoModifiedItems() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoModifiedItems" ); + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoModifiedItems, invalid state %d.", iCurrentState ); + } + + TInt error( KErrNone ); + + // Clear updated-items array + iUpdatedItems->Reset(); + + // Search for updated items + TRAP( error, iChangeFinder->FindChangedItemsL( *iUpdatedItems ) ) + if ( error != KErrNone ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoModifiedItems, iChangeFinder->FindChangedItemsL leaved with %d.", error ); + } + + LOGGER_WRITE_1( "Modified item count: %d.", iUpdatedItems->ItemCount() ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoModifiedItems" ); + return *iUpdatedItems; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoMovedItems +// Finds all moved items in the data store +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CBookmarkDataStore::DoMovedItems() const + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoMovedItems" ); + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoMovedItems, invalid state %d.", iCurrentState ); + } + + TInt error( KErrNone ); + + // Clear moved-items array + iMovedItems->Reset(); + + TRAP( error, iChangeFinder->FindMovedItemsL( *iMovedItems ) ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoMovedItems, iChangeFinder->FindMovedItemsL leaved with %d.", error ); + } + + LOGGER_WRITE_1( "Moved item count: %d.", iMovedItems->ItemCount() ); + LOGGER_LEAVEFN( "CBookmarkDataStore::DoMovedItems" ); + return *iMovedItems; + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoResetChangeInfoL +// Resets change history in the data store. All content is considered +// new in the data store point of view. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoResetChangeInfoL( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoResetChangeInfoL" ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoResetChangeInfoL, invalid state %d.", iCurrentState ); + } + + // Reset change info in ChangeFinder + iChangeFinder->ResetL(); + iHasHistory = EFalse; + + // Signal we're done + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoResetChangeInfoL" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCommitChangeInfoL +// Commits change info. These items are no longer reported, when change +// information is being queried. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCommitChangeInfoL( TRequestStatus& aStatus, + const MSmlDataItemUidSet& aItems ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCommitChangeInfoL(1)" ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState ); + } + + // Notify ChangeFinder + LOGGER_WRITE_1( "CBookmarkDataStore::DoCommitChangeInfoL, item count %d.", aItems.ItemCount() ); + iChangeFinder->CommitChangesL( aItems ); + iHasHistory = ETrue; + + // Signal we're done + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN(" CBookmarkDataStore::DoCommitChangeInfoL(1)" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::DoCommitChangeInfoL +// Commits change info. There is no more nothing to report when change +// information is being queried. +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::DoCommitChangeInfoL( TRequestStatus& aStatus ) + { + LOGGER_ENTERFN( "CBookmarkDataStore::DoCommitChangeInfoL(2)" ); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure that we're in a proper state + if ( iCurrentState != EOpenAndWaiting ) + { + LOGGER_WRITE_1( "CBookmarkDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState ); + } + + // Notify ChangeFinder + iChangeFinder->CommitChangesL(); + iHasHistory = ETrue; + + // Signal we're done + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::DoCommitChangeInfoL(2)" ); + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::RegisterSnapshotL +// Sets Changefinder to compare against current bookmark store content +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::RegisterSnapshotL() + { + LOGGER_ENTERFN( "CBookmarkDataStore::RegisterSnapshotL()" ); + + CArrayFixSeg* snapshot = + new ( ELeave ) CArrayFixSeg( KSnapshotGranularity ); + CleanupStack::PushL( snapshot ); + + + RegisterToSnapshotL( snapshot, KFavouritesRootUid ); + + if ( iRootFolder.HasRootFolderItem() ) + { + RegisterRssFeedsToSnapshotL( snapshot, iRootFolder.RootFolderItem() ); + } + + // Set new snapshot to compare against + iChangeFinder->SetNewSnapshot( snapshot ); + + // Changefinder takes ownership of the snapshot + CleanupStack::Pop( snapshot ); + + LOGGER_LEAVEFN( "CBookmarkDataStore::RegisterSnapshotL()" ); + } + + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::RegisterToSnapshotL +// Adds recursively all the bookmark items to the snapshot +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::RegisterToSnapshotL( CArrayFixSeg* aSnapshot, + TInt aFolderUid ) + { + CFavouritesItemList* list = new ( ELeave ) CFavouritesItemList; + CleanupStack::PushL( list ); + TInt error = iDb.GetAll( *list, aFolderUid ); + if ( error == KErrNone ) + { + // Loop through the list. Add folders and items to the snapshot + TInt count = list->Count(); + for ( TInt i = 0; i < count; ++i ) + { + CFavouritesItem* item = (*list)[i]; + // No matter whether it's a folder or item, we'll add it to snapshot + TSnapshotItem snapshotItem( item->Uid() ); + snapshotItem.SetParentId( item->ParentFolder() ); + snapshotItem.CreateHashL( item->Name(), item->Url() ); + TKeyArrayFix key( iKey ); + aSnapshot->InsertIsqL( snapshotItem, key ); + + // Remember to add also childs in case of folder (recurse) + if ( item->Type() == CFavouritesItem::EFolder ) + { + RegisterToSnapshotL( aSnapshot, item->Uid() ); + } + } + } + CleanupStack::PopAndDestroy( list ); //list + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::RegisterRssFeedsToSnapshotL +// Adds recursively all the rssFeed items to the snapshot +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::RegisterRssFeedsToSnapshotL( CArrayFixSeg* aSnapshot, + const CFolderItem& folder ) + { + TSnapshotItem snapshotItem( folder.Id() + KRssFeedsOffset ); + + const CFolderItem* parent = folder.Parent(); + if ( parent ) + { + snapshotItem.SetParentId( parent->Id() + KRssFeedsOffset ); + } + else + { + snapshotItem.SetParentId( KErrNotFound ); + } + snapshotItem.CreateHashL( folder.Name(), folder.SourceUrl() ); + + TKeyArrayFix key( iKey ); + aSnapshot->InsertIsqL( snapshotItem, key ); + + // add subfolders + for ( TInt i = 0; i < folder.FolderItemCount(); i++) + { + RegisterRssFeedsToSnapshotL( aSnapshot, *(folder.FolderItemAt( i ) )); + } + } + +// ----------------------------------------------------------------------------- +// CBookmarkDataStore::AssignString +// Assigns data from one descriptor into another, truncates if too long +// ----------------------------------------------------------------------------- +void CBookmarkDataStore::AssignString( TDes8& aDestination, const TDesC8& aSource ) + { + TInt targetLength = aSource.Length(); + if ( aDestination.MaxLength() < targetLength ) + { + targetLength = aDestination.MaxLength(); + } + + aDestination.Copy( aSource.Ptr(), targetLength ); + }