// Copyright (c) 2001-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:
//


#include "smsppara.h"
#include "smsuset.h"
#include "smsulog.h"
#include "smspmain.h"

#include "gsmubuf.h"
#include "Gsmumsg.h"
#include <mmretrieve.h>
#include "SmsuTimer.h"


/**
 *  Constructor
 *  
 *  @param aSmsComm a reference to the protocol.
 *  @param aSmsSettings a reference to the global SMS settings.
 *  @param aSmsMessaging a reference to the ETEL SMS messaging subsession.
 *  
 */
CSmsParamsBase::CSmsParamsBase(MSmsComm& aSmsComm,const TSmsSettings& aSmsSettings,RMobileSmsMessaging& aSmsMessaging)
  : CSmsuActiveBase(KSmsSessionPriority),
	iSmsComm(aSmsComm),
	iSmsSettings(aSmsSettings),
	iSmsMessaging(aSmsMessaging)
	{
	} // CSmsParamsBase::CSmsParamsBase


/**
 *  2nd Phase of construction.
 *  
 *  Creates CSmsTimeout object.
 *  
 */
void CSmsParamsBase::ConstructL()
	{
	LOGSMSPROT1("CSmsParamsBase::ConstructL()");

	ConstructTimeoutL();
	} // CSmsParamsBase::ConstructL


/**
 *  2 Phase constructor.
 *  
 *  @param aSmsComm a reference to the protocol.
 *  @param aSmsSettings a reference to the global SMS settings.
 *  @param aSmsMessaging a reference to the ETEL SMS messaging subsession.
 *  @leave Leaves if ContructL() leaves, or not enough memory is available.
 *  @return a new CSmsReadParams object.
 *  
 */
CSmsReadParams* CSmsReadParams::NewL(MSmsComm& aSmsComm,const TSmsSettings& aSmsSettings,RMobileSmsMessaging& aSmsMessaging)
	{
	LOGSMSPROT1("CSmsReadParams::NewL()");

	CSmsReadParams* smsReadParams=new(ELeave) CSmsReadParams(aSmsComm,aSmsSettings,aSmsMessaging);
	CleanupStack::PushL(smsReadParams);
	smsReadParams->ConstructL();
	CleanupStack::Pop(smsReadParams);
	return smsReadParams;
	} // CSmsReadParams::NewL


/**
 *  Destructor
 *  
 *  Cancel reading process and delete all created objects.
 *  
 */
CSmsReadParams::~CSmsReadParams()
	{
	Cancel();
	delete iRetrieveMobilePhoneSmspList;
	delete iMobilePhoneSmspList;
	} // CSmsReadParams::~CSmsReadParams


/**
 *  Start retrieving of SMS parameters. Called by CSmsProtocol.
 *  
 *  The behavour has been changed so that these parameters
 *  will always be retrieved from the TSY. [Previously the
 *  algorithm only retrieved the parameters from the TSY once
 *  and cached them so the TSY would not need to be polled if
 *  a client asked for the again, the assumption being that the
 *  SC number would never change. Subsequent client requests to
 *  read the SMS parameters would result in the cached parameters
 *  being returned rather than retrieving the parameters from the
 *  SIM. However this can cause problems (DEF40029) if the SIM is
 *  replaced with a new SIM that has an incorrect service center
 *  number: the stack can be requested to load the SMS parameters
 *  twice, once when the phone boots with the new SIM and again when
 *  the SIM is updated with the new Service Centre Number. If 2nd
 *  request only results in the cached parameters being returned then
 *  the incorrect SC Address will be returned.]
 *  
 *  @param aObserver a reference to the observer object.
 */
void CSmsReadParams::Start(MSmsMessageObserver& aObserver)
	{
	LOGSMSPROT1("CSmsReadParams::Start()");

	__ASSERT_DEBUG(iSmsMessageObserver == NULL  &&  iReport == NULL,
				   SmspPanic(KSmspPanicUnexpectedState));

	//
	// Store the observer interface object for and start the retrieve
	// operation.
	//
	iSmsMessageObserver = &aObserver;

	iRetrieveMobilePhoneSmspList->Start(iStatus);

	TimedSetActive(iSmsSettings.Timeout());
	} // CSmsReadParams::Start


