filemanager/src/inc/fmutils_s60.cpp
author hgs
Thu, 05 Aug 2010 11:30:07 +0800
changeset 33 328cf6fbe40c
parent 32 39cf9ced4cc4
child 40 4167eb56f30d
permissions -rw-r--r--
201031

/*
* 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:
*     Zhiqiang Yang <zhiqiang.yang@nokia.com>
* 
* Description:
*     The source file of the file manager utilities
*/


#include "fmutils.h"
#include "fms60utils.h"
#include "fmcommon.h"

#include <QRegExp>

#include <coemain.h>
#include <driveinfo.h>
#include <e32property.h>
#include <coreapplicationuisdomainpskeys.h>
#include <f32file.h>
#include <apgcli.h>
#include <pathinfo.h>
#include <CDirectoryLocalizer.h>
#include <XQConversions>
#include <QStringList>
#include <QFileInfoList>
#include <QDir>
#include <QFile>
#include <QIODevice>
#include <XQConversions>
#include <hbglobal.h>

#include <xqaiwrequest.h>
#include <xqappmgr.h>

#include <shareui.h>

#define BURCONFIGFILE  "z:/private/2002BCC0/burconfig.xml"


/*!
    Used to get drive type for convenience.
*/
FmDriverInfo::DriveType FmDriverInfo::driveType()
{
    FmDriverInfo::DriveType driveType;
    if( mDriveState & FmDriverInfo::EDriveRemovable ) {
        if( mDriveState & FmDriverInfo::EDriveMassStorage ) {
            driveType = FmDriverInfo::EDriveTypeMassStorage;
        } else if( mDriveState & FmDriverInfo::EDriveUsbMemory ) {
            driveType = FmDriverInfo::EDriveTypeUsbMemory;
        } else if( mDriveState & FmDriverInfo::EDriveRemote ){
            driveType = FmDriverInfo::EDriveTypeRemote;
        } else {
            driveType = FmDriverInfo::EDriveTypeMemoryCard;
        }
    } else if( mDriveState & FmDriverInfo::EDriveRom ) {
        driveType = FmDriverInfo::EDriveTypeRom;
    } else if( mDriveState & FmDriverInfo::EDriveRam ) {
        driveType = FmDriverInfo::EDriveTypeRam;
    } else {
        driveType = FmDriverInfo::EDriveTypePhoneMemory;
    }
    
    return driveType;
}

QString FmUtils::getDriveNameFromPath( const QString &path )
{
    // fillPathWithSplash make sure path length will be at least 3 if it is not empty.
    QString checkedPath( fillPathWithSplash( path ) );
    if( checkedPath.length() < 3 ) {
        return QString();
    }
    return checkedPath.left( 3 );
}

QString FmUtils::getDriveLetterFromPath( const QString &path )
{
	if( path.length() <2 ) {
        return QString();
    }
    return path.left( 1 );
}

