// Copyright (c) 2003-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 "Ctlsbrowsetoken.h"
#include "tlsprovider.h"

#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include <tlstypedef_internal.h>
#endif


//
//  CTlsBrowseToken
//


CTlsBrowseToken* CTlsBrowseToken::NewL()
	{ 
	CTlsBrowseToken* aPtrClnt = new (ELeave)CTlsBrowseToken();
	return(aPtrClnt);
	}


CTlsBrowseToken::CTlsBrowseToken():CActive(0)
	{
	if(CActiveScheduler::Current()) //Already installed?
		{
		CActiveScheduler::Add( this );
		}
	}

void CTlsBrowseToken::StartBrowsingL(RArray<CTokenTypesAndTokens>& aListAllTokensAndTypes,
									TRequestStatus& aStatus)
	{
	
	
	aStatus = KRequestPending;
	User::LeaveIfError(iFs.Connect());
	iOriginalRequestStatus = &aStatus;

	iListAllTokensAndTypes = &aListAllTokensAndTypes;
	TLSPROV_LOG(_L("Listing all types and tokens"))

	//The following functions fills the tokentype info in iTokenTypeInfo array.
	TLSPROV_LOG(_L("Browsing for Tokens..."))
	ListTokenTypesL();		
	}

void CTlsBrowseToken::ListTokenTypesL()
	{
	iCurrentTokentype= 0;  
		
	//Filter defining the expected interface
	RArray<TUid> Interface;
	CleanupClosePushL(Interface);	
	User::LeaveIfError(Interface.Append(TUid::Uid(KInterfaceTLSTokenProvider)));
	User::LeaveIfError(Interface.Append(TUid::Uid(KInterfaceTLSSession)));
	TCTFindTokenTypesByInterface filter(Interface.Array());
			
	//List all the tokentypes supported [eg. Software Token, WIM1, WIM2, etc]	
	CCTTokenTypeInfo::ListL(iTokenTypeInfo, filter);
	CleanupStack::Pop(&Interface);	// Interface
	Interface.Close();

	iTotalTokenTypeCount = iTokenTypeInfo.Count();
	if(!iTotalTokenTypeCount)
		{
		//Not possible..Software token always present
		User::Leave(KErrNoTokenTypes);
		}	
	BrowseTokenTypesL();
	}

TInt CTlsBrowseToken::TotalTypeCount()
	{
	return iTotalTokenTypeCount;
	}

/*
The following function gets a handle to a new token type. If any of the interfaces in opening 
a token fails and if no other tokens are present in the token type, this function will be then called 
to browse for the next token type if any.
*/
void CTlsBrowseToken::BrowseTokenTypesL()
	{
	//Now we try opening the token types here
	TInt Error = KErrNone;
	while( iCurrentTokentype  < iTotalTokenTypeCount)
		{
		if(iPtrTokenType)
			iPtrTokenType->Release();
	
		TRAP(Error,(iPtrTokenType = MCTTokenType::NewL(*iTokenTypeInfo[iCurrentTokentype], iFs)));
		
		if(Error != KErrNone)
			{
			//This Token type couldnt be opened..try the next one if present
         iPtrTokenType = NULL;
			if((iCurrentTokentype + 1) <= iTotalTokenTypeCount)
				{
				(iCurrentTokentype++);
				continue;
				}
			else
				User::Leave(Error); 
			}
		else
			{
			//List all those tokens in that type
			iCurrentState = EGetTokenList;
			iStatus = KRequestPending;
			iTokenList.Close();
			iPtrTokenType->List(iTokenList,iStatus);
			SetActive();
			return;
			}		
		}

	//Will only come here if every token has been browsed
	iCurrentTokentype= 0;
	User::RequestComplete(iOriginalRequestStatus, Error); 
	}


void CTlsBrowseToken::OnEGetTokenListL()
	{

	TLSPROV_LOG(_L("Obtaining the list of Tokens in a type"))
				
	if(!iStatus.Int()) //Token list for a particular Token type obtained successfully
		{
		iTotalTokensinType = iTokenList.Count();
		iCurrentToken = 0;
		if(iTotalTokensinType)
			{
			iStatus = KRequestPending;
			iCurrentState = EOpenToken;	
			iPtrTokenType->OpenToken((*iTokenList[0]), iTokenHandle, iStatus);
			SetActive();
			return;							
			}
		}	
	//Try for any other TokenTypes? If not present BrowseTokenTypesL() will complete
	iCurrentTokentype++;
	BrowseTokenTypesL();									
	}

void CTlsBrowseToken::OnEOpenTokenL()
	{		
	if(!iStatus.Int())
		{		
		iStatus = KRequestPending;
		iCurrentState = EGetProviderInterface;
		iTokenHandle->GetInterface(UidProv,iTokenInterface,iStatus);
		SetActive();
		return;
		}		
	
	//This token failed, try another one
	iCurrentTokentype++;
	BrowseTokenTypesL();
	}