/**
 *  Start retrieving of SMS parameters. Called by CSmsWriteParams.
 *  
 *  The behavour has been changed so that these parameters
 *  will always be retrieved from the TSY. [Previously the
 *  algorithm only retrieved the parameters from the TSY once
 *  and cached them so the TSY would not need to be polled if
 *  a client asked for the again, the assumption being that the
 *  SC number would never change. Subsequent client requests to
 *  read the SMS parameters would result in the cached parameters
 *  being returned rather than retrieving the parameters from the
 *  SIM. However this can cause problems (DEF40029) if the SIM is
 *  replaced with a new SIM that has an incorrect service center
 *  number: the stack can be requested to load the SMS parameters
 *  twice, once when the phone boots with the new SIM and again when
 *  the SIM is updated with the new Service Centre Number. If 2nd
 *  request only results in the cached parameters being returned then
 *  the incorrect SC Address will be returned.]
 *  
 *  @param aStatus a reference to the outstanding request.
 */
void CSmsReadParams::Start(TRequestStatus& aStatus)
	{
	LOGSMSPROT1("CSmsReadParams::Start()");

	__ASSERT_DEBUG(iSmsMessageObserver == NULL  &&  iReport == NULL,
				   SmspPanic(KSmspPanicUnexpectedState));

	//
	// Store the TRequestStatus in the CSmsuActiveBase object for later
	// completion and start the retrieve operation.
	//
	Queue(aStatus);

	iRetrieveMobilePhoneSmspList->Start(iStatus);

	TimedSetActive(iSmsSettings.Timeout());
	} // CSmsReadParams::Start


/**
 *  Retrieves parameter list from CRetrieveMobilePhoneSmspList object.
 *  Cancel timeout timer. Delete old SMSP list and retrieve new list from
 *  CMobilePhoneSmspList object if retrieving was successful.
 *  
 *  @leave Leave if RetrieveListL() leaves.
 */
void CSmsReadParams::DoRunL()
	{
	LOGSMSPROT2("CSmsReadParams::RunL [iStatus=%d]", iStatus.Int() );

	//
	// If the start retrieve was successful, then continue retrieving the list.
	// A temporary variable is used to keep the old list until the new one is
	// obtained successfully.
	//
	if (iStatus == KErrNone)
		{
		CMobilePhoneSmspList* tempList = iRetrieveMobilePhoneSmspList->RetrieveListL();

		delete iMobilePhoneSmspList;
		iMobilePhoneSmspList = tempList;
		}

	//
	// DoRunL() will now return to CSmsuActiveBase which if the object
	// is not active, will call Complete().
	//
	} // CSmsReadParams::DoRunL


/**
 *  Handles cancel read parameters request.
 *  
 *  Cancel timeout timer.
 *  Cancel also retrieving of parameters process.
 *  Call complete.
 */
void CSmsReadParams::DoCancel()
	{
	LOGSMSPROT1("CSmsReadParams::DoCancel()");

	TimedSetActiveCancel();

	//
	// Cancel the request...
	//
	iRetrieveMobilePhoneSmspList->Cancel();

	//
	// Handle completion of this Active Object. Note that the object
	// may well still be active at this point...
	//
	if (TimedOut())
		{
		Complete(KErrTimedOut);
		}
	else
		{
		Complete(KErrCancel);
		}
	} // CSmsReadParams::DoCancel


/**
 *  Constructor
 *  
 *  @param aSmsComm a reference to the protocol.
 *  @param aSmsSettings a reference to the global SMS settings.
 *  @param aSmsMessaging a reference to the ETEL SMS messaging subsession.
 *  
 */