FmDriverInfo FmUtils::queryDriverInfo( const QString &driverName )
{
    if( driverName.isEmpty() ) {
        return FmDriverInfo( 0, 0, driverName, QString(), FmDriverInfo::EDriveNotPresent );
    }
    CCoeEnv *env = CCoeEnv::Static();
    RFs& fs = env->FsSession();

    TVolumeInfo volumeInfo;
    TInt drive = 0;
    drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;

    quint32 state( 0 );
    int volumeInfoErr( KErrNone );
    int driveInfoErr( KErrNone );
    int errorCode( KErrNone );
    volumeInfoErr = fs.Volume( volumeInfo, drive );
    errorCode = volumeInfoErr;
    QString volumeName( (QChar*)( volumeInfo.iName.Des().Ptr() ), volumeInfo.iName.Length() );
    
    TDriveInfo driveInfo;
    if( volumeInfoErr == KErrNone ) {
        driveInfo = volumeInfo.iDrive;
    } else {
        driveInfoErr = fs.Drive( driveInfo, drive );
        if( driveInfoErr != KErrNone ) {
            errorCode = driveInfoErr;
        }
    }
    
    if( volumeInfoErr == KErrNone || driveInfoErr == KErrNone ) {
        //TDriveInfo driveInfo = volumeInfo.iDrive;
    
        quint32 drvStatus( 0 );
        int err = DriveInfo::GetDriveStatus( fs, drive, drvStatus );
        if( err == KErrNone ) {
            
            if ( ( drvStatus & DriveInfo::EDriveInternal ) &&
                 ( drvStatus & DriveInfo::EDriveExternallyMountable ) ){
                // Handle mass storage bits here
        
                state |= FmDriverInfo::EDriveMassStorage | FmDriverInfo::EDriveRemovable;
            }
        
            if ( drvStatus & DriveInfo::EDriveUsbMemory )
                {
                state |= FmDriverInfo::EDriveUsbMemory;
                }
            
            if ( drvStatus & DriveInfo::EDriveRemote )
                {
                state |= FmDriverInfo::EDriveRemote;
                }
            
            if ( drvStatus & DriveInfo::EDriveRom ){
                state |= FmDriverInfo::EDriveRom;  
            }
            
            if ( drvStatus & DriveInfo::EDriveRam ){
                state |= FmDriverInfo::EDriveRam;  
            }
        
            if ( driveInfo.iMediaAtt & KMediaAttFormattable ){
                state |= FmDriverInfo::EDriveFormattable;
            }
            if ( driveInfo.iMediaAtt & KMediaAttWriteProtected ){
                state |= FmDriverInfo::EDriveWriteProtected;
            }
            if ( driveInfo.iMediaAtt & KMediaAttHasPassword ){
                state |= FmDriverInfo::EDrivePasswordProtected;
            }    
            if ( driveInfo.iMediaAtt & KMediaAttLocked ){
                state |= FmDriverInfo::EDriveLocked;
            }
        
            if ( driveInfo.iDriveAtt & KDriveAttRemovable ){
                state |= FmDriverInfo::EDriveRemovable;
        
                if ( drvStatus & DriveInfo::EDriveSwEjectable ){
                    state |= FmDriverInfo::EDriveEjectable;
                }
            }
            
            if( driveInfo.iType == EMediaNotPresent ){
                state |= FmDriverInfo::EDriveNotPresent;    
            }
        }
        // If memory card is not ready but type is present,
        // then check if it is reserved.
        if( err == KErrNone && volumeInfoErr == KErrNotReady &&
            driveInfo.iType != EMediaNotPresent )
            {
            // Check USB file transfer state
            TInt prop( ECoreAppUIsUSBFileTransferUninitialized );
            RProperty::Get(
                KPSUidCoreApplicationUIs,
                KCoreAppUIsUSBFileTransfer, prop );
            if ( prop == ECoreAppUIsUSBFileTransferActive )
                {
                errorCode = KErrInUse; // Reserved for file transfer
                }
            }
        if( err!= KErrNone )
            {
            errorCode = err;
            }
    }

    // handle error code
    // volumeInfoErr will occur while drive is lock,corrupted...
    // driveInfoErr can not be promoted for locked, corrupted drive.
    // so we can not use driveInfoErr to justify EDriveAvailable
    switch( errorCode )
    {
    case KErrNone:
        // this drive could be used as it is not be locked, or corrupt.
        state |= FmDriverInfo::EDriveAvailable; 
        break;
    case KErrLocked:
        state |= FmDriverInfo::EDriveLocked;
        break;
    case KErrCorrupt:
        state |= FmDriverInfo::EDriveCorrupted;
        break;
    case KErrInUse:
        state |= FmDriverInfo::EDriveInUse;
        break;
    default: // other errors
        state |= FmDriverInfo::EDriveNotPresent;
        break;
    }
    QString logString ( "FmUtils::queryDriverInfo_" + driverName + 
            "_volumeInfoErr:" + QString::number( volumeInfoErr ) +
            "_driveInfoErr:" + QString::number( driveInfoErr ) +
            "_errorCode:" + QString::number( errorCode ) + 
            "_driveSatus:" + QString::number( state ) );
    FM_LOG( logString );
    return FmDriverInfo( volumeInfo.iSize, volumeInfo.iFree, driverName, volumeName, state );
}

QString FmUtils::formatStorageSize( quint64 size )
{
	if ( size < 1000 ) {
		return QString::number( size ) + " B";
	} else if ( size < 1000 * 1000 ) {
		return QString::number( size / 1024.0, 'f', 2 ) + " KB";
	} else if ( size < 1000 * 1000 * 1000 ) {
		return QString::number( size / (1024.0 * 1024.0), 'f', 1 ) + " MB";
	} else {
	    return QString::number( size / ( 1024.0 * 1024.0 * 1024.0 ), 'f', 1 ) + " GB";	    
	}
}

