/*
* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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 <mctkeystore.h>
#include <asn1dec.h>
#include <asnpkcs.h>
#include <unifiedkeystore.h>
#include <securityerr.h>
#include <mctwritablecertstore.h>

#include "certtool_commands.h"
#include "certtool_controller.h"
#include "keytool_commands.h"


const TInt KASN1SequenceTagValue = 0x30;
const TInt KWTLSCertificateVersionValue = 0x01;

/*static*/ CCertToolAdd* CCertToolAdd::NewLC(CCertToolController* aController)
	{
	CCertToolAdd* self = new (ELeave) CCertToolAdd(aController);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;	
	}

/*static*/ CCertToolAdd* CCertToolAdd::NewL(CCertToolController* aController)
	{
	CCertToolAdd* self = CCertToolAdd::NewLC(aController);
	CleanupStack::Pop(self);
	return self;	
	}

CCertToolAdd::~CCertToolAdd()
	{
	Cancel();	
	delete iCertData;	
	}

void CCertToolAdd::ConstructL()
	{

	}


TCertificateFormat CCertToolAdd::DoRecognizeL(const TDesC8& iData)
	{
	// Ensure length is sufficient for checking type
	if ( iData.Size() >= 1 )
		{
		// First byte of X.509 certificate is an ANS.1 SEQUENCE tag
		if ( iData[0] == KASN1SequenceTagValue )
			{
			return EX509Certificate;
			}
		// First byte of WTLS certificate is version == 1
		else if ( iData[0] == KWTLSCertificateVersionValue )
			{
			return EWTLSCertificate;
			}
		}
	User::Leave(KErrEof);
	return EWTLSCertificate;
	}


/**
 * Inserts a certificate in the certstore. 
 * If a specific certstore implementation is given using
 * the -store command line parameter the certificate is inserted
 * there. If no implementation is specified the first one is used.
 * Initially we try to add the certificate as a *user* certificate
 * if this fails (no corresponding private key in the keystore)
 * the certificate is added a root (CA) certificate.
 * If the option -private was present then the private key is in the
 * keystore and the certificate will be a user certificate.
 */
void CCertToolAdd::DoCommandL(CUnifiedCertStore& aCertStore, CKeyToolParameters* aParam)
	{
	Cancel();	
	iParams = aParam;	
	iCertStore = &aCertStore;

	if (!aParam->iDefault)
		{
		iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_CERTFILE);			
		User::Leave(KErrNotFound);
		CActiveScheduler::Stop();		
		}

		// must get proper certstore, hard-coded 0 is no good!
		if (aParam->iCertstoreIndex == -1)
			{
			aParam->iCertstoreIndex = 0;
			}
		if (aParam->iCertstoreIndex >= iCertStore->WritableCertStoreCount())
			{
			iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_NOTEXIST);	
			User::Leave(KErrCorrupt);
			}
		MCTWritableCertStore& wCertStore = iCertStore->WritableCertStore(aParam->iCertstoreIndex);

		if (!iParams->iLabel)
			{
			iParams->iLabel	= (iParams->iDefault)->AllocL();
			}
			
		// Get the certificate binary!
		RFs fs;
		CleanupClosePushL(fs);
		User::LeaveIfError(fs.Connect());	
	
		RFile file;
		CleanupClosePushL(file);	
		TInt r = file.Open(fs, *(iParams->iDefault), EFileRead);
		if (r != KErrNone)
			{
			iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_OPENFAIL);				
			User::Leave(r);
			}
	        
		TInt fileSize = 0;
		file.Size(fileSize);

		if (fileSize <= 0)
		{
			iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_EMPTYFILE);	
			User::Leave(KErrCorrupt);
		}

		iCertData = HBufC8::NewMaxL(fileSize);
		TPtr8 data(iCertData->Des());
		data.FillZ();
		User::LeaveIfError(file.Read(data, fileSize));

		// Use the recognizer to see what kind of certificate we have!
		TCertificateFormat format = DoRecognizeL(*iCertData);
						
		iState = EIntermediate;

		SetActive();
		//wCertStore.Add(*iParams->iLabel, format, ECACertificate, NULL, NULL, *iCertData, iStatus);
		wCertStore.Add(*iParams->iLabel, format, EUserCertificate, NULL, NULL, *iCertData, iStatus);
		CleanupStack::PopAndDestroy(2, &fs);
	}


void CCertToolAdd::RunL()
	{	
	if ((iStatus.Int() != KErrNone) && (iStatus.Int() != KErrPrivateKeyNotFound))
		{
		// A problem occured. Handle gracefully.
		User::Leave(iStatus.Int());
		}
	switch (iState)
		{
		case EIntermediate :
			{
			if (iStatus.Int() == KErrPrivateKeyNotFound)
				{
				// Not an user certificate add as root!
				iState = EFinish;
				MCTWritableCertStore& wCertStore = iCertStore->WritableCertStore(iParams->iCertstoreIndex);
				TCertificateFormat format = DoRecognizeL(*iCertData);
				SetActive();				
				wCertStore.Add(*iParams->iLabel, format, ECACertificate, NULL, NULL, *iCertData, iStatus);				
				}
			else 
				{
				iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_IMPORTSUCCESS);			
				CActiveScheduler::Stop();				
				}
			}
			break;
		case EFinish : 
			{
			iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_IMPORTSUCCESS);
			CActiveScheduler::Stop();			
			}	
			break;
		default :
			{
			}
		}
	
	}
	
TInt CCertToolAdd::RunError(TInt aError)
	{
	CActiveScheduler::Stop();
	switch (aError)
		{
		case KErrBadName:
			{
			// Most likely it was there already
			TRAP_IGNORE(iController->DisplayErrorL(_L("The given label is invalid, or already present in the certstore."), iParams->iPageWise));
			}
			break;
		case KErrKeyNotWeakEnough:
			{
			TRAP_IGNORE(iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_WEAK, iStatus.Int()));			
			}
			break;			
		default:
			{
			TRAP_IGNORE(iController->DisplayLocalisedMsgL(R_CERTTOOL_ERR_IMPORT, iStatus.Int()));			
			}
		}	
	return KErrNone;
	}
	
void CCertToolAdd::DoCancel()
	{
	
	}
	
CCertToolAdd::CCertToolAdd(CCertToolController* aController) : CCertToolCommand(aController)
	{
	CActiveScheduler::Add(this);	
	}

