// Copyright (c) 2005-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 Phone IMS Authorization/Authentication code.
// 
//

/**
 @file
*/

#include <testconfigfileparser.h>
#include <etelmmerr.h>
#include "CSimPhone.h"
#include "Simlog.h"

//
// CSimPhoneIMSAuth
//

CSimPhoneIMSAuth* CSimPhoneIMSAuth::NewL(CSimPhone* aPhone)
/**
 * Standard two phase constructor.
 * @param aPhone The phone object from which the Phone Smart Card applications will open
 */
	{
	CSimPhoneIMSAuth* obj=new(ELeave) CSimPhoneIMSAuth(aPhone);
	CleanupStack::PushL(obj);
	obj->ConstructL();
	CleanupStack::Pop();
	return obj;
	}

CSimPhoneIMSAuth::CSimPhoneIMSAuth(CSimPhone* aPhone)
	: iPhone(aPhone)
/**
 * Trivial first phase constructor.
 * @param aPhone	The phone object from which this Phone SmartCard App was opened.
 */
	{}


void CSimPhoneIMSAuth::ConstructL()
/**
* Second phase of the 2-phase constructor.
* Constructs all the member data and retrieves all the data from the config file specific to this class.
*
* @leave Leaves due to not enough memory or if any data member does not construct for any reason.
*/
	{
	iTimer=CSimTimer::NewL(iPhone);
	iGetAuthorizationData = new CArrayPtrFlat<CListReadAllAttempt>(1);
	LOGPHONE1("Starting to parse Phone IMS Authorization/Authentication config params...");
	ParseAuthorizationInfoL();
	ParseAuthenticationInfoL();
	LOGPHONE1("Finished parsing Phone IMS Authorization/Authentication config params...");
	}


CSimPhoneIMSAuth::~CSimPhoneIMSAuth()
/**
 * Standard destructor.  Any objects created by the ::ConstructL() function
 * will be destroyed here.
 */
	{
	delete iTimer;
	if(iGetAuthorizationData)
		{
		iGetAuthorizationData->ResetAndDestroy();
		}
	delete iGetAuthorizationData;

	TInt authInfoCount = iAuthorizationInfoList.Count();
	TInt ii;
	for(ii = 0; ii < authInfoCount; ii++)
		{
		iAuthorizationInfoList[ii].iIMPUArray.Close();
		}
	iAuthorizationInfoList.Close();

	iAuthenticationInfoList.Close();

	//RAJ TODO
	}


const CTestConfigSection* CSimPhoneIMSAuth::CfgFile()
/**
* Returns a pointer to the config file section
*
* @return CTestConfigSection a pointer to the configuration file data section
*/
	{
	LOGPHONE1(">>CSimPhoneIMSAuth::CfgFile");
	return iPhone->CfgFile();
	}

void CSimPhoneIMSAuth::TimerCallBack(TInt /*aId*/)
/**
* Timer callback function.  When the timer goes off, it will call back into this
* function for further processing.
*
* @param aId an id identifying which timer callback is being called
*/	
	{
	iTimerStarted = EFalse;
	iCurrentAuthorizationInfo++;
	if(iAuthInfoChangeNotifyPending)
		{
		iAuthInfoChangeNotifyPending = EFalse;
		iPhone->ReqCompleted(iAuthInfoChangeNotifyReqHandle, KErrNone);
		}
	}
	