int FmUtils::removeDrivePwd( const QString &driverName,  const QString &Pwd )
{
    if( driverName.isEmpty() || Pwd.length() > FmMaxLengthofDrivePassword ) {
        return FmErrWrongParam;
    }
    QString logString = "Drive name:" + driverName;
    FM_LOG( logString );
    logString = "Password:" + Pwd;
    FM_LOG( logString );

    CCoeEnv *env = CCoeEnv::Static();
	RFs& fs = env->FsSession();

    TInt drive = 0;

    drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;

    HBufC* password16 = XQConversions::qStringToS60Desc( Pwd );
    TMediaPassword password;   
    TPtr ptrPassword16( password16->Des() );  
    FmS60Utils::ConvertCharsToPwd( ptrPassword16, password );

    int err( fs.ClearPassword( drive, password ) );

    logString = "Drive:" + QString::number( drive );
    FM_LOG( logString );

    logString = "Clear password error:" + QString::number( err );
    FM_LOG( logString );

    delete password16;

    if( err == KErrNone ){
        return FmErrNone;   
    }
    else if( err == KErrAccessDenied ){
        return FmErrAccessDenied;
    }
    else{
        return FmErrUnKnown;
    }
}

int FmUtils::unlockDrive( const QString &driverName,  const QString &Pwd )
{
    if( driverName.isEmpty() || Pwd.length() > FmMaxLengthofDrivePassword ) {
        return FmErrWrongParam;
    }
    QString logString = "Drive name:" + driverName;
    FM_LOG( logString );
    logString = "Password:" + Pwd;
    FM_LOG( logString );

    CCoeEnv *env = CCoeEnv::Static();
	RFs& fs = env->FsSession();

    TInt drive = 0;
	drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;
    
    HBufC* password16 = XQConversions::qStringToS60Desc( Pwd );
    TMediaPassword password;   
    TPtr ptrPassword16( password16->Des() );  
    FmS60Utils::ConvertCharsToPwd( ptrPassword16, password );

    int err( fs.UnlockDrive( drive, password, ETrue) );

    logString = "Drive:" + QString::number( drive );
    FM_LOG( logString );
    logString = "Unlock drive error:" + QString::number( err );
    FM_LOG( logString );

    delete password16;

    if( err == KErrNone ){
        return FmErrNone;   
    }
    else if( err == KErrAccessDenied ){
        return FmErrAccessDenied;
    }
    else if( err == KErrAlreadyExists ){
        return FmErrAlreadyExists;
    }
    else if( err == KErrNotSupported ){
        return FmErrNotSupported;
    }
    else{
        return FmErrUnKnown;
    }
}

int FmUtils::checkDrivePwd( const QString &driverName, const QString &pwd )
{
    if( driverName.isEmpty() || pwd.length() > FmMaxLengthofDrivePassword ) {
        return FmErrWrongParam;
    }
    QString logString = "checkDrivePwd Drive name:" + driverName;
    logString += " password:" + pwd;
    FM_LOG( logString );

    return setDrivePwd( driverName, pwd, pwd );
}

int FmUtils::setDrivePwd( const QString &driverName, const QString &oldPwd, const QString &newPwd)
{
    if( driverName.isEmpty() || 
        oldPwd.length() > FmMaxLengthofDrivePassword || newPwd.length() > FmMaxLengthofDrivePassword  ) {
        return FmErrWrongParam;
    }
    QString logString = "setDrivePwd Drive name:" + driverName ;
    logString += " Old password:" + oldPwd;
    logString += " New password:" + newPwd;
    FM_LOG( logString );

    CCoeEnv *env = CCoeEnv::Static();
	RFs& fs = env->FsSession();

    TInt drive = 0;
	drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;
	
    HBufC* newPassword16 = XQConversions::qStringToS60Desc( newPwd);
    HBufC* oldPassword16 = XQConversions::qStringToS60Desc( oldPwd );

    TMediaPassword oldPassword;
    TMediaPassword newPassword;
    
    TPtr ptrNewPassword16( newPassword16->Des() );
    TPtr ptrOldPassword16( oldPassword16->Des() );
    
    FmS60Utils::ConvertCharsToPwd( ptrNewPassword16, newPassword );
    FmS60Utils::ConvertCharsToPwd( ptrOldPassword16, oldPassword );

    int err( fs.LockDrive( drive, oldPassword, newPassword, ETrue ) );

    logString = "Drive:" + QString::number( drive );
    FM_LOG( logString );
    logString = "Password set error:" + QString::number( err );
    FM_LOG( logString );

    delete newPassword16;
    delete oldPassword16;
    if( err == KErrNone ){
        return FmErrNone;   
    }
    else if( err == KErrNotSupported ){
        return FmErrNotSupported;
    }
    else{
        return FmErrUnKnown;
    }
}

