csxhelp/HelpEngine/src/CSXHRuntimeIndexing.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:30:56 +0100
branchRCL_3
changeset 45 cbffe13eac63
child 49 a7ccb69868af
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201031 Kit: 201035

/*
* Copyright (c) 2006 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:  CCSXHRuntimeIndexing class definition
*
*/


#include <pathinfo.h>
#include <utf.h>
#include <bautils.h>
#include <eikenv.h>
#include <aknnotedialog.h> // for CAknNoteDialog
#include <aknnotewrappers.h>
#include <SenXmlUtils.h>
#include <SenXmlConstants.h>

#include "CSXHRuntimeIndexing.h"
#include "CSXHHtmlTOC1.h"
#include "csxhconstants.h"

// buffer length of Drive information in index file
//
const TInt KMaxDriveInfo = 100;

CCSXHRuntimeIndexing::CCSXHRuntimeIndexing()
    {
    iCoeEnv = CCoeEnv::Static();
    }
    
CCSXHRuntimeIndexing::~CCSXHRuntimeIndexing()
    {
    delete iFullDirName;
    iFile.Close();
    }
    
CCSXHRuntimeIndexing* CCSXHRuntimeIndexing::NewL()
    {
    CCSXHRuntimeIndexing* self = new ( ELeave ) CCSXHRuntimeIndexing();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }
    
void CCSXHRuntimeIndexing::ConstructL()
    {
    RFs& fileSession = iCoeEnv->FsSession();
    iFullDirName = HBufC::NewL( KMaxFileName );

    TFileName fullDirName;
    
    GetPrivatePath( fullDirName );
    if ( !BaflUtils::PathExists( fileSession, fullDirName ) )
        {
        fileSession.CreatePrivatePath( EDriveC );
        }
    
    TInt len = fullDirName.Length();
    TDriveList dirList; 
    if( fileSession.DriveList( dirList ) == KErrNone )
        {
        TDriveInfo info;
        TInt driveListLen = dirList.Length();
        
        for ( TInt i = 0; i < driveListLen; i++ )
            {
            // make separate folder for C/D/E/... drive
            // e.g. C:\\private\\10005234\\C\\

            TInt err = fileSession.Drive( info, i );
            if ( err == KErrNone &&
                    info.iType != EMediaNotPresent )
                {
                TChar driveChar;
                RFs::DriveToChar( i, driveChar );
                fullDirName.Append( driveChar );
                fullDirName.Append( KFwdSlash );
                fileSession.MkDir( fullDirName );
                fullDirName.Delete( len, 3 );
                }
            }
        
        }
    }
    
TBool CCSXHRuntimeIndexing::IndexFileExistsL()
    {
    RFs& fileSession = iCoeEnv->FsSession();
    TBuf<KMaxFileName> fileName;
    GetPrivatePath( fileName );
    fileName.Append( _L("Z\\") );
    AppendLocaleL( fileName );
    fileName.Append( KMasterMetaFile );
    
    // Now the dirName is C:\\private\\<app-uid>\\Z\\index.xml
    // check if it exists, if yes, runtime indexing must be launched before
    // since Z based Help content must be delivered with cell phone
    //
    return BaflUtils::FileExists( fileSession, fileName );
    
    }
    
void CCSXHRuntimeIndexing::BeginIndexFileL( const TChar& aDrive )
    {
    RFs& fileSession = iCoeEnv->FsSession();
    TPtr des = iFullDirName->Des();
    iDriveLetter = aDrive;
    des.Zero();
    GetPrivatePath( des );
    des.Append( aDrive );
    des.Append( KFwdSlash );
    AppendLocaleL( des );
    if ( !BaflUtils::PathExists( fileSession, des ) )
        {
        // generate C:\\private\\<help-uid>\\<aDrive>\\ folder
        //
        fileSession.MkDir( des );
        }
    
    // for temporary usage, once it's finished successfully,
    // rename to index.xml. otherwise, the old index file still exists.
    //
    des.Append( KMasterMetaTmpFile );
    iFile.Replace( fileSession, des, EFileWrite );
    
    HBufC8* driveInfo = HBufC8::NewLC( KMaxDriveInfo );
    TPtr8 ptr = driveInfo->Des();
    ptr.Append( KIndexXMLVesion );
    ptr.Append( _L( "<collections drive=\"" ) );
    ptr.Append( aDrive);
    ptr.Append( _L( "\">\r\n" ) );
    iFile.Write( *driveInfo );
    CleanupStack::PopAndDestroy( driveInfo );
    }
    
