--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/widgetregistry/Server/src/WidgetRegistry.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,2221 @@
+/*
+* Copyright (c) 2006, 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: Manages list of widget entries.
+*
+*/
+
+
+#include <e32base.h>
+#include <f32file.h>
+#include <s32file.h>
+#include <s32mem.h>
+#include <bautils.h>
+
+#include "WidgetEntry.h"
+#include "WidgetRegistry.h"
+#include "WidgetInstaller.h"
+#include <libxml2_globals.h>
+#include <libc\stdlib.h>
+#include <libxml2_parser.h>
+#include <libxml2_tree.h>
+#include "WidgetMMCHandler.h"
+#include "UidAllocator.h"
+#if defined( BRDO_WRT_SECURITY_MGR_FF )
+#include <RTSecManager.h>
+#endif
+#include <e32property.h>
+
+// CONSTANTS
+
+static const TInt KDefaultWidgetCount = 20; // used for initial RArray size
+static const TInt KAppArchTimeout = 10000000; // 10 seconds in microseconds
+static const TInt KAppArchDelayInterval = 500000; // 500 milliseonds in microseconds
+
+enum
+ {
+ EAppListFlagEntry = 1
+ };
+
+enum
+ {
+ EInstallListFlagEntry = 1
+ };
+
+// Be sure that length of literal pathname strings is less than
+// KWidgetRegistryMaxPathName in header file.
+//
+// drive letter a: is used as a placeholder, it will be set as needed
+_LIT( KWidgetInstallPath,
+ "a:\\private\\10282822\\" );
+_LIT( KWidgetEntryStoreBinaryFile,
+ "a:\\private\\10282f06\\WidgetEntryStore.dat" );
+_LIT( KWidgetEntryStoreXmlFile,
+ "a:\\private\\10282f06\\WidgetEntryStore.xml" );
+_LIT( KWidgetEntryStoreXmlTempFile,
+ "a:\\private\\10282f06\\WidgetEntryStoreTemp.xml" );
+_LIT( KWidgetDirFile, "widget_lproj.xml" );
+_LIT( KWidgetAccessPolicy, "WidgetAccessPolicy.xml" );
+_LIT( KWidgetPolicyIdFile, "WidgetPolicyId.dat" );
+
+_LIT( KWidgetDefaultLangDir, "en" );
+_LIT8( KLangID, "LangID" );
+_LIT8( KLangDir, "LangDir" );
+
+// for exteranlize
+_LIT( KXmlHeader,
+ "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\" ?>" );
+_LIT( KXmlRootStart, "<widgetregistry>" );
+_LIT( KXmlRootEnd, "</widgetregistry>" );
+_LIT( KWidgetEntryStart, "<entry>" );
+_LIT( KWidgetEntryEnd, "</entry>" );
+_LIT( KXmlNewline, "\x0D\x0A" ); // DOS/Symbian style works with XML parsers
+
+// for internalize
+_LIT8( KWidgetRegistry, "widgetregistry" );
+_LIT8( KEntry, "entry" );
+
+LOG_NAMES( "widreg", "widreg.txt" )
+
+void XmlDocFree( TAny* aPtr )
+ {
+ __ASSERT_DEBUG( aPtr, User::Invariant() );
+ xmlDocPtr ptr( (xmlDocPtr)(aPtr) );
+ xmlFreeDoc( ptr );
+ }
+
+// ============================================================================
+// Traverse to the next Node
+//
+// @param aNode: current node
+// @since 3.1
+// @return next node
+// ============================================================================
+//
+xmlNode* TraverseNextNode( xmlNode* n )
+ {
+ // depth first
+ if ( n->children )
+ {
+ n = n->children;
+ }
+ else
+ {
+ // go up while no sibling
+ while ( n->parent && !n->next )
+ {
+ n = n->parent;
+ }
+ // sibling?
+ if ( n->next )
+ {
+ n = n->next;
+ }
+ else // done
+ {
+ n = NULL;
+ }
+ }
+ return n;
+ }
+// ============================================================================
+// Changes the Publish & Subscribe key value
+// ============================================================================
+//
+
+static void NotifyWidgetAltered()
+ {
+ const TUid KMyPropertyCat = { 0x10282E5A };
+ enum TMyPropertyKeys { EMyPropertyAltered = 110 };
+ TInt altered( 1 );
+ RProperty::Set( KMyPropertyCat, EMyPropertyAltered , altered );
+ }
+// ============================================================================
+// CWidgetRegistry::NewL()
+// two-phase constructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetRegistry* CWidgetRegistry::NewL( RFs& aFs )
+ {
+ CWidgetRegistry* widgetRegistry = new ( ELeave ) CWidgetRegistry( aFs );
+ CleanupStack::PushL( widgetRegistry );
+ TRAP_IGNORE( widgetRegistry->ConstructL() );
+ CleanupStack::Pop( widgetRegistry );
+ return widgetRegistry;
+ }
+
+// ============================================================================
+// CWidgetRegistry::CWidgetRegistry()
+// C++ constructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetRegistry::CWidgetRegistry( RFs& aFs ):
+ iFs( aFs ),
+ iWidgetInstallPath( KWidgetInstallPath ),
+ iRegistryBinaryFileName( KWidgetEntryStoreBinaryFile ),
+ iRegistryXmlFileName( KWidgetEntryStoreXmlFile ),
+ iRegistryXmlTempFileName( KWidgetEntryStoreXmlTempFile ),
+ iPolicyId( 0 )
+ {
+ }
+
+// ============================================================================
+// CWidgetRegistry::~CWidgetRegistry()
+// destructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetRegistry::~CWidgetRegistry()
+ {
+ iEntries.ResetAndDestroy();
+ iUsedUids.Close();
+ // iFs not owned
+ iAppArch.Close();
+ delete iInstaller;
+ iLangDirList.ResetAndDestroy();
+ delete iMMCHandler;
+ delete iXmlProcessor;
+
+ iFs.Close();
+ LOG_DESTRUCT;
+ }
+
+// ============================================================================
+// CWidgetRegistry::ConstructL()
+// Symbian second phase constructor
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::ConstructL()
+ {
+ LOG_CONSTRUCTL;
+ LOG_OPEN;
+ LOG( "CWidgetRegistry::ConstructL internalize" );
+
+ User::LeaveIfError( iFs.Connect() );
+ iFs.CreatePrivatePath( EDriveC );
+ iFs.SetSessionToPrivate( EDriveC );
+ User::LeaveIfError( iAppArch.Connect() );
+ iInstaller = CWidgetInstaller::NewL();
+
+ // If internalizing leaves, then the registry will be out-of-sync
+ // with the installed widgets and apparc. But that's okay since
+ // it should be detected and corrected once the resource limit
+ // that caused the leave is removed.
+ TBool dirtyFlag = EFalse;
+ iXmlProcessor = CWidgetRegistryXml::NewL();
+ TRAP_IGNORE( InternalizeL( dirtyFlag ) );
+ if ( dirtyFlag )
+ {
+ // Basically same reason to ignore leaves here.
+ TRAP_IGNORE( ExternalizeL() );
+ }
+
+ LOG( " ctor internalize done" );
+
+#if defined( BRDO_WRT_SECURITY_MGR_FF )
+ FetchSecurityPolicyIdL();
+#endif
+
+ LOG1( "ConstructL internalize done, registry count %d",
+ iEntries.Count() );
+ LOG_CLOSE;
+
+ iMMCHandler = CWidgetMMCHandler::NewL( *this, iFs );
+ iMMCHandler->Start();
+ }
+
+// ============================================================================
+// CWidgetRegistry::FetchSecurityPolicyIdL()
+// Get policyId from security manager
+//
+// @since 5.0
+// ============================================================================
+//
+TInt CWidgetRegistry::FetchSecurityPolicyIdL()
+ {
+#if defined( BRDO_WRT_SECURITY_MGR_FF )
+ if ( !iPolicyId )
+ {
+ if ( KErrNone == iFs.ShareProtected() )
+ {
+ TFileName secPolicyFileName;
+ RFile secPolicyFile;
+ iFs.PrivatePath( secPolicyFileName );
+#ifdef __WINSCW__
+ secPolicyFileName.Insert( 0, _L( "C:" ));
+#else
+ secPolicyFileName.Insert( 0, _L( "Z:" ));
+#endif
+ secPolicyFileName.Append( KWidgetAccessPolicy );
+
+ if ( KErrNone == secPolicyFile.Open( iFs, secPolicyFileName, EFileShareAny ) )
+ {
+ CleanupClosePushL( secPolicyFile );
+ CRTSecManager* secMgr = CRTSecManager::NewL();
+ iPolicyId = secMgr->SetPolicy( secPolicyFile );
+ CleanupStack::PopAndDestroy( &secPolicyFile );
+
+ CleanupStack::PushL( secMgr );
+ // read old policyId, unset old policy file; store new policyId
+ RFile policyIdFile;
+ TFileName policyIdFileName;
+ iFs.PrivatePath( policyIdFileName );
+ policyIdFileName.Insert( 0, _L( "C:" ));
+ policyIdFileName.Append( KWidgetPolicyIdFile );
+
+ TInt error = KErrNotFound;
+ error = policyIdFile.Open( iFs, policyIdFileName, EFileShareAny );
+ // policy Id file exists
+ if ( error == KErrNone )
+ {
+ CleanupClosePushL( policyIdFile );
+ RFileReadStream readStream;
+ CleanupClosePushL( readStream );
+ readStream.Attach( policyIdFile );
+
+ TInt oldPolicyId = 0;
+ TRAP_IGNORE( oldPolicyId = readStream.ReadInt32L() );
+ // clean the old policy file
+ if ( oldPolicyId > 0 )
+ {
+ secMgr->UnSetPolicy( oldPolicyId );
+ }
+
+ CleanupStack::PopAndDestroy( &readStream );
+ }
+ // create policy Id file
+ else if ( error == KErrNotFound )
+ {
+ User::LeaveIfError( policyIdFile.Create( iFs, policyIdFileName, EFileShareAny ) );
+ CleanupClosePushL( policyIdFile );
+ }
+
+ // we should have a good policyIdFile by now, store iPolicyId there
+ RFileWriteStream writeStream;
+ CleanupClosePushL( writeStream );
+ writeStream.Replace( iFs, policyIdFileName, EFileShareAny );
+
+ TRAP_IGNORE( writeStream.WriteInt32L( iPolicyId ) );
+
+ CleanupStack::PopAndDestroy( 2, &policyIdFile );// writeStream, policyIdFile
+
+ CleanupStack::PopAndDestroy( secMgr );
+ }
+ }
+ }
+#else
+ iPolicyId = KErrNotSupported;
+#endif
+ return iPolicyId;
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetEntryL()
+// Get widget entry by UID or leave with KErrNotFound
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetEntry& CWidgetRegistry::GetWidgetEntryL( const TUid& aUid ) const
+ {
+ for( TInt i = 0; i < iEntries.Count(); i++)
+ {
+ CWidgetEntry* entry = iEntries[i];
+ if ( TUid::Uid( (*entry)[EUid] ) == aUid )
+ {
+ return *entry;
+ }
+ }
+ User::Leave( KErrNotFound );
+ return *iEntries[0]; // just for compiler
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetEntry()
+// Get the widget entry
+//
+// @since 3.1
+// ============================================================================
+//
+// TODO use leaving version GetWidgetEntryL everywhere and delete this version
+TInt CWidgetRegistry::GetWidgetEntry(
+ const TUid& aUid,
+ CWidgetEntry*& aEntry) const
+ {
+ for(TInt i = 0;i < iEntries.Count();i++)
+ {
+ CWidgetEntry* entry = iEntries[i];
+ if ( TUid::Uid( (*entry)[EUid] ) == aUid )
+ {
+ aEntry = entry;
+ return i;
+ }
+ }
+ return -1;
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetEntry()
+// Get the widget entry
+//
+// @since 3.1
+// ============================================================================
+//
+TInt CWidgetRegistry::GetWidgetEntry(
+ const TDesC& aBundleId,
+ CWidgetEntry*& aEntry) const
+ {
+ for(TInt i = 0;i < iEntries.Count();i++)
+ {
+ CWidgetEntry* entry = iEntries[i];
+ const TDesC& widgetBundleId = (*entry)[EBundleIdentifier];
+ if ( widgetBundleId.CompareF( aBundleId ) == 0 )
+ {
+ aEntry = entry;
+ return i;
+ }
+ }
+ return -1;
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetEntry()
+// Returns the WidgetEntry at a particular index
+//
+// @since 3.1
+// ============================================================================
+//
+const CWidgetEntry* CWidgetRegistry::GetWidgetEntry( const TInt& aPos )
+ {
+ return iEntries[aPos];
+ }
+
+
+// ============================================================================
+// CWidgetRegistry::InsertL()
+// Insert the widget entry into the list if BundleID is not already in
+// the list.
+//
+// @since 3.1
+// ============================================================================
+//
+TInt CWidgetRegistry::InsertL( CWidgetEntry* aEntry )
+ {
+ CWidgetEntry* entry = NULL;
+ TDesC bundleID = (*aEntry)[EBundleIdentifier];
+ TInt pos = GetWidgetEntry( bundleID, entry );
+ if ( pos == KErrNotFound )
+ {
+ iUsedUids.AppendL( TUid::Uid( (*aEntry)[EUid] ) );
+ TInt error = iEntries.Append( aEntry );
+ if ( KErrNone != error )
+ {
+ TInt upos = iUsedUids.FindReverse( TUid::Uid( (*aEntry)[EUid] ) );
+ iUsedUids.Remove( upos );
+ User::Leave( error );
+ }
+ }
+ return pos;
+ }
+
+// ============================================================================
+// CWidgetRegistry::Remove()
+// Remove the widget entry from the list
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::Remove( const TDesC& aBundleId )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aBundleId, entry );
+
+ if ( pos != -1 )
+ {
+ TInt upos = iUsedUids.Find( TUid::Uid( (*entry)[EUid] ) );
+ if ( upos >= 0 )
+ {
+ iUsedUids.Remove( upos );
+ }
+
+ iEntries.Remove( pos );
+
+ delete entry;
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::Remove()
+// Remove the widget entry from the list
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::Remove( const TUid& aUid )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+
+ if ( pos != -1 )
+ {
+ TInt upos = iUsedUids.Find( TUid::Uid( (*entry)[EUid] ) );
+ if ( upos >= 0 )
+ {
+ iUsedUids.Remove( upos );
+ }
+
+ iEntries.Remove( pos );
+ delete entry;
+ }
+
+ }
+
+
+// ============================================================================
+// CWidgetRegistry::InternalizeL()
+// Read entry info from data file into memory
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::InternalizeL( TBool& aDirtyFlag )
+ {
+ LOG_OPEN;
+ LOG( "Internalize" );
+
+ // prepare for consistency enforcement
+ RArray<TUid> appArchList( KDefaultWidgetCount );
+ RArray<TInt> appArchListFlags( KDefaultWidgetCount );
+ // default is internalization just imports files without
+ // modification, if dirty flag gets set to true, do externalize
+ // after internalize to bring files into sync with modified
+ // registry contents
+ aDirtyFlag = EFalse;
+
+ // internal dirty flag, will be copied to arg dirty flag at
+ // end if no leave occurs
+ TBool dirtyFlag = EFalse;
+
+ // empty the registry
+ iEntries.ResetAndDestroy();
+ iUsedUids.Reset();
+
+ CleanupClosePushL( appArchList );
+ CleanupClosePushL( appArchListFlags );
+ TBool doConsistency = AppArchWidgets( appArchList, appArchListFlags );
+ if ( doConsistency )
+ {
+
+ // UIDs are the key differentiator of apps in app arch. The
+ // widget implementation used BundleID to differentiate
+ // widgets on installation (overwrite is keyed by BundleID).
+ // But once widgets are installed, they are assigned a unique
+ // UID. For UID allocation purposes, it is important that
+ // UIDs already known to app arch be reserved.
+ for ( TInt i = 0; i < appArchList.Count(); i++ )
+ {
+ if ( KErrNone != iUsedUids.Append( (appArchList)[i] ) )
+ {
+ // no recovery possible
+ doConsistency = EFalse;
+ break;
+ }
+ }
+ }
+ LOG2( " iUsedUids %d and doConsistency %d",
+ (TInt)(iUsedUids.Count()), (TInt)doConsistency );
+
+ TRAPD( error, GetLprojNameL( iLprojName ) );
+ if ( KErrNone != error )
+ {
+ // on error use english
+ iLprojName = _L("en");
+ }
+
+ // List all drives in the system
+ TDriveList driveList;
+ User::LeaveIfError( iFs.DriveList(driveList) );
+
+ // Check all drives but Z and D. Scan from Y to A because that is
+ // the order that the loader and AppArch follow when "shadowing"
+ // UID identical apps. Drive Z is ignored because it is used for
+ // the phone ROM image and is not an installation location for
+ // widgets. Drive D is ignored because it is a temporary RAM disk
+ // and not a widget install location.
+ for ( TInt driveNumber = EDriveY; driveNumber >= EDriveA; driveNumber-- )
+ {
+ // The drives that will be filtered out are the same ones that
+ // WidgetInstaller filters out in CWidgetUIHandler::SelectDriveL()
+ if ( (EDriveD == driveNumber)
+ || !driveList[driveNumber] )
+ {
+ // EDriveD is a temporary drive usually a RAM disk
+ continue;
+ }
+
+ TVolumeInfo volInfo;
+ if ( iFs.Volume( volInfo, driveNumber ) != KErrNone )
+ {
+ // volume is not usable (e.g. no media card inserted)
+ continue;
+ }
+ if ( (volInfo.iDrive.iType == EMediaNotPresent) ||
+ (volInfo.iDrive.iType == EMediaRom) ||
+ (volInfo.iDrive.iType == EMediaRemote) ||
+ (volInfo.iDrive.iDriveAtt & KDriveAttRom) ||
+ (volInfo.iDrive.iDriveAtt & KDriveAttSubsted) )
+ {
+ // not a suitable widget install drive
+ continue;
+ }
+
+ // found a usable drive
+ TDriveUnit driveUnit( driveNumber );
+ LOG1( " Drive %c", (TUint)(driveUnit.Name()[0]) );
+
+ // prepare for consistency enforcement
+ CDir* installedListForDrive = NULL;
+ RArray<TInt> installedListForDriveFlags;
+ if ( doConsistency )
+ {
+ doConsistency = InstallDirWidgets( driveUnit,
+ installedListForDrive,
+ installedListForDriveFlags );
+ }
+ LOG1( " after InstallDirWidgets doConsistency %d",
+ (TInt)doConsistency );
+
+ // direct install path to this drive
+ iWidgetInstallPath[0] = driveUnit.Name()[0];
+
+ // which persistent data files exist?
+ iRegistryBinaryFileName[0] = driveUnit.Name()[0];
+ TBool binaryExists = BaflUtils::FileExists( iFs,
+ iRegistryBinaryFileName );
+
+ iRegistryXmlFileName[0] = driveUnit.Name()[0];
+ TBool xmlExists = BaflUtils::FileExists( iFs,
+ iRegistryXmlFileName );
+
+ // Here internalizing a single drive. If internalizing
+ // leaves, then the registry will be out-of-sync with the
+ // installed widgets and apparc. But that's okay since it
+ // should be detected and corrected once the resource limit
+ // that caused the leave is removed.
+ if ( xmlExists )
+ {
+ TRAP_IGNORE( InternalizeXmlL( iRegistryXmlFileName,
+ driveUnit,
+ doConsistency,
+ appArchList,
+ appArchListFlags,
+ installedListForDrive,
+ installedListForDriveFlags,
+ dirtyFlag ) );
+ }
+ else if ( binaryExists )
+ {
+ TRAP_IGNORE( InternalizeBinaryL( iRegistryBinaryFileName,
+ driveUnit,
+ doConsistency,
+ appArchList,
+ appArchListFlags,
+ installedListForDrive,
+ installedListForDriveFlags,
+ dirtyFlag ) );
+ }
+
+ if ( doConsistency )
+ {
+ InstallDirConsistency( installedListForDrive,
+ installedListForDriveFlags,
+ dirtyFlag );
+ }
+ delete installedListForDrive;
+ installedListForDriveFlags.Close();
+ } // for
+ if ( doConsistency )
+ {
+ AppArchListConsistency( appArchList, appArchListFlags );
+ }
+ CleanupStack::PopAndDestroy( 2, &appArchList );//appArchListFlags, appArchList
+
+ aDirtyFlag = dirtyFlag;
+ LOG1( "Internalize done, dirty flag %d", (TInt)dirtyFlag );
+ LOG_CLOSE;
+ }
+
+// ============================================================================
+// CWidgetRegistry::InternalizeBinaryL()
+// Read entry info from data file into memory
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::InternalizeBinaryL( const TDesC& aFileName,
+ const TDriveUnit& aDriveUnit,
+ TBool aDoConsistency,
+ RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags,
+ const CDir* aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags,
+ TBool& aDirtyFlag )
+ {
+ LOG( "InternalizeBinaryL" );
+ RFile file;
+ User::LeaveIfError( file.Open( iFs, aFileName, EFileRead ) );
+ CleanupClosePushL( file );
+
+ RFileReadStream readStream;
+ CleanupClosePushL( readStream );
+ readStream.Attach( file );
+
+ TInt error = KErrNone;
+ TInt entryCount = 0;
+ TRAP( error, entryCount = readStream.ReadInt32L() );
+ // TODO should limit entryCount to something like 1024
+ // for each entry in the registry file
+ for ( TInt i = 0 ; i < entryCount; i++ )
+ {
+ CWidgetEntry* entry = CWidgetEntry::NewL();
+ CleanupStack::PushL( entry );
+
+ // extract one entry
+ TRAP( error,
+ entry->InternalizeBinaryL( readStream ) );
+ if ( KErrNone == error )
+ {
+ CWidgetEntry* res( NULL );
+ if ( aDoConsistency )
+ {
+ res = EntryConsistency( entry,
+ aAppArchList,
+ aAppArchListFlags,
+ aInstalledListForDrive,
+ aInstalledListForDriveFlags,
+ aDriveUnit,
+ aDirtyFlag );
+ }
+ if ( NULL != res )
+ {
+ TRAP( error, InsertL( entry ) );
+ if ( KErrNone != error )
+ {
+ CleanupStack::PopAndDestroy( entry );
+ }
+ else
+ {
+ __ASSERT_DEBUG( res == entry, User::Invariant() );
+ // Entry was inserted successfully.
+ CleanupStack::Pop( entry );
+ // add uid to AppArchList if not there,
+ // this can happend due to UID
+ // reallocation for UID collision resolution
+ TInt uidInt = (*entry)[EUid];
+ if ( aDoConsistency &&
+ ( KErrNotFound
+ == aAppArchList.Find(TUid::Uid(uidInt)) ) )
+ {
+ User::LeaveIfError( aAppArchList.Append( TUid::Uid(uidInt) ) );
+ User::LeaveIfError( aAppArchListFlags.Append( EAppListFlagEntry ) );
+ }
+ LOG2( " entry 0x%x (%d) added to registry",
+ uidInt, uidInt );
+ }
+ }
+ }
+ else
+ {
+ // entry error
+ CleanupStack::PopAndDestroy( entry );
+ }
+ } // for
+
+ CleanupStack::PopAndDestroy( 2, &file ); // readStream, file
+ }
+
+// ============================================================================
+// CWidgetRegistry::InternalizeXmlL()
+// Read entry info from data file into memory
+//
+// @since 5.0
+// ============================================================================
+//
+void CWidgetRegistry::InternalizeXmlL( const TDesC& aFileName,
+ const TDriveUnit& aDriveUnit,
+ TBool aDoConsistency,
+ RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags,
+ const CDir* aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags,
+ TBool& aDirtyFlag )
+ {
+ LOG( "InternalizeXmlL" );
+ RFile file;
+ User::LeaveIfError( file.Open( iFs, aFileName, EFileRead ) );
+ CleanupClosePushL( file );
+
+ TInt size;
+ User::LeaveIfError( file.Size( size ) );
+ HBufC8* buf = HBufC8::NewLC( size );
+ TPtr8 bufPtr( buf->Des() );
+ User::LeaveIfError( file.Read( bufPtr ) );
+
+ // initialize the parser and check compiled code matches lib version
+ LIBXML_TEST_VERSION
+
+ xmlDocPtr doc; // resulting document tree
+
+ doc = xmlReadMemory( (const char *)bufPtr.Ptr(), bufPtr.Length(),
+ NULL, // no base URL
+ NULL, // get encoding from doc
+ 0); // options
+
+ if ( !doc )
+ {
+ LOG( " leaving: parse failed XML corrupt" );
+ User::Leave( KErrCorrupt );
+ }
+
+ //TCleanupItem item( XmlDocFree, doc );
+ //CleanupStack::PushL( item );
+ xmlNode* rootElement = xmlDocGetRootElement( doc );
+ TPtrC8 rootTag( rootElement->name );
+ if ( 0 != rootTag.Compare( KWidgetRegistry() ) )
+ {
+ LOG( " leaving: XML root element mismatch" );
+ User::Leave( KErrCorrupt );
+ }
+
+ for ( xmlNode* n = rootElement->children;
+ n;
+ n = n->next )
+ {
+ if ( n->type == XML_ELEMENT_NODE )
+ {
+ TPtrC8 element( n->name );
+
+ if ( 0 == element.Compare( KEntry() ) )
+ {
+ if ( NULL == n->children )
+ {
+ // malformed? should we require entry to have
+ // some minimal info?
+ continue;
+ }
+ CWidgetEntry* entry = CWidgetEntry::NewL();
+ CleanupStack::PushL( entry );
+
+ // extract one entry
+ TRAPD( error,
+ entry->InternalizeXmlL( iFs, doc, n->children,
+ iXmlProcessor ) );
+ LOG2( " entry 0x%x read from XML with error %d",
+ (error == KErrNone)? (*entry)[EUid] : 0,
+ error );
+ if ( KErrNone == error )
+ {
+ if ( aDoConsistency )
+ {
+ entry = EntryConsistency( entry,
+ aAppArchList,
+ aAppArchListFlags,
+ aInstalledListForDrive,
+ aInstalledListForDriveFlags,
+ aDriveUnit,
+ aDirtyFlag );
+ }
+ if ( NULL != entry )
+ {
+ TRAP( error, InsertL( entry ) );
+ if ( KErrNone != error )
+ {
+ delete entry;
+ }
+ else
+ {
+ entry->SetBlanketPermission((*entry)[EBlanketPermGranted] );
+ // add uid to AppArchList if not there,
+ // this can happend due to UID
+ // reallocation for UID collision resolution
+ TInt uidInt = (*entry)[EUid];
+ if ( aDoConsistency &&
+ ( KErrNotFound
+ == aAppArchList.Find(TUid::Uid(uidInt)) ) )
+ {
+ aAppArchList.Append( TUid::Uid(uidInt) );
+ aAppArchListFlags.Append( EAppListFlagEntry );
+ }
+ LOG2( " entry 0x%x (%d) added to registry",
+ uidInt, uidInt );
+ }
+ }
+ }
+ else
+ {
+ // entry error
+ delete entry;
+ LOG( " entry internalize failed" );
+ }
+
+ CleanupStack::Pop(); //entry
+ } // if <entry>
+ } // if n is element
+ } // for
+
+ xmlFreeDoc( doc );
+ xmlCleanupParser();
+
+ CleanupStack::PopAndDestroy( 2, &file ); // buf, file
+ }
+
+// ============================================================================
+// CWidgetRegistry::ExternalizeL()
+// Write entry info in memory into data file
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::ExternalizeL()
+ {
+ // in order to have a list of all entries for a particular drive,
+ // create a hash map from the entries with the key as drive name
+ // and value as an array of entry indices for that drive
+ RPtrHashMap< TInt, CArrayFixFlat<TInt> > driveEntryHashMap;
+ CleanupClosePushL( driveEntryHashMap );
+
+ for (TInt i = 0 ;i < iEntries.Count(); i++)
+ {
+ CWidgetEntry* entry = iEntries[i];
+ const TDesC& driveName = (*entry)[EDriveName];
+ TDriveUnit driveUnit( driveName );
+ CArrayFixFlat<TInt>* array =
+ driveEntryHashMap.Find( driveUnit );
+ if( !array )
+ {
+ TInt* driveNo = new (ELeave) TInt( driveUnit );
+ CArrayFixFlat<TInt>* drArray = new (ELeave) CArrayFixFlat<TInt>(1);
+ CleanupStack::PushL( drArray );
+ drArray->AppendL(i);
+ driveEntryHashMap.Insert(driveNo, drArray);
+ }
+ else
+ {
+ array->AppendL(i);
+ }
+ }
+
+ // List all drives in the system
+ TDriveList driveList;
+ User::LeaveIfError( iFs.DriveList(driveList) );
+
+ // Check all drives
+ for ( TInt driveNumber = EDriveA; driveNumber <= EDriveZ; driveNumber++ )
+ {
+ // The drives that will be filtered out are the same ones that
+ // WidgetInstaller filters out in CWidgetUIHandler::SelectDriveL()
+ if ( (EDriveD == driveNumber)
+ || !driveList[driveNumber] )
+ {
+ // EDriveD is a temporary drive, usually a RAM disk
+ continue;
+ }
+
+ TVolumeInfo volInfo;
+ if ( iFs.Volume( volInfo, driveNumber ) != KErrNone )
+ {
+ // The volume is not usable (e.g. no media card inserted)
+ continue;
+ }
+ if ( (volInfo.iDrive.iType == EMediaNotPresent) ||
+ (volInfo.iDrive.iType == EMediaRom) ||
+ (volInfo.iDrive.iType == EMediaRemote) ||
+ (volInfo.iDrive.iDriveAtt & KDriveAttRom) ||
+ (volInfo.iDrive.iDriveAtt & KDriveAttSubsted) )
+ {
+ continue;
+ }
+
+ // found a usable drive
+ TDriveUnit driveUnit( driveNumber );
+
+ // redirect paths to this drive
+ iRegistryBinaryFileName[0] = driveUnit.Name()[0];
+ iRegistryXmlFileName[0] = iRegistryBinaryFileName[0];
+ iRegistryXmlTempFileName[0] = iRegistryBinaryFileName[0];
+
+ const CArrayFixFlat<TInt>* indices =
+ driveEntryHashMap.Find( driveNumber );
+ if ( NULL == indices )
+ {
+ // not in hash map, delete any existing versions
+ BaflUtils::DeleteFile( iFs, iRegistryBinaryFileName );
+ BaflUtils::DeleteFile( iFs, iRegistryXmlFileName );
+ BaflUtils::DeleteFile( iFs, iRegistryXmlTempFileName );
+ }
+ else
+ {
+ iFs.CreatePrivatePath( driveUnit );
+
+ // a transactional file update to protect against
+ // disk full, etc: overwrite temp then rename temp to original
+
+ TRAPD( error,
+ ExternalizeXmlL( iRegistryXmlTempFileName, indices ) );
+ if ( KErrNone == error )
+ {
+ // last steps in transactional update
+ BaflUtils::DeleteFile( iFs, iRegistryXmlFileName );
+ BaflUtils::RenameFile( iFs,
+ iRegistryXmlTempFileName,
+ iRegistryXmlFileName );
+ }
+ else // handle leave by deleting temp file
+ {
+ BaflUtils::DeleteFile( iFs, iRegistryXmlTempFileName );
+ }
+ }
+ }
+
+ for ( TInt i = 0; i < driveEntryHashMap.Count(); i++ )
+ {
+ CleanupStack::Pop();
+ }
+ CleanupStack::Pop( &driveEntryHashMap );
+ driveEntryHashMap.ResetAndDestroy();
+ driveEntryHashMap.Close();
+ }
+
+// ============================================================================
+// CWidgetRegistry::ExternalizeBinaryL
+// Externalize Binary file
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::ExternalizeBinaryL( const TDesC& aFilename,
+ const CArrayFixFlat<TInt>* aIndices )
+ {
+ RFileWriteStream writeStream;
+ CleanupClosePushL( writeStream );
+
+ RFile file;
+ User::LeaveIfError( file.Replace( iFs, aFilename, EFileWrite ) );
+ CleanupClosePushL( file );
+ writeStream.Attach( file );
+ writeStream.WriteInt32L( aIndices->Count() );
+ for ( TInt i = 0; i < aIndices->Count() ; i++ )
+ {
+ TInt pos = (*aIndices)[i];
+ CWidgetEntry* entry = iEntries[pos];
+ if(entry)
+ {
+ TRAPD( error, entry->ExternalizeBinaryL( writeStream ) );
+ if ( KErrNone != error )
+ {
+ // TODO how to recover from error?
+ continue;
+ }
+ }
+ }
+ writeStream.CommitL();
+ CleanupStack::PopAndDestroy(2);
+ }
+
+// ============================================================================
+// CWidgetRegistry::ExternalizeXmlL
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::ExternalizeXmlL( const TDesC& aFilename,
+ const CArrayFixFlat<TInt>* aIndices )
+ {
+ // sequence: write XML header, write each entry including
+ // unrecognized XML, write closing XML
+
+ RFileWriteStream writeStream;
+ CleanupClosePushL( writeStream );
+
+ RFile file;
+ User::LeaveIfError( file.Replace( iFs, aFilename, EFileWrite ) );
+ CleanupClosePushL( file );
+ writeStream.Attach( file );
+
+ // write XML header
+ TInt bom = 0xfeff; // byte-order mark
+ writeStream.WriteInt16L( bom );
+ writeStream.WriteL( KXmlHeader );
+ writeStream.WriteL( KXmlNewline );
+ writeStream.WriteL( KXmlRootStart );
+ writeStream.WriteL( KXmlNewline );
+
+ for ( TInt i = 0; i < aIndices->Count() ; i++ )
+ {
+ TInt pos = (*aIndices)[i];
+ CWidgetEntry* entry = iEntries[pos];
+ if ( entry )
+ {
+ writeStream.WriteL( KWidgetEntryStart );
+ writeStream.WriteL( KXmlNewline );
+ // TODO handle unrecognized XML from internalize
+ TRAPD( error, entry->ExternalizeXmlL( writeStream,
+ iXmlProcessor,
+ iFs) );
+ writeStream.WriteL( KWidgetEntryEnd );
+ writeStream.WriteL( KXmlNewline );
+ if ( KErrNone != error )
+ {
+ // TODO how to recover from error?
+ continue;
+ }
+ }
+ }
+
+ writeStream.WriteL( KXmlRootEnd );
+ writeStream.WriteL( KXmlNewline );
+ writeStream.CommitL();
+
+ CleanupStack::PopAndDestroy( 2 ); // file, writeStream
+ }
+
+// ============================================================================
+// CWidgetRegistry::RegisterWidget()
+// Creates CWidgetEntry
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::RegisterWidgetL( RReadStream& aStream )
+ {
+ CWidgetEntry* entry = CWidgetEntry::NewL();
+ CleanupStack::PushL( entry );
+
+ entry->InternalizeBinaryL( aStream );
+ InsertL( entry );
+
+ CleanupStack::Pop(); //entry
+ ExternalizeL();
+
+ //Notify WRT Harvester that widget registry has changed
+ NotifyWidgetAltered();
+ }
+
+// ============================================================================
+// CWidgetRegistry::IsWidget()
+// Returns true if the Uid falls within the range specified for widgets
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetRegistry::IsWidget( const TUid& aUid ) const
+ {
+ if ( ( aUid.iUid >= KWidgetUidLowerBound ) &&
+ ( aUid.iUid <= KWidgetUidUpperBound ) )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+
+ }
+
+// ============================================================================
+// CWidgetRegistry::WidgetExists()
+// Returns true if the widget is installed
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetRegistry::WidgetExists( const TDesC& aWidgetId ) const
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( TPtrC( aWidgetId ), entry );
+ return ( pos != -1 )? ETrue : EFalse;
+ }
+
+// ============================================================================
+// CWidgetRegistry::IsWidgetRunning()
+// Returns true if the widget is running
+//
+// @since 3.1
+// ============================================================================
+//
+TBool CWidgetRegistry::IsWidgetRunning( const TUid& aUid ) const
+ {
+ TBool active = EFalse;
+ CWidgetEntry* entry = NULL;
+
+ GetWidgetEntry( aUid, entry );
+ if ( entry && entry->ActiveL() )
+ {
+ active = ETrue;
+ }
+ return active;
+ }
+
+// ============================================================================
+// CWidgetRegistry::WidgetSapiAccessState()
+// Returns sapi widget access state
+//
+// @since 5.0
+// ============================================================================
+//
+TInt CWidgetRegistry::WidgetSapiAccessState( const TUid& aUid ) const
+ {
+ CWidgetEntry* entry = NULL;
+
+ GetWidgetEntry( aUid, entry );
+ if ( entry)
+ {
+ return entry->SapiAccessState();
+ }
+ return -1;
+ }
+
+// ============================================================================
+// CWidgetRegistry::IsWidgetInMiniView()
+// Returns true if the widget is in miniview
+//
+// @since 5.0
+// ============================================================================
+//
+TBool CWidgetRegistry::IsWidgetInMiniView( const TUid& aUid ) const
+ {
+ TBool state = EFalse;
+ CWidgetEntry* entry = NULL;
+
+ GetWidgetEntry( aUid, entry );
+ if ( entry && entry->GetMiniViewState())
+ {
+ state = ETrue;
+ }
+ return state;
+ }
+
+// ============================================================================
+// CWidgetRegistry::IsWidgetInFullView()
+// Returns true if the widget is in miniview
+//
+// @since 5.0
+// ============================================================================
+//
+TBool CWidgetRegistry::IsWidgetInFullView( const TUid& aUid ) const
+ {
+ TBool state = EFalse;
+ CWidgetEntry* entry = NULL;
+
+ GetWidgetEntry( aUid, entry );
+ if ( entry && entry->GetFullViewState())
+ {
+ state = ETrue;
+ }
+ return state;
+ }
+
+TBool CWidgetRegistry::IsBlanketPermGranted( const TUid& aUid ) const
+ {
+ TBool state = EFalse;
+ CWidgetEntry* entry = NULL;
+
+ GetWidgetEntry( aUid, entry );
+ if ( entry && entry->GetBlanketPermGranted())
+ {
+ state = ETrue;
+ }
+ return state;
+ }
+
+// ============================================================================
+// CWidgetRegistry::InstalledWidgets()
+// Returns widget info for all the installed widgets
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::InstalledWidgetsL( RWidgetInfoArray& aWidgetInfoArr )
+ {
+ for ( TInt pos = 0; pos < iEntries.Count(); pos++ )
+ {
+ CWidgetEntry* entry = iEntries[pos];
+ if(entry)
+ {
+ CWidgetInfo *info = new ( ELeave ) CWidgetInfo();
+ info->iUid = TUid::Uid( (*entry)[EUid] );
+ info->iFileSize = (*entry)[EFileSize];
+ *(info->iBundleName) = (*entry)[EBundleName];
+ *(info->iDriveName) = (*entry)[EDriveName];
+ aWidgetInfoArr.AppendL( info );
+ }
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::RunningWidgetsL()
+// Returns widget info for all the running widgets
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::RunningWidgetsL( RWidgetInfoArray& aWidgetInfoArr )
+ {
+ for ( TInt pos = 0; pos < iEntries.Count(); pos++ )
+ {
+ CWidgetEntry* entry = iEntries[pos];
+
+ if ( entry && entry->ActiveL() )
+ {
+ CWidgetInfo* info = new ( ELeave ) CWidgetInfo();
+ info->iUid = TUid::Uid( (*entry)[EUid] );
+ info->iFileSize = (*entry)[EFileSize];
+ *(info->iBundleName) = (*entry)[EBundleName];
+ *(info->iDriveName) = (*entry)[EDriveName];
+ aWidgetInfoArr.AppendL( info );
+ }
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::DeRegisterWidgetL()
+// Deregister the widget
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::DeRegisterWidgetL( const TUid& aUid )
+ {
+ Remove( aUid );
+ ExternalizeL( );
+ //Notify WRT Harvester that widget registry has changed
+ NotifyWidgetAltered();
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetBundleId()
+// Returns bundleId of the widget with a particular UId.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::GetWidgetBundleId( const TUid& aUid, TDes& aBundleId )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+
+ if ( pos != -1 )
+ {
+ const TDesC& widgetBundleId = (*entry)[EBundleIdentifier];
+ aBundleId.Copy( widgetBundleId );
+ aBundleId.SetLength( widgetBundleId.Length() );
+ }
+ else
+ {
+ aBundleId.SetLength( 0 );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetBundleName()
+// Returns bundle display name of the widget with a particular UId.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::GetWidgetBundleName( const TUid& aUid, TDes& aBundleName )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+
+ if ( pos != -1 )
+ {
+ const TDesC& widgetBundleName = (*entry)[EBundleName];
+ aBundleName.Copy( widgetBundleName );
+ aBundleName.SetLength( widgetBundleName.Length() );
+ }
+ else
+ {
+ aBundleName.SetLength( 0 );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetPropertyValueL()
+// return serialized value of property aId for the widget aUid or leave
+//
+// @since 3.1
+// ============================================================================
+//
+CBufFlat* CWidgetRegistry::GetWidgetPropertyValueL(
+ const TUid& aUid,
+ TWidgetPropertyId aId,
+ TInt aMaxLength )
+ {
+ CWidgetEntry& entry = GetWidgetEntryL( aUid );
+ CBufFlat* buf = CBufFlat::NewL( aMaxLength );
+ CleanupStack::PushL( buf );
+ RBufWriteStream stream( *buf ); // stream over the buffer
+ CleanupClosePushL( stream );
+
+ // TBD safe array indexing (leave if out of range)
+ entry[aId].SerializeL( stream ); // serialize
+
+ CleanupStack::PopAndDestroy( &stream );
+ CleanupStack::Pop(); // buf
+ return buf;
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetPath()
+// Returns path of the widget with a particular UId.
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::GetWidgetPath( const TUid& aUid, TDes& aPath )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+
+ if ( pos != -1 )
+ {
+ const TDesC& widgetBasePath = (*entry)[EBasePath];
+ aPath.Copy( widgetBasePath );
+ aPath.SetLength( widgetBasePath.Length() );
+ }
+ else
+ {
+ aPath.SetLength( 0 );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetLprojName()
+// Returns lproj name
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::GetLprojNameL( TDes& aPath )
+ {
+ if ( !iLangDirList.Count() )
+ {
+ CreateLangDirListL();
+ }
+ HBufC8* lprojName = iLangDirList.Find( User::Language() );
+ if ( lprojName )
+ {
+ TPtr8 lprojNamePtr = lprojName->Des();
+ aPath.Copy( lprojNamePtr );
+ }
+ else
+ {
+ aPath.Copy( KWidgetDefaultLangDir );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetUid()
+// Returns UId of the widget with a particular bundle identifier
+//
+// @since 3.1
+// ============================================================================
+//
+TUid CWidgetRegistry::GetWidgetUid( const TDesC& aBundleId ) const
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aBundleId, entry );
+
+ if ( pos != -1 )
+ {
+ return TUid::Uid( (*entry)[EUid] );
+ }
+ else
+ {
+ return KNullUid;
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetWidgetUidForUrl()
+// Returns uid of the widget with a patricular html path
+//
+// @since 3.1
+// ============================================================================
+//
+TUid CWidgetRegistry::GetWidgetUidForUrl( const TDesC& aUrl ) const
+ {
+ for( TInt i = 0; i < iEntries.Count(); i++)
+ {
+ CWidgetEntry* entry = iEntries[i];
+
+ if ( aUrl.CompareF( (*entry)[EMainHTML] ) == 0 )
+ {
+ return TUid::Uid( (*entry)[EUid] );
+ }
+ }
+ return KNullUid;
+ }
+
+// ============================================================================
+// CWidgetRegistry::UsedUids()
+// Returns array of used UIds
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::UsedUidsL( RUidArray& aUsedUids )
+ {
+ for( TInt i = 0; i < iUsedUids.Count(); i++ )
+ {
+ aUsedUids.AppendL( iUsedUids[i] );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::GetAvailableUidL()
+// Get next availble uid from the pool using a random generation
+//
+// @since 3.1
+// ============================================================================
+//
+TUid CWidgetRegistry::GetAvailableUidL( TInt aDriveLetter )
+ {
+ TUidAllocator uidAllocator;
+ return TUid::Uid( uidAllocator.AllocateL( iUsedUids, aDriveLetter ) );
+ }
+
+// ============================================================================
+// CWidgetRegistry::SetActive()
+// Set/Reset active status of the widget with a particular UId
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::SetActive( TUid aUid, TInt aStatus )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+ if ( pos != -1 )
+ {
+ entry->SetActive( aStatus );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::SetMiniView()
+// Set/Reset Widget status for launched in MiniView
+//
+// @since 5.0
+// ============================================================================
+//
+void CWidgetRegistry::SetMiniView( TUid aUid, TInt aStatus )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+ if ( pos != -1 )
+ {
+ entry->SetMiniView( aStatus );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::SetFullView()
+// Set/Reset Widget status in FullView
+//
+// @since 5.0
+// ============================================================================
+//
+void CWidgetRegistry::SetFullView( TUid aUid, TInt aStatus )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+ if ( pos != -1 )
+ {
+ entry->SetFullView( aStatus );
+ }
+ }
+
+// ============================================================================
+// CWidgetRegistry::SetBlanketPermissionL()
+// Set/Reset Widget Blanket Permission
+//
+// @since 5.0
+// ============================================================================
+//
+void CWidgetRegistry::SetBlanketPermissionL( TUid aUid, TInt aStatus )
+ {
+ CWidgetEntry* entry = NULL;
+ TInt pos = GetWidgetEntry( aUid, entry );
+ if ( pos != -1 )
+ {
+ entry->SetBlanketPermission( aStatus );
+ }
+ ExternalizeL();
+ }
+
+// ============================================================================
+// CWidgetRegistry::CreateLangDirListL()
+// create the mapping table for language and lproj dir
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetRegistry::CreateLangDirListL()
+ {
+ TLanguage defaultLanguage = User::Language();
+ RFile file;
+ TFileName langDirFile;
+ iFs.PrivatePath( langDirFile );
+#ifdef __WINSCW__
+ langDirFile.Insert( 0, _L( "C:" ));
+#else
+ langDirFile.Insert( 0, _L( "Z:" ));
+#endif
+ langDirFile.Append( KWidgetDirFile );
+ User::LeaveIfError( file.Open( iFs, langDirFile, EFileRead ) );
+ CleanupClosePushL( file );
+
+ TInt size;
+ User::LeaveIfError( file.Size( size ) );
+ HBufC8* buf = HBufC8::NewLC( size );
+ TPtr8 bufPtr( buf->Des() );
+ User::LeaveIfError( file.Read( bufPtr ) );
+ CleanupStack::Pop( buf );
+ CleanupStack::PopAndDestroy( &file );
+ CleanupStack::PushL( buf );
+
+ // initialize the parser and check compiled code matches lib version
+ LIBXML_TEST_VERSION
+
+ xmlDocPtr doc; // resulting document tree
+
+ doc = xmlReadMemory( (const char *)bufPtr.Ptr(), bufPtr.Length(),
+ NULL, // no base URL
+ NULL, // get encoding from doc
+ 0); // options
+
+ if ( !doc )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ xmlNode* rootElement = xmlDocGetRootElement( doc );
+
+ TInt* langID = NULL;
+ xmlNode* n;
+
+ for ( n = rootElement; n; n = TraverseNextNode( n ) )
+ {
+ HBufC8* langDir;
+ if ( n->type == XML_ELEMENT_NODE )
+ {
+ TPtrC8 element( n->name );
+
+ if ( element.Compare( KLangID() ) == 0 )
+ {
+ if ( n->children && n->children->type == XML_TEXT_NODE )
+ {
+ TPtrC8 content( n->children->content );
+ langID = new TInt( atoi( (const char *)content.Ptr() ) );
+ CleanupStack::PushL( langID );
+ }
+ }
+ if ( element.Compare( KLangDir() ) == 0 )
+ {
+ if ( n->children && n->children->type == XML_TEXT_NODE )
+ {
+ TPtrC8 content( n->children->content );
+ langDir = HBufC8::NewLC( content.Length() );
+ langDir->Des().Copy( content );
+ if ( *langID <= 0 )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ TInt* currentLangID = new TInt(*langID);
+ CleanupStack::Pop(langDir);
+ iLangDirList.Insert( currentLangID, langDir );
+ *langID = 0;
+ CleanupStack::PopAndDestroy(langID);
+ langID = NULL;
+ }
+ }
+ } // if n is element
+
+ } // for
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ xmlCleanupGlobalData();
+ CleanupStack::PopAndDestroy( buf );
+ }
+
+TBool CWidgetRegistry::InstallDirWidgets(
+ const TDriveUnit& aDriveUnit,
+ CDir*& aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags )
+ {
+ LOG( "InstallDirWidgets" );
+ TBool doConsistency = ETrue;
+ aInstalledListForDrive = NULL;
+ aInstalledListForDriveFlags.Reset();
+ iWidgetInstallPath[0] = aDriveUnit.Name()[0];
+ TInt error = iFs.GetDir( iWidgetInstallPath,
+ KEntryAttDir | KEntryAttMatchExclusive,
+ ESortNone,
+ aInstalledListForDrive );
+ if ( KErrPathNotFound == error )
+ {
+ LOG( "install path not found" );
+ delete aInstalledListForDrive;
+ aInstalledListForDrive = NULL;
+ return doConsistency;
+ }
+ if ( KErrNone != error || NULL == aInstalledListForDrive )
+ {
+ delete aInstalledListForDrive;
+ aInstalledListForDrive = NULL;
+ doConsistency = EFalse;
+ LOG( "error listing install directory, doConsistency 0" );
+ }
+ else
+ {
+ TInt count =
+ ( (NULL == aInstalledListForDrive) ?
+ 0 : aInstalledListForDrive->Count() );
+ if ( count )
+ {
+ for ( TInt i = 0; i < aInstalledListForDrive->Count(); i++ )
+ {
+ error = aInstalledListForDriveFlags.Append( 0 );
+ if ( KErrNone != error )
+ {
+ break;
+ }
+ }
+ if ( KErrNone != error )
+ {
+ doConsistency = EFalse;
+ aInstalledListForDriveFlags.Reset();
+
+ delete aInstalledListForDrive;
+ aInstalledListForDrive = NULL;
+ }
+ }
+ }
+ LOG_CODE( if ( aInstalledListForDrive ) )
+ LOG2( "InstallDirWidgets done count %d doConsistency %d",
+ aInstalledListForDrive->Count(),
+ (TInt)doConsistency );
+ LOG_CODE( else )
+ LOG1( "InstallDirWidgets return NULL list doConsistency %d",
+ (TInt)doConsistency );
+ return doConsistency;
+ }
+
+// a routine to build an array of widgets according to app arch app list
+// returns NULL on error, otherwise a UID list (possibly with no entries)
+TInt CWidgetRegistry::AppArchWidgetUids( RArray< TUid >& aUids )
+ {
+ LOG( "AppArchWidgetUids" );
+ TInt error = iAppArch.GetAllApps();
+ aUids.Reset();
+ if ( KErrNone != error )
+ {
+ LOG ( "AppArchWidgetUids done error NULL list" );
+
+ return error;
+ }
+ TInt appArchWaitTotal = 0;
+ TApaAppInfo info;
+ do
+ {
+ error = iAppArch.GetNextApp( info );
+ if ( KErrNone == error )
+ {
+ if ( TUidAllocator::IsWidget( info.iUid ) )
+ {
+ LOG2( " widget uid 0x%x (%d)",
+ (TUint)(info.iUid.iUid), info.iUid.iUid );
+ error = aUids.Append( info.iUid );
+ if ( KErrNone != error )
+ {
+ break;
+ }
+ }
+ continue;
+ }
+ else if ( RApaLsSession::EAppListInvalid == error )
+ {
+ if ( appArchWaitTotal > KAppArchTimeout )
+ {
+ LOG( " appArchWaitTotal > KAppArchTimeout" );
+ break;
+ }
+ appArchWaitTotal += KAppArchDelayInterval;
+ LOG1( " appArchWaitTotal %d", appArchWaitTotal );
+ User::After( KAppArchDelayInterval );
+ continue;
+ }
+ } while ( RApaLsSession::ENoMoreAppsInList != error );
+ if ( RApaLsSession::ENoMoreAppsInList != error )
+ {
+ aUids.Reset();
+ }
+ LOG_CODE( if ( aUids.Count() ) )
+ LOG1( "AppArchWidgetUids done widget count %d",
+ aUids.Count() );
+ LOG_CODE( else )
+ LOG( "AppArchWidgetUids done error NULL list" );
+
+ return error;
+ }
+
+// if primary return bool is T then arg lists will be non NUll, else
+// return bool will be F and arg lists will be NULL (error condition)
+TBool CWidgetRegistry::AppArchWidgets( RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags )
+ {
+ TBool doConsistency = ETrue;
+ TInt error = AppArchWidgetUids( aAppArchList );
+ aAppArchListFlags.Reset();
+ // NULL means AppArchWidgetUids encountered an error
+ if ( error )
+ {
+ // doConsistency flase means there is an unrecoverable error
+ // in consistency logic
+ doConsistency = EFalse;
+ }
+ else
+ {
+ TInt error = KErrNone;
+ for ( TInt i = 0 ; i < aAppArchList.Count(); i++ )
+ {
+ error = aAppArchListFlags.Append( 0 );
+ if ( KErrNone != error )
+ {
+ break;
+ }
+ }
+
+ if ( KErrNone != error )
+ {
+ doConsistency = EFalse;
+ aAppArchListFlags.Reset();
+ aAppArchList.Reset();
+ }
+ }
+ LOG_CODE( if ( aAppArchList.Count() ) )
+ LOG2( "AppArchWidgets done widgets count %d doConsistency %d",
+ aAppArchListFlags.Count(), (TInt)doConsistency );
+ LOG_CODE( else )
+ LOG1( "AppArchWidgets done error doConsistency %d",
+ (TInt)doConsistency );
+ return doConsistency;
+ }
+
+// when called: aAppArchList and Flags must not be
+// NULL. aInstalledListForDrive and Flags may be NULL
+CWidgetEntry* CWidgetRegistry::EntryConsistency(
+ CWidgetEntry* aEntry,
+ const RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags,
+ const CDir* aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags,
+ const TDriveUnit& aDriveUnit,
+ TBool& aDirtyFlag )
+ {
+ LOG( "EntryConsistency" );
+ TInt error;
+ TBool inAppList;
+ TUid uid;
+
+ if ( IsEntryInstalled( aEntry, aInstalledListForDrive,
+ aInstalledListForDriveFlags ) )
+ {
+ error = IsEntryInAppList( aEntry,
+ aAppArchList,
+ aAppArchListFlags,
+ inAppList,
+ uid );
+ if ( ( inAppList == EFalse ) || ( KErrNone != error ) )
+ {
+ if ( KErrNone == error )
+ {
+ LOG( " entry not in AppArch" );
+ // not in AppArch but may be using a UID already in
+ // use (UID conflict)
+ error =
+ InternalizeEntryNewUidIfNeeded( aEntry, aDriveUnit );
+ if ( KErrNone == error )
+ {
+ iInstaller->RenameIconFile( iFs, aEntry->Properties() );
+ TInt uidInt = (*aEntry)[EUid];
+ TRAP( error,
+ iInstaller->RegisterWidgetL(
+ (*aEntry)[EMainHTML],
+ (*aEntry)[EBundleDisplayName],
+ (*aEntry)[EIconPath],
+ (*aEntry)[EDriveName],
+ TUid::Uid( uidInt ) ) );
+ if ( KErrNone == error )
+ {
+ LOG2( " registered widget 0x%x (%d)",
+ uidInt, uidInt );
+ LOG( " registry dirty flag set" );
+ aDirtyFlag = ETrue;
+ }
+ }
+ }
+ // catches errors from several prior lines
+ if ( KErrNone != error )
+ {
+ // allocated uid hasn't been added to iUsedUid yet so
+ // just delete entry
+
+ // on error don't put entry in registry
+ LOG( " error entry deleted" );
+ delete aEntry;
+ aEntry = NULL;
+ }
+ }
+ }
+ else
+ {
+ LOG( " entry is not installed" );
+ // entry is not installed, clean up app list if needed
+ error = IsEntryInAppList( aEntry,
+ aAppArchList,
+ aAppArchListFlags,
+ inAppList,
+ uid );
+ if ( ( (TInt)ETrue == inAppList ) && ( KErrNone == error ) )
+ {
+ LOG( " removing from AppArch" );
+ // there is nothing useful to do on error
+ TRAP_IGNORE( iInstaller->DeregisterWidgetL( uid ) );
+ }
+
+ // don't put entry in registry
+ LOG( " entry deleted" );
+ delete aEntry;
+ aEntry = NULL;
+ aDirtyFlag = ETrue;
+ }
+ LOG( "EntryConsistency done " );
+ return aEntry;
+ }
+
+// aInstalledListForDrive and Flags may be NULL (meaning no installed widgets)
+TBool CWidgetRegistry::IsEntryInstalled(
+ CWidgetEntry* aEntry,
+ const CDir* aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags )
+ {
+ TBool result = EFalse;
+ // NULL is an expected input due to GetDir producing it for empty lists
+ if ( NULL != aInstalledListForDrive )
+ {
+ const TDesC& bundleIdentifier = (*aEntry)[EBundleIdentifier];
+ for ( TInt i = 0; i < aInstalledListForDrive->Count(); i++ )
+ {
+ if ( !((aInstalledListForDriveFlags)[i] & EInstallListFlagEntry ))
+ {
+ TEntry dirEntry = (*aInstalledListForDrive)[i];
+ if ( 0 == bundleIdentifier.Compare( dirEntry.iName ) )
+ {
+ (aInstalledListForDriveFlags)[i] |= EInstallListFlagEntry;
+ result = ETrue;
+ break;
+ }
+ }
+ }
+ }
+ LOG1( "IsEntryInstalled result %d", (TInt)result );
+ return result;
+ }
+
+// aAppArchList and Flags must not be NULL but may be empty (0 count)
+TInt CWidgetRegistry::IsEntryInAppList( CWidgetEntry* aEntry,
+ const RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags,
+ TBool& aInAppList,
+ TUid& uid )
+ {
+ // entry has uid and EMainHTML, appInfo has uid and iFullName,
+ // both should match exactly
+ TInt error = KErrNone;
+ aInAppList = EFalse;
+ for ( TInt i = 0; i < aAppArchList.Count(); i++ )
+ {
+ if ( !( (aAppArchListFlags)[i] & EAppListFlagEntry ) )
+ {
+ uid = aAppArchList[i];
+ TInt uidInt = (*aEntry)[EUid];
+ TUid uid2 = TUid::Uid( uidInt );
+ if ( uid == uid2 )
+ {
+ TApaAppInfo appInfo;
+ error = iAppArch.GetAppInfo( appInfo, uid );
+ if ( KErrNone == error )
+ {
+ const TDesC& mainHtml = (*aEntry)[EMainHTML];
+ if ( 0 == mainHtml.Compare( appInfo.iFullName ) )
+ {
+ aAppArchListFlags[i] |= EAppListFlagEntry;
+ aInAppList = ETrue;
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ LOG2( "IsEntryInAppList done %d error %d",
+ (TInt)aInAppList, error );
+ return error;
+ }
+
+// This will assign a new UID if the UID in the entry appears either
+// in iUsedUids or a call to GetAppInfo returns some info (something
+// is using the UID). The new UID will *not* be placed in iUsedUids and
+// GetAppInfo using the new UID will return KErrNotFound.
+TInt CWidgetRegistry::InternalizeEntryNewUidIfNeeded(
+ CWidgetEntry* aEntry,
+ const TDriveUnit& aDriveUnit )
+ {
+ LOG( "InternalizeEntryNewUidIfNeeded" );
+ // entry has a uid but it may already be in use by another widget
+ // according to app arch or iUsedUids
+ TUidAllocator uidAllocator;
+ TInt upos = iUsedUids.Find( TUid::Uid( (*aEntry)[EUid] ) );
+ TApaAppInfo appInfo;
+ TInt error = iAppArch.GetAppInfo( appInfo, TUid::Uid( (*aEntry)[EUid] ) );
+ if ( KErrNotFound != upos || KErrNotFound != error )
+ {
+ LOG( " widget needs a new UID" );
+ LOG_CLOSE;
+ LOG_OPEN;
+ do
+ {
+ TInt uidInt = 0;
+ TRAP( error,
+ uidInt = uidAllocator.AllocateL( iUsedUids,
+ aDriveUnit.Name()[0] ) );
+ if ( KErrNone != error )
+ {
+ LOG(
+ "InternalizeEntryNewUidIfNeeded done error failed to allocate a new UID" );
+ return KErrNotFound;
+ }
+ TUid uid = TUid::Uid( uidInt );
+ error = iAppArch.GetAppInfo( appInfo, uid );
+ if ( KErrNotFound == error )
+ {
+ // use new uid (do icon mbm file rename elsewhere) and
+ // don't add it to iUsedUids yet as that will be done
+ // when entry is finally inserted in registry
+ (*aEntry)[EUid] = uidInt;
+ LOG2(
+ "InternalizeEntryNewUidIfNeeded done new uid is 0x%x (%d)", uidInt, uidInt );
+ return KErrNone;
+ }
+ else if ( KErrNone == error )
+ {
+ // don't allocate this uid because AppArch thinks it
+ // is in use
+ error = iUsedUids.Append( uid );
+ }
+ } while ( KErrNone == error );
+ LOG(
+ "InternalizeEntryNewUidIfNeeded done error failed to allocate a new UID" );
+ return KErrNotFound;
+ }
+ LOG( "InternalizeEntryNewUidIfNeeded done widget already has a unique ID" ); LOG_CLOSE;
+ LOG_OPEN;
+ return KErrNone;
+ }
+
+
+// this examines the installed widget list after the persistent
+// registry entries have been processed for any installed widgets that
+// don't yet have a registry entry. An entry is generated and the
+// widget is registered with app arch.
+void CWidgetRegistry::InstallDirConsistency(
+ const CDir* aInstalledListForDrive,
+ RArray<TInt>& aInstalledListForDriveFlags,
+ TBool& aDirtyFlag )
+ {
+ LOG( "InstallDirConsistency" );
+ if ( NULL == aInstalledListForDrive
+ || ( ( NULL != aInstalledListForDrive)
+ && ( 0 == aInstalledListForDrive->Count() ) ) )
+ {
+ LOG( " nothing is installed" );
+ return;
+ }
+ TInt error = KErrNone;
+ TUidAllocator uidAllocator;
+ for ( TInt i = 0; i < aInstalledListForDrive->Count(); i++ )
+ {
+ if ( !( aInstalledListForDriveFlags[i] & EInstallListFlagEntry ) )
+ {
+ TFileName widgetPath( iWidgetInstallPath );
+ widgetPath.Append( (*aInstalledListForDrive)[i].iName );
+ widgetPath.Append( _L("\\") );
+ // assume directory under this is widget top-level dir
+ CDir *listing = NULL;
+ error = iFs.GetDir( widgetPath,
+ KEntryAttDir | KEntryAttMatchExclusive,
+ ESortNone,
+ listing );
+ if ( ( KErrNone != error )
+ || ( 1 != listing->Count() ) )
+ {
+ // skip this widget
+ LOG( " rejecting a directory that has unexpected contents" );
+ delete listing;
+ continue;
+ }
+ LOG( " found inconsistency" );
+ widgetPath.Append( ((*listing)[0]).iName );
+ widgetPath.Append( _L("\\") );
+ delete listing;
+
+ TInt uidInt = 0;
+ TRAP( error, uidInt =
+ uidAllocator.AllocateL( iUsedUids,
+ iWidgetInstallPath[0] ) );
+ if ( KErrNone != error )
+ {
+ LOG1( " uid allocate error %d", error );
+ continue; // skip this widget
+ }
+
+ LOG( " getting properties from installed widget" );
+ LOG_CLOSE;
+ LOG_OPEN;
+ RPointerArray<CWidgetPropertyValue>* tmp;
+ TRAP( error,
+ tmp =
+ iInstaller->WidgetPropertiesFromInstalledWidgetL(
+ iFs, widgetPath, iLprojName, TUid::Uid( uidInt ) ) );
+ if ( KErrNone != error || !tmp )
+ {
+ LOG1( " props from installed widget error %d", error );
+ continue; // skip this widget
+ }
+ LOG( " got properties from installed widget" );
+ // transfer ownership of tmp
+ CWidgetEntry* entry = NULL;
+ TRAP( error, entry = CWidgetEntry::NewL( &tmp ) );
+ if ( KErrNone != error )
+ {
+ LOG1( " new entry copy ctor error %d", error );
+ if ( tmp )
+ {
+ tmp->ResetAndDestroy();
+ }
+ continue; // skip this widget
+ }
+ // app arch may have this widget under another uid
+ // but if we assign a new uid and register the
+ // widget then the duplicate app arch entry will
+ // be removed when app arch list is made
+ // consistent by removing entries not in the
+ // registry by uid
+
+ // check that uid is unknown to app arch
+ TDriveUnit driveUnit( widgetPath );
+ error = InternalizeEntryNewUidIfNeeded( entry, driveUnit );
+ if ( KErrNone != error )
+ {
+ LOG1( " new uid if needed error %d", error );
+ delete entry;
+ continue; // skip this widget
+ }
+ LOG_CODE( TInt uidLog = (*entry)[EUid] );
+ LOG1( " uid 0x%x", uidLog );
+ LOG_CODE( const TDesC& logDes = (*entry)[EMainHTML] );
+ LOG1( " mainHTML %S", &logDes );
+ LOG_CODE( const TDesC& logDes2 = (*entry)[EBundleDisplayName] );
+ LOG1( " bundleDiplayname %S", &logDes2 );
+
+ TRAP( error,
+ iInstaller->RegisterWidgetL(
+ (*entry)[EMainHTML],
+ (*entry)[EBundleDisplayName],
+ (*entry)[EIconPath],
+ (*entry)[EDriveName],
+ TUid::Uid( (*entry)[EUid]) ) );
+
+ if ( KErrNone == error )
+ {
+ LOG2( " registered widget 0x%x (%d)",
+ uidLog, uidLog );
+ TRAP( error,
+ InsertL( entry ) );
+ if ( KErrNone != error )
+ {
+ LOG1( " insert entry error %d", error );
+ delete entry;
+ continue; // skip this widget
+ }
+ LOG2( " entry 0x%x (%d) added to registry",
+ uidLog, uidLog );
+ LOG( "registry dirty flag set" );
+ aDirtyFlag = ETrue;
+ }
+ else
+ {
+ // allocated uid hasn't been added to iUsedUid yet so
+ // just delete entry
+ delete entry;
+ LOG( "failed to recover an installed widget" );
+ continue; // skip this widget
+ }
+ }
+ }
+ LOG( "InstallDirConsistency done" );
+ }
+
+void CWidgetRegistry::AppArchListConsistency( const RArray<TUid>& aAppArchList,
+ RArray<TInt>& aAppArchListFlags )
+ {
+ LOG( "AppArchListConsistency" );
+ for ( TInt i = 0; i < aAppArchList.Count(); i++ )
+ {
+ if ( !( aAppArchListFlags[i] & EAppListFlagEntry ) )
+ {
+ LOG_CODE( TInt uidIntLog = aAppArchList[i].iUid );
+ LOG2( " deregistered widget 0x%x (%d)",
+ uidIntLog, uidIntLog );
+ TRAP_IGNORE( iInstaller->DeregisterWidgetL( aAppArchList[i] ) );
+ }
+ }
+ LOG( "AppArchListConsistency done" );
+ }
+
+
+// End of File