void FmUtils::emptyPwd( QString &pwd )
{
    TBuf< FmMaxLengthofDrivePassword > nullPwd;
    nullPwd.FillZ( nullPwd.MaxLength() );
    nullPwd.Zero();
    pwd = XQConversions::s60DescToQString( nullPwd );
}

int FmUtils::renameDrive( const QString &driverName, const QString &newVolumeName)
{
    if( driverName.isEmpty() ) {
        return FmErrWrongParam;
    }
    foreach( const QChar &ch, newVolumeName )
    {
        bool a = ch.isSpace();
        bool b = ch.isLetterOrNumber();
        // If not alphadigit or space, return error
        if( !ch.isLetterOrNumber() && !ch.isSpace() )
        {
            return FmErrBadName;
        }   
    }
        
    CCoeEnv *env = CCoeEnv::Static();
	RFs& fs = env->FsSession();

    TInt drive = 0;
	drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;

    TPtr newName ( ( XQConversions::qStringToS60Desc( newVolumeName ) )->Des() );

    int err( fs.SetVolumeLabel( newName, drive ));
    
    QString logString = "Rename error:" + QString::number( err );
    FM_LOG( logString );

    if( err == KErrNone ){
        return FmErrNone;   
    }
    else if( err == KErrNotReady ){
        return FmErrNotReady;
    }
    else{
        return FmErrUnKnown;
    }
}

int FmUtils::ejectDrive( const QString &driverName )
{
    if( driverName.isEmpty() ) {
        return FmErrWrongParam;
    }
    QString logString = "FmUtils::ejectDrive start";
    FM_LOG( logString );

    TInt drive = 0;
	drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;

    const int KDriveShift = 16;

    // Let SysAp handle eject
    RProperty::Set(
        KPSUidCoreApplicationUIs,
        KCoreAppUIsMmcRemovedWithoutEject,
        ECoreAppUIsEjectCommandUsedToDrive | ( drive << KDriveShift )
        );
    return FmErrNone;
}

QString FmUtils::getFileType( const QString &filePath  )
{
    RApaLsSession apaSession;
    TDataType dataType;
    TUid appUid;
    
    TBuf<128> mimeTypeBuf;
        
    int err = apaSession.Connect();
    
    if ( err == KErrNone ){   
        err = apaSession.AppForDocument( XQConversions::qStringToS60Desc( filePath )->Des(), 
                                         appUid, dataType );
        
        if( err == KErrNone ){
            mimeTypeBuf.Copy(dataType.Des8());
        }  
    }
    
    apaSession.Close();
    return XQConversions::s60DescToQString( mimeTypeBuf );
}

quint64 FmUtils::getDriveDetailsResult( const QString &folderPath, const QString &extension )
{
    int err;
    
    RFs fs;
    err = fs.Connect();
    
    QString string( fillPathWithSplash( folderPath ) );

    TPtrC desFolderPath( XQConversions::qStringToS60Desc( string )->Des() );
    TPtrC ptrExtension( XQConversions::qStringToS60Desc( extension )->Des() );
    
    CDir* results = 0;
    TParse parse;
    
    quint64 size = 0;
    
    const TInt pathlength = ptrExtension.Length() + desFolderPath.Length();
    
    if ( pathlength > KMaxFileName ){
        err = KErrNotFound;   
    }
    else{
        err = fs.Parse( ptrExtension, desFolderPath, parse );
        err = fs.GetDir( parse.FullName(), KEntryAttMaskSupported|KEntryAttAllowUid, 
            ESortNone, results );
        
        TDesC des = parse.FullName();
        
        if (err == KErrNotFound)
            {
            return 0;
            }
    }
    
    if ( results ){
        CleanupStack::PushL(results);

        // Go through all files in the list and tell subclass
        TFileName file;
        const TInt count = results->Count();
        for( TInt i=0; i<count; ++i ){
            const TEntry& entry = (*results)[i];
            file = desFolderPath;
            file += entry.iName;
            size += entry.iSize;          
        }
        CleanupStack::PopAndDestroy(results);
    }
    
    fs.Close();
    
    return size;  
}

bool FmUtils::isDriveC( const QString &driverName )
{
    if( driverName.isEmpty() ) {
        return false;
    }
    TInt drive = 0;
    drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;
    if( drive == EDriveC ){
        return true;
    }
    else{
        return false;
    }
   
}

