// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Implements the session functinality of the Core Dump Server
//



/**
 @file
 @internalTechnology
 @released
*/
#include <scmconfigitem.h>

#include "coredumpsession.h"

/**
C++ constructor
@param aSession RSecuritySvrSession session parameter
*/
EXPORT_C CCoreDumpSession::CCoreDumpSession( RSecuritySvrSession &aSession )
	: iSecSess( aSession )
	{
	LOG_MSG("->CCoreDumpSession::CCoreDumpSession()\n");
	// No implementation required
	}

/**
C++ Destructor. Saves the current configuration to the standard configuration file
Calls REComSession::FinalClose() to finish the ECOM session.
Disconnect from the Core Dump Server by calling its SessionClosed() method.
*/
EXPORT_C CCoreDumpSession::~CCoreDumpSession()
	{

	LOG_MSG("CCoreDumpSession::~CCoreDumpSession()\n" );

	TRAPD( err, SaveConfigFileL() );
	if( KErrNone != err )
		{
		_LIT(KSaveConfigFileErrorMsg ,"Warning :Core Dump Server Could Not Save Configuration File.");
		User::InfoPrint( KSaveConfigFileErrorMsg );
		}

	iPluginList.Reset();
	LOG_MSG("<-iPluginList.Reset()" );

	iThreadPointerList.ResetAndDestroy();
	LOG_MSG("<-iThreadPointerList.ResetAndDestroy()" );

	iProcessPointerList.ResetAndDestroy();
	LOG_MSG("<-iProcessPointerList.ResetAndDestroy()" );

	iExecutablePointerList.ResetAndDestroy();
	LOG_MSG("<-iProcessPointerList.ResetAndDestroy()" );

	iObservationList.ResetAndDestroy();
	LOG_MSG("<-iObservationList.ResetAndDestroy()" );

    iConfigList.ResetAndDestroy();
	LOG_MSG("<-iConfigList.ResetAndDestroy()" );
	
	
	iScmConfigList.ResetAndDestroy();

    iTotalConfigList.Reset();

    iAllowedPlugins.Reset();

    if(iDataSource)
        {
		LOG_MSG("->delete iDataSource" );
        delete iDataSource;
        iDataSource = NULL;
        }
    
    if(iFlashDataSource)
    	{
		LOG_MSG("->delete iFlashDataSource" );
        delete iFlashDataSource;
        iFlashDataSource = NULL;    	
    	}

    if( iCrashHandler )
        {
		LOG_MSG("->delete iCrashHandler" );
        delete iCrashHandler;
        iCrashHandler = NULL;
        }

    iFormatterPlugins.ResetAndDestroy();
    iFormatterInfos.ResetAndDestroy();
    if(iMarshalledFormatterList)
    {
        delete iMarshalledFormatterList;
    }

    iWriterPlugins.ResetAndDestroy();
    iWriterInfos.ResetAndDestroy();
    if(iMarshalledWriterList)
    {
        delete iMarshalledWriterList;
    }


	LOG_MSG( "->RProperty::Delete(KCoreDumpServUid, ECancelCrash)" );
    err = RProperty::Delete(KCoreDumpServUid, ECancelCrash);
    if(err != KErrNone)
        {
        LOG_MSG2("CCoreDumpSession::~CCoreDumpSession - unable to delete 'cancel crash' property! err:%d\n", err);
        }

	LOG_MSG("->RProperty::Delete(KCoreDumpServUid, ECrashProgress)" );
    err = RProperty::Delete(KCoreDumpServUid, ECrashProgress);
    if(err != KErrNone)
        {
        LOG_MSG2("CCoreDumpSession::~CCoreDumpSession - unable to delete 'crash progress' property! err:%d\n", err);
        }

	
    err = RProperty::Delete(KCoreDumpServUid, ECrashCount);
    if(err != KErrNone)
        {
        LOG_MSG2("CCoreDumpSession::~CCoreDumpSession - unable to delete 'crash count' property! err:%d\n", err);
        }
    
    err = RProperty::Delete(KCoreDumpServUid, ECrashMediaName);
    if(err != KErrNone)
        {
        LOG_MSG2("CCoreDumpSession::~CCoreDumpSession - unable to delete 'crash media name' property! err:%d\n", err);
        }

    if(iMarshalledProcessList != NULL)
        {
		LOG_MSG("->delete iMarshalledProcessList;\n" );
        delete iMarshalledProcessList;
        }

    if(iMarshalledExecutableList != NULL)
        {
		LOG_MSG("->delete iMarshalledExecutableList;\n" );
        delete iMarshalledExecutableList;
        }

    if(iMarshalledThreadList != NULL)
        {
		LOG_MSG( "->delete iMarshalledThreadList;\n" );
        delete iMarshalledThreadList;
        }
    
    iCrashList.ResetAndDestroy();
    if(iMarshalledCrashList != NULL)
    	{
		LOG_MSG( "->delete iMarshalledCrashList;\n" );
        delete iMarshalledCrashList;   	
    	}
    
	LOG_MSG("REComSession::FinalClose()" );
    REComSession::FinalClose();

	Server().SessionClosed();

	LOG_MSG("<-CCoreDumpSession::~CCoreDumpSession()" );

	}