void CTlsBrowseToken::OnEGetProviderInterfaceL()
	{
	if(!iStatus.Int()) 
		{
		TLSPROV_LOG(_L("Provider Interface for this token obtained successfully"))
				
      CTokenTypesAndTokens* tempObj = new CTokenTypesAndTokens;
      if ( !tempObj || iListAllTokensAndTypes->Append(*tempObj) != KErrNone )
         {
   		delete tempObj;
         iTokenHandle->Release();
         iTokenHandle = NULL;
         User::Leave( KErrNoMemory );
         }
  		delete tempObj;
      CTokenTypesAndTokens& Tokens = (*iListAllTokensAndTypes)[iListAllTokensAndTypes->Count() - 1];
      Tokens.iTokenInfo = new CTokenInfo;
      if ( !Tokens.iTokenInfo  )
         {
         iTokenHandle->Release();
         iTokenHandle = NULL;
         User::Leave( KErrNoMemory );
         }

      iTokenHandle = NULL; //owned by iProviderInterface
		Tokens.iProviderInterface = static_cast<MTLSTokenProvider*>(iTokenInterface);
      iTokenInterface = NULL;
   
					
		iCurrentState = EGetCiphers;
		iStatus = KRequestPending;
		
		Tokens.iProviderInterface->CryptoCapabilities(
			Tokens.iTokenInfo->iSupportedProtocols,
			Tokens.iTokenInfo->aKeyExchAlgs,
			Tokens.iTokenInfo->aSignatureExchAlgs,
			iStatus);		
		SetActive();
		return;

		}
	
	iCurrentTokentype++;
	BrowseTokenTypesL();
	}


void CTlsBrowseToken::RunL()
	{
	if(iStatus.Int() == KErrNoMemory)
		{
		User::RequestComplete(iOriginalRequestStatus, iStatus.Int()); 
		iCurrentState = ENullState;
		return;
		}

	switch(iCurrentState)
		{
	case EGetTokenList:
		OnEGetTokenListL();
		break;
	case EOpenToken:
		OnEOpenTokenL();
		break;
	case EGetProviderInterface:
		{
		OnEGetProviderInterfaceL();
		}
		break;
	case EGetCiphers:
		{		

      CTokenTypesAndTokens& Tokens = (*iListAllTokensAndTypes)[iListAllTokensAndTypes->Count() - 1];
		Tokens.iTotalTokenCount = iTotalTokensinType;

		const TUid KSoftwareTokenType = {0x101FE20D};
		TLSPROV_LOG2(_L("loaded ECOM TLS tokentype plugin with uid = %08x"), ((Tokens.iProviderInterface->Token()).TokenType()).Type())
		if(((Tokens.iProviderInterface->Token()).TokenType()).Type() == KSoftwareTokenType)
			Tokens.iSoftwareToken = ETrue;
		else
			Tokens.iSoftwareToken = EFalse;

		
		iCurrentTokentype++;
		BrowseTokenTypesL();
		}
		break;
	case EGetSessionInterface:
		{
		TLSPROV_LOG(_L("Session Interface for this token obtained successfully"))
		*iSessionInterface = static_cast<MTLSSession*>(iTokenInterface);
      iTokenInterface = NULL;
		User::RequestComplete(iOriginalRequestStatus, iStatus.Int()); 
		}
		break;
	default:
		break;
		}

	}


void CTlsBrowseToken::GetSessionInterface(MTLSTokenProvider* aProviderInterface,
										  MTLSSession*& aSessionInterface,
										  TRequestStatus& aStatus)
	{
	aStatus = KRequestPending;	
	iSessionInterface = &aSessionInterface;
	iCurrentState = EGetSessionInterface;
	iOriginalRequestStatus = &aStatus;
	iTokenInterface = 0;
	iStatus = KRequestPending;
	iTokenProvider = aProviderInterface;
	(aProviderInterface->Token()).GetInterface(UidSess,iTokenInterface,iStatus);
	SetActive();
	return;
	}

TInt CTlsBrowseToken::RunError(TInt aError)
	{
	User::RequestComplete(iOriginalRequestStatus, aError); 
	return KErrNone;
	}

void CTlsBrowseToken::CancelRequest()
	{
	Cancel();
	return;
	}
void CTlsBrowseToken::DoCancel()
	{
	switch (iCurrentState)
		{
	case EGetTokenList:
		iPtrTokenType->CancelList();
		break;
		
	case EOpenToken:
		iPtrTokenType->CancelOpenToken();
		break;
		
	case EGetProviderInterface:
		iTokenHandle->CancelGetInterface();
		break;
	
	case EGetSessionInterface:
		(iTokenProvider->Token()).CancelGetInterface();
		break;		

	case EGetCiphers:
		MTLSTokenProvider* provider = static_cast<MTLSTokenProvider*>(iTokenInterface);
		provider->CancelCryptoCapabilities();
		break;

		}
	iCurrentState=ENullState;
	User::RequestComplete(iOriginalRequestStatus, KErrCancel);
	return;
	}

CTlsBrowseToken::~CTlsBrowseToken()
	{
	if(iPtrTokenType)
		{
		iPtrTokenType->Release();
		}
		
	iTokenTypeInfo.Close();
	iTokenList.Close();
	
	if ( iTokenInterface )
		{
		iTokenInterface->Release();
		}
		
	if(iTokenHandle)
		{
		iTokenHandle->Release();
		}
		
	iFs.Close();
	
	return;
	}