CSmsReadParams::CSmsReadParams(MSmsComm& aSmsComm,const TSmsSettings& aSmsSettings,RMobileSmsMessaging& aSmsMessaging):
	CSmsParamsBase(aSmsComm,aSmsSettings,aSmsMessaging)
	{
	} // CSmsReadParams::CSmsReadParams


/**
 *  2nd Phase of construction.
 *  
 *  Creates CRetrieveMobilePhoneSmspList object.
 *  
 */
void CSmsReadParams::ConstructL()
	{
	LOGSMSPROT1("CSmsReadParams::ConstructL()");

	CSmsParamsBase::ConstructL();

	iRetrieveMobilePhoneSmspList = CRetrieveMobilePhoneSmspList::NewL(iSmsMessaging);
	} // CSmsReadParams::ConstructL


/**
 *  Check validity of SMSP list. List shouldn't contain more entries that can be stored
 *  to phone-side storage.
 *  Set maximum number of enties value to the client's list.
 *  
 *  @param aMobilePhoneSmspList a reference to the CMobilePhoneSmspList object.
 *  @leave Leave if aMobilePhoneSmspList object contains too many SMSP sets.
 *  
 */
void CSmsReadParams::CheckListValidityL(CMobilePhoneSmspList& aMobilePhoneSmspList)
	{
	LOGSMSPROT1("CSmsReadParams::CheckListValidityL()");

	//
	// MaxNumberEntries method returns the maximum number of entries that can
	// be stored in this list. This attribute is required because most phone-side
	// storage will have an upper storage limit. If the TSY has not set this
	// attribute during a list retrieval then the value returned will be -1.
	//
	if (iMobilePhoneSmspList->MaxNumberEntries() != -1)
		{
		if (aMobilePhoneSmspList.Enumerate() > iMobilePhoneSmspList->MaxNumberEntries())
			{
			User::Leave(KErrArgument); 
			}

		aMobilePhoneSmspList.SetMaxNumberEntries(iMobilePhoneSmspList->MaxNumberEntries());
		}
	} // CSmsReadParams::CheckListValidityL


/**
 *  Store successfully saved parameters also to SMSPROT's internal memory. Actually
 *  StoreParameters takes ownership of aMobilePhoneSmspList.
 *  
 *  Delete old list and set iMobilePhoneSmspList to point to the new SMSP list.
 *  
 *  @param aMobilePhoneSmspList a reference to the CMobilePhoneSmspList object.
 *  
 */
void CSmsReadParams::StoreParameters(CMobilePhoneSmspList* aMobilePhoneSmspList)
	{
	LOGSMSPROT1("CSmsReadParams::StoreParameters()");

	__ASSERT_DEBUG(iMobilePhoneSmspList != NULL && aMobilePhoneSmspList != NULL && iMobilePhoneSmspList->MaxNumberEntries() == aMobilePhoneSmspList->MaxNumberEntries(),SmspPanic(KSmspPanicCorruptedSmspList));

	delete iMobilePhoneSmspList;
	iMobilePhoneSmspList = aMobilePhoneSmspList;
	} // CSmsReadParams::StoreParameters


/**
 *  Completes read request or cancel read request.
 *  
 *  Cancel timeout timer.
 *  Complete request to the CSmsWriteParams object or observer.
 *  
 *  @param aStatus a status value.
 *  
 */
void CSmsReadParams::Complete(TInt aStatus)
	{
	LOGSMSPROT1("CSmsReadParams::Complete()");

	//
	// Call the base function to perform the actual complete...
	//
	CSmsuActiveBase::Complete(aStatus);

	if (iSmsMessageObserver != NULL  &&
		iSmsComm.ObserverIsPresent(*iSmsMessageObserver))
		{
		iSmsMessageObserver->ReadSmsParamsCompleted(aStatus, iMobilePhoneSmspList);
		iSmsMessageObserver = NULL;
		}
	} // CSmsReadParams::Complete


