htiui/HtiServicePlugins/HtiPIMServicePlugin/src/HtiBookmarkHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:17:27 +0200
changeset 0 d6fe6244b863
child 11 454d022d514b
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 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:  Implementation of browser bookmark handling.
*
*/


// INCLUDE FILES
#include "HtiBookmarkHandler.h"
#include "HtiPIMServicePlugin.h"

#include <cmconnectionmethod.h>
#include <cmconnectionmethoddef.h>
#include <cmdestination.h>
#include <cmmanager.h>

#include <FavouritesItem.h>
#include <FavouritesItemList.h>
#include <FavouritesDb.h>
#include <FavouritesFile.h>
#include <FavouritesWapAp.h>

#include <HtiDispatcherInterface.h>
#include <HTILogging.h>

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS
_LIT8( KErrorUnrecognizedCommand, "Unrecognized command" );
_LIT8( KErrorInvalidParameters, "Invalid command parameters" );
_LIT8( KErrorCreateFailed, "Bookmark creation failed" );
_LIT8( KErrorDeleteFailed, "Bookmark deletion failed" );
_LIT8( KErrorBookmarkNotFound, "Bookmark not found" );
_LIT8( KErrorFolderNotFound, "Folder not found" );
_LIT8( KErrorApNotFound, "Access point not found" );
_LIT8( KErrorFolderSearchFailed, "Error when searching folder" );
_LIT8( KErrorApSearchFailed, "Error when searching access point" );

const TInt KCreateMessageMinLength = 10;
const TInt KDeleteMessageMinLength = 3;

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CHtiBookmarkHandler::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
CHtiBookmarkHandler* CHtiBookmarkHandler::NewL()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::NewL" );
    CHtiBookmarkHandler* self = new ( ELeave ) CHtiBookmarkHandler();
    CleanupStack::PushL ( self );
    self->ConstructL();
    CleanupStack::Pop();
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::NewL" );
    return self;
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::CHtiBookmarkHandler
// C++ default constructor can NOT contain any code, that
// might leave.
// ----------------------------------------------------------------------------
CHtiBookmarkHandler::CHtiBookmarkHandler()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::CHtiBookmarkHandler" );
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::CHtiBookmarkHandler" );
    }


// -----------------------------------------------------------------------------
// CHtiBookmarkHandler::~CHtiBookmarkHandler
// Destructor.
// -----------------------------------------------------------------------------
CHtiBookmarkHandler::~CHtiBookmarkHandler()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::~CHtiBookmarkHandler" );
    delete iUrl;
    iFavSession.Close();
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::~CHtiBookmarkHandler" );
    }


// -----------------------------------------------------------------------------
// CHtiBookmarkHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
void CHtiBookmarkHandler::ConstructL()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::ConstructL" );
    User::LeaveIfError( iFavSession.Connect() );
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::ConstructL" );
    }


// -----------------------------------------------------------------------------
// CHtiBookmarkHandler::SetDispatcher
// Sets the dispatcher pointer.
// -----------------------------------------------------------------------------

void CHtiBookmarkHandler::SetDispatcher( MHtiDispatcher* aDispatcher )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::SetDispatcher" );
    iDispatcher = aDispatcher;
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::SetDispatcher" );
    }