void CCSXHRuntimeIndexing::FinishAndCloseIndexFileL()
    {
    RFs& fileSession = iCoeEnv->FsSession();
    iFile.Write( KIndexCollectEnd );
    iFile.Close();  
      
    TTime time;
    // Replace the index.xml with temporary file, in case it fails, will have no impact
    // the original index.xml, it's a backup solution
    //
    TBuf<KMaxFileName> newName;
    TInt err = KErrNone;
    newName.Copy( *iFullDirName );
    TInt pos = newName.LocateReverse( TChar('\\') );
    newName.Delete( pos + 1, newName.Length() - pos - 1 ); // remove the temp name
    newName.Append( KMasterMetaFile ); //  and append index.xml
    
    err = fileSession.Replace( *iFullDirName, newName );
    
    if ( err == KErrNone )
        {
        // set the modified date of master index.xml
        // to be the same with related help content folder
        // e.g. C:\\resource\\xhtml\\01\\ modified time is 2009.3.1
        // C:\\private\\10005234\\C\\01\\index.xml will be 2009.3.1
        // this will make sure once help content folder changed, index.xml can be
        // determined to change.
        TBuf<KMaxFileName> helpDir;
        helpDir.Append( iDriveLetter );  
        helpDir.Append( KInstallPath );
        // append locale information
        AppendLocaleL( helpDir );
        
        fileSession.Modified( helpDir, time );
        err = fileSession.SetModified( newName, time );
        
        }
    
    }
      
void CCSXHRuntimeIndexing::RuntimeGenerateIndexL( const CCSXHHtmlTOC1& aToc1, const TDesC& aFeature )
    {
    // Form into an entry, like
    // <collection FeatureID="-1" id="0x10005951" navtitle="Bluetooth"></collection>
    HBufC8* appName = CnvUtfConverter::ConvertFromUnicodeToUtf8L( aToc1.GetName() );
    CleanupStack::PushL(appName);
    TRAPD( err, SenXmlUtils::LeaveOnXmlEscapesL( *appName ) );
    TInt length = KMaxIndexEntryExclude;
    TBuf8<KMaxUidLength> buffUid;
    
    buffUid.Append( KHexPrefix );
    buffUid.AppendNumFixedWidth( aToc1.GetAppUid().iUid, EHex, 8 );
    length += appName->Length();
    length += aFeature.Length();
    HBufC8* entry = HBufC8::NewLC( length );
    TPtr8 des = entry->Des();
    // Append entry tag
    des.Append( KIndexXMLEntryBegin );
    // Append feature id attribute "FeatureID"
    des.Append( KAppFeatureIDTag );
    des.Append( KIndexQuoteBegin );
    // Append feature id
    des.Append( aFeature );
    des.Append( KIndexQuoteEnd );
    // Append app id attribute "id"
    des.Append( KMasterCollection_idTag );
    des.Append( KIndexQuoteBegin );
    // Append app id
    des.Append( buffUid );
    des.Append( KIndexQuoteEnd );
    // Append app priority 
    des.Append( KPriorityTag );
    des.Append( KIndexQuoteBegin );
    des.AppendNum(aToc1.Priority());
    des.Append( KIndexQuoteEnd );
    // Append app name attribut "navtitle"
    des.Append( KTOC2NameTag );
    des.Append( KIndexQuoteBegin );
    if ( err == KErrSenInvalidCharacters )
        {
        // special handling to the XML-Escaped char
        HBufC8* newElement = SenXmlUtils::EncodeHttpCharactersLC( *appName );
        des.Append( *newElement );
        CleanupStack::PopAndDestroy( newElement );
        }
    else
        {
        des.Append( *appName );
        }

    des.Append( KIndexXMLEntryEnd );
    iFile.Write( *entry );
    
    CleanupStack::PopAndDestroy( entry );
    CleanupStack::PopAndDestroy( appName );
    
    }
    