bool FmUtils::isDrive( const QString &path )
{
   bool ret( false );
   if( path.length() <= 3 && path.length() >=2 ) {
       ret = true;
   }
   
   return ret;   
}

void FmUtils::createDefaultFolders( const QString &driverName )
{
    if( driverName.isEmpty() ) {
        return;
    }
    int err;
    
    TInt drive = 0;
    drive = driverName[0].toUpper().toAscii() - 'A' + EDriveA;
    
    RFs fs;
    err = fs.Connect();
    
    if( err != KErrNone ){
        return;
    }
    
    quint32 drvStatus( 0 );
    err = DriveInfo::GetDriveStatus( fs, drive, drvStatus );
    if ( !( drvStatus & DriveInfo::EDriveUserVisible ) ||
        ( drvStatus & ( DriveInfo::EDriveRemote |
                        DriveInfo::EDriveReadOnly |
                        DriveInfo::EDriveUsbMemory ) ) ){
            return; 
        }
    
    TEntry entry;
    CDesCArray* array = PathInfo::GetListOfPathsLC( drive );
    
    TInt count( array->MdcaCount() );
    for ( TInt i( 0 ); i < count; ++i )
        {
        TPtrC fullPath( array->MdcaPoint( i ) );
        TBool allow( ETrue );

        if ( drvStatus & DriveInfo::EDriveRemovable )
            {
            // Filter few folder types from physically removable memory cards
            TInt pathType( PathInfo::PathType( fullPath ) );
            switch( pathType )
                {
                case PathInfo::EGamesPath: // FALL THROUGH
                case PathInfo::EInstallsPath: // FALL THROUGH
                case PathInfo::EGsmPicturesPath: // FALL THROUGH
                case PathInfo::EMmsBackgroundImagesPath: // FALL THROUGH
                case PathInfo::EPresenceLogosPath:
                    {
                    allow = EFalse;
                    }
                default:
                    {
                    break;
                    }
                }
            }

        if ( allow ){
            fs.MkDirAll( fullPath ); // Ignore error

            if ( fs.Entry( fullPath, entry ) == KErrNone ){
                if( entry.IsHidden() ){
                // If setting fails, File Manager can still go on
                    fs.SetEntry(
                         fullPath, entry.iModified, 0, KEntryAttHidden );
                }
            }
        }
    }
    CleanupStack::PopAndDestroy( array );
}

/*!
    fill splash in the end of \a filePath if the path is not a file
    All "/" and "\" will be changed to QDir::separator
    \sa formatPath only changed "/" and "\" to QDir::separator
*/
QString FmUtils::fillPathWithSplash( const QString &filePath )
{
	QString newFilePath;
    if( filePath.isEmpty() ) {
        return newFilePath;
    }

    newFilePath = formatPath( filePath );
    
    if( newFilePath.right( 1 )!= QDir::separator() ){
        newFilePath.append( QDir::separator() );
    }
    return newFilePath;
}

QString FmUtils::removePathSplash( const QString &filePath )
{
    QString newFilePath( filePath );
    if( filePath.right( 1 ) == QChar( '/' ) || filePath.right(1) == QString( "\\" ) ) {
        newFilePath = filePath.left( filePath.length() - 1 );
    }
    return newFilePath;
}

// filter un-accessable drive
bool FmUtils::checkDriveAccessFilter( const QString &driveName )
{
    if( driveName.isEmpty() ) {
        return false;
    }
    FmDriverInfo driveInfo = queryDriverInfo( driveName );
    if( ( driveInfo.driveState()& FmDriverInfo::EDriveRam ) ||
        ( driveInfo.driveState()& FmDriverInfo::EDriveRom ) ) {
        return false;
    }
    return true;
}

QString FmUtils::checkDriveToFolderFilter( const QString &path )
{
    /*
    QFileInfo fileInfo( path );
    if( !fileInfo.exists() ) {
            return QString();
        }
    */
    QString checkedPath = fillPathWithSplash( path );
    if( checkedPath.compare( Drive_C, Qt::CaseInsensitive ) == 0 ) {
        checkedPath += QString( "data" ) + QDir::separator();
        return checkedPath;
    }
    return path;

}

QString FmUtils::checkFolderToDriveFilter( const QString &path )
{
    QString logString;
    logString = QString( "checkFolderToDriveFilter: " ) + path;
    FM_LOG( logString );
    QString checkedPath = fillPathWithSplash( path );

    logString = QString( "checkFolderToDriveFilter_fillPathWithSplash: " ) + checkedPath;
    FM_LOG( logString );
    
    if( checkedPath.compare( Folder_C_Data, Qt::CaseInsensitive ) == 0 ) {
        FM_LOG( QString( " change from c:/data/ to C:/" ) );
        return Drive_C;
    }
    return path;

}