// -----------------------------------------------------------------------------
// CHtiBookmarkHandler::ProcessMessageL
// Parses the received message and calls handler functions.
// -----------------------------------------------------------------------------
void CHtiBookmarkHandler::ProcessMessageL( const TDesC8& aMessage,
    THtiMessagePriority /*aPriority*/ )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::ProcessMessageL" );
    // Zero legth of aMessage tested already in CHtiPIMServicePlugin.
    // Other sanity checks must be done here.
    if ( aMessage[0] == CHtiPIMServicePlugin::ECreateBookmark )
        {
        TRAPD( err, ParseCreateMessageL( aMessage ) );
        if ( err != KErrNone )
            {
            SendErrorMessageL( KErrArgument, KErrorInvalidParameters );
            }
        else
            {
            TRAP( err, HandleCreateBookmarkL() );
            if ( err != KErrNone )
                {
                SendErrorMessageL( err, KErrorCreateFailed );
                }
            }
        }

    else if ( aMessage[0] == CHtiPIMServicePlugin::EDeleteBookmark )
        {
        TRAPD( err, ParseDeleteMessageL( aMessage ) );
        if ( err != KErrNone )
            {
            SendErrorMessageL( KErrArgument, KErrorInvalidParameters );
            }
        else
            {
            TRAP( err, HandleDeleteBookmarkL() );
            if ( err != KErrNone )
                {
                SendErrorMessageL( err, KErrorDeleteFailed );
                }
            }
        }

    else
        {
        SendErrorMessageL( KErrArgument, KErrorUnrecognizedCommand );
        }
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::ProcessMessageL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::IsBusy
// Returns the status whether this handler is busy processing a request.
// ----------------------------------------------------------------------------
TBool CHtiBookmarkHandler::IsBusy()
    {
    // Never busy if ProcessMessageL has completed.
    return EFalse;
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::HandleCreateBookmarkL
// Handles the bookmark and/or folder creation command.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::HandleCreateBookmarkL()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::HandleCreateBookmarkL" );
    TInt err = KErrNone;
    // If folder given, get the UID if it exists
    TInt folderUid = KFavouritesRootUid;
    if ( iFolderName.Length() > 0 )
        {
        TRAP( err, folderUid = GetFolderUidL( iFolderName ) );
        if ( err != KErrNone )
            {
            SendErrorMessageL( err, KErrorFolderSearchFailed );
            return;
            }
        }
    HTI_LOG_FORMAT( "Folder UID = %d", folderUid );

    // If access point given, search the UID. It's an error if AP is not found.
    TInt apUid = KErrNotFound;
    if ( iApName.Length() > 0 )
        {
        TRAP( err, apUid = GetApUidL( iApName ) );
        if ( err != KErrNone )
            {
            SendErrorMessageL( err, KErrorApSearchFailed );
            return;
            }
        if ( apUid == KErrNotFound )
            {
            SendErrorMessageL( KErrNotFound, KErrorApNotFound );
            return;
            }
        }

    RFavouritesDb db;
    User::LeaveIfError( db.Open( iFavSession, KBrowserBookmarks ) );
    CleanupClosePushL<RFavouritesDb>( db );

    TInt itemsCreated = 0;
    // If folder was given but was not found, create the folder first.
    if ( iFolderName.Length() > 0 && folderUid == KErrNotFound )
        {
        CFavouritesItem* folder = CFavouritesItem::NewLC();
        folder->SetType( CFavouritesItem::EFolder );
        folder->SetParentFolder( KFavouritesRootUid ) ;
        folder->SetNameL( iFolderName );

        HTI_LOG_TEXT( "Adding the folder item to DB" );
        err = db.Add( *folder, EFalse );
        HTI_LOG_FORMAT( "Add returned %d", err );
        if ( err != KErrNone )
            {
            User::Leave( err );
            }
        folderUid = folder->Uid();
        HTI_LOG_FORMAT( "New folder UID = %d", folderUid );
        CleanupStack::PopAndDestroy(); // folder
        itemsCreated++;
        }

    // Now create the actual bookmark item
    CFavouritesItem* item = CFavouritesItem::NewLC();
    item->SetType( CFavouritesItem::EItem );
    item->SetParentFolder( folderUid ) ;
    item->SetNameL( iBookmarkName );
    item->SetUrlL( *iUrl );
    if ( apUid != KErrNotFound )
        {
        TFavouritesWapAp favAp;
        favAp.SetApId(  ( TUint32 ) apUid );
        item->SetWapAp( favAp );
        }
    if ( iUserName.Length() > 0 )
        {
        item->SetUserNameL( iUserName );
        }
    if ( iPassword.Length() > 0 )
        {
        item->SetPasswordL( iPassword );
        }

    HTI_LOG_TEXT( "Adding the bookmark item to DB" );
    err = db.Add( *item, EFalse );
    HTI_LOG_FORMAT( "Add returned %d", err );
    if ( err )
        {
        User::Leave( err );
        }
    HTI_LOG_FORMAT( "Bookmark UID = %d", item->Uid() );
    CleanupStack::PopAndDestroy(); // item
    itemsCreated++;

    CleanupStack::PopAndDestroy(); // db

    TBuf8<1> response;
    response.Append( itemsCreated );
    SendOkMsgL( response );

    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::HandleCreateBookmarkL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::HandleDeleteBookmarkL
// Handles the bookmark and/or folder deletion.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::HandleDeleteBookmarkL()
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::HandleDeleteBookmarkL" );
    TInt err = KErrNone;
    // If folder given, get the UID if it exists.
    // It is an error if the given folder does not exist.
    TInt folderUid = KFavouritesRootUid;
    if ( iFolderName.Length() > 0 )
        {
        TRAP( err, folderUid = GetFolderUidL( iFolderName ) );
        if ( err != KErrNone )
            {
            SendErrorMessageL( err, KErrorFolderSearchFailed );
            return;
            }
        if ( folderUid == KErrNotFound )
            {
            SendErrorMessageL( KErrNotFound, KErrorFolderNotFound );
            return;
            }
        }
    HTI_LOG_FORMAT( "Folder UID = %d", folderUid );

    RFavouritesDb db;
    User::LeaveIfError( db.Open( iFavSession, KBrowserBookmarks ) );
    CleanupClosePushL<RFavouritesDb>( db );

    CArrayFixFlat<TInt>* deleteList = new ( ELeave ) CArrayFixFlat<TInt>( 10 );
    CleanupStack::PushL( deleteList );
    if ( iBookmarkName.Length() > 0 )
        {
        // Get the UID of bookmark item matching to iBookmarkName
        // It is an error if nothing found.
        CFavouritesItemList* items = new ( ELeave ) CFavouritesItemList();
        CleanupStack::PushL( items );
        User::LeaveIfError( db.GetAll( *items, folderUid,
            CFavouritesItem::EItem ) );
        TInt uid = KErrNotFound;
        TInt itemCount = items->Count();
        HTI_LOG_FORMAT( "Found %d items", itemCount );
        TInt i = 0;
        while ( uid == KErrNotFound && i < itemCount )
            {
            if ( ( *items )[i]->Name().CompareF( iBookmarkName ) == 0 )
                {
                uid = ( *items )[i]->Uid();
                }
            i++;
            }
        CleanupStack::PopAndDestroy(); // items
        HTI_LOG_FORMAT( "Matching item UID: %d", uid );
        if ( uid == KErrNotFound )
            {
            SendErrorMessageL( KErrNotFound, KErrorBookmarkNotFound );
            CleanupStack::PopAndDestroy( 2 ); // deleteList, db
            return;
            }
        else
            {
            deleteList->AppendL( uid );
            }
        }
    else
        {
        // We are deleting a folder (whose UID we already have) or deleting all.
        if ( folderUid != KFavouritesRootUid )
            {
            deleteList->AppendL( folderUid );
            }
        else
            {
            // We don't have folder or bookmark name - deleting all
            User::LeaveIfError( db.GetUids( *deleteList, KFavouritesRootUid ) );
            HTI_LOG_FORMAT( "Found %d matching items", deleteList->Count() );
            }
        }

    TInt beginningCount = KErrNotFound;
    User::LeaveIfError( db.Count( beginningCount ) );
    HTI_LOG_FORMAT( "Items in DB before delete: %d", beginningCount );

    // Start deleting
    TInt deleteCount = 0;
    for ( TInt i = 0; i < deleteList->Count(); i++ )
        {
        HTI_LOG_FORMAT( "Deleting with UID %d", ( *deleteList )[i] );
        err = db.Delete( ( *deleteList )[i] );
        HTI_LOG_FORMAT( "Delete returned %d", err );
        if ( err == KErrNone )
            {
            deleteCount++;
            }
        if ( err != KErrNone && err != KErrAccessDenied )
            {
            HTI_LOG_TEXT( "Unexpected error when deleting - leaving" );
            User::Leave( err );
            }
        }

    TInt endingCount = KErrNotFound;
    User::LeaveIfError( db.Count( endingCount ) );
    HTI_LOG_FORMAT( "Items in DB after delete: %d", endingCount );

    CleanupStack::PopAndDestroy( 2 ); // deleteList, db

    TBuf8<1> response;
    response.Append( beginningCount - endingCount );
    SendOkMsgL( response );

    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::HandleDeleteBookmarkL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::ParseCreateMessageL
// Extracts the parameters from a create bookmark message.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::ParseCreateMessageL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::ParseCreateMessageL" );
    TInt length = aMessage.Length();
    HTI_LOG_FORMAT( "CreateBookmark message length = %d", length );

    if ( length < KCreateMessageMinLength )
        {
        User::Leave( KErrArgument );
        }

    // Extract folder name
    TInt offset = 1; // skip the command code in position 0
    offset = ExtractStringL( aMessage, offset, 1, 0, KFavouritesMaxName,
                             iFolderName );
    HTI_LOG_FORMAT( "Folder name: %S", &iFolderName );

    // Extract bookmark name
    offset = ExtractStringL( aMessage, offset, 1, 1, KFavouritesMaxName,
                             iBookmarkName );
    HTI_LOG_FORMAT( "Bookmark name: %S", &iBookmarkName );

    // Extract URL
    delete iUrl;
    iUrl = NULL;
    iUrl = HBufC::NewL( KFavouritesMaxUrl );
    TPtr urlPtr = iUrl->Des();
    offset = ExtractStringL( aMessage, offset, 2, 1, KFavouritesMaxUrl,
                             urlPtr );
    HTI_LOG_FORMAT( "URL: %S", iUrl );

    // Extract AP name
    offset = ExtractStringL( aMessage, offset, 1, 0, KApMaxConnNameLength,
                             iApName );
    HTI_LOG_FORMAT( "AP name: %S", &iApName );

    // Extract user name
    offset = ExtractStringL( aMessage, offset, 1, 0, KFavouritesMaxUserName,
                             iUserName );
    HTI_LOG_FORMAT( "User name: %S", &iUserName );

    // Extract password
    offset = ExtractStringL( aMessage, offset, 1, 0, KFavouritesMaxPassword,
                             iPassword );
    HTI_LOG_FORMAT( "Password: %S", &iPassword );

    // Check that there's no extra data
    if ( offset != length  )
        {
        User::Leave( KErrArgument );
        }

    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::ParseCreateMessageL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::ParseDeleteMessageL
// Extracts the parameters from a delete bookmark message.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::ParseDeleteMessageL( const TDesC8& aMessage )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::ParseDeleteMessageL" );
    TInt length = aMessage.Length();
    HTI_LOG_FORMAT( "DeleteBookmark message length = %d", length );

    if ( length < KDeleteMessageMinLength )
        {
        User::Leave( KErrArgument );
        }

    // Extract folder name
    TInt offset = 1; // skip the command code in position 0
    offset = ExtractStringL( aMessage, offset, 1, 0, KFavouritesMaxName,
                             iFolderName );
    HTI_LOG_FORMAT( "Folder name: %S", &iFolderName );

    // Extract bookmark name
    offset = ExtractStringL( aMessage, offset, 1, 0, KFavouritesMaxName,
                             iBookmarkName );
    HTI_LOG_FORMAT( "Bookmark name: %S", &iBookmarkName );

    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::ParseDeleteMessageL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::ExtractStringL
// Extract one string from the given message. Leaves on syntax errors.
// ----------------------------------------------------------------------------
TInt CHtiBookmarkHandler::ExtractStringL( const TDesC8& aMessage, TInt aOffset,
        TInt aLengthBytes, TInt aMinLength, TInt aMaxLength, TDes& aResult )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::ExtractStringL" );
    __ASSERT_ALWAYS( aResult.MaxLength() >= aMaxLength,
                     User::Panic( _L( "HtiPimAssert" ), 1 ) );
    __ASSERT_ALWAYS( aLengthBytes > 0, User::Panic( _L( "HtiPimAssert" ), 2 ) );

    TInt length = aMessage.Length();
    if ( length < aOffset + 1 )
        {
        User::Leave( KErrArgument );
        }
    TInt parseLength = aMessage[aOffset];
    aOffset++;
    if ( aLengthBytes > 1 )
        {
        for ( TInt i = 1; i < aLengthBytes; i++ )
            {
            parseLength += aMessage[aOffset] << ( i * 8 );
            aOffset++;
            }
        }
    HTI_LOG_FORMAT( "Parse length = %d", parseLength );
    if ( parseLength < aMinLength  || parseLength > aMaxLength ||
         parseLength + aOffset > length )
        {
        User::Leave( KErrArgument );
        }
    else
        {
        aResult.Copy( aMessage.Mid( aOffset, parseLength ) );
        aOffset += parseLength;
        }
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::ExtractStringL" );
    return aOffset;
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::GetFolderUidL
// Finds the UID of the named folder if it exists.
// ----------------------------------------------------------------------------
TInt CHtiBookmarkHandler::GetFolderUidL( const TDesC& aFolderName )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::GetFolderUidL" );
    HTI_LOG_FORMAT( "Searching folder %S", &aFolderName );
    RFavouritesDb db;
    User::LeaveIfError( db.Open( iFavSession, KBrowserBookmarks ) );
    CleanupClosePushL<RFavouritesDb>( db );

    /* Doing the name matching ourselves 'cause giving the name match pattern
     * parameter to GetAll or GetUids methods crashes the favourites server.
     */
    CFavouritesItemList* folders = new ( ELeave ) CFavouritesItemList();
    CleanupStack::PushL( folders );
    User::LeaveIfError( db.GetAll( *folders, KFavouritesNullUid,
        CFavouritesItem::EFolder ) );
    TInt uid = KErrNotFound;
    TInt folderCount = folders->Count();
    HTI_LOG_FORMAT( "Found %d folders", folderCount );
    TInt i = 0;
    while ( uid == KErrNotFound && i < folderCount )
        {
        if ( ( *folders )[i]->Name().CompareF( aFolderName ) == 0 )
            {
            uid = ( *folders )[i]->Uid();
            }
        i++;
        }

    CleanupStack::PopAndDestroy( 2 ); // folders, db
    HTI_LOG_FORMAT( "Matching UID: %d", uid );
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::GetFolderUidL" );
    return uid;
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::GetApUidL
// Gets the WAP Access Point ID of access point named by iConnName.
// Favourites item needs the WAP ID for identifying access point.
// Returns KErrNotFound if AP not found.
// ----------------------------------------------------------------------------
TInt CHtiBookmarkHandler::GetApUidL( const TDesC& aApName )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::GetApUidL" );
    TInt uid = KErrNotFound;

    RCmManager cmManager;
    cmManager.OpenL();
    CleanupClosePushL( cmManager );

    // Search from uncategorised first
    RArray<TUint32> array = RArray<TUint32>();
    cmManager.ConnectionMethodL( array );
    CleanupClosePushL( array );
    TInt i = 0;
    while ( i < array.Count() && uid == KErrNotFound )
        {
        RCmConnectionMethod cm = cmManager.ConnectionMethodL( array[i] );
        CleanupClosePushL( cm );
        HBufC* name = cm.GetStringAttributeL( CMManager::ECmName );
        HTI_LOG_FORMAT( "Found name: %S", name );
        CleanupStack::PushL( name );
        if ( aApName.Compare( *name ) == 0 )
            {
            uid = cm.GetIntAttributeL( CMManager::ECmWapId );
            HTI_LOG_FORMAT( "Match: UID = %d", uid );
            }
        CleanupStack::PopAndDestroy(); // name
        CleanupStack::PopAndDestroy(); // cm
        i++;
        }
    CleanupStack::PopAndDestroy(); // array

    // If not found from uncategorised, search from all destinations
    if ( uid == KErrNotFound )
        {
        HTI_LOG_TEXT( "Not found from uncategorised" );
        RArray<TUint32> destIdArray = RArray<TUint32>();
        cmManager.AllDestinationsL( destIdArray );
        CleanupClosePushL( destIdArray );
        i = 0;
        while ( i < destIdArray.Count() && uid == KErrNotFound )
            {
            RCmDestination dest = cmManager.DestinationL( destIdArray[i] );
            CleanupClosePushL( dest );
            TInt j = 0;
            while ( j < dest.ConnectionMethodCount() && uid == KErrNotFound )
                {
                HBufC* name = dest.ConnectionMethodL( j ).GetStringAttributeL(
                        CMManager::ECmName );
                CleanupStack::PushL( name );
                HTI_LOG_FORMAT( "Found name: %S", name );
                if ( aApName.Compare( *name ) == 0 )
                    {
                    uid = dest.ConnectionMethodL( j ).GetIntAttributeL(
                            CMManager::ECmWapId );
                    HTI_LOG_FORMAT( "Match: UID = %d", uid );
                    }
                CleanupStack::PopAndDestroy(); // name
                j++;
                }
            CleanupStack::PopAndDestroy(); // dest
            i++;
            }
        CleanupStack::PopAndDestroy(); // destIdArray
        }

    CleanupStack::PopAndDestroy(); // cmManager
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::GetApUidL" );
    return uid;
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::SendOkMsgL
// Helper function for sending response messages.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::SendOkMsgL( const TDesC8& aData )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::SendOkMsgL" );
    User::LeaveIfNull( iDispatcher );
    HBufC8* temp = HBufC8::NewL( aData.Length() + 1 );
    TPtr8 response = temp->Des();
    response.Append( ( TChar ) CHtiPIMServicePlugin::EResultOk );
    response.Append( aData );
    User::LeaveIfError( iDispatcher->DispatchOutgoingMessage(
        temp, KPIMServiceUid ) );
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::SendOkMsgL" );
    }


// ----------------------------------------------------------------------------
// CHtiBookmarkHandler::SendErrorMessageL
// Helper function for sending error response messages.
// ----------------------------------------------------------------------------
void CHtiBookmarkHandler::SendErrorMessageL( TInt aError,
        const TDesC8& aDescription )
    {
    HTI_LOG_FUNC_IN( "CHtiBookmarkHandler::SendErrorMessageL" );
    User::LeaveIfNull( iDispatcher );
    User::LeaveIfError( iDispatcher->DispatchOutgoingErrorMessage(
        aError, aDescription, KPIMServiceUid ) );
    HTI_LOG_FUNC_OUT( "CHtiBookmarkHandler::SendErrorMessageL" );
    }


// End of file