landmarks/locationlandmarks/localdbmanprov/src/EPos_CPosLmLocalDatabaseManager.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 02 Sep 2010 20:51:33 +0300
changeset 46 df1a0df61209
parent 0 667063e416a2
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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 "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:  See class description below.
*
*/


// INCLUDE FILES
#include <d32dbms.h>
#include <badesca.h>
#include <EPos_Landmarks.h>
#include <epos_poslmdatabaseutility.h>
#include <epos_cposlmdiskutilities.h>
#include <EPos_PosLmDbInfoExtension.h>
#include "EPos_CPosLmLocalDatabaseManager.h"

// CONSTANTS
const TInt KPosDbListGranularity = 2;
const TInt KDriveAndDelimiterLength = 2;

_LIT(KFileProtocol, "file");
_LIT(KProtocolDelimiter, "://");
_LIT(KFileExtension, ".ldb");

// ================= LOCAL FUNCTIONS ========================

void CleanupRPointerArray(TAny* aArray)

    {
    (static_cast<RPointerArray<HPosLmDatabaseInfo>*>(
        aArray))->ResetAndDestroy();
    }

TBool MediaInfoIsEqual(const TMediaInfo& m1, const TMediaInfo& m2)
    {
    return m1.iDrive == m2.iDrive;
    }

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

// -----------------------------------------------------------------------------
// CPosLmLocalDatabaseManager::CPosLmLocalDatabaseManager
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CPosLmLocalDatabaseManager::CPosLmLocalDatabaseManager()
    : CPosLmDatabaseManagerPluginBase()
    {
    }

// -----------------------------------------------------------------------------
// CPosLmLocalDatabaseManager::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CPosLmLocalDatabaseManager::ConstructL()
    {
    User::LeaveIfError(iSubsession.Open(Session()));
    SynchronizeRegistryL();
    CreateDriveInfoListL();
    }

