/*
* Copyright (c) 2002 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 authentication
*
*/



#include <imcvcodc.h>
#include <e32math.h>
#include "NSmlAuth.h"
#include "nsmlcliagconstants.h"
#include "NSmlAgentBase.h"
#include "nsmlagenttestdefines.h"



// ---------------------------------------------------------
// CNSmlAuth::CNSmlAuth()
// Constructor, nothing special in here.
// ---------------------------------------------------------
//
CNSmlAuth::CNSmlAuth()
	{
	}

// ---------------------------------------------------------
// CNSmlAuth::~CNSmlAuth()
// Destructor
// ---------------------------------------------------------
//
CNSmlAuth::~CNSmlAuth()
	{
	delete iCredential;
	delete iType;
	delete iFormat;
	delete iNonce;
	delete iB64Nonce;
	}

// ---------------------------------------------------------
// CNSmlAuth::NewL()
// Creates new instance of CNSmlAuth. 
// ---------------------------------------------------------
//
EXPORT_C CNSmlAuth* CNSmlAuth::NewL()
	{
	CNSmlAuth* self = new (ELeave) CNSmlAuth();
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop();
	return( self );
	}
// ---------------------------------------------------------
// CNSmlAuth::SetSyncAgent()
// 
// ---------------------------------------------------------
EXPORT_C void CNSmlAuth::SetSyncAgent( CNSmlAgentBase* aAgent ) 
	{
	iAgent = aAgent;
	}
// ---------------------------------------------------------
// CNSmlAuth::SetCredentialL()
// 
// ---------------------------------------------------------
//
EXPORT_C void CNSmlAuth::SetCredentialL( const TDesC8& aCredential )
	{
	delete iCredential;
	iCredential = NULL;
	iCredential = aCredential.AllocL();
	
	}
// ---------------------------------------------------------
// CNSmlAuth::SetTypeL()
// 
// ---------------------------------------------------------
//	
void CNSmlAuth::SetTypeL( const TDesC8& aType )
	{
	delete iType;
	iType = NULL;
	iType = aType.AllocL();
	}
// ---------------------------------------------------------
// CNSmlAuth::SetFormatL()
// 
// ---------------------------------------------------------
//	
void CNSmlAuth::SetFormatL( const TDesC8& aFormat )
	{
	delete iFormat;
	iFormat = NULL;
	iFormat = aFormat.AllocL();
	}

// ---------------------------------------------------------
// CNSmlAuth::SetAuthRequiredL()
// 
// ---------------------------------------------------------
//	
EXPORT_C void CNSmlAuth::SetAuthRequiredL()
	{
	iAuthState = ENotAuthenticated;
	HBufC* unicodeNonce = iAgent->ServerNonceAllocL();
	CleanupStack::PushL( unicodeNonce );
	iNonce = HBufC8::NewL( unicodeNonce->Length() );
	iNonce->Des().Copy( *unicodeNonce ); 
	CleanupStack::PopAndDestroy(); //unicodeNonce 
	if ( iNonce->Length() == 0 )
		{
		CreateAndSaveNewNonceL();
		}
	}
// ---------------------------------------------------------
// CNSmlAuth::SetChallenced()
// 
// ---------------------------------------------------------
//	
void CNSmlAuth::SetChallenced()
	{
	if ( iAuthState == ENotAuthenticated )
		{
		iAuthState = EAuthChallenced;
		}
	if ( iAuthState == EAuthenticated )
		{
		iAuthState = EChallencedForNext;
		}
	}

// ---------------------------------------------------------
// CNSmlAuth::CreateAndSaveNewNonceL()
// ---------------------------------------------------------
void CNSmlAuth::CreateAndSaveNewNonceL()
	{
	delete iNonce;
	iNonce = NULL;
	iNonce = HBufC8::NewL( 5 );
	_LIT8( KNSmlNonceMask, "%05d" );
	TInt64 seed = User::TickCount();
	TInt nonce = Math::Rand( seed );
	iNonce->Des().Format( KNSmlNonceMask, nonce );
#ifdef __CONSTANT_NONCE
	*iNonce = _L8("nonce");
#endif
	HBufC* unicodeNonce = HBufC::NewLC( iNonce->Length() );
	unicodeNonce->Des().Copy( *iNonce );
	iAgent->SetServerNonceL( *unicodeNonce );
	CleanupStack::PopAndDestroy(); //unicodeNonce 
	}