/**
 *  2 Phase constructor.
 *  
 *  @param aSmsComm a reference to the protocol.
 *  @param aSmsSettings a reference to the global SMS settings.
 *  @param aSmsMessaging a reference to the ETEL SMS messaging subsession.
 *  @param aSmsReadParams a reference to the CSmsReadParams object.
 *  @leave Leaves if ContructL() leaves, or not enough memory is available.
 *  @return a new CSmsReadParams object.
 *  
 */
CSmsWriteParams* CSmsWriteParams::NewL(MSmsComm& aSmsComm,const TSmsSettings& aSmsSettings,RMobileSmsMessaging& aSmsMessaging,CSmsReadParams& aSmsReadParams)
	{
	LOGSMSPROT1("CSmsWriteParams::NewL()");

	CSmsWriteParams* smsWriteParams=new(ELeave) CSmsWriteParams(aSmsComm,aSmsSettings,aSmsMessaging,aSmsReadParams);
	CleanupStack::PushL(smsWriteParams);
	smsWriteParams->ConstructL();
	CleanupStack::Pop(smsWriteParams);
	return smsWriteParams;
	} // CSmsWriteParams::NewL


/**
 *  Destructor
 *  
 *  Cancel writing process and delete all created objects.
 *  
 */
CSmsWriteParams::~CSmsWriteParams()
	{
	Cancel();
	delete iMobilePhoneSmspList;
	} // CSmsWriteParams::~CSmsWriteParams


/**
 *  Start writing of SMS parameters process.
 *  Set state to ESmsParamsStoringList.
 *  Read parameters to SMSPROT's internal memory if client tries to write
 *  parameters before SMSPROT has read them. This is because SMSPROT has to
 *  deliver whole SMSP list while making StoreSmspList request to the MM ETel.
 *  If client deliver only some SMSP sets while making write request, we have
 *  to add missing SMSP sets to the clients list.
 *  Set timeout timer on.
 *  
 *  @param aObserver a reference to the observer object.
 *  @param aMobilePhoneSmspList a pointer to SMSP list to be saved.
 *  
 */
void CSmsWriteParams::Start(MSmsMessageObserver& aObserver,CMobilePhoneSmspList* aMobilePhoneSmspList)
	{
	LOGSMSPROT1("CSmsWriteParams::Start()");

	__ASSERT_DEBUG(iState==ESmsParamsIdle,SmspPanic(KSmspPanicUnexpectedState));
	
	iState = ESmsParamsStoringList;

	iSmsMessageObserver= &aObserver;
	iMobilePhoneSmspList=aMobilePhoneSmspList;

	//
	//Read parameters to SMSPROT's internal memory before starting writing process...
	//
	iSmsReadParams.Start(iStatus);

	TimedSetActive(iSmsSettings.Timeout());
	} // CSmsWriteParams::Start


/**
 *  Store SMSP list to phone. If storing was successful, store list also
 *  to CSmsReadParams object.
 *  
 *  Cancel timeout timer.
 *  State ESmsParamsStoringList:
 *  Change state to ESmsParamsStoringListToInternal.
 *  Check validity of SMSP list using CSmsReadParams objects services.
 *  After that makes StoreSmspList request to the MM ETel.
 *  Set timeout timer on.
 *  State ESmsParamsStoringListToInternal:
 *  Store successfully stored parameters to CSmsReadParams object.
 *  
 *  @leave Leaves if there was an error.
 *  @leave Leave if RetrieveListL() leaves.
 *  @leave Leave if StoreSmspListL() leaves.
 *  @leave Panic if RunL is called while object is in idle state.
 *  
 */