void CCSXHRuntimeIndexing::GetPrivatePath( TDes& aName )
    {
    RFs& fileSession = iCoeEnv->FsSession();
    TBuf<KMaxFileName> privatePath;
    TChar drive;
    RFs::DriveToChar( EDriveC, drive );
    
    fileSession.PrivatePath( privatePath );
    aName.Append( drive );
    aName.Append( TChar(':') ); 
    aName.Append( privatePath );
    }

void CCSXHRuntimeIndexing::AppendLocaleL( TDes& aDir )
    {
    RFs& fileSession = iCoeEnv->FsSession();
    RArray<TLanguage> langs;
    BaflUtils::GetDowngradePathL( fileSession, User::Language(), langs );
    TInt len = aDir.Length();
    
    if ( len > 0 )
        {
        TLanguage lang = langs[0];
        if(lang < 10)
            {
            aDir.AppendNumFixedWidth( lang, EDecimal,2 );
            }
        else
            {
            aDir.AppendNum( lang );
            }
        }
    else
        {
        // rarely case, if no current language, use English
        aDir.Append( _L("01") );
        }
        
    aDir.Append( KFwdSlash );
    langs.Reset();
    }
    
void CCSXHRuntimeIndexing::DeleteIndexFileL( const TChar& aDrive )
    {
    RFs& fileSession = iCoeEnv->FsSession();
    TBuf<KMaxFileName> des;
    GetPrivatePath( des );
    des.Append( aDrive );
    des.Append( KFwdSlash );
    AppendLocaleL( des );
    // C:\\private\\<app-uid>\\<drive letter>\\<language-id>\\index.xml
    des.Append( KMasterMetaFile );
    
    if ( BaflUtils::FileExists( fileSession, des ) )
        {
        fileSession.Delete( des );
        }

    }
    
TInt CCSXHRuntimeIndexing::CheckDirChangeL( const TChar& aDrive )
    {
    RFs& fsSession = iCoeEnv->FsSession();
    
    // Begin to search help content folder to see if there are date modify
    // meanwhile, compare to the related folder in private directory
    TFileName dirName;
    dirName.Append( aDrive );
    dirName.Append( KInstallPath );

    // Begin to append locale, note this will append current locale,
    // thru which, app can determine if it's caused by user changed locales
    AppendLocaleL( dirName );

    TTime dirModified(0);
    TTime fileModified(0);
    
    if ( BaflUtils::PathExists( fsSession, dirName ) )
        {
        // here is modified time of help content folder
        fsSession.Modified( dirName, dirModified );
        }
    else
        {
        // fast return, no need to go on checking
        return KNoDirExist;
        }

    TFileName filename;
    GetPrivatePath( filename );
    filename.Append( aDrive );
    filename.Append( KFwdSlash );
    AppendLocaleL( filename );
    filename.Append( KMasterMetaFile );
                
    if ( BaflUtils::FileExists( fsSession, filename ) )
        {
        // here is modified time of index.xml
        //
        fsSession.Modified( filename, fileModified );
        }
    else
        {
        return KNoIndexExist;
        }
                    
    if ( fileModified != dirModified )
        {
        // folder changed, return it
        TInt ret = KErrNotFound;
        RFs::CharToDrive( aDrive, ret );
        return ret;
        }
    
    return KNoChange;
    }