int FmUtils::isPathAccessabel( const QString &path )
{
    // Used to check if path is accessable, very important feature
    // and will return filemanager error.
    FM_LOG( QString( "isPathAccessabel:" ) + path );
    if( path.isEmpty() ) {
        return FmErrPathNotExist;
    }

    // used to filter locked/ejected/corrupted drive
    // check if drive is available, no matter if it is a drive, a folder, or a file.
    if( !isDriveAvailable( path ) ) {
        FM_LOG( QString( "isPathAccessabel false: path is drive and not available" ) );
        return FmErrDriveNotAvailable;
    }

    QFileInfo fileInfo( path );
    if( fileInfo.absoluteFilePath().contains( Drive_C, Qt::CaseInsensitive ) &&
        !fileInfo.absoluteFilePath().contains( Folder_C_Data, Qt::CaseInsensitive ) ) {
        FM_LOG( QString( "isPathAccessabel false: path contain C and not in data folder" ) );
        return FmErrPathDenied;
    }
    if( !checkDriveAccessFilter( FmUtils::getDriveNameFromPath( fileInfo.absoluteFilePath() ) ) ){
        return FmErrDriveDenied;
    }
    if( !fileInfo.exists() ) {
        FM_LOG( QString( "isPathAccessabel false: path not exist" ) );
        return FmErrPathNotExist;
    }
    FM_LOG( QString( "isPathAccessabel FmErrNone" ) );
    return FmErrNone;
}

// only used to check drive, when MMC is not inserted, also return false
bool FmUtils::isDriveAvailable( const QString &path )
{
    FM_LOG( QString( "isDriveAvailable:" ) + path );
    if( path.isEmpty() ) {
        return false;
    }
    FmDriverInfo::DriveState driveState = queryDriverInfo( path ).driveState();
    if( ( driveState & FmDriverInfo::EDriveAvailable ) ) {
        FM_LOG( QString( "isDriveAvailable true" ) );
        return true;
    }
    FM_LOG( QString( "isDriveAvailable false" ) );
    return false;
}

void FmUtils::getDriveList( QStringList &driveList, bool isHideUnAvailableDrive )
{
    if( isHideUnAvailableDrive ) {
        FM_LOG( QString( "getDriveList HideUnAvailableDrive_true" ) );
    } else {
        FM_LOG( QString( "getDriveList HideUnAvailableDrive_false" ) );
    }
    QFileInfoList infoList = QDir::drives();

    foreach( QFileInfo fileInfo, infoList ) {
        QString driveName = fileInfo.absolutePath();
        if( checkDriveAccessFilter( driveName ) ) {
            if( !isHideUnAvailableDrive ) {
                driveList.append( driveName );
            }
            else if ( isDriveAvailable( driveName ) ) {
                driveList.append( driveName );
            }
        }
    }
    return;
}

/*!
    fill volume name for \a driveName, with drive letter at the front, for example, C: Phone memory
    if \a isFillWithDefaultVolume is true, default volume is provided for non-volume drive.
*/
QString FmUtils::fillDriveVolume( QString driveName, bool isFillWithDefaultVolume )
{
    QString ret;
    if( driveName.isEmpty() ) {
        return ret;
    }
    QString tempDriveName = fillPathWithSplash( driveName );

    QString checkedDriveName( removePathSplash( driveName ) );
    
    FmDriverInfo driverInfo = FmUtils::queryDriverInfo( tempDriveName );
    QString volumeName = driverInfo.volumeName();
    
    if( volumeName.isEmpty() && isFillWithDefaultVolume ){
        switch ( driverInfo.driveType() )
            {
            case FmDriverInfo::EDriveTypeMassStorage:
                ret = hbTrId( "txt_fmgr_dblist_1_mass_storage" ).arg( checkedDriveName );
                break;
            case FmDriverInfo::EDriveTypeUsbMemory:
                ret = hbTrId( "txt_fmgr_dblist_1_usb_memory" ).arg( checkedDriveName );
                break;
            case FmDriverInfo::EDriveTypeMemoryCard:
                ret = hbTrId( "txt_fmgr_dblist_1_memory_card" ).arg( checkedDriveName );
                break;
            case FmDriverInfo::EDriveTypePhoneMemory:
                ret = hbTrId( "txt_fmgr_dblist_1_device_memory" ).arg( checkedDriveName );
                break;
            default:
                Q_ASSERT_X( false, "FmUtils::fillDriveVolume", "please handle drive type");
                break;
            }    
    }
    
    if( ret.isEmpty() ) {
        // ret is not got. fill ret as default method
        // txt_fmgr_dblist_1_2 is not correct, can not use.
        ret = hbTrId( "%1 %2" ).arg( checkedDriveName ).arg( volumeName );
    }
    return ret;
}