void CSmsWriteParams::DoRunL()
	{
	LOGSMSPROT2("CSmsWriteParams::DoRunL [iStatus=%d]", iStatus.Int() );

	switch (iState)
		{
		case ESmsParamsStoringList:
			{
			//
			// Request the list to be stored...
			//
			if (iStatus.Int() == KErrNone)
				{
				iState = ESmsParamsStoringListToInternal;

				iSmsReadParams.CheckListValidityL(*iMobilePhoneSmspList);
				iSmsMessaging.StoreSmspListL(iStatus, iMobilePhoneSmspList);

				TimedSetActive(iSmsSettings.Timeout());
				}
			}
			break;

		case ESmsParamsStoringListToInternal:
			{
			//
			// If the list was stored successfully, then store it internally.
			//
			if (iStatus.Int() == KErrNone)
				{
				iSmsReadParams.StoreParameters(iMobilePhoneSmspList);

				//
				// Set iMobilePhoneSmspList to NULL because it points now to SMSPROT's
				// internal parameter storage.
				//
				iMobilePhoneSmspList = NULL;
				}
			}
			break;

		default:
			{
			SmspPanic(KSmspPanicUnexpectedState);
			}
			break;
		}

	//
	// DoRunL() will now return to CSmsuActiveBase which if the object
	// is not active, will call Complete().
	//
	} // CSmsWriteParams::DoRunL


/**
 *  Handles cancel write parameters request.
 *  
 *  Cancel timeout timer. Cancel reading and writing processes
 *  if they are running.
 *  
 */
void CSmsWriteParams::DoCancel()
	{
	LOGSMSPROT1("CSmsWriteParams::DoCancel()");

	TimedSetActiveCancel();

	switch (iState)
		{
		case ESmsParamsStoringList:
			{
			iSmsReadParams.Cancel();
			}
			break;

		case ESmsParamsStoringListToInternal:
			{
			iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingStoreSmspList);
			}
			break;

		default:
			{
			SmspPanic(KSmspPanicUnexpectedState);
			}
			break;
		}

	//
	// Handle completion of this Active Object. Note that the object
	// may well still be active at this point...
	//
	if (TimedOut())
		{
		Complete(KErrTimedOut);
		}
	else
		{
		Complete(KErrCancel);
		}
	} // CSmsWriteParams::DoCancel


/**
 *  Constructor
 *  
 *  @param aSmsComm a reference to the protocol.
 *  @param aSmsSettings a reference to the global SMS settings.
 *  @param aSmsMessaging a reference to the ETEL SMS messaging subsession.
 *  @param aSmsReadParams a reference to the CSmsReadParams object.
 *  
 */
CSmsWriteParams::CSmsWriteParams(MSmsComm& aSmsComm,const TSmsSettings& aSmsSettings,RMobileSmsMessaging& aSmsMessaging,CSmsReadParams& aSmsReadParams):
	CSmsParamsBase(aSmsComm,aSmsSettings,aSmsMessaging),
	iState(ESmsParamsIdle),
	iSmsReadParams(aSmsReadParams)
	{
	} // CSmsWriteParams::CSmsWriteParams


/**
 *  2nd Phase of construction.
 *  
 *  Creates CSmsuTimeout object.
 *  
 */
void CSmsWriteParams::ConstructL()
	{
	LOGSMSPROT1("CSmsWriteParams::ConstructL()");

	CSmsParamsBase::ConstructL();
	} // CSmsWriteParams::ConstructL


/**
 *  Completes write request or cancel write request.
 *  
 *  Cancel timeout timer. Set state to ESmsParamsIdle. Complete request to the
 *  observer.
 *  
 *  @param aStatus a status value.
 *  @leave Panic if Complete is called while object is in ESmsParamsIdle state.
 *  
 */
void CSmsWriteParams::Complete(TInt aStatus)
	{
	LOGSMSPROT1("CSmsWriteParams::Complete()");

	//
	// Call the base function to perform the actual complete...
	//
	CSmsuActiveBase::Complete(aStatus);

	delete iMobilePhoneSmspList;
	iMobilePhoneSmspList = NULL;

	iState = ESmsParamsIdle;

	if (iSmsComm.ObserverIsPresent(*iSmsMessageObserver))
		{
		iSmsMessageObserver->WriteSmsParamsCompleted(aStatus);
		iSmsMessageObserver = NULL;
		}
	} // CSmsWriteParams::Complete