// -----------------------------------------------------------------------------
// CPosLmLocalDatabaseManager::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CPosLmLocalDatabaseManager* CPosLmLocalDatabaseManager::NewL(
    TAny* aConstructionParams)
    {
    CPosLmLocalDatabaseManager* self =
        new (ELeave) CPosLmLocalDatabaseManager();
    CleanupStack::PushL(self);
    self->BaseConstructL(aConstructionParams);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// Destructor
CPosLmLocalDatabaseManager::~CPosLmLocalDatabaseManager()
    {
    iSubsession.Close();
    iMediaInfoList.Close();
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::DatabaseMedia
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TMediaType CPosLmLocalDatabaseManager::DatabaseMedia(
    const TDesC&  aDatabaseUri)
    {
    TMediaType result = EMediaUnknown;
    TMediaInfo searchItem;
    searchItem.iDrive = DatabaseDrive(aDatabaseUri);

    TInt index = iMediaInfoList.Find(
        searchItem,
        TIdentityRelation<TMediaInfo>(MediaInfoIsEqual));
    if (index != KErrNotFound)
        {
        result = iMediaInfoList[index].iMediaType;
        }

    return result;
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::DatabaseDrive
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TChar CPosLmLocalDatabaseManager::DatabaseDrive(
    const TDesC&  aDatabaseUri)
    {
    TChar sysDriveChar = RFs::GetSystemDriveChar();
    
    // if protocol delimiter present,
    // verify that URI starts with "file://"
    TInt offset = aDatabaseUri.Find(KProtocolDelimiter);
    if (offset != KErrNotFound && aDatabaseUri.Left(offset) != KFileProtocol)
        {
        // wrong protocol
        return 0;
        }

    // adjust offset depending on whether or not protocol is present
    offset = offset == KErrNotFound ?
             0 :
             KFileProtocol().Length() + KProtocolDelimiter().Length();

    if (aDatabaseUri.Length() < offset + KDriveAndDelimiterLength)
        {
        return 0;
        }

    // if second character is ":", return first character
    // otherwise return default drive
    if (aDatabaseUri[offset + 1] == KDriveDelimiter)
        {
        return TChar(aDatabaseUri[offset]).GetUpperCase();
        }
    return sysDriveChar;
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::Protocol
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
TPtrC CPosLmLocalDatabaseManager::Protocol()
    {
    return TPtrC(KFileProtocol);
    }


// -----------------------------------------------------------------------------
// CPosLmLocalDatabaseManager::ListDatabasesLC
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CDesCArray* CPosLmLocalDatabaseManager::ListDatabasesLC()
    {
    CDesCArray* dbArray = new (ELeave) CDesCArrayFlat(KPosDbListGranularity);
    CleanupStack::PushL(dbArray);

    RFs fs;
    CleanupClosePushL(fs);
    User::LeaveIfError(fs.Connect());

    TDriveList driveList;
    User::LeaveIfError(fs.DriveList(driveList));

    RDbs dbSession;
    CleanupClosePushL(dbSession);
    User::LeaveIfError(dbSession.Connect());

    for (TInt drive = EDriveA; drive <= EDriveZ; drive++)
        {
        if ( driveList[drive] && !( driveList[drive] & KDriveAttRemote ) ) // avoid remote drives
            {
            TDriveInfo drvInfo;
            TInt err = fs.Drive( drvInfo, drive );

            if ( !err && drvInfo.iType != EMediaNotPresent )
                {
                CDbDatabaseNames* dbNames = NULL;

                TRAPD(err, dbNames = dbSession.DatabaseNamesL(
                    static_cast<TDriveNumber>(drive), KPosLmDbSecureUid));

                // Ignore all errors except KErrNoMemory (and KErrNone)
                if (err == KErrNone)
                    {
                    CleanupStack::PushL(dbNames);
                    for (TInt i = 0; i < dbNames->Count(); i++)
                        {
                        TPtrC ptr = (*dbNames)[i];

                        if (ptr.Right(KFileExtension().Length()).
                            CompareF(KFileExtension) == 0)
                            {
                            HBufC* fullName = HBufC::NewLC(
                                KFileProtocol().Length() +
                                KProtocolDelimiter().Length() +
                                KDriveAndDelimiterLength +
                                (*dbNames)[i].Length());

                            TChar chr;
                            fs.DriveToChar(drive, chr);

                            TPtr ptr2 = fullName->Des();

                            ptr2.Append(KFileProtocol);
                            ptr2.Append(KProtocolDelimiter);
                            ptr2.Append(chr);
                            ptr2.Append(KDriveDelimiter);
                            ptr2.Append((*dbNames)[i]);

                            dbArray->AppendL(*fullName);
                            CleanupStack::PopAndDestroy(fullName);
                            }
                        }
                    CleanupStack::PopAndDestroy(dbNames);
                    }
                else if (err == KErrNoMemory)
                    {
                    User::Leave(err);
                    }
                }
            }
        }
    CleanupStack::PopAndDestroy(2, &fs); //dbSession
    return dbArray;
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::ListDatabasesL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::ListDatabasesL(
    RPointerArray<HPosLmDatabaseInfo>& aDatabaseInfoArray)
    {
    // list URIs
    CDesCArray* dbUriArray = ListDatabasesLC();
    // list registered databases
    Session().ListDatabasesL(aDatabaseInfoArray, KFileProtocol);
    // delete from URI list those databases that are registered
    for (TInt i = aDatabaseInfoArray.Count() - 1; i >= 0; i--)
        {
        TInt index;
        if (dbUriArray->Find(aDatabaseInfoArray[i]->DatabaseUri(), index) == 0)
            {
            dbUriArray->Delete(index);
            }
        }

    // for each remaining URI in the list, fill in database info
    // and add to list
    TInt count = dbUriArray->Count();
    for (TInt i = 0; i < count; i++)
        {
        HPosLmDatabaseInfo* info = HPosLmDatabaseInfo::NewLC((*dbUriArray)[i]);
        aDatabaseInfoArray.AppendL(info);
        CleanupStack::Pop(info); // transfer of ownership to array
        }

    CleanupStack::PopAndDestroy(dbUriArray);
    // database drive, database media and default flag
    // will be filled in by database management provider.
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::RegisterDatabaseL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::RegisterDatabaseL(
               HPosLmDatabaseInfo& /* aDatabaseInfo */)
    {
    User::Leave(KErrNotSupported);
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::UnregisterDatabaseL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::UnregisterDatabaseL(
    const TDesC& /* aDatabaseUri */)
    {
    User::Leave(KErrNotSupported);
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::UnregisterAllDatabasesL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::UnregisterAllDatabasesL()
    {
    User::Leave(KErrNotSupported);
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::ModifyDatabaseSettingsL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::ModifyDatabaseSettingsL(
    const TDesC& aDatabaseUri,
    const TPosLmDatabaseSettings& aDatabaseSettings
        )
    {
    // validate URI
    HBufC* uri = PosLmDatabaseUtility::CreateDatabaseUriL(aDatabaseUri);
    CleanupStack::PushL(uri);

    if(!DatabaseExistsL(*uri))
        {
        User::Leave(KErrNotFound);
        }

    TChar drive = DatabaseDrive(*uri);
    TInt err = Session().ModifyDatabaseSettings(*uri,
                                                aDatabaseSettings,
                                                drive);
    if (err == KErrNotFound)
        {
        // database was not registered
        HPosLmDatabaseInfo* info =
            HPosLmDatabaseInfo::NewLC(*uri);
        info->Settings() = aDatabaseSettings;
        PosLmDbInfoExtension::SetDatabaseDrive(*info, drive);
        User::LeaveIfError(Session().RegisterDatabase(*info));
        CleanupStack::PopAndDestroy(info);
        }
    else if (err != KErrNone)
        {
        User::LeaveIfError(err);
        }

    // report event

    // To remove a warning, the event must be default constructed.
    TPosLmDatabaseEvent event =
        {
        EPosLmDbSettingsModified,
        {0,0,0,0,0,0,0,0}
        };

    User::LeaveIfError(Session().ReportEvent(event, *uri));

    CleanupStack::PopAndDestroy(uri);
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::GetDatabaseInfoL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::GetDatabaseInfoL(
    HPosLmDatabaseInfo& aDatabaseInfo
        )
    {
    // database drive, database media and default flag
    // will be filled in by database management provider.

    // must validate URI, copy to new object
    HBufC* uri = PosLmDatabaseUtility::CreateDatabaseUriL(
        aDatabaseInfo.DatabaseUri());
    CleanupStack::PushL(uri);

    if(!DatabaseExistsL(*uri))
        {
        User::Leave(KErrNotFound);
        }

    HPosLmDatabaseInfo* info = HPosLmDatabaseInfo::NewLC(*uri);
    PosLmDbInfoExtension::SetDatabaseDrive(
        *info,
        aDatabaseInfo.DatabaseDrive());

    TInt err = Session().GetDatabaseInfo(*info);

    if (err == KErrNone)
        {
        // database is registered, transfer settings to original object
        aDatabaseInfo.Settings() = info->Settings();
        }
    else if (err != KErrNotFound)
        {
        User::Leave(err);
        }

    // database is not registered - do nothing.

    CleanupStack::PopAndDestroy(2, uri); // info
    }

// -----------------------------------------------------------------------------
// CPosLmLocalDatabaseManager::DatabaseExistsL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CPosLmLocalDatabaseManager::DatabaseExistsL(const TDesC& aDatabaseUri)
    {
    // validate URI
    HBufC* uri = PosLmDatabaseUtility::CreateDatabaseUriL(aDatabaseUri);
    CleanupStack::PushL(uri);

    TPtrC ptr(uri->Des());
    PosLmDatabaseUtility::RemoveProtocolFromUriL(ptr);

    TParse parse;
    User::LeaveIfError(parse.Set(ptr, NULL, NULL));
    TFileName searchUri = parse.NameAndExt();
    searchUri.UpperCase();

    TInt drive;
    User::LeaveIfError(RFs::CharToDrive(parse.Drive()[0], drive));

    RDbs dbSession;
    CleanupClosePushL(dbSession);
    User::LeaveIfError(dbSession.Connect());

    CDbDatabaseNames* names = dbSession.DatabaseNamesL(
            static_cast<TDriveNumber>(drive), KPosLmDbSecureUid);
    CleanupStack::PushL(names);

    TBool exists(EFalse);
    for (TInt i = 0; i < names->Count() && !exists; i++)
        {
        HBufC* databaseName = (*names)[i].AllocLC();
        databaseName->Des().UpperCase();
        if (searchUri == *databaseName)
            {
            exists = ETrue;
            }
        CleanupStack::PopAndDestroy(databaseName);
        }

    CleanupStack::PopAndDestroy(3, uri);  //dbSession
    return exists;
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::CreateDatabaseL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::CreateDatabaseL(
    HPosLmDatabaseInfo& aDatabaseInfo)
    {
    // database drive and database media has been filled in by
    // database management provider.

    User::LeaveIfError(iSubsession.CreateDatabase(aDatabaseInfo));
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::DeleteDatabaseL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::DeleteDatabaseL(
    const TDesC&  aDatabaseUri)
    {
    HPosLmDatabaseInfo* info = HPosLmDatabaseInfo::NewLC(aDatabaseUri);
    PosLmDbInfoExtension::SetDatabaseDrive(*info,
                                           DatabaseDrive(aDatabaseUri));

    TInt err = iSubsession.DeleteDatabase(*info);
    if (err != KErrNone && err != KErrNotFound)
        {
        User::Leave(err);
        }

    CleanupStack::PopAndDestroy(info);
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::CopyDatabaseL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::CopyDatabaseL(
    const TDesC&  aSourceUri,
    const TDesC&  aTargetUri)
    {
    User::LeaveIfError(iSubsession.CopyDatabase(aSourceUri, aTargetUri));
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::SynchronizeRegistryL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::SynchronizeRegistryL()
    {
    RPointerArray<HPosLmDatabaseInfo> databaseInfoArray(KPosDbListGranularity);
    CleanupStack::PushL(TCleanupItem(CleanupRPointerArray, &databaseInfoArray));

    // list URIs
    CDesCArray* dbUriArray = ListDatabasesLC();

    // list registered databases
    Session().ListDatabasesL(databaseInfoArray, KFileProtocol);

    // unregister database which cannot be found on disk
    for (TInt i = databaseInfoArray.Count() - 1; i >= 0; i--)
        {
        TInt index;
        TPtrC registeredUri = databaseInfoArray[i]->DatabaseUri();
        if (dbUriArray->Find(registeredUri, index) != 0)
            {
            // unregister database
            User::LeaveIfError(Session().UnregisterDatabase(registeredUri,
                DatabaseDrive(registeredUri)));
            }
        }
    CleanupStack::PopAndDestroy(2, &databaseInfoArray);  // dbUriArray
    }

// ---------------------------------------------------------
// CPosLmLocalDatabaseManager::CreateDriveInfoListL
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CPosLmLocalDatabaseManager::CreateDriveInfoListL()
    {
    RFs fs;
    CleanupClosePushL(fs);
    User::LeaveIfError(fs.Connect());

    TDriveList driveList;
    User::LeaveIfError(fs.DriveList(driveList));

    for (TInt drive = EDriveA; drive <= EDriveZ; drive++)
        {
        if ( driveList[drive] && !( driveList[drive] & KDriveAttRemote ) ) // avoid remote drives
            {
            TDriveInfo drvInfo;
            TInt err = fs.Drive( drvInfo, drive );

            if ( !err && drvInfo.iType != EMediaNotPresent )
                {
                TMediaInfo mediaInfo;
                mediaInfo.iMediaType = drvInfo.iType;

                User::LeaveIfError(fs.DriveToChar(drive, mediaInfo.iDrive));

                User::LeaveIfError(iMediaInfoList.Append(mediaInfo));
                }
            }
        }
    CleanupStack::PopAndDestroy(&fs);
    }

//  End of File