/*
* Copyright (c) 2008 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 FILES
#include "tstsdistinguishednameconverter.h"
#include "tstscharactersetconverter.h"
#include "javasymbianoslayer.h" // for CleanupResetAndDestroy
#include "stspkiconstants.h" // for error constants
#include <x500dn.h>
#include <charconv.h>




// CONSTANTS
const TInt KSTSGeneratedNameLength = 23;

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// TSTSDistinguishedNameConverter::TSTSDistinguishedNameConverter
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
TSTSDistinguishedNameConverter::TSTSDistinguishedNameConverter()
{
}

// -----------------------------------------------------------------------------
// TSTSDistinguishedNameConverter::CreateDNL
// Create CX500DistinguishedName
// -----------------------------------------------------------------------------
CX500DistinguishedName* TSTSDistinguishedNameConverter::CreateDNL(
    const TDesC& aNameInfo)
{

    CArrayPtrFlat< CX520AttributeTypeAndValue>* elements =
        new(ELeave) CArrayPtrFlat<CX520AttributeTypeAndValue> (1);
    CleanupStack::PushL(elements);
    CleanupResetAndDestroyPushL(*elements);
    TInt pos(0);
    TInt nameLength(aNameInfo.Length());
    TInt elementStart(0);

    while (pos < nameLength)
    {
        if (aNameInfo[ pos ] == '\\')
        {
            // next character is escaped, so we jump over it
            pos++;
        }
        else if ((aNameInfo[ pos ] == ',') || (pos == (nameLength - 1)))
        {
            // found the end of single element, parse it
            TInt elementLength = pos - elementStart;
            if (pos == (nameLength - 1))
            {
                elementLength++;
            }
            TPtrC elementDes(aNameInfo.Mid(elementStart, elementLength));
            CX520AttributeTypeAndValue* element =
                ParseDNElementL(elementDes);
            if (element)
            {
                CleanupStack::PushL(element);
                elements->AppendL(element);
                CleanupStack::Pop();  // element
            }
            elementStart = pos + 1;
        }
        pos++;
    }

    TInt elementCount = elements->Count();

    if (elementCount == 0)
    {
        CX520AttributeTypeAndValue* element = GenerateDNElementLC();
        elements->AppendL(element);
        CleanupStack::Pop();  // element
        elementCount++;
    }

    // In certificates the element order is reversed
    CArrayPtrFlat< CX520AttributeTypeAndValue>* reversedElements =
        new(ELeave) CArrayPtrFlat<CX520AttributeTypeAndValue> (elementCount);
    CleanupStack::PushL(reversedElements);

    for (TInt i = elementCount - 1; i >= 0; i--)
    {
        reversedElements->AppendL(elements->At(i));
    }

    CX500DistinguishedName* dn =
        CX500DistinguishedName::NewL(*reversedElements);

    CleanupStack::PopAndDestroy(3);   // elements, reversedElements


    return dn;
}

// -----------------------------------------------------------------------------
// TSTSDistinguishedNameConverter::GenerateDNElementL
// Generates a pseudo random distinguished name element
// -----------------------------------------------------------------------------
CX520AttributeTypeAndValue*
TSTSDistinguishedNameConverter::GenerateDNElementLC()
{
    TTime currentTime;
    currentTime.UniversalTime();
    TBuf< KSTSGeneratedNameLength > value;
    currentTime.FormatL(value, KSTSDistinguishedNameFormat());

    TSTSCharacterSetConverter csConverter;
    HBufC8* byteValue = csConverter.EscapedUnicodeToPrintableLC(value);

    CX520AttributeTypeAndValue* retVal =
        CX520AttributeTypeAndValue::NewL(ECommonName, *byteValue);

    CleanupStack::PopAndDestroy(byteValue);
    CleanupStack::PushL(retVal);

    return retVal;
}

// -----------------------------------------------------------------------------
// TSTSDistinguishedNameConverter::ParseDNElementLC
// Parse single element from distinguished name
// -----------------------------------------------------------------------------
CX520AttributeTypeAndValue* TSTSDistinguishedNameConverter::ParseDNElementL(
    TDesC& aSingleElement)
{

    TInt elementLength = aSingleElement.Length();
    TInt pos(0);

    CX520AttributeTypeAndValue* retVal = NULL;

    while (pos < elementLength)
    {
        if (aSingleElement[ pos ] == '=')
        {
            TPtrC type = aSingleElement.Left(pos);
            TPtrC value = aSingleElement.Mid(pos + 1);
            retVal = CreateDNElementL(type, value);
            // break in order to get quickly out of the while loop
            break;
        }
        pos++;
    }
    if (pos == elementLength)
    {
        User::Leave(KSTSErrInvalidCAName);
    }

    return retVal;
}


// -----------------------------------------------------------------------------
// TSTSDistinguishedNameConverter::CreateDNElementLC
// Create a single DN element from given parameters
// -----------------------------------------------------------------------------
CX520AttributeTypeAndValue* TSTSDistinguishedNameConverter::CreateDNElementL(
    TDesC& aType, TDesC& aValue)
{

    TLex typeLexer(aType);
    typeLexer.SkipSpace();
    TPtrC16 lexedType = typeLexer.Remainder();

    TSTSCharacterSetConverter csConverter;

    HBufC8* value = csConverter.EscapedUnicodeToPrintableLC(aValue);

    CX520AttributeTypeAndValue* retVal = NULL;
    if (lexedType.Compare(KSTSX500AttributeCN()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(ECommonName, *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeL()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(ELocalityName, *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeST()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(EStateOrProvinceName,
                 *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeO()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(EOrganizationName, *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeOU()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(EOrganizationalUnitName,
                 *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeC()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(ECountryName, *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeSTREET()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(ERFC2256Street, *value);
    }
    else if (lexedType.Compare(KSTSX500AttributeDC()) == 0)
    {
        retVal = CX520AttributeTypeAndValue::NewL(ERFC2247DomainComponent,
                 *value);
    }
    // UID is mentioned in RFC2253, but its not supported by native
    // implementation
    else if (lexedType.Compare(KSTSX500AttributeUID()) != 0)
    {
        User::Leave(KErrArgument);
    }
    CleanupStack::PopAndDestroy(value);


    return retVal;
}


//  End of File