/*!
    return volume name for \a driveName. without drive letter at the front.
    \a defaultName is set true if default volume name is return for volume name
*/
QString FmUtils::getVolumeNameWithDefaultNameIfNull( const QString &diskName, bool &defaultName )
{
    FmDriverInfo driverInfo = FmUtils::queryDriverInfo( diskName );
          
    QString volumeName = driverInfo.volumeName();    
    //save the volume status, whether it is default name
    defaultName = false;
    //volume name may be null if not set, it will be set at least for one time in the following while cycling.
    if ( volumeName.isEmpty() ) {
        defaultName = true;
        switch ( driverInfo.driveType() )
            {
            case FmDriverInfo::EDriveTypeMassStorage:
                volumeName = hbTrId("Mass storage"); 
                break;
            case FmDriverInfo::EDriveTypeUsbMemory:
                volumeName = hbTrId("USB memory"); 
                break;
            case FmDriverInfo::EDriveTypeMemoryCard:
                volumeName = hbTrId("Memory card");
                break;
            case FmDriverInfo::EDriveTypePhoneMemory:
                volumeName = hbTrId("Device memory");
                break;
            default:
                Q_ASSERT_X( false, "FmUtils::getVolumeNameWithDefaultNameIfNull", "please handle drive type" );
                break;
            }   
    }
    return volumeName;
}

int FmUtils::launchFile( const QString &filePath )
{
    QFile file( filePath );
    if( !file.exists() ) {
        return false;
    }
        
    XQApplicationManager mAiwMgr;
    XQAiwRequest *request = mAiwMgr.create(file);
    if ( request == 0 ) {
        // No handlers for the URI
        return FmErrUnKnown;
    }
    
    // Set function parameters
    QList<QVariant> args;
    args << file.fileName();
    request->setArguments(args);
    
    // Send the request
    bool res = request->send();
    if  (!res) 
    {
       // Request failed. 
      int error = request->lastError();
      
      delete request;
      return FmErrUnKnown;
    }
    
    delete request;
    return FmErrNone;
}

void FmUtils::sendFiles( QStringList &filePathList )
{
    ShareUi shareui;
    shareui.send( filePathList, false );
}

QString FmUtils::getBurConfigPath( QString appPath )
{
    Q_UNUSED( appPath );
    QString path( BURCONFIGFILE );
    return path;
}

bool FmUtils::isPathEqual( const QString &pathFst, const QString &pathLast )
{
    QString fst( fillPathWithSplash( pathFst ) );
    QString last( fillPathWithSplash( pathLast ) );
    if( fst.compare( last, Qt::CaseInsensitive ) == 0 ) {
        return true;
    }
    return false;
}

bool FmUtils::isDefaultFolder( const QString &folderPath  )
{
    TPtrC desFolderPath( XQConversions::qStringToS60Desc( folderPath )->Des() );
    
    TInt pathType( PathInfo::PathType( desFolderPath ) );
    switch( pathType ){
       case PathInfo::ENotSystemPath:{
           QString locString( Localize( folderPath ) );
            if ( locString.isEmpty() ){
                return false;
            }
            return true;
            }
        case PathInfo::EPhoneMemoryRootPath: // FALL THROUGH
        case PathInfo::EMemoryCardRootPath: // FALL THROUGH
        case PathInfo::ERomRootPath:{
            return false;
        }
        // Accept other folders
        default:{
            return true;
        }
    }
}

QString FmUtils::Localize( const QString &path )
{
    QString locPath = fillPathWithSplash( path );

    TPtrC desPath( XQConversions::qStringToS60Desc( locPath )->Des() );
    CDirectoryLocalizer *localizer = CDirectoryLocalizer::NewL();

    localizer->SetFullPath( desPath );
    if( localizer->IsLocalized() ){   
        return XQConversions::s60DescToQString( localizer->LocalizedName() );
    }
    
    return QString();
}