#define KObservationListGranularity (20)

/**
* Symbian OS 2nd stage construction
*/
void CCoreDumpSession::ConstructL()
	{
	LOG_MSG( "CCoreDumpSession::ConstructL()\n" );

    iMarshalledThreadList = NULL;
	iTotalThreadListDescSize = 0;
    iMarshalledProcessList = NULL;
	iTotalProcessListDescSize = 0;
    iMarshalledExecutableList = NULL;
	iTotalExecutableListDescSize = 0;
    iMarshalledFormatterList = NULL;
	iTotalFormatterListDescSize = 0;
    iMarshalledWriterList = NULL;
	iTotalWriterListDescSize = 0;

	iObservationList.ReserveL(KObservationListGranularity);

    static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); //do we want to limit it?? DOS attack via CancelCrash

    //UI sets to ETrue, formatter gets, crash handler resets
    TInt err = RProperty::Define(KCoreDumpServUid, ECancelCrash, RProperty::EInt, KAllowAllPolicy, KAllowAllPolicy);
    if( (err != KErrAlreadyExists) && (err != KErrNone) )
        { 
        LOG_MSG2("CCoreDumpSession::ConstrucL - unable to create 'cancel crash' property! err:%d\n", err);
        User::LeaveIfError(err);
        }

    //UI gets and displays, formatter sets to update the progress, crash handler resets
    err = RProperty::Define(KCoreDumpServUid, ECrashProgress, RProperty::EText, KAllowAllPolicy, KAllowAllPolicy);
    if( (err != KErrAlreadyExists) && (err != KErrNone) )
        {
        LOG_MSG2("CCoreDumpSession::ConstrucL - unable to create 'crash progress' property! err:%d\n", err);
        User::LeaveIfError(err);
        }

    //UI gets crash count
    err = RProperty::Define(KCoreDumpServUid, ECrashCount, RProperty::EInt, KAllowAllPolicy, KAllowAllPolicy);
    if( (err != KErrAlreadyExists) && (err != KErrNone) )
        {
        LOG_MSG2("CCoreDumpSession::ConstrucL - unable to create 'crash count' property! err:%d\n", err);
        User::LeaveIfError(err);
        }
    
    //UI gets the crash media name
    err = RProperty::Define(KCoreDumpServUid, ECrashMediaName, RProperty::ELargeByteArray, KAllowAllPolicy, KAllowAllPolicy, RProperty::KMaxLargePropertySize);
    if( (err != KErrAlreadyExists) && (err != KErrNone) )
        {
        LOG_MSG2("CCoreDumpSession::ConstrucL - unable to create 'crash media name' property! err:%d\n", err);
        User::LeaveIfError(err);
        }

    
    iCrashHandler = CCrashHandler::NewL(*this);

	iConfigList.ReserveL( (TInt)ELastParam );
	
	iScmConfigList.ReserveL((TInt)Debug::TConfigItem::ELast);
	
	

	// This list will contain all the configuration parameters for the entire system,
	// but we do not know how many there are. At least hold our own params.

	//LOG_MSG( "  -> new (ELeave) RConfigParameterList()\n" );

	iTotalConfigList.ReserveL( (TInt)ELastParam );

	COptionConfig * config;

	//LOG_MSG( "  -> NewL KSuspendOwningProcsPrompt\n" );

	RProcess thisProc;
	iOurSecureID = thisProc.SecureId();
	TUint32 ourSecureID = iOurSecureID.iUid;
	//LOG_MSG2( "  thisProc.SecureId()=0x%X\n", ourSecureID );

    
	// This is stored as a bitfield
	_LIT( KCrashedEventTypePrompt, "Select Crash Trigger:\n  1-HW Exception,\n  2-Thread Kill,\n  3-Both" );
	iCrashEventTypes = ECrashHwExcAndKillThread;
	config = COptionConfig::NewL(  (TInt)ECrashEventTypes,
									ourSecureID,
									COptionConfig::ECoreDumpServer,
									COptionConfig::ETUInt, 
									KCrashedEventTypePrompt, 
									1,
									KNullDesC,
									iCrashEventTypes,
									KNullDesC );
    
	iConfigList.AppendL( config );


	_LIT( KPreCrashEventActionPrompt, "Action On Crash:\n  0-None,\n  1-Suspend Thread,\n  2-Suspend Process" );
	iPreCrashEventAction = ESuspendThread;
	config = COptionConfig::NewL(  (TInt)EPreCrashEventAction,
									ourSecureID,
									COptionConfig::ECoreDumpServer,
									COptionConfig::ETUInt, 
									KPreCrashEventActionPrompt, 
									1,
									KNullDesC,
									iPreCrashEventAction,
									KNullDesC );
	iConfigList.AppendL( config );
    

	_LIT( KPostCrashEventActionPrompt, "Action After Crash:\n  0-None,\n  1-Resume Thread,\n  2-Resume Process,\n  4-Kill Process" );
	iPostCrashEventAction = EResumeThread;
	config = COptionConfig::NewL(  (TInt)EPostCrashEventAction,
									ourSecureID,
									COptionConfig::ECoreDumpServer,
									COptionConfig::ETUInt, 
									KPostCrashEventActionPrompt, 
									1,
									KNullDesC,
									iPostCrashEventAction,
									KNullDesC );

	iConfigList.AppendL( config );

	iDataSource = CServerCrashDataSource::NewL(iSecSess);
	iFlashDataSource = CFlashDataSource::NewL(iSecSess);

	ReadPluginUidFilesL();	
    }

