remotestoragefw/mountstore/src/rsfwmountstore.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:15:08 +0100
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201021 Kit: 201035

/*
* Copyright (c) 2002-2004 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:  Access mount configuration storage
 *
*/


// In order to use the central repository,
// The repository initialization file must be put in
// [epoc32/release/winscw/udeb/]z/private/10202be9/101F9775.txt

// The mount configurations form a table where
// individual configuration entries form the rows and
// the entry items form the columns.
// - rows are indexed with the upper 24 bits of the Id, starting from 1.
// - columns are indexed by the lower 8 bits of the Id, starting from 1.
//
// Row number 0 is reserved for system config name/value pairs (see RsfwConfig)

// INCLUDES
#include <centralrepository.h>
#include <badesca.h>
#include <aknnotewrappers.h> 
#include <rsfwmountman.h>
#include <rsfwmountentry.h>
#include <rsfwmountentryitem.h>

#include "rsfwmountstore.h"


// CONSTANTS
const TUid  KCRUidRsfwCtrl    = { 0x101F9775 };

// Current mount configuration repository version
const TInt  KCurrentVersion   = 1000;
const TUint KCurrentVersionId = 0xff;

const TInt  KColumnMaskSize   = 8;
const TUint KRowMask          = 0xffffff00;
const TUint KColumnMask       = 0x000000ff;

const TUint KColumnName       = EMountEntryItemName;

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