void CSimPhoneIMSAuth::ParseAuthorizationInfoL()
/**
* Parses the list of Authorization Info tags from the Config file
*
*/
	{
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;
	TPtrC8 IMPI, IMPUValue, HNDN;
	TInt IMPUCount, authorizationDataSource, infoChangeDelay;
	TAuthorizationInfo authorizationInfo;
	
	LOGPHONE1("Starting to Parse IMS Authorization Info");
	TInt count = CfgFile()->ItemCount(KAuthorizationInfo);
	
	TInt index;
	for(index=0;index<count;index++)
		{
		item=CfgFile()->Item(KAuthorizationInfo,index);
		TInt delimiterNum = 0;
		if(!item)
			{
			break;
			}
			
		//Get the IMPI
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,IMPI);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
			continue;
			}
		else
			{
			authorizationInfo.iIMPI.Copy(IMPI);
			delimiterNum++;
			}

		//Get number of elements in the IMPU Array
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,IMPUCount);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
			continue;
			}
		else
			{
			delimiterNum++;
			RArray<RMobilePhone::TIMPU> IMPUArray;
			TBool IMPUError = EFalse;
			
			//Get the IMPU values
			TInt ii;
			for(ii = 0;ii < IMPUCount; ii++)
				{
				ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,IMPUValue);
				if(ret!=KErrNone)
					{
					LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
					IMPUError = ETrue;
					break;
					}
				else
					{
					IMPUArray.Append(IMPUValue);
					delimiterNum++;
					}
				}
			
			if(IMPUError)
				{
				LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
				continue;
				}
			else
				{
				authorizationInfo.iIMPUArray = IMPUArray;	
				}
			}
			
		//Get the HNDN
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,HNDN);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
			continue;
			}
		else
			{
			authorizationInfo.iHomeNetworkDomainName.Copy(HNDN);
			delimiterNum++;
			}
			
		//Get the Authorization Data Source
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,authorizationDataSource);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
			continue;
			}
		else
			{
			authorizationInfo.iAuthenticationDataSource = 
				static_cast<RMobilePhone::TAuthorizationDataSource>(authorizationDataSource);
				
			delimiterNum++;
			}
		
		//Get the Authorization Info change delay
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,delimiterNum,infoChangeDelay);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHORIZATION INFO TAG");
			continue;
			}
		else
			{
			authorizationInfo.iInfoChangeDelay = infoChangeDelay;
			}		
		
		iAuthorizationInfoList.Append(authorizationInfo);
		}//end FOR Loop
	iCurrentAuthorizationInfo = 0;
	}

void CSimPhoneIMSAuth::ParseAuthenticationInfoL()
/**
* Parses the list of Authentication Info tags from the Config file
*
*/
	{
	const CTestConfigItem* item=NULL;
	TInt ret=KErrNone;
	TPtrC8 AUTN, RAND, RES, IK, CK, AUTS;
	TInt authErr;
	TAuthenticationInfo authenticationInfo;
	
	LOGPHONE1("Starting to Parse IMS Authentication Info");
	TInt count = CfgFile()->ItemCount(KAuthenticationInfo);
	
	TInt index;
	for(index=0; index<count; index++)
		{
		item=CfgFile()->Item(KAuthenticationInfo,index);
		if(!item)
			{
			break;
			}
			
		//Get the AUTN
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,AUTN);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iAUTN.Copy(AUTN);
			}

		//Get the RAND
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,RAND);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iRAND.Copy(RAND);
			}

		//Get the RES
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,RES);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iRES.Copy(RES);
			}
		
		//Get the IK
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,3,IK);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iIK.Copy(IK);
			}

		//Get the CK
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,4,CK);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iCK.Copy(CK);
			}

		//Get the AUTS
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,5,AUTS);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iAUTS.Copy(AUTS);
			}
		
		//Get authentication error
		ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,6,authErr);
		if(ret!=KErrNone)
			{
			LOGPHONE1("ERROR IN CONFIGURATION FILE PARSING: BAD AUTHENTICATION INFO TAG");
			continue;
			}
		else
			{
			authenticationInfo.iAuthenticationErr = authErr;
			}
		
		iAuthenticationInfoList.Append(authenticationInfo);	
		}//end FOR Loop
	}

TInt CSimPhoneIMSAuth::GetAuthorizationInfoPhase1(const TTsyReqHandle aTsyReqHandle, 
			RMobilePhone::TClientId* aClientId,TInt* aBufSize)
	{
	LOGPHONE1("CSimPhoneIMSAuth::GetAuthorizationInfoPhase1 called");
	TInt ret(KErrNone);
	TInt leaveCode(KErrNone);
	TRAP(leaveCode, ret=ProcessGetAuthorizationInfoPhase1L(aTsyReqHandle, aClientId, aBufSize););
	if (leaveCode != KErrNone)
		{
		iPhone->ReqCompleted(aTsyReqHandle,leaveCode);
		}
		
	return ret;
	}