void CCoreDumpSession::CreateL()
{
    LOG_MSG("->CCoreDumpSession::CreateL()\n");
	Server().SessionOpened();
}

/**
* Symbian OS 1st stage construction called by CCoreDumpServer::NewSessionL()
*/
EXPORT_C CCoreDumpSession* CCoreDumpSession::NewL( RSecuritySvrSession &aSession )
	{
	LOG_MSG( "CCoreDumpSession::NewL()\n" );
	CCoreDumpSession* self = new (ELeave) CCoreDumpSession( aSession );
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return self;
	}

CCoreDumpServer& CCoreDumpSession::Server() const
{
    LOG_MSG("->CCoreDumpServer::Server()\n");
    return *static_cast<CCoreDumpServer*>(const_cast<CServer2*>(CSession2::Server()));
}

/*
* Called each time a client request message is received
*/
EXPORT_C void CCoreDumpSession::ServiceL(const RMessage2& aMessage)
	{
	// Any security checks on a connected client can be made here using the aMessage parameter.
	// aMessage is the service request message from the client thread.
    TInt err = KErrNone;

	TRAP(err, DispatchMessageL(aMessage));

	if ((aMessage.Function()) != ECoreDumpProcessCrashAsync)
		{//ECoreDumpProcessFlashCrashAsync is an async request so we complete the request when we are done
		aMessage.Complete(err);
		}
    	
	}