// ---------------------------------------------------------
// CNSmlAuth::NonceL()
// 
// ---------------------------------------------------------
//
TPtrC8 CNSmlAuth::NonceL()
	{
	if ( iAuthState == EAuthenticated )
		{
		CreateAndSaveNewNonceL();
		}
	TImCodecB64 B64Coder;
	delete iB64Nonce;
	iB64Nonce = NULL;
	iB64Nonce = HBufC8::NewL( iNonce->Length() * 2 + 1 );
	TPtr8 B64NoncePtr( iB64Nonce->Des() );
	User::LeaveIfError( B64Coder.Encode( *iNonce, B64NoncePtr ) );
	return *iB64Nonce;
	}

// ---------------------------------------------------------
// CNSmlAuth::ChallengeNeeded()
// 
// ---------------------------------------------------------
//
TBool CNSmlAuth::ChallengeNeeded() const
	{
	if ( iAuthState == ENotAuthenticated || iAuthState == EAuthenticated )
		{
		return ETrue;
		}
	return EFalse;
	}

// ---------------------------------------------------------
// CNSmlAuth::Challenged()
// 
// ---------------------------------------------------------
//
EXPORT_C TBool CNSmlAuth::Challenged() const
	{
	if ( iAuthState == EAuthChallenced )
		{
		return ETrue;
		}
	return EFalse;
	}

// ---------------------------------------------------------
// CNSmlAuth::StatusCodeL()
// 
// ---------------------------------------------------------
//
TNSmlError::TNSmlSyncMLStatusCode CNSmlAuth::StatusCodeL()
	{
	if ( iAuthState == ENotInUse )
		{
		return TNSmlError::ESmlStatusOK;
		}
	if ( iAuthState == EAuthenticated || iAuthState == EChallencedForNext )
		{
		return TNSmlError::ESmlStatusAuthenticationAccepted;
		}
	TNSmlError::TNSmlSyncMLStatusCode statusCode = TNSmlError::ESmlStatusOK;
	if ( iCredential == NULL || iType == NULL )
		{
		statusCode = TNSmlError::ESmlStatusClientAuthenticationRequired;
		}
	else
		{
		if ( iType->Des() !=  KNSmlAgentAuthMD5 )
			{
			statusCode = TNSmlError::ESmlStatusClientAuthenticationRequired;
			}
		else
			{
            statusCode = CheckCredentialL();
			if ( statusCode == TNSmlError::ESmlStatusAuthenticationAccepted )
				{
				iAuthState = EAuthenticated;
				}
			}
		}	
	if ( iAuthState == EAuthChallenced && statusCode == TNSmlError::ESmlStatusClientAuthenticationRequired )
		{
		statusCode = TNSmlError::ESmlStatusUnauthorized;
		}
	return statusCode;
	}
// ---------------------------------------------------------
// CNSmlAuth::ConstructL()
// ---------------------------------------------------------
//
void CNSmlAuth::ConstructL()
	{
	iAuthState = ENotInUse;
	iType = KNSmlAgentAuthMD5().AllocL();
	iFormat = HBufC8::NewL(0);
	}

// ---------------------------------------------------------
// CNSmlAuth::CheckCredentialL()
// ---------------------------------------------------------
TNSmlError::TNSmlSyncMLStatusCode CNSmlAuth::CheckCredentialL() 
	{
	HBufC8* B64Cred;
	if ( iFormat->Des() != KNSmlAgentBase64Format )
		{
		TImCodecB64 B64Coder;
		B64Cred = HBufC8::NewLC( iCredential->Length() * 2 + 1 );
		TPtr8 B64CredPtr( B64Cred->Des() );
		User::LeaveIfError( B64Coder.Encode( *iCredential, B64CredPtr ) );
		}
	else
		{
		B64Cred = iCredential->AllocLC();
		}
	HBufC8* digest = iAgent->Md5CredentialL( ETrue );
	TNSmlError::TNSmlSyncMLStatusCode statusCode = TNSmlError::ESmlStatusAuthenticationAccepted;
	if ( *digest != *B64Cred )
		{
		statusCode = TNSmlError::ESmlStatusClientAuthenticationRequired;
		}
	CleanupStack::PopAndDestroy(); //B64Cred
	delete digest;
	return statusCode;
	}