// ----------------------------------------------------------------------------
// CRsfwMountStore::NewL
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
EXPORT_C CRsfwMountStore* CRsfwMountStore::NewL(
    MRsfwMountStoreObserver* aMountStoreObserver)
    {
    CRsfwMountStore* self = new (ELeave) CRsfwMountStore();
    CleanupStack::PushL(self);
    self->ConstructL(aMountStoreObserver);
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::CRsfwMountStore
// ----------------------------------------------------------------------------
//
CRsfwMountStore::CRsfwMountStore()
    {
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::ConstructL
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::ConstructL(MRsfwMountStoreObserver* aMountStoreObserver)
    {
    iMountStoreObserver = aMountStoreObserver;
    // if CenRep not found, just leave
    iRepository = CRepository::NewL(KCRUidRsfwCtrl);

    // Check version
    TInt version;
    // allow versionless repositories until the version id is
    // included in the backup/restore scheme.
    if (iRepository->Get(KCurrentVersionId, version) == KErrNone)
        {
        if (version != KCurrentVersion)
            {
            // This causes the repository to be cleared and
            // stamped with the current version
            CommitL();
            }
        }
    LoadEntriesL();

    // Start listening to changes in the repository
    iCenRepNotifyHandler = CCenRepNotifyHandler::NewL(*this, *iRepository);
    iCenRepNotifyHandler->StartListeningL();
    iReceivingCenRepNotifications = ETrue;
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::~CRsfwMountStore
// ----------------------------------------------------------------------------
//
EXPORT_C CRsfwMountStore::~CRsfwMountStore()
    {
    iMountEntries.ResetAndDestroy();
    if (iCenRepNotifyHandler) 
      {
      iCenRepNotifyHandler->StopListening();
      delete iCenRepNotifyHandler;
      }
    delete iRepository;
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::LoadEntriesL
// CenRep keeps data in alphabetical order, and we want also iMountEntries to
// to be filled in the same order
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::LoadEntriesL()
    {
    iMountEntries.ResetAndDestroy();

    // go through the records in CenRep and populate the array
    RArray<TUint32> nameIds;
    CleanupClosePushL(nameIds);
    User::LeaveIfError(iRepository->FindL(KColumnName, KColumnMask, nameIds));		
   	HBufC* item = HBufC::NewLC(KMaxMountConfItemLength);
   	TPtr itemPtr = item->Des();
   	TInt row;
	for (row = 0; row < nameIds.Count(); row++)
    	{
    	TUint rowId = (nameIds[row] & KRowMask);
    	// don't touch record number 0, as it stores RSFW general data
    	if (rowId > 0)
        	{
        	CRsfwMountEntry* entry = CRsfwMountEntry::NewLC();
        	TUint i;
        	for (i = EMountEntryItemIndex; i < EMountEntryItemCount; i++)
            	{
            	TInt err = iRepository->Get(rowId | i, itemPtr);
                if ( err != KErrNone && err != KErrNotFound )
                    {
                    User::Leave(err);
                    }
           	    entry->SetItemL(i, itemPtr);	
            	}
            User::LeaveIfError(iMountEntries.Append(entry));
            // ownership's been taken by the array
            CleanupStack::Pop(entry);
        	}
    	}
    CleanupStack::PopAndDestroy(item);
    CleanupStack::PopAndDestroy(&nameIds);
    
    // now mount entries array is up-to-date
    iCenRepChanged = EFalse;
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::GetNamesL
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::GetNamesL(CDesC16Array* aNames)
    {
    ReloadEntriesL();
    aNames->Reset();
    HBufC* name = HBufC::NewLC(KMaxMountConfItemLength);
    TPtr namePtr = name->Des();
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        namePtr.Copy(*iMountEntries[i]->Item(EMountEntryItemName));
        aNames->AppendL(namePtr);
        }
    CleanupStack::PopAndDestroy(name);
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::GetDriveLettersL
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::GetDriveLettersL(TDriveList& aDriveList)
    {
    ReloadEntriesL();
    aDriveList.Zero();
    HBufC* name = HBufC::NewLC(KMaxMountConfItemLength);
    TPtr namePtr = name->Des();
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        namePtr.Copy(*iMountEntries[i]->Item(EMountEntryItemDrive));
        aDriveList.Append(namePtr);
        }
    CleanupStack::PopAndDestroy(name);
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::LookupEntryByName
// ----------------------------------------------------------------------------
//
EXPORT_C const CRsfwMountEntry* CRsfwMountStore::LookupEntryByNameL(const TDesC& aName)
    {
    ReloadEntriesL();
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        CRsfwMountEntry* entry = iMountEntries[i];
        const HBufC* name = entry->Item(EMountEntryItemName);
        if (name && name->CompareF(aName) == 0)
            {
            return entry;
            }
        }
    return NULL;
    }
 
// ----------------------------------------------------------------------------
// CRsfwMountStore::LookupEntryByDrive
// ----------------------------------------------------------------------------
//
EXPORT_C const CRsfwMountEntry* CRsfwMountStore::LookupEntryByDriveL(TChar aDriveLetter)
    {
    ReloadEntriesL();
    TBuf<1> driveBuf;
    driveBuf.Append(aDriveLetter);
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        CRsfwMountEntry* entry = iMountEntries[i];
        const HBufC* drive = entry->Item(EMountEntryItemDrive);
        if (drive && drive->CompareF(driveBuf) == 0)
            {
            return entry;
            }
        }
    return NULL;
    }
 
// ----------------------------------------------------------------------------
// CRsfwMountStore::AddEntryL
// Adds entry to CenRep, replaces existing item, so it can be used 
// for edit operation as well
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::AddEntryL(CRsfwMountEntry* aMountEntry)
    {
    // Take ownership
    CleanupStack::PushL(aMountEntry);

    if ((!aMountEntry) || 
        (!aMountEntry->Item(EMountEntryItemDrive)))
        {
        User::Leave(KErrArgument);
        }

    ReloadEntriesL();

    TPtrC drive(*aMountEntry->Item(EMountEntryItemDrive));

    // Check whether an entry with given drive letter exists.
    // If so, delete it and remember index of deleted item.
    // Otherwise find the index at which a new item should be added.
    // Keep in mind the order is aphabetical.
    TInt i;
    TInt index = -1;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        CRsfwMountEntry* entry = iMountEntries[i];
        TInt cmp = entry->Item(EMountEntryItemDrive)->CompareF(drive);
        if (cmp == 0)
            {
            // Replace an existing entry
            RemoveFromRepositoryL(entry);
            delete entry;
            entry = NULL;
            iMountEntries.Remove(i);
            // save the position, new item will be added here
            index = i;
            break;
            }
        else if (cmp > 0)
            {
            // we've found the entry whose drive letter is larger, which
            // means we've found the place where a new entry should be added
            index = i;
            break;
            }
        }
    
    // before we add a new entry, make sure that we don't exceed max drives allowed
    if (iMountEntries.Count() >= KMaxRemoteDrives)    
        {
        User::Leave(KErrInUse);
        }

    // add entry to the array
    if (index < 0)
        {
        // this means the drive letter of newly added entry is the latest 
        // in the alphabet. hence just append the entry
        User::LeaveIfError(iMountEntries.Append(aMountEntry));        
        }
    else
        {
        User::LeaveIfError(iMountEntries.Insert(aMountEntry, index));
        }


    // add to repository  
    AddToRepositoryL(aMountEntry);

    // cleanup
    CleanupStack::Pop(aMountEntry);
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::RemoveEntryL
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::RemoveEntryL(const TDesC& aName)
    {
    ReloadEntriesL();
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        CRsfwMountEntry* entry = iMountEntries[i];
        const HBufC* name = entry->Item(EMountEntryItemName);
        if (name && name->CompareF(aName) == 0)
            {
            RemoveFromRepositoryL(entry);
            iMountEntries.Remove(i);
            delete entry;
            break;
            }
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::RemoveEntryL
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::RemoveEntryL(TChar aDrive)
    {
    ReloadEntriesL();
    TBuf<1> driveBuf;
    driveBuf.Append(aDrive);
    TInt i;
    for (i = 0; i < iMountEntries.Count(); i++)
        {
        CRsfwMountEntry* entry = iMountEntries[i];
        const HBufC* drive = entry->Item(EMountEntryItemDrive);
        if (drive && drive->CompareF(driveBuf) == 0)
            {
            RemoveFromRepositoryL(entry);
            iMountEntries.Remove(i);
            delete entry;
            break;
            }
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::CommitL
// ----------------------------------------------------------------------------
//
EXPORT_C void CRsfwMountStore::CommitL()
    {
    if (iRepository) 
        {
        // We don't want to get reports of our own changes
        iCenRepNotifyHandler->StopListening();
        ClearRepositoryL();
        TInt i;
        for (i = 0; i < iMountEntries.Count(); i++)
            {
            CRsfwMountEntry* entry = iMountEntries[i];
            AddToRepositoryL(entry);
            }
        // Set correct version id
        User::LeaveIfError(iRepository->Set(KCurrentVersionId, KCurrentVersion));
        // Restart listening
        iCenRepNotifyHandler->StartListeningL();
        }
    else 
        {
        _LIT(KWarningText, "Cannot store entries permanently!");
        TRAP_IGNORE(CAknWarningNote* note = new (ELeave) CAknWarningNote;
                    note->ExecuteLD(KWarningText);
            );
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::AddToRepositoryL
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::AddToRepositoryL(const CRsfwMountEntry* aMountEntry)
    {
    // retrieve drive letter
    const HBufC* drive = aMountEntry->Item(EMountEntryItemDrive);

    // calculate record ID for the drive letter
    TInt recordId = MapDriveLetterToRecordIdL(drive);

    // write down the entry settings to given record ID
    TInt i = 0;
    for (i = EMountEntryItemIndex; i < EMountEntryItemCount; i++)
        {
        TInt fieldId = (recordId << KColumnMaskSize) | i;
        const HBufC* item = aMountEntry->Item(i);
        if (item)
            {
            User::LeaveIfError(iRepository->Create(fieldId, *item));
            }
        else
            {
            TPtrC null;
            User::LeaveIfError(iRepository->Create(fieldId, null));
            }
        }
    }    

// ----------------------------------------------------------------------------
// CRsfwMountStore::RemoveFromRepositoryL
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::RemoveFromRepositoryL(const CRsfwMountEntry* aMountEntry)
    {
    // retrieve drive letter
    const HBufC* drive = aMountEntry->Item(EMountEntryItemDrive);

    // calculate record ID for the drive letter
    TInt recordId = MapDriveLetterToRecordIdL(drive);

    // delete settings from given record ID
    TInt i = 0;
    for (i = EMountEntryItemIndex; i < EMountEntryItemCount; i++)
        {
        TInt fieldId = (recordId << KColumnMaskSize) | i;
        User::LeaveIfError(iRepository->Delete(fieldId));
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::ClearRepositoryL
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::ClearRepositoryL()
    {
    // find all non-empty records
    RArray<TUint32> nameIds;
    CleanupClosePushL(nameIds);
    User::LeaveIfError(iRepository->FindL(KColumnName, KColumnMask, nameIds));
    
    TInt record;
    for (record = 0; record < nameIds.Count(); record++)
        {
        TUint recordId = (nameIds[record] & KRowMask);
        // don't touch record number 0, as it stores RSFW general data
        if (recordId > 0)
            {
            TInt i;
            for (i = EMountEntryItemIndex; i < EMountEntryItemCount; i++)
                {
                TUint fieldId = (recordId | i);
                User::LeaveIfError(iRepository->Delete(fieldId));
                }            
            }
        }
    CleanupStack::PopAndDestroy(&nameIds);
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::ReloadEntriesL
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::ReloadEntriesL()
    {
    if (!iReceivingCenRepNotifications || iCenRepChanged)
        {
        // We only need reload if it is not done automatically
        // through notifications
        LoadEntriesL();
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::HandleNotifyGeneric
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::HandleNotifyGeneric(TUint32 /* aId */)
    {
    iCenRepChanged = ETrue;
    if (iMountStoreObserver)
        {
        iMountStoreObserver->HandleMountStoreEvent(
            EMountStoreEventMountConfigurationChanged,
            0,
            NULL);
        }
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::HandleNotifyError
// ----------------------------------------------------------------------------
//
void CRsfwMountStore::HandleNotifyError(TUint32 /* aId */,
                                    TInt /* aError */, 
                                    CCenRepNotifyHandler* /* aHandler */)
    {
    iReceivingCenRepNotifications = EFalse;
    }

// ----------------------------------------------------------------------------
// CRsfwMountStore::MapDriveLetterToRecordIdL
// drive with letter 'J' will take record number 1
// drive with letter 'K' will take record number 2
// etc.
// (remember that record number 0 stores RSFW general data, so don't touch it)
// ----------------------------------------------------------------------------
//
TInt CRsfwMountStore::MapDriveLetterToRecordIdL(const HBufC* drive)
    {
    if (!drive || !drive->Length())
        {
        User::Leave(KErrArgument);
        }
        
    // we have to convert HBufC to TChar and then TChar to TInt
    TChar driveChar = (*drive)[0];        
    TInt driveNumber;
    RFs fs;
	User::LeaveIfError(fs.Connect());
	TInt err = fs.CharToDrive(driveChar, driveNumber);
	fs.Close();
    User::LeaveIfError(err);

    // count record ID based on drive number
    // +1 is to omit record number 0!
    return driveNumber - EDriveJ + 1;
    }

//  End of File