//
_LIT(KSessionPanic,"CCoreDumpSession panic");
/*
* Called when the client should be panicked
*/
void CCoreDumpSession::PanicClient(const RMessage2& aMessage, TInt aPanic)
	{
	aMessage.Panic(KSessionPanic, aPanic);
	}


/*
* Called by ServiceL() when a request message is received, calls the appropriate service
*/
void CCoreDumpSession::DispatchMessageL(const RMessage2& aMessage)
	{
	// Call the required service given by the request message's function number
	switch(aMessage.Function())
		{
		case ECoreDumpServGetPluginList:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpServerGetPluginList\n" );
			GetPluginListL(aMessage);
			break;
			}
		case ECoreDumpPluginRequest:
			{
			LOG_MSG("CCoreDumpSession::DispatchMessageL() ECoreDumpPluginRequest\n");
            if(iCrashHandler->CrashInProgress())
                {
                LOG_MSG( "CCoreDumpSession::DispatchMessageL - unable to handle because of crash in progress\n" );
                User::Leave(KErrServerBusy);
                }
            else	
            	{
			    PluginRequestL( aMessage );
            	}
			break;
			}
		case ECoreDumpGetListInfo:
			{
			LOG_MSG("CCoreDumpSession::DispatchMessageL() ECoreDumpListInfo\n");
			ListInfoL( aMessage );
			break;
			}
		case ECoreDumpGetListData:
			{
			LOG_MSG("CCoreDumpSession::DispatchMessageL() ECoreDumpGetList\n");
			GetListL( aMessage );
			break;
			}
		case ECoreDumpGetNumberConfigParams :
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpGetNumberConfigParams\n" );
			GetNumberConfigParametersL( aMessage );
			break;
			}
		case ECoreDumpGetConfigParam :
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpGetConfigParam\n" );
			GetConfigParameterL( aMessage );
			break;
			}
		case ECoreDumpSetConfigParam :
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpSetConfigParam\n" );
            if(iCrashHandler->CrashInProgress())
                {
                LOG_MSG( "CCoreDumpSession::DispatchMessageL - unable to handle because of crash in progress\n");
                User::Leave(KErrServerBusy);
                }
            else	
            	{
			    SetConfigParameterL( aMessage );
            	}
			break;
			}
        case ECoreDumpObservationRequest:
        	{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpObservationRequest\n" );
            ObservationRequestL( aMessage );
            break;
        	}
		case ECoreDumpLoadConfig :
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpLoadConfig\n" );
			LoadConfigFileL( &aMessage );
			break;
			}
		case ECoreDumpSaveConfig :
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpSaveConfig\n" );
			SaveConfigFileL( &aMessage );
			break;
			}
		case ECoreDumpDeleteCrashPartitionRequest:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpDeleteCrashPartitionRequest\n" );
			DeleteCrashPartitionL();
			break;
			}
		case ECoreDumpDeleteLogRequest:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpDeleteLogRequest\n" );
			//DeleteCrashLogL(aMessage);
			User::Leave(KErrNotSupported);
			break;
			}
		case ECoreDumpProcessFlashCrash:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpProcessFlashCrash\n" );
			ProcessCrashLogL(aMessage);
			break;
			}
		case ECoreDumpProcessCrashAsync:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpProcessFlashCrashAsync\n" );
			ProcessCrashLogAsyncL(aMessage);
			break;			
			}
		case ECoreDumpCancelProcessCrashAsync:
			{
			LOG_MSG( "CCoreDumpSession::DispatchMessageL() ECoreDumpCancelProcessFlashCrashAsync\n" );
			CancelProcessCrashLogAsync(aMessage);
			break;			
			}
		default:
			{
			// Unknown function number - panic the client
			PanicClient(aMessage, EBadRequest);
			}
		}
	}