/*!
    All "/" and "\" in \a path will be changed to QDir::separator
    \sa fillPathWithSplash, fillPathWithSplash will append QDir::separator in the end if path is no a file
*/
QString FmUtils::formatPath( const QString &path  )
{
    QString formatPath;
    if( path.isEmpty() ) {
        return formatPath;
    }
    
	foreach( QChar ch, path ) {
		if( ch == QChar('\\') || ch == QChar('/') ) {
			formatPath.append( QDir::separator() );
		} else {
			formatPath.append( ch );
		}
    }

    return formatPath;
}

int FmUtils::getMaxFileNameLength()
{
    return KMaxFileName;
}

bool FmUtils::checkMaxPathLength( const QString& path )
{
    if( path.length() > KMaxPath ) {
        return false;
    }
    return true;
}

bool FmUtils::checkFolderFileName( const QString& name )
{
    // trim space firest, because there may be some spaces after "." ,  it is also not valid
    QString trimmedName( name.trimmed() );
	if( trimmedName.isEmpty() ) {
		return false;
	}
    if( trimmedName.endsWith( QChar('.'),  Qt::CaseInsensitive ) ) {
        return false;
    }
    if( trimmedName.contains( QChar('\\'), Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('/'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar(':'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('*'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('?'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('\"'), Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('<'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('>'),  Qt::CaseInsensitive ) ||
        trimmedName.contains( QChar('|'),  Qt::CaseInsensitive ) ){
        return false;
    }
    // use orignal name to exam max size of file name
    if( name.length() > KMaxFileName ) {
        return false;
    }
    return true;
}

bool FmUtils::checkNewFolderOrFile( const QString &fileName, const QString &path, QString &errString )
{
    // first check if fileName is valid, then check if path length is valid, and check if file/foler is existed at last
    QFileInfo fileInfo( path );
    bool ret( true );   
    if (!FmUtils::checkFolderFileName( fileName ) ) {
        errString = hbTrId( "Invalid file or folder name!" );
        ret = false;
    } else if( !FmUtils::checkMaxPathLength( path ) ) {
        errString = hbTrId( "the path you specified is too long!" );
        ret = false;
    } else if (fileInfo.exists()) {
        errString = hbTrId( "%1 already exist!" ).arg( fileInfo.fileName() );
        ret = false;
    }
    return ret;
}

/*!
    Check if \a dest is sub level path of \a src
    Used to check True/False when copy a folder to itself or its subfolder
    For example, c:\data\test is sub path of c:\data.
    But c:\data123\test is not sub path of c:\data.
    So after got right part of path, the first char must be \ or /
*/
bool FmUtils::isSubLevelPath( const QString &src, const QString &dest )
{
    FM_LOG("FmUtils::isSubFolder: src=" + src + " dest=" + dest);
    QString checkedSrc( FmUtils::fillPathWithSplash( src ) );
    QString checkedDest( FmUtils::fillPathWithSplash( dest ) );
    
    if( checkedDest.contains( checkedSrc, Qt::CaseInsensitive) &&
            checkedDest.length() > checkedSrc.length() ) {
        // for example c:\data\ vs c:\data\123\ 
        FM_LOG("FmUtils::isSubFolder: true");
        return true;
    }
    // for example c:\data\ vs c:\data\ 
    // for example c:\data\ vs c:\data123\ 

    FM_LOG("FmUtils::isSubFolder: false");
    return false;
}

/*!
    set the \a desFile attributes as the same with \a srcFile
*/
int FmUtils::setFileAttributes( const QString &srcFile, const QString &desFile )
{
    RFs fsSession;
    User::LeaveIfError( fsSession.Connect() ); 
    CleanupClosePushL( fsSession );
    RFile64 src;
    RFile64 des;
    HBufC *buf1 = XQConversions::qStringToS60Desc( removePathSplash( formatPath( srcFile ) ) );
    HBufC *buf2 = XQConversions::qStringToS60Desc( removePathSplash( formatPath( desFile ) ) );
    User::LeaveIfError( src.Open( fsSession, *buf1, EFileRead | EFileShareReadersOnly ) );
    User::LeaveIfError( des.Open( fsSession, *buf2, EFileWrite | EFileShareExclusive ) );
    TTime mod;
    int err = src.Modified( mod );;
    if ( err == FmErrNone ) {
        err = des.SetModified( mod );    
    }
    TUint att( 0 );
    if ( err == FmErrNone ) {
        err = src.Att( att );        
    }
    if ( err == FmErrNone ) {
        des.SetAtt( att, ( ~att ) & KEntryAttMaskSupported );
    }    
    src.Close();
    des.Close();
    fsSession.Close();
    CleanupStack::PopAndDestroy(); // fsSession
    return err;
}