imagehandlingutilities/thumbnailmanager/thumbnailserver/src/thumbnailserversession.cpp
changeset 0 2014ca87e772
child 1 235a7fc86938
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagehandlingutilities/thumbnailmanager/thumbnailserver/src/thumbnailserversession.cpp	Tue Jan 26 15:18:05 2010 +0200
@@ -0,0 +1,1327 @@
+/*
+* Copyright (c) 2006-2007 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:  Server side session for Thumbnail Manager Server
+ *
+*/
+
+#include <imageconversion.h> 
+
+#include "thumbnailserversession.h"
+#include "thumbnailserver.h"
+#include "thumbnailtaskprocessor.h"
+#include "thumbnailmanagerconstants.h"
+#include "thumbnailgeneratetask.h"
+#include "thumbnailscaletask.h"
+#include "thumbnaildecodetask.h"
+#ifdef RD_MDS_2_5
+#include "thumbnailmdsquerytask.h"
+#endif // RD_MDS_2_5
+#include "thumbnaillog.h"
+#include "thumbnailpanic.h"
+
+#include "thumbnailcenrep.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CThumbnailServerSession::CThumbnailServerSession()
+// C++ default constructor can NOT contain any code, that might leave.
+// ---------------------------------------------------------------------------
+//
+CThumbnailServerSession::CThumbnailServerSession(): CSession2()
+    {
+    iBitmapHandle = 0;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CThumbnailServerSession::~CThumbnailServerSession()
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CThumbnailServerSession::~CThumbnailServerSession()
+    {
+    Server()->DropSession(this);
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::DispatchMessageL()
+// Message dispatcher.
+// -----------------------------------------------------------------------------
+//
+TInt CThumbnailServerSession::DispatchMessageL( const RMessage2& aMessage )
+    {
+    TInt err( KErrNone );
+
+    switch ( aMessage.Function())
+        {
+        case ERequestThumbByFileHandleAsync:
+                {
+                RequestThumbByFileHandleAsyncL( aMessage );
+                break;
+                }
+        case ERequestThumbByPathAsync:
+                {
+                RequestThumbByPathAsyncL( aMessage );
+                break;
+                }
+        case ERequestSetThumbnailByBuffer:
+                {
+                RequestSetThumbnailByBufferL( aMessage );
+                break;
+                }
+        case ERequestSetThumbnailByBitmap:
+                {
+                RequestSetThumbnailByBitmapL( aMessage );
+                break;
+                }                
+        case EReleaseBitmap:
+                {
+                ReleaseBitmap( aMessage );
+                break;
+                }
+        case ECancelRequest:
+                {
+                err = CancelRequest( aMessage );
+                break;
+                }
+        case EChangePriority:
+                {
+                err = ChangePriority( aMessage );
+                break;
+                }
+        case ECreateThumbnails:
+                {
+                CreateThumbnailsL( aMessage );
+                break;
+                }
+        case EDeleteThumbnails:
+                {
+                DeleteThumbnailsL( aMessage );
+                break;
+                }
+        case EDeleteThumbnailsById:
+                {
+                DeleteThumbnailsByIdL( aMessage );
+                break;
+                }                
+        case EGetMimeTypeBufferSize:
+                {
+                GetMimeTypeBufferSizeL( aMessage );
+                break;
+                }
+        case EGetMimeTypeList:
+                {
+                GetMimeTypeListL( aMessage );
+                break;
+                }
+        case ERequestThumbByIdAsync:
+                {
+                RequestThumbByIdAsyncL( aMessage );
+                break;
+                }
+        case EUpdateThumbnails:
+                {
+                UpdateThumbnailsL( aMessage );
+                break;
+                }                  
+        default:
+                {
+                err = KErrUnknown;
+                break;
+                }
+        }
+
+    return err;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CThumbnailServerSession::CreateL()
+// ---------------------------------------------------------------------------
+//
+void CThumbnailServerSession::CreateL()
+    {
+    Server()->AddSession();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::ServiceL()
+// Handles service request messages from clients.
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::ServiceL( const RMessage2& aMessage )
+    {
+    __ASSERT_DEBUG( !iMessage.Handle(), ThumbnailPanic(
+        EThumbnailMessageNotCompleted ));
+    if ( iMessage.Handle())
+        {
+        iMessage.Complete( KErrUnknown );
+        iMessage = RMessage2();
+        }
+    iMessage = aMessage;
+
+    // clean up possible trash
+    if (iBitmapHandle)
+        {
+        Server()->DeleteBitmapFromPool( iBitmapHandle );
+        iBitmapHandle = 0;
+        }
+    delete iBitmap;
+    iBitmap = NULL;
+    delete iBuffer;
+    iBuffer = NULL;
+    iOriginalSize = TSize();
+    
+    TInt ret = KErrNone;
+
+    TRAPD( err, 
+        {
+        ret = DispatchMessageL( aMessage ); 
+        }
+     );
+    if ( iMessage.Handle())
+        {
+        iMessage.Complete( ConvertSqlErrToE32Err( err != KErrNone ? err : ret ));
+        iMessage = RMessage2();
+        }
+    else
+    	{
+    	return;
+    	}
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::Server()
+// Returns the server pointer.
+// -----------------------------------------------------------------------------
+//
+CThumbnailServer* CThumbnailServerSession::Server()
+    {
+    return ( CThumbnailServer* )( CSession2::Server());
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::Cancel()
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::Cancel()
+    {
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::UpdateThumbnailsL()
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::UpdateThumbnailsL( const RMessage2& aMessage )
+    {
+    TN_DEBUG1( "CThumbnailServerSession::UpdateThumbnailsL()" );
+    
+    if(aMessage.Int1() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::UpdateThumbnailsL() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+    
+    // read message params
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    
+    TBool finished = Server()->UpdateThumbnailsL( params.iThumbnailId, params.iFileName, params.iOrientation, params.iModified );
+    
+    if (finished)
+        {
+        TN_DEBUG1( "CThumbnailServerSession::UpdateThumbnailsL() - finished" );
+        
+        aMessage.Complete( KErrNone );
+        }
+    else
+        {
+        TN_DEBUG1( "CThumbnailServerSession::UpdateThumbnailsL() - need to recreate thumbs" );
+        
+        // need to create new thumbs
+        aMessage.Complete( KThumbnailErrThumbnailNotFound );
+        }
+    
+    iMessage = RMessage2();
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::RequestThumbByIdAsyncL()
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::RequestThumbByIdAsyncL( const RMessage2&
+    aMessage )
+    {
+#ifdef _DEBUG
+    TTime aStart, aStop;
+    aStart.UniversalTime();
+#endif
+    
+    TN_DEBUG1( "CThumbnailServerSession::RequestThumbByIdAsyncL() - begin" );
+    
+    if(aMessage.Int1() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::RequestThumbByIdAsync() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    TRAPD( err, Server()->FetchThumbnailL( params.iThumbnailId, iBitmap, iBuffer,
+                                           params.iThumbnailSize, iOriginalSize ));
+    if ( !err && iBitmap )
+        {
+        TN_DEBUG1( 
+            "CThumbnailServerSession::RequestThumbByIdAsyncL() - found existing thumbnail- bitmap" );
+
+        ProcessBitmapL();
+        }
+    else if ( !err && iBuffer)
+        {
+        TN_DEBUG1( 
+             "CThumbnailServerSession::RequestThumbByIdAsyncL() - found existing thumbnail- jpeg" );
+        
+        CThumbnailDecodeTask* task = new( ELeave )CThumbnailDecodeTask( Server()
+                 ->Processor(), * Server(), iBuffer, params.iPriority, params.iDisplayMode );
+        
+        CleanupStack::PushL( task );
+        task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ), iMessage );
+        Server()->QueueTaskL( task );
+        CleanupStack::Pop( task ); // owned by processor now
+        
+        // Decode task is now responsible for completing the message
+        iMessage = RMessage2();
+        
+        //CThumbnailDecodeTask is responsible freeing
+        iBuffer = NULL;
+        }
+    else if( err == KErrCompletion )                
+        {
+        // If thumbnail of requested size is blacklisted, fetching is left with KErrCompletion
+        TN_DEBUG1( 
+            "CThumbnailServerSession::RequestThumbByIdAsyncL() - thumbnail blacklisted" );
+        aMessage.Complete( err );
+        iMessage = RMessage2();
+        }
+    else                
+        {
+        TN_DEBUG2( 
+            "CThumbnailServerSession::RequestThumbByIdAsyncL() - thumbnail not found ( query path from MDS ), err=%d ", err );
+
+#ifdef RD_MDS_2_5        
+        // try to query path from MDS
+        CThumbnailMDSQueryTask* task = new( ELeave )CThumbnailMDSQueryTask(
+                Server()->Processor(), params.iPriority + 1, Server()->GetMdESession(), *Server());
+        
+        CleanupStack::PushL( task );
+        task->QueryPathByIdL(params.iThumbnailId);
+        task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ), iMessage );
+        Server()->QueueTaskL( task );
+        CleanupStack::Pop( task ); // owned by processor now
+        
+        // query task is now responsible for completing the message
+        iMessage = RMessage2();
+#else
+        User::Leave(KThumbnailErrThumbnailNotFound);
+#endif // RD_MDS_2_5
+        
+        }   
+    
+#ifdef _DEBUG
+    aStop.UniversalTime();
+    TN_DEBUG2( "CThumbnailStore::RequestThumbByIdAsyncL() request took %d ms", (TInt)aStop.MicroSecondsFrom(aStart).Int64()/1000 );
+#endif 
+    
+    TN_DEBUG1("CThumbnailServerSession::RequestThumbByIdAsyncL() - end" );
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::RequestThumbByFileHandleAsync()
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::RequestThumbByFileHandleAsyncL( const RMessage2&
+    aMessage )
+    {
+    TN_DEBUG1( "CThumbnailServerSession::RequestThumbByFileHandleAsyncL()" );
+    
+    if(aMessage.Int1() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::RequestThumbByFileHandleAsync() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+    
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+
+    RFile64 file;
+    User::LeaveIfError( file.AdoptFromClient( aMessage, 2, 3 ));
+    
+    ResolveMimeTypeL(&file);
+    
+    if(params.iThumbnailSize == EFullScreenThumbnailSize ||
+       params.iThumbnailSize == EGridThumbnailSize ||
+       params.iThumbnailSize == EListThumbnailSize )
+        {
+        TInt sourceType = TThumbnailPersistentSize::EUnknownSourceType;
+        sourceType = Server()->SourceTypeFromMimeType( params.iMimeType );
+        ModifyThumbnailSize(sourceType);
+        }
+    
+    // CreateThumbnails
+    if (params.iControlFlags == EThumbnailGeneratePersistentSizesOnly)
+        {
+        CleanupClosePushL( file );
+        CreateGenerateTaskFromFileHandleL( &file );
+        CleanupStack::Pop( &file );         
+        }
+    // single thumbnail request
+    else
+        {
+        TRAPD( err, FetchThumbnailL());
+        
+        if ( !err && iBitmap )
+            {
+            TN_DEBUG1( "CThumbnailServerSession::RequestThumbByFileHandleAsyncL() - found existing thumbnail - bitmap " );
+
+            // Thumbnail already stored
+            file.Close();
+            TN_DEBUG1("CThumbnailServerSession::RequestThumbByFileHandleAsyncL - file handle closed");
+
+            ProcessBitmapL();
+            }
+        else if ( (err == KErrNotFound || err == KErrAccessDenied) && 
+                 !(params.iFlags& CThumbnailManager::EDoNotCreate) )
+            {
+            CreateGenerateTaskFromFileHandleL( &file);
+            }
+        else if (!err && iBuffer)
+            {
+            TN_DEBUG1( 
+                "CThumbnailServerSession::RequestThumbByFileHandleAsyncL() - found existing thumbnail - jpeg " );
+            
+            CThumbnailDecodeTask* task = new( ELeave )CThumbnailDecodeTask( Server()
+                        ->Processor(), * Server(), iBuffer, params.iPriority, params.iDisplayMode );
+            
+            CleanupStack::PushL( task );
+            task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ), iMessage );
+            Server()->QueueTaskL( task );
+            CleanupStack::Pop( task ); // owned by processor now
+            
+            // Decode task is now responsible for completing the message
+            iMessage = RMessage2();
+            
+            //CThumbnailDecodeTask is responsible freeing
+            iBuffer = NULL;
+            file.Close();
+            TN_DEBUG1("CThumbnailServerSession::RequestThumbByFileHandleAsyncL - file handle closed");
+            }
+        else
+            {
+            TN_DEBUG2( 
+                "CThumbnailServerSession::RequestThumbByFileHandleAsyncL() - thumbnail not found, err=%d", err );
+            aMessage.Complete( ConvertSqlErrToE32Err( err ));
+            iMessage = RMessage2();
+            }     
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::RequestThumbByPathAsync()
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::RequestThumbByPathAsyncL( const RMessage2&
+    aMessage )
+    {
+    TN_DEBUG1( "CThumbnailServerSession::RequestThumbByPathAsyncL()" );
+    
+#ifdef _DEBUG
+    TTime aStart, aStop;
+    aStart.UniversalTime();
+#endif
+    
+    if(aMessage.Int1() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::RequestThumbByPathAsync() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    
+    ResolveMimeTypeL(NULL);
+    
+    if(params.iThumbnailSize == EFullScreenThumbnailSize ||
+       params.iThumbnailSize == EGridThumbnailSize ||
+       params.iThumbnailSize == EListThumbnailSize )
+        {
+        TInt sourceType = TThumbnailPersistentSize::EUnknownSourceType;
+        sourceType = Server()->SourceTypeFromMimeType( params.iMimeType );
+        ModifyThumbnailSize(sourceType);
+        }
+    
+    // should always be true
+    if (params.iControlFlags != EThumbnailGeneratePersistentSizesOnly)
+		{
+	    TRAPD( err, FetchThumbnailL());
+	    
+	    if ( !err && iBitmap )
+	        {
+	        TN_DEBUG1( 
+	            "CThumbnailServerSession::RequestThumbByPathAsyncL() - found existing thumbnail- bitmap" );
+
+	        ProcessBitmapL();
+	        }
+	    else if ( !err && iBuffer)
+	        {
+	        TN_DEBUG1( 
+	            "CThumbnailServerSession::RequestThumbByPathAsyncL() - found existing thumbnail- jpeg" );
+	        
+	        CThumbnailDecodeTask* task = new( ELeave )CThumbnailDecodeTask( Server()
+	               ->Processor(), * Server(), iBuffer, params.iPriority, params.iDisplayMode );
+	        
+	        CleanupStack::PushL( task );
+	        task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ), iMessage );
+	        Server()->QueueTaskL( task );
+	        CleanupStack::Pop( task ); // owned by processor now
+	        
+	        // Decode task is now responsible for completing the message
+	        iMessage = RMessage2();
+	        
+	        //CThumbnailDecodeTask is responsible freeing
+	        iBuffer = NULL;
+	        }
+	    else if( err == KErrCompletion )
+	        {
+            // If thumbnail of requested size is blacklisted, fetching is left with KErrCompletion
+            TN_DEBUG1( 
+                "CThumbnailServerSession::RequestThumbByIdAsyncL() - thumbnail blacklisted" );
+            aMessage.Complete( err );
+            iMessage = RMessage2();
+	        }
+	    else 
+	        {
+	        TN_DEBUG2( 
+	            "CThumbnailServerSession::RequestThumbByPathAsyncL() - thumbnail not found, err = %d", err );
+	        
+	        if ( (err == KErrNotFound || err == KErrAccessDenied) && 
+	            !(params.iFlags& CThumbnailManager::EDoNotCreate) )
+	            {
+	            // Special error code so that the client side can open the file
+	            // and retry the request using file handle
+	            err = KThumbnailErrThumbnailNotFound;
+	            }
+	        else
+	            {
+                User::Leave(err);
+                }
+
+#ifdef RD_MDS_2_5	        
+            // try to query ID from MDS
+            CThumbnailMDSQueryTask* task = new( ELeave )CThumbnailMDSQueryTask(
+                    Server()->Processor(), params.iPriority + 1, Server()->GetMdESession(), *Server());
+            
+            CleanupStack::PushL( task );
+            task->SetUpdateToDb( EFalse );
+            task->QueryIdByPathL( params.iFileName );
+            task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ), iMessage );
+            Server()->QueueTaskL( task );
+            CleanupStack::Pop( task ); // owned by processor now
+            
+            // query task is now responsible for completing the message
+            iMessage = RMessage2();	            
+#else
+            User::Leave(err);
+#endif // RD_MDS_2_5
+	        
+	        }   
+	   }
+    
+#ifdef _DEBUG
+    aStop.UniversalTime();
+    TN_DEBUG2( "CThumbnailStore::RequestThumbByPathAsyncL() request took %d ms", (TInt)aStop.MicroSecondsFrom(aStart).Int64()/1000 );
+#endif
+    }   
+    
+void CThumbnailServerSession::RequestSetThumbnailByBufferL( const RMessage2& aMessage )
+    {
+    TN_DEBUG1( "CThumbnailServerSession::RequestSetThumbnailByBufferL()" );
+    
+    if(aMessage.Int3() != KCheckValue)
+        {
+        TN_DEBUG1( "CThumbnailServerSession::RequestSetThumbnailByBufferL() - error in aMessage - leaving" );
+        User::Leave(KErrArgument);
+        }
+      
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    
+    if(params.iThumbnailSize != EUnknownThumbnailSize)
+        {
+        Server()->DeleteThumbnailsL( params.iTargetUri);
+        }
+    
+    if(params.iThumbnailSize == EFullScreenThumbnailSize ||
+       params.iThumbnailSize == EGridThumbnailSize ||
+       params.iThumbnailSize == EListThumbnailSize )
+       {
+       TInt sourceType = TThumbnailPersistentSize::EUnknownSourceType;
+       TDataType mimetype;
+       Server()->MimeTypeFromFileExt( params.iTargetUri, mimetype );
+       sourceType = Server()->SourceTypeFromMimeType( mimetype );   
+       ModifyThumbnailSize(sourceType);
+       }
+    
+    TInt bufferSize = aMessage.Int2();
+    HBufC8* buffer = HBufC8::NewMaxLC( bufferSize );
+    TPtr8 ptr = buffer->Des();
+    aMessage.ReadL( 1 /* buffer pointer */, ptr );
+    
+    CreateGenerateTaskFromBufferL( buffer );
+    CleanupStack::Pop( buffer );
+    }
+
+void CThumbnailServerSession::RequestSetThumbnailByBitmapL( const RMessage2& aMessage )
+    {
+    TN_DEBUG1( "CThumbnailServerSession::RequestSetThumbnailByBitmapL()" );
+
+    if(aMessage.Int2() != KCheckValue)
+        {
+        TN_DEBUG1( "CThumbnailServerSession::RequestSetThumbnailByBitmapL() - error in aMessage - leaving" );
+        User::Leave(KErrArgument);
+        }
+        
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    
+    TInt bitmapHandle = aMessage.Int1();
+    TThumbnailServerRequestId &reqId = (TThumbnailServerRequestId&)params.iRequestId;
+    
+    // get bitmap
+    CFbsBitmap* bitmap = new( ELeave )CFbsBitmap();
+    CleanupStack::PushL( bitmap );
+    User::LeaveIfError( bitmap->Duplicate( bitmapHandle ) );
+    Server()->AddBitmapToPoolL( reqId.iSession, bitmap );
+    CleanupStack::Pop( bitmap );
+    iBitmapHandle = bitmap->Handle();
+    
+    RArray < TThumbnailPersistentSize >* missingSizes = NULL;
+    
+    // source type
+    TDataType mimeType;
+    TInt sourceType = 0;
+    TInt err = Server()->MimeTypeFromFileExt( params.iTargetUri, mimeType );
+    TBool missingIDs(EFalse);
+    
+    // get missing sizes
+    if ( err == KErrNone && ( params.iControlFlags & EThumbnailGeneratePersistentSizesOnly ) != 0 )
+        {
+        sourceType = Server()->SourceTypeFromMimeType( mimeType );
+        
+        missingSizes = new (ELeave) RArray < TThumbnailPersistentSize >;
+        CleanupClosePushL( *missingSizes );
+    
+        Server()->GetMissingSizesAndIDsL( params.iTargetUri, sourceType, *missingSizes, missingIDs);
+            
+        if ( missingSizes->Count() == 0)
+            {
+            // all thumbs already exist
+            CleanupStack::PopAndDestroy( missingSizes );
+            delete missingSizes;
+            missingSizes = NULL;
+            }            
+        }
+    
+    // if missing sizes, create scale tasks
+    if ( missingSizes )
+        {
+        const TInt count = missingSizes->Count();
+        
+        TSize bitmapSize = bitmap->SizeInPixels();
+        
+        for ( TInt i( 0 ); i < count; i++ )
+            {           
+            if( bitmapSize.iWidth < bitmapSize.iHeight )
+               {
+               TInt height = (*missingSizes)[i].iSize.iHeight;
+               (*missingSizes)[i].iSize.iHeight = (*missingSizes)[i].iSize.iWidth;
+               (*missingSizes)[i].iSize.iWidth = height;
+               TN_DEBUG1( "CThumbnailServerSession::RequestSetThumbnailByBitmapL() - portrait");
+               }
+            
+            CThumbnailScaleTask* scaleTask = CThumbnailScaleTask::NewL( Server()->Processor(),
+                *Server(), params.iTargetUri, bitmap, bitmapSize,
+                (*missingSizes)[i].iSize, (*missingSizes)[i].iCrop, params.iDisplayMode,
+                KMaxPriority, KNullDesC, (*missingSizes)[i].iType, params.iThumbnailId, EFalse, EFalse );
+            CleanupStack::PushL( scaleTask );
+            scaleTask->SetDoStore( ETrue );
+            //increase priority, scale needs to run before ID update below
+            scaleTask->SetPriority( params.iPriority + 1 );
+            Server()->Processor().AddTaskL( scaleTask );
+            CleanupStack::Pop( scaleTask );
+            
+            if( i == count-1 )
+                {
+                // scaleTask is now responsible for completing the RMessage
+                scaleTask->SetMessageData( reqId, iMessage );
+                iMessage = RMessage2();
+                }
+            }
+        
+        TN_DEBUG3("CThumbnailServerSession::RequestSetThumbnailByBitmapL() ID = %d, missingIDs = %d", params.iThumbnailId, missingIDs);
+        }
+    else
+        {
+        // complete message
+        aMessage.Complete( KErrNone );
+        iMessage = RMessage2();
+        }
+    
+    if ( missingSizes )
+        {
+        CleanupStack::PopAndDestroy( missingSizes );
+        delete missingSizes;
+        missingSizes = NULL;
+        }
+    
+    Server()->DeleteBitmapFromPool( iBitmapHandle );
+    iBitmapHandle = 0;
+    bitmap = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::CreateThumbnailsL()
+// Create thumbnails for given object file
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::CreateThumbnailsL( const RMessage2& aMessage )
+    {
+    RFile64 file;
+    CleanupClosePushL( file );
+	User::LeaveIfError( file.AdoptFromClient( aMessage, 1, 2 ));
+
+	CreateGenerateTaskFromFileHandleL( &file);
+        
+	CleanupStack::Pop( &file );
+    }      
+
+ 
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::CreateGenerateTaskL()
+// Create a task to generate a new thumbnail
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::CreateGenerateTaskFromFileHandleL( RFile64* aFile)
+    {
+    const TThumbnailRequestParams& params = iRequestParams();
+
+    TN_DEBUG2( 
+        "CThumbnailServerSession::CreateGenerateTaskFromFileHandleL() -- create thumbnail generation task for %S", &params.iFileName );
+      
+    TBool missingIDs = EFalse;
+    
+    RArray < TThumbnailPersistentSize >* missingSizes = NULL;
+    
+    // get missing sizes
+    if ( ( params.iControlFlags & EThumbnailGeneratePersistentSizesOnly ) != 0 )
+        {
+        TInt sourceType = TThumbnailPersistentSize::EUnknownSourceType;
+        sourceType = Server()->SourceTypeFromMimeType( params.iMimeType );
+        missingSizes = new (ELeave) RArray < TThumbnailPersistentSize >;
+        CleanupClosePushL( *missingSizes );
+        
+        Server()->GetMissingSizesAndIDsL( params.iFileName, sourceType, *missingSizes, missingIDs );
+#ifdef RD_MDS_2_5        
+        if( missingIDs )
+            {
+            TN_DEBUG1("CThumbnailServerSession::CreateGenerateTaskFromFileHandleL() some IDs missing");
+            
+            if( params.iThumbnailId == KNoId)
+                {
+                TN_DEBUG1("CThumbnailServerSession::CreateGenerateTaskFromFileHandleL() query fro MDS");
+                // try to query ID from MDS
+                CThumbnailMDSQueryTask* task = new( ELeave )CThumbnailMDSQueryTask(
+                        Server()->Processor(), params.iPriority + 1, Server()->GetMdESession(), *Server());
+                
+                CleanupStack::PushL( task );
+                task->QueryIdByPathL( params.iFileName );
+                
+                task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ) );
+                Server()->QueueTaskL( task );
+                CleanupStack::Pop( task ); // owned by processor now
+                TN_DEBUG1("CThumbnailServerSession::CreateGenerateTaskFromFileHandleL() query from MDS queued" );
+                }
+            else
+                {
+                TN_DEBUG2("CThumbnailServerSession::CreateGenerateTaskFromFileHandleL() got ID %d from params", params.iThumbnailId);
+                TRAP_IGNORE( Server()->UpdateIDL(params.iFileName, params.iThumbnailId ) );
+                }
+            }
+#endif // RD_MDS_2_5
+        
+        if ( missingSizes->Count() == 0)
+            {
+            // all thumbs already exist
+            CleanupStack::PopAndDestroy( missingSizes );
+            delete missingSizes;
+            if( aFile )
+               {
+               aFile->Close();
+               }
+            return;
+            }            
+        }
+    
+    // priority
+    TInt priority = params.iPriority;
+    if ( priority > KMaxGeneratePriority )
+        {
+        priority = KMaxGeneratePriority;
+        }
+    
+    // create new task
+    if( !aFile)
+        {
+        User::Leave( KErrArgument );
+        }
+    CleanupClosePushL( *aFile );
+    CThumbnailGenerateTask* task = new( ELeave )CThumbnailGenerateTask( Server()
+        ->Processor(), * Server(), aFile, NULL, &params.iMimeType, params.iFlags,
+        params.iSize, params.iDisplayMode, priority, missingSizes, params.iTargetUri,
+        params.iThumbnailSize, params.iThumbnailId, params.iQualityPreference );
+
+    // do not store bitmaps to server pool when generating only
+    if( params.iControlFlags & EThumbnailGeneratePersistentSizesOnly )
+        {
+        task->ScaledBitmapToPool( EFalse );
+        }
+        
+    CleanupStack::Pop( aFile );
+    
+    CleanupStack::PushL( task );
+    task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ),
+        iMessage );
+    Server()->QueueTaskL( task );
+    CleanupStack::Pop( task ); // owned by processor now
+    
+    if ( missingSizes )
+        {
+        CleanupStack::Pop( missingSizes );
+        }
+
+    // Generate task is now responsible for completing the message
+    iMessage = RMessage2();
+    } 
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::CreateGenerateTaskL()
+// Create a task to generate a new thumbnail
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::CreateGenerateTaskFromBufferL( TDesC8* aBuffer )
+    {
+    const TThumbnailRequestParams& params = iRequestParams();
+
+    TN_DEBUG2( 
+        "CThumbnailServerSession::CreateGenerateTaskFromBufferL() -- create thumbnail generation task for %S", &params.iTargetUri );
+  
+    if(aBuffer && params.iMimeType.Des().Match( KVideoMime ) == 0 )
+        {
+        User::Leave( KErrNotSupported );
+        }
+    
+    TInt sourceType = TThumbnailPersistentSize::EUnknownSourceType;
+    
+    TDataType mimetype;
+    TInt ret = Server()->MimeTypeFromFileExt( params.iTargetUri, mimetype );
+    if(ret == KErrNotFound)
+        {
+        Server()->Fs().ShareProtected();
+        RFile64 file;
+        CleanupClosePushL( file );
+        
+        User::LeaveIfError( file.Open( Server()->Fs(), params.iTargetUri, EFileShareReadersOrWriters )); 
+        TN_DEBUG2( "CThumbnailServerSession::CreateGenerateTaskFromBufferL - file handle opened for %S", &params.iFileName );
+                
+        mimetype = Server()->ResolveMimeTypeL(file);
+                
+        file.Close();
+        TN_DEBUG1("CThumbnailServerSession::CreateGenerateTaskFromBufferL - file handle closed");
+        
+        CleanupStack::Pop( &file );    
+        }
+        
+    sourceType = Server()->SourceTypeFromMimeType( mimetype );    
+    
+    RArray < TThumbnailPersistentSize >* missingSizes = NULL;
+    
+    // get missing sizes
+    if ( ( params.iControlFlags & EThumbnailGeneratePersistentSizesOnly ) != 0 )
+        {
+        missingSizes = new (ELeave) RArray < TThumbnailPersistentSize >;
+        CleanupClosePushL( *missingSizes );
+        
+        TBool missingIDs;
+        Server()->GetMissingSizesAndIDsL( params.iTargetUri, sourceType, *missingSizes, missingIDs );
+            
+        if ( missingSizes->Count() == 0)
+            {
+            // all thumbs already exist
+            CleanupStack::PopAndDestroy( missingSizes );
+            delete missingSizes;
+            if ( aBuffer)
+               {
+               delete aBuffer;
+               aBuffer = NULL; 
+               }
+            return;
+            }            
+        }
+    
+    // priority
+    TInt priority = params.iPriority;
+    if ( priority > KMaxGeneratePriority )
+        {
+        priority = KMaxGeneratePriority;
+        }
+    
+    // create new task
+    if( !aBuffer)
+        {
+        User::Leave( KErrArgument );
+        }
+    
+    CThumbnailGenerateTask* task = new( ELeave )CThumbnailGenerateTask( Server()
+        ->Processor(), * Server(), NULL, aBuffer, &params.iMimeType, params.iFlags,
+        params.iSize, params.iDisplayMode, priority, missingSizes, params.iTargetUri,
+        params.iThumbnailSize, params.iThumbnailId, params.iQualityPreference );
+
+    // do not store bitmaps to server pool when generating only
+    if( params.iControlFlags & EThumbnailGeneratePersistentSizesOnly )
+        {
+        task->ScaledBitmapToPool( EFalse );
+        }  
+    
+    CleanupStack::PushL( task );
+    task->SetMessageData( TThumbnailServerRequestId( this, params.iRequestId ),
+        iMessage );
+    Server()->QueueTaskL( task );
+    CleanupStack::Pop( task ); // owned by processor now
+    
+    if ( missingSizes )
+        {
+        CleanupStack::Pop( missingSizes );
+        }
+
+    // Generate task is now responsible for completing the message
+    iMessage = RMessage2();
+    } 
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::FetchThumbnailL()
+// Fetch thumbnail data from database
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::FetchThumbnailL()
+    {
+    TN_DEBUG1("CThumbnailServerSession::FetchThumbnailL()");
+    __ASSERT_DEBUG( !iBitmap, ThumbnailPanic( EThumbnailBitmapNotReleased ));
+
+    delete iBitmap;
+    iBitmap = NULL;
+
+    TThumbnailRequestParams& params = iRequestParams();
+    
+    if ( params.iThumbnailSize != EUnknownThumbnailSize &&
+         params.iThumbnailSize != ECustomThumbnailSize )
+        {
+        TThumbnailPersistentSize & persistentSize = Server()->PersistentSizeL( params.iThumbnailSize );
+        params.iSize = persistentSize.iSize;
+        }
+    
+    if( params.iFileName != KNullDesC )
+        {
+        TN_DEBUG4( "CThumbnailServerSession::FetchThumbnailL( TNId==%d ThumbnailSize=%d ( Path=%S ))", 
+                params.iThumbnailId, params.iThumbnailSize, &params.iFileName );
+        Server()->FetchThumbnailL( params.iFileName, iBitmap, iBuffer, params.iThumbnailSize, iOriginalSize);
+        }
+    else
+        {
+        TN_DEBUG3( "CThumbnailServerSession::FetchThumbnailL(Path=%S ThumbnailSize=%d)", 
+                        &params.iFileName, params.iThumbnailSize );
+        Server()->FetchThumbnailL( params.iThumbnailId, iBitmap, iBuffer,  params.iThumbnailSize, iOriginalSize );
+        }
+#ifdef _DEBUG
+    if( iBitmap)
+        {
+        TN_DEBUG4( "CThumbnailServerSession::FetchThumbnailL() size %d x %d displaymode %d", iBitmap->SizeInPixels().iWidth, iBitmap->SizeInPixels().iHeight, iBitmap->DisplayMode());
+        }
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::ProcessBitmapL()
+// Process a fetched bitmap by creating scale tasks or by returning the
+// bitmap as such.
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::ProcessBitmapL()
+    {   
+    TThumbnailRequestParams& params = iRequestParams();
+    
+    // in import case store bitmap
+    if (params.iTargetUri != KNullDesC)
+        {
+        Server()->StoreThumbnailL( params.iTargetUri, iBitmap, iOriginalSize,
+                                   params.iFlags& CThumbnailManager::ECropToAspectRatio, params.iThumbnailSize, params.iThumbnailId );
+        }
+    
+    // No need to scale, return iBitmap directly
+    Server()->AddBitmapToPoolL( this, iBitmap );
+    CFbsBitmap* bitmap = iBitmap;
+    iBitmap = NULL; // owned by server now
+    
+    params.iBitmapHandle = bitmap->Handle();
+    const TSize bitmapSize = bitmap->SizeInPixels();
+
+    if ( params.iQualityPreference == CThumbnailManager
+        ::EOptimizeForQualityWithPreview && bitmapSize.iWidth <
+        params.iSize.iWidth && bitmapSize.iHeight < params.iSize.iHeight &&
+        bitmapSize.iWidth < iOriginalSize.iWidth && bitmapSize.iHeight <
+        iOriginalSize.iHeight )
+        {
+        // This is a non-scaled preview bitmap
+        params.iControlFlags = EThumbnailPreviewThumbnail;
+        }
+
+    if ( iMessage.Handle() )
+        {
+        iMessage.WriteL( 0, iRequestParams );
+        iMessage.Complete( KErrNone );
+        iMessage = RMessage2();
+        }            
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::ReleaseBitmap()
+// Release bitmap from bitmap pool
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::ReleaseBitmap( const RMessage2& aMessage )
+    {
+    TN_DEBUG2( "CThumbnailServerSession::ReleaseBitmap(%d)", aMessage.Int0());
+    Server()->DeleteBitmapFromPool( aMessage.Int0());
+    }
+
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::CancelRequest()
+// Cancel pending request.
+// -----------------------------------------------------------------------------
+//
+TInt CThumbnailServerSession::CancelRequest( const RMessage2& aMessage )
+    {
+    const TThumbnailServerRequestId requestId( this, aMessage.Int0());
+    const TInt err = Server()->DequeTask( requestId );
+    TN_DEBUG4( 
+        "CThumbnailServerSession::CancelRequest(0x%08x/%d) - returning %d",
+        requestId.iSession, requestId.iRequestId, err );
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::ChangePriority()
+// Change priority of pending request.
+// -----------------------------------------------------------------------------
+//
+TInt CThumbnailServerSession::ChangePriority( const RMessage2& aMessage )
+    {
+    const TThumbnailServerRequestId requestId( this, aMessage.Int0());
+    const TInt newPriority = aMessage.Int1();
+
+    const TInt err = Server()->ChangeTaskPriority( requestId, newPriority );
+    TN_DEBUG5( 
+        "CThumbnailServerSession::ChangePriority(0x%08x/%d, %d) - returning %d",
+        requestId.iSession, requestId.iRequestId, newPriority, err );
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::DeleteThumbnailsL()
+// Delete thumbnails for given object file
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::DeleteThumbnailsL( const RMessage2& aMessage )
+    {
+    if(aMessage.Int2() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::DeleteThumbnailsL() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+    
+    HBufC* fileName = HBufC::NewLC( KMaxFileName );
+    TPtr ptr = fileName->Des();
+    aMessage.ReadL( 1, ptr );
+    Server()->DeleteThumbnailsL( ptr );
+    CleanupStack::PopAndDestroy( fileName );
+    
+    aMessage.Complete( KErrNone );
+    iMessage = RMessage2();
+    }
+
+// -----------------------------------------------------------------------------
+// CThumbnailServerSession::DeleteThumbnailsByIdL()
+// Delete thumbnails by TThumbnailId.
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::DeleteThumbnailsByIdL( const RMessage2& aMessage )
+    {
+    if(aMessage.Int2() != KCheckValue)
+       {
+       TN_DEBUG1( "CThumbnailServerSession::DeleteThumbnailsByIdL() - error in aMessage - leaving" );
+       User::Leave(KErrArgument);
+       }
+    
+    // read message params
+    aMessage.ReadL( 0, iRequestParams );
+    const TThumbnailRequestParams& params = iRequestParams();
+    
+    TThumbnailId id = params.iThumbnailId;
+    Server()->DeleteThumbnailsByIdL( id );
+    
+    aMessage.Complete( KErrNone );
+    iMessage = RMessage2();
+    }
+
+// -----------------------------------------------------------------------------
+// Get the required size (in characters) for a buffer that contains the
+// list of supported MIME types
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::GetMimeTypeBufferSizeL( const RMessage2& aMessage
+    )
+    {
+    TPckgBuf < TInt > buf;
+    buf() = Server()->GetMimeTypeBufferSize();
+    aMessage.WriteL( 0, buf );
+    }
+
+// -----------------------------------------------------------------------------
+// Get the list of supported MIME types and store them in the buffer
+// allocated by the client.
+// -----------------------------------------------------------------------------
+//
+void CThumbnailServerSession::GetMimeTypeListL( const RMessage2& aMessage )
+    {
+    TInt len = aMessage.GetDesMaxLengthL( 0 );
+    HBufC* buf = HBufC::NewLC( len );
+    TPtr ptr = buf->Des();
+    Server()->GetMimeTypeList( ptr );
+    aMessage.WriteL( 0, * buf );
+    CleanupStack::PopAndDestroy( buf );
+    }
+
+// ---------------------------------------------------------------------------
+// CThumbnailServerSession::ModifyThumbnailSize
+// ---------------------------------------------------------------------------
+//
+void CThumbnailServerSession::ModifyThumbnailSize( TInt aSourceType )   
+    {
+    TThumbnailRequestParams& params = iRequestParams();
+    if(aSourceType == TThumbnailPersistentSize::EImage)
+        {
+        if(params.iThumbnailSize == EFullScreenThumbnailSize)
+            {
+            params.iThumbnailSize = EImageFullScreenThumbnailSize;
+            }
+        else if(params.iThumbnailSize == EGridThumbnailSize)
+            {
+            params.iThumbnailSize = EImageGridThumbnailSize;
+            }
+        else if(params.iThumbnailSize == EListThumbnailSize)
+            {
+            params.iThumbnailSize = EImageListThumbnailSize;
+            }       
+        }
+    else if(aSourceType == TThumbnailPersistentSize::EVideo)
+           {
+           if(params.iThumbnailSize == EFullScreenThumbnailSize)
+               {
+               params.iThumbnailSize = EVideoFullScreenThumbnailSize;
+               }
+           else if(params.iThumbnailSize == EGridThumbnailSize)
+               {
+               params.iThumbnailSize = EVideoGridThumbnailSize;
+               }
+           else if(params.iThumbnailSize == EListThumbnailSize)
+               {
+               params.iThumbnailSize = EVideoListThumbnailSize;
+               }       
+           }
+    else if(aSourceType == TThumbnailPersistentSize::EAudio)
+           {
+           if(params.iThumbnailSize == EFullScreenThumbnailSize)
+               {
+               params.iThumbnailSize = EAudioFullScreenThumbnailSize;
+               }
+           else if(params.iThumbnailSize == EGridThumbnailSize)
+               {
+               params.iThumbnailSize = EAudioGridThumbnailSize;
+               }
+           else if(params.iThumbnailSize == EListThumbnailSize)
+               {
+               params.iThumbnailSize = EAudioListThumbnailSize;
+               }       
+           }
+    }
+
+//------------------------------------------------------------------------
+// CThumbnailServerSession::ModifyThumbnailSize
+// ---------------------------------------------------------------------------
+//
+void CThumbnailServerSession::ResolveMimeTypeL( RFile64* aFile )
+    { 
+    TThumbnailRequestParams& params = iRequestParams();
+    TInt res = 0;
+        
+    // mime type
+    if ( params.iMimeType.Des8() == KNullDesC8 && !Server()->SupportedMimeType(params.iMimeType) )
+       {
+       // try parsing from file extension
+       res = Server()->MimeTypeFromFileExt( params.iFileName, params.iMimeType );
+       if ( res == KErrNotFound )
+           {
+          if( aFile )
+             {
+             // parsed type not in the list, resolve from file
+             params.iMimeType = Server()->ResolveMimeTypeL(*aFile);
+             }
+          else
+             {
+             Server()->Fs().ShareProtected();
+             RFile64 file;
+             CleanupClosePushL( file );
+             
+             User::LeaveIfError( file.Open( Server()->Fs(), params.iFileName, EFileShareReadersOrWriters )); 
+             TN_DEBUG2( "CThumbnailServerSession::ResolveMimeType - file handle opened for %S", &params.iFileName );
+             
+             params.iMimeType = Server()->ResolveMimeTypeL(file);
+             
+             file.Close();
+             TN_DEBUG1("CThumbnailServerSession::ResolveMimeType - file handle closed");
+             
+             CleanupStack::Pop( &file );    
+             }    
+          }        
+       }      
+    }
+
+
+// ---------------------------------------------------------------------------
+// RThumbnailMessage::FilterSqlErr
+// ---------------------------------------------------------------------------
+//
+TInt CThumbnailServerSession::ConvertSqlErrToE32Err( TInt aReason )
+    {
+    TInt e32Err;
+    if ( aReason >=  - 144 )
+    // magic: [-1..-144] is E32 error range 
+        {
+        // E32 error value or non-negative value
+        e32Err = aReason;
+        }
+    else
+        {
+        switch ( aReason )
+            {
+            case KSqlErrGeneral:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrInternal:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrPermission:
+                e32Err = KErrPermissionDenied;
+                break;
+            case KSqlErrAbort:
+                e32Err = KErrAbort;
+                break;
+            case KSqlErrBusy:
+                e32Err = KErrServerBusy;
+                break;
+            case KSqlErrLocked:
+                e32Err = KErrLocked;
+                break;
+            case KSqlErrReadOnly:
+                e32Err = KErrAccessDenied;
+                break;
+            case KSqlErrInterrupt:
+                e32Err = KErrAbort;
+                break;
+            case KSqlErrIO:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrCorrupt:
+                e32Err = KErrCorrupt;
+                break;
+            case KSqlErrNotFound:
+                e32Err = KErrNotFound;
+                break;
+            case KSqlErrFull:
+                e32Err = KErrOverflow;
+                break;
+            case KSqlErrCantOpen:
+                e32Err = KErrCouldNotConnect;
+                break;
+            case KSqlErrProtocol:
+                e32Err = KErrLocked;
+                break;
+            case KSqlErrEmpty:
+                e32Err = KErrNotFound;
+                break;
+            case KSqlErrSchema:
+                e32Err = KErrAbort;
+                break;
+            case KSqlErrTooBig:
+                e32Err = KErrTooBig;
+                break;
+            case KSqlErrConstraint:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrMismatch:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrMisuse:
+                e32Err = KErrGeneral;
+                break;
+            case KSqlErrRange:
+                e32Err = KErrOverflow;
+                break;
+            case KSqlErrNotDb:
+                e32Err = KErrCorrupt;
+                break;
+            case KSqlErrStmtExpired:
+                e32Err = KErrAbort;
+                break;
+            default:
+                e32Err = aReason;
+            }
+        }
+    return e32Err;
+    }
+
+// End of file