TInt CSimPhoneIMSAuth::ProcessGetAuthorizationInfoPhase1L(const TTsyReqHandle aTsyReqHandle,
			RMobilePhone::TClientId* aClientId, TInt* aBufSize)
	{
		LOGPHONE1("CSimPhoneIMSAuth::GetAuthorizationInfoPhase1 called");	

	// Store the streamed list and the client ID
	CListReadAllAttempt* read=CListReadAllAttempt::NewL(*aClientId,aTsyReqHandle);
	CleanupStack::PushL(read);
	
	RMobilePhone::CImsAuthorizationInfoV5* iAuthInfo = RMobilePhone::CImsAuthorizationInfoV5::NewL();
    CleanupStack::PushL(iAuthInfo);

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(*iAuthInfo);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aTsyReqHandle, err);
        CleanupStack::PopAndDestroy(2, read); // iAuthInfo, read		
		return KErrNone;
		}

	iAuthInfo->iIMPI = iAuthorizationInfoList[iCurrentAuthorizationInfo].iIMPI;

	TInt IMPUCount = iAuthorizationInfoList[iCurrentAuthorizationInfo].iIMPUArray.Count();
	TInt index;
	for(index = 0; index < IMPUCount; index++)
		{
		iAuthInfo->iIMPUArray.Append(iAuthorizationInfoList[iCurrentAuthorizationInfo].iIMPUArray[index]);
		}

	iAuthInfo->iHomeNetworkDomainName = 
		iAuthorizationInfoList[iCurrentAuthorizationInfo].iHomeNetworkDomainName;
	iAuthInfo->iAuthenticationDataSource = 
		iAuthorizationInfoList[iCurrentAuthorizationInfo].iAuthenticationDataSource;
	
	HBufC8* iBuff=NULL;
	iAuthInfo->ExternalizeL(iBuff);
    CleanupStack::PopAndDestroy(iAuthInfo);	
	CleanupDeletePushL(iBuff);
		
	CBufFlat* buf=CBufFlat::NewL(iBuff->Length());
	CleanupStack::PushL(buf);
	buf->InsertL(0,*iBuff);	
	
	read->iListBuf = buf;
	CleanupStack::Pop(buf);	
	CleanupStack::PopAndDestroy(iBuff);
	
	iGetAuthorizationData->AppendL(read);
    CleanupStack::Pop(read);
	
	// return the CBufBase’s size to client
	*aBufSize=(read->iListBuf)->Size();
	
	// Complete first phase of list retrieval
	iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
	return KErrNone;
	
	}


TInt CSimPhoneIMSAuth::GetAuthorizationInfoPhase2(const TTsyReqHandle aTsyReqHandle,
			RMobilePhone::TClientId* aClientId, TDes8* aBuffer)
	{
	LOGPHONE1("CSimPhoneIMSAuth::GetAuthorizationInfoPhase2 called");	
	CListReadAllAttempt* read=NULL;

	// Find the get Authorization Info attempt from this client
	TInt index;
	for (index = 0; index < iGetAuthorizationData->Count(); index++)
		{
		read = iGetAuthorizationData->At(index);
		if ((read->iClient.iSessionHandle==aClientId->iSessionHandle) &&
		    (read->iClient.iSubSessionHandle==aClientId->iSubSessionHandle))
			{
			TPtr8 bufPtr((read->iListBuf)->Ptr(0));
			// Copy the streamed list to the client
			aBuffer->Copy(bufPtr);
			delete read;
			iGetAuthorizationData->Delete(index);
			iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
			return KErrNone;
			}
		}
	iPhone->ReqCompleted(aTsyReqHandle,KErrBadHandle);
	return KErrNone;	
	}


TInt CSimPhoneIMSAuth::GetAuthorizationInfoCancel(const TTsyReqHandle aTsyReqHandle)
	{
	LOGPHONE1("CSimPhoneIMSAuth::GetAuthorizationInfoCancel called");

	// Remove the read all attempt from iGetAuthorizationData
	CListReadAllAttempt* read=NULL;
	TInt index;
	for (index = 0; index <iGetAuthorizationData->Count(); index++)
		{
		read = iGetAuthorizationData->At(index);
		if (read->iReqHandle == aTsyReqHandle)
			{
			delete read;
			iGetAuthorizationData->Delete(index);
			break;
			}
		}
		
	iPhone->ReqCompleted(aTsyReqHandle,KErrCancel);
	return KErrNone;
	}


TInt CSimPhoneIMSAuth::NotifyImsAuthorizationInfoChanged(const TTsyReqHandle aTsyReqHandle)
	{
	LOGPHONE1("CSimPhoneIMSAuth::NotifyImsAuthorizationInfoChanged called");
	__ASSERT_ALWAYS(!iAuthInfoChangeNotifyPending,SimPanic(ENotificationReqAlreadyOutstanding));

	TInt count=iAuthorizationInfoList.Count();
	if(iCurrentAuthorizationInfo < count)
		{
		iTimer->Start(iAuthorizationInfoList[iCurrentAuthorizationInfo].iInfoChangeDelay,this);
		iTimerStarted = ETrue;
		}

	iAuthInfoChangeNotifyPending=ETrue;
	iAuthInfoChangeNotifyReqHandle = aTsyReqHandle;		

	return KErrNone;
	}


TInt CSimPhoneIMSAuth::NotifyImsAuthorizationInfoChangedCancel(const TTsyReqHandle aTsyReqHandle)
	{
	LOGPHONE1("CSimPhoneIMSAuth::NotifyImsAuthorizationInfoChangedCancel called");
	if(iAuthInfoChangeNotifyPending)
		{
		if(iTimerStarted)
			{
			iTimer->Cancel();
			}

		iAuthInfoChangeNotifyPending=EFalse;
		iPhone->ReqCompleted(aTsyReqHandle, KErrCancel);
		}

	return KErrNone;
	}


TInt CSimPhoneIMSAuth::GetAuthenticationData(const TTsyReqHandle aTsyReqHandle,TDes8* aAuthenticationData)
	{
	LOGPHONE1("CSimPhoneIMSAuth::AuthentificationData called");

	RMobilePhone::TImsAuthenticateDataV5Pckg* authenticateDataPckgd =
			(RMobilePhone::TImsAuthenticateDataV5Pckg*)aAuthenticationData;
	RMobilePhone::TImsAuthenticateDataV5& authenticateData=(*authenticateDataPckgd)();

	// Check that the data structure is supported by the simulated TSY version
	TInt err = iPhone->CheckSimTsyVersion(authenticateData);
	if(err != KErrNone)
		{
		iPhone->ReqCompleted(aTsyReqHandle, err);
		return KErrNone;
		}

	TInt index;
	for(index = 0; index < iAuthenticationInfoList.Count(); index++)
		{
		if(authenticateData.iAUTN == iAuthenticationInfoList[index].iAUTN &&
			authenticateData.iRAND == iAuthenticationInfoList[index].iRAND)
			{
			TInt ret = iAuthenticationInfoList[index].iAuthenticationErr;
			if(ret != KErrNone)
				{
				//return the AUTS and blank everything else
				authenticateData.iAUTS = iAuthenticationInfoList[index].iAUTS;
				authenticateData.iRES = _L8("");
				authenticateData.iIK = _L8("");
				authenticateData.iCK = _L8("");
				}
			else
				{
				authenticateData.iRES = iAuthenticationInfoList[index].iRES;
				authenticateData.iIK = iAuthenticationInfoList[index].iIK;
				authenticateData.iCK = iAuthenticationInfoList[index].iCK;
				}

			iPhone->ReqCompleted(aTsyReqHandle, ret);
			return KErrNone;
			}
		}

	iPhone->ReqCompleted(aTsyReqHandle, KErrCorrupt);
	return KErrNone;
	}


TInt CSimPhoneIMSAuth::GetAuthenticationDataCancel(const TTsyReqHandle aTsyReqHandle)
	{
	LOGPHONE1("CSimPhoneIMSAuth::AuthentificationDatCancel called");	
	iPhone->ReqCompleted(aTsyReqHandle, KErrCancel);
	return KErrNone;
	}
