//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996-1998
//
// File:        kp.cpp
//
// Contents:    
//              Contains wrapper call to deal with concepture 
//              license key pack table, this includes LicPack, LicPackStatus,
//              and LicPackDesc table.
//
// History:     
//          04/16/98      HueiWang        Created.
//---------------------------------------------------------------------------

#include "pch.cpp"
#include "kp.h"
#include "globals.h"
#include "server.h"
#include "lkplite.h"
#include "keypack.h"
#include "lkpdesc.h"
#include "misc.h"
#include "permlic.h"


//++-------------------------------------------------------------------------------
BOOL 
ValidLicenseKeyPackParameter(
    IN LPLSKeyPack lpKeyPack, 
    IN BOOL bAdd
    )
/*++

Abtract:

    Validate a LSKeyPack value.

Parameter:

    lpKeyPack - keypack value to be validated,
    bAdd - TRUE if this value is to be inserted into table, FALSE otherwise, note
           if value is to be inserted into table, it require more parameters.

Return:

    TRUE if valid LSKeyPack value, FALSE otherwise.

++*/
{
    BOOL bValid=FALSE;

    do {
        // verify input parameter
        if((lpKeyPack->ucKeyPackType & ~LSKEYPACK_RESERVED_TYPE) < LSKEYPACKTYPE_FIRST || 
           (lpKeyPack->ucKeyPackType & ~LSKEYPACK_RESERVED_TYPE) > LSKEYPACKTYPE_LAST)
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid key pack type - %d\n"), 
                    lpKeyPack->ucKeyPackType
                );
            break;
        }

        UCHAR ucKeyPackStatus = lpKeyPack->ucKeyPackStatus & ~LSKEYPACKSTATUS_RESERVED;

        if((ucKeyPackStatus < LSKEYPACKSTATUS_FIRST || 
            ucKeyPackStatus > LSKEYPACKSTATUS_LAST) &&
            ucKeyPackStatus != LSKEYPACKSTATUS_DELETE)
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid key pack status - %d\n"), 
                    lpKeyPack->ucKeyPackStatus
                );
            break;
        }

        if(lpKeyPack->ucLicenseType < LSKEYPACKLICENSETYPE_FIRST || 
           lpKeyPack->ucLicenseType > LSKEYPACKLICENSETYPE_LAST)
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid license type - %d\n"), 
                    lpKeyPack->ucLicenseType
                );
            break;
        }

        if(!bAdd)
        {
            bValid = TRUE;
            break;
        }

        if(lpKeyPack->ucChannelOfPurchase < LSKEYPACKCHANNELOFPURCHASE_FIRST ||
           lpKeyPack->ucChannelOfPurchase > LSKEYPACKCHANNELOFPURCHASE_LAST)
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid channel of purchase - %d\n"), 
                    lpKeyPack->ucChannelOfPurchase
                );
            break;
        }

        if(!_tcslen(lpKeyPack->szCompanyName))
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid company name\n")
                );
            break;
        }

        if(!_tcslen(lpKeyPack->szKeyPackId))
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid key pack id\n")
                );
            break;
        }

        if(!_tcslen(lpKeyPack->szProductName))
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid product name\n")
                );
            break;
        }

        if(!_tcslen(lpKeyPack->szProductId))
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid product id\n")
                );
            break;
        }

        if(!_tcslen(lpKeyPack->szProductDesc))
        {
            // set product desc = product name
            _tcscpy(lpKeyPack->szProductDesc, lpKeyPack->szProductName);
        }

        if(!_tcslen(lpKeyPack->szBeginSerialNumber))
        {
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("ValidLicenseKeyPackParameter : invalid serial number\n")
                );
            break;
        }

        bValid=TRUE;
    } while(FALSE);
 
    return bValid;
}


//++----------------------------------------------------------------------
DWORD
TLSDBLicenseKeyPackAdd( 
    IN PTLSDbWorkSpace pDbWkSpace, 
    IN LPLSKeyPack lpLsKeyPack 
    )
/*++

Abstract:

    Add an entry into concepture keypack table, this includes LicPack, 
    LicPackStatus, and LicPackDesc table.

Parameter:

    pDbWkSpace : workspace handle.
    lpLsKeyPack : license key pack to be added into table.

Returns: 

++*/
{
    DWORD   dwStatus;
    TLSLICENSEPACK LicPack;
    LICPACKDESC LicPackDesc;

    if(!ValidLicenseKeyPackParameter(lpLsKeyPack, TRUE))
        return TLS_E_INVALID_DATA;

    TLSDBLockKeyPackTable();
    TLSDBLockKeyPackDescTable();

    do {
        if(ConvertLsKeyPackToKeyPack(
                            lpLsKeyPack,    
                            &LicPack, 
                            &LicPackDesc
                        ) == FALSE)
        {
            dwStatus = GetLastError();
            break;
        }

        //
        // Add license server info into TLSLICENSEPACK
        //
        //LicPack.pbDomainSid = g_pbDomainSid;
        //LicPack.cbDomainSid = g_cbDomainSid;

        _tcscpy(LicPack.szInstallId, (LPTSTR)g_pszServerPid);
        _tcscpy(LicPack.szTlsServerName, g_szComputerName);

        //
        // No domain name at this time
        //
        memset(LicPack.szDomainName, 0, sizeof(LicPack.szDomainName));


        if(lpLsKeyPack->ucKeyPackStatus != LSKEYPACKSTATUS_ADD_DESC)
        {
            dwStatus = TLSDBKeyPackAdd(pDbWkSpace, &LicPack);
            if(dwStatus != ERROR_SUCCESS)
            {
                // this is global memory, destructor will try to free it.
                LicPack.pbDomainSid = NULL;
                LicPack.cbDomainSid = 0;
                break;
            }
        }

        LicPack.pbDomainSid = NULL;
        LicPack.cbDomainSid = 0;

        //
        // Make sure keypack got inserted
        //
        dwStatus = TLSDBKeyPackEnumBegin( 
                                    pDbWkSpace, 
                                    TRUE, 
                                    LSKEYPACK_EXSEARCH_DWINTERNAL, 
                                    &LicPack 
                                );
        if(dwStatus != ERROR_SUCCESS)
            break;

        dwStatus = TLSDBKeyPackEnumNext(
                                pDbWkSpace, 
                                &LicPack
                            );

        TLSDBKeyPackEnumEnd(pDbWkSpace);

        if(dwStatus != ERROR_SUCCESS)
            break;

        LicPackDesc.dwKeyPackId = LicPack.dwKeyPackId;

        //
        // Add keypack description into keypack desc
        //
        dwStatus = TLSDBKeyPackDescAddEntry(
                                    pDbWkSpace, 
                                    &LicPackDesc
                                );

        ConvertKeyPackToLsKeyPack(
                            &LicPack, 
                            &LicPackDesc, 
                            lpLsKeyPack
                        );
    } while(FALSE);

    TLSDBUnlockKeyPackDescTable();
    TLSDBUnlockKeyPackTable();
    return dwStatus;
}

//++-----------------------------------------------------------------------
DWORD
TLSDBLicenseKeyPackSetStatus( 
    IN PTLSDbWorkSpace pDbWkSpace, 
    IN DWORD       dwSetStatus,
    IN LPLSKeyPack  lpLsKeyPack
    )
/*++

Abstract:

    Set the status of Licensed KeyPack.

Parameter:

    pDbWkSpace - workspace handle.
    dwSetStatus - type of status to be set.
    lpLsKeyPack - record/value to be set.

Returns:

++*/
{
    TLSLICENSEPACK LicPack;
    
    //
    // Status of keypack is in KeyPack table
    //
    if(ConvertLsKeyPackToKeyPack(
                        lpLsKeyPack, 
                        &LicPack, 
                        NULL
                    ) == FALSE)
    {
        return GetLastError();
    }

    return TLSDBKeyPackSetValues(pDbWkSpace, FALSE, dwSetStatus, &LicPack);
}

//++---------------------------------------------------------------------
DWORD
TLSDBLicenseKeyPackUpdateLicenses( 
    PTLSDbWorkSpace pDbWkSpace, 
    BOOL bAdd, 
    IN LPLSKeyPack lpLsKeyPack 
    )
/*++
    
Abstract:

    Add/Remove license from a keypack.

Parameter:

    pDbWkSpace - workspace handle.
    bAdd - TRUE if add entry into table, FALSE otherwise.
    lpLsKeyPack - 

Returns:

++*/
{
    DWORD dwStatus;
    TLSLICENSEPACK LicPack;

    //
    // Redirect call to KeyPack Table, not thing in KeyPackDesc can be updated.
    //
    if(ConvertLsKeyPackToKeyPack(
                        lpLsKeyPack, 
                        &LicPack, 
                        NULL
                    ) == FALSE)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    dwStatus=TLSDBKeyPackUpdateNumOfAvailableLicense(
                            pDbWkSpace, 
                            bAdd, 
                            &LicPack
                        );

    //
    // return new value back to caller
    //
    ConvertKeyPackToLsKeyPack( 
                        &LicPack, 
                        NULL, 
                        lpLsKeyPack 
                    );

cleanup:
    return dwStatus;
}

//++---------------------------------------------------------------------
LPENUMHANDLE 
TLSDBLicenseKeyPackEnumBegin(
    BOOL bMatchAll, 
    DWORD dwSearchParm, 
    LPLSKeyPack lpLsKeyPack
    )
/*++

Abstract:

    Begin enumeration of concepture License Key Pack table.

Parameter:

    bMatchAll - TRUE if match all search value, FALSE otherwise.
    dwSearchParm - Field to be included in search.
    lpLsKeyPack - KeyPack value to search.
    
Returns:


++*/
{
    DWORD dwStatus;
    LPENUMHANDLE hEnum=NULL;
    TLSLICENSEPACK licpack;

    licpack.pbDomainSid = NULL;

    hEnum = new ENUMHANDLE;
    if(hEnum == NULL)
        return NULL;

    hEnum->pbWorkSpace=AllocateWorkSpace(g_EnumDbTimeout);
    if(hEnum->pbWorkSpace == NULL)
    {
        SetLastError(TLS_E_ALLOCATE_HANDLE);
        TLSDBLicenseKeyPackEnumEnd(hEnum);
        return NULL;
    }

    memset(&hEnum->CurrentKeyPack, 0, sizeof(hEnum->CurrentKeyPack));
    memset(&hEnum->KPDescSearchValue, 0, sizeof(hEnum->KPDescSearchValue));
    hEnum->dwKPDescSearchParm = 0;

    if(ConvertLsKeyPackToKeyPack(
                        lpLsKeyPack, 
                        &licpack, 
                        &hEnum->KPDescSearchValue
                    ) == FALSE)
    {
        TLSDBLicenseKeyPackEnumEnd(hEnum);
        return NULL;
    }

    //
    // establish KeyPack enumeration
    dwStatus = TLSDBKeyPackEnumBegin(
                                hEnum->pbWorkSpace, 
                                bMatchAll, 
                                dwSearchParm, 
                                &licpack
                            );
    if(dwStatus != ERROR_SUCCESS)
    {
        SetLastError(dwStatus);
        TLSDBLicenseKeyPackEnumEnd(hEnum);
        return NULL;
    }


    //
    // Store keypack desc search value
    //
    if(dwSearchParm & LSKEYPACK_SEARCH_LANGID)
        hEnum->dwKPDescSearchParm |= LICPACKDESCRECORD_TABLE_SEARCH_LANGID;
    
    if(dwSearchParm & LSKEYPACK_SEARCH_COMPANYNAME)
        hEnum->dwKPDescSearchParm |= LICPACKDESCRECORD_TABLE_SEARCH_COMPANYNAME;

    if(dwSearchParm & LSKEYPACK_SEARCH_PRODUCTNAME)
        hEnum->dwKPDescSearchParm |= LICPACKDESCRECORD_TABLE_SEARCH_PRODUCTNAME;

    if(dwSearchParm & LSKEYPACK_SEARCH_PRODUCTDESC)
        hEnum->dwKPDescSearchParm |= LICPACKDESCRECORD_TABLE_SEARCH_PRODUCTDESC;

    hEnum->bKPDescMatchAll=bMatchAll;
    hEnum->chFetchState=ENUMHANDLE::FETCH_NEXT_KEYPACK;
    return hEnum;
}

//++----------------------------------------------------------------------
DWORD 
TLSDBLicenseKeyPackEnumNext(
    LPENUMHANDLE lpEnumHandle, 
    LPLSKeyPack lpLsKeyPack,
    BOOL bShowAll
    )
/*++

Abstract:

    Fetch next combined LicPack, LicPackStatus, and LicPackDesc record that
    match search condiftion.

Parameter:

    lpEnumHandle - enumeration handle return by TLSDBLicenseKeyPackEnumBegin().
    lpLsKeyPack - return value found.
    bShowAll - return all keypack

Returns:


Note:
    Caller need to discard return value and call TLSDBLicenseKeyPackEnumNext() 
    again when this function return TLS_I_MORE_DATA, this is to prevent 
    stack overflow in recursive call.

++*/
{
    //
    // No recursive call to prevent stack overflow
    // 

    DWORD dwStatus;

    switch(lpEnumHandle->chFetchState)
    {
        case ENUMHANDLE::FETCH_NEXT_KEYPACK:

            //
            // Retrieve next row in keypack
            dwStatus=TLSDBKeyPackEnumNext(
                                lpEnumHandle->pbWorkSpace, 
                                &lpEnumHandle->CurrentKeyPack
                            );
            if(dwStatus != ERROR_SUCCESS)
                break;

            if(bShowAll == FALSE)
            {

                //
                // Never return keypack that is solely for issuing certificate to 
                // Hydra Server
                if(_tcsicmp(lpEnumHandle->CurrentKeyPack.szKeyPackId, 
                            HYDRAPRODUCT_HS_CERTIFICATE_KEYPACKID) == 0 &&
                   _tcsicmp(lpEnumHandle->CurrentKeyPack.szProductId, 
                            HYDRAPRODUCT_HS_CERTIFICATE_SKU) == 0)
                {
                    //
                    // Prevent infinite recursive call, let calling routine handle this
                    return TLS_I_MORE_DATA;
                }

                //
                // Do not show remote key pack
                //
                if( lpEnumHandle->CurrentKeyPack.ucAgreementType & LSKEYPACK_REMOTE_TYPE)
                {
                    return TLS_I_MORE_DATA;
                }

                if( lpEnumHandle->CurrentKeyPack.ucKeyPackStatus & LSKEYPACKSTATUS_REMOTE)
                {
                    return TLS_I_MORE_DATA;
                }

                lpEnumHandle->CurrentKeyPack.ucAgreementType &= ~LSKEYPACK_RESERVED_TYPE;
                lpEnumHandle->CurrentKeyPack.ucKeyPackStatus &= ~LSKEYPACKSTATUS_RESERVED;
            }

            //
            // Fetch KeyPackDesc table
            //
            lpEnumHandle->chFetchState=ENUMHANDLE::FETCH_NEW_KEYPACKDESC;
           
            // 
            // FALL THRU.
            //

        case ENUMHANDLE::FETCH_NEW_KEYPACKDESC:
            //
            // retrieve new keypackdesc that match up with keypack
            lpEnumHandle->KPDescSearchValue.dwKeyPackId = lpEnumHandle->CurrentKeyPack.dwKeyPackId;
            lpEnumHandle->dwKPDescSearchParm |= LICPACKDESCRECORD_TABLE_SEARCH_KEYPACKID;
            // lpEnumHandle->pbWorkSpace->Cleanup();

            //
            // First issue a query to see if product has matching language ID
            LICPACKDESC kpDesc;

            memset(&kpDesc, 0, sizeof(LICPACKDESC));
            kpDesc = lpEnumHandle->KPDescSearchValue;
            dwStatus = TLSDBKeyPackDescFind(
                                        lpEnumHandle->pbWorkSpace, 
                                        TRUE,
                                        lpEnumHandle->dwKPDescSearchParm, 
                                        &kpDesc,
                                        NULL
                                    );

            if(dwStatus == TLS_E_RECORD_NOTFOUND)
            {
                //
                // Show description in English
                kpDesc.dwLanguageId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);

                dwStatus = TLSDBKeyPackDescFind(
                                            lpEnumHandle->pbWorkSpace, 
                                            TRUE,
                                            lpEnumHandle->dwKPDescSearchParm, 
                                            &kpDesc,
                                            NULL
                                        );

                if(dwStatus == TLS_E_RECORD_NOTFOUND)
                {
                    //
                    // No product description for this lanuage ID and english
                    //
                    _tcscpy(kpDesc.szCompanyName, lpEnumHandle->CurrentKeyPack.szCompanyName);
                    _tcscpy(kpDesc.szProductName, lpEnumHandle->CurrentKeyPack.szProductId);
                    _tcscpy(kpDesc.szProductDesc, lpEnumHandle->CurrentKeyPack.szProductId);
        
                    ConvertKeyPackToLsKeyPack(
                                        &lpEnumHandle->CurrentKeyPack, 
                                        &kpDesc, 
                                        lpLsKeyPack
                                    );

                    dwStatus = ERROR_SUCCESS;
                    lpEnumHandle->chFetchState=ENUMHANDLE::FETCH_NEXT_KEYPACK;
                    break;
                }
            }

            dwStatus = TLSDBKeyPackDescEnumBegin(
                                        lpEnumHandle->pbWorkSpace, 
                                        lpEnumHandle->bKPDescMatchAll,
                                        lpEnumHandle->dwKPDescSearchParm,
                                        &kpDesc
                                    );

                
            if(dwStatus != ERROR_SUCCESS)
                break;

            lpEnumHandle->chFetchState=ENUMHANDLE::FETCH_NEXT_KEYPACKDESC;

            //
            // FALL THRU
            //

        case ENUMHANDLE::FETCH_NEXT_KEYPACKDESC:
            {
                LICPACKDESC licpackdesc;
                dwStatus = TLSDBKeyPackDescEnumNext(
                                            lpEnumHandle->pbWorkSpace, 
                                            &licpackdesc
                                        );
                if(dwStatus == ERROR_SUCCESS)
                {
                    ConvertKeyPackToLsKeyPack(
                                        &lpEnumHandle->CurrentKeyPack, 
                                        &licpackdesc, 
                                        lpLsKeyPack
                                    );
                }
                else if(dwStatus == TLS_I_NO_MORE_DATA)
                {
                    lpEnumHandle->chFetchState=ENUMHANDLE::FETCH_NEXT_KEYPACK;
                    
                    //
                    // Set the status to MORE DATA 
                    //
                    dwStatus = TLS_I_MORE_DATA;
                    
                    // terminate enumeration for keypack description table
                    TLSDBKeyPackDescEnumEnd(lpEnumHandle->pbWorkSpace);                    
                } 
            }
            break;
    }

    return dwStatus;
}

//++------------------------------------------------------------------
DWORD 
TLSDBLicenseKeyPackEnumEnd(
    LPENUMHANDLE lpEnumHandle
    )
/*++

Abstract:

    End enumeration of concepture license key pack table.

Parameter;

    lpEnumHandle - enumeration handle return by TLSDBLicenseKeyPackEnumBegin().

Returns:

++*/
{
    if(lpEnumHandle)
    {
        if(lpEnumHandle->pbWorkSpace)
        {
            TLSDBKeyPackDescEnumEnd(lpEnumHandle->pbWorkSpace);
            TLSDBKeyPackEnumEnd(lpEnumHandle->pbWorkSpace);

            //FreeTlsLicensePack(&(lpEnumHandle->CurrentKeyPack));
            ReleaseWorkSpace(&(lpEnumHandle->pbWorkSpace));
        }
        delete lpEnumHandle;
    }

    return ERROR_SUCCESS;
}



//+--------------------------------------------------------------------

#define CH_PLATFORMID_OTHERS    3
#define CH_PLATFORMID_UPGRADE   2

BOOL
VerifyInternetLicensePack(
    License_KeyPack* pLicensePack
    )
/*++

--*/
{
    BOOL bSuccess = TRUE;

    switch(pLicensePack->dwKeypackType)
    {
        case LICENSE_KEYPACK_TYPE_SELECT:
        case LICENSE_KEYPACK_TYPE_MOLP:
        case LICENSE_KEYPACK_TYPE_RETAIL:
            break;           
            
        default:
            DBGPrintf(
                    DBG_ERROR,
                    DBG_FACILITY_RPC,
                    DBG_FACILITY_KEYPACK,
                    _TEXT("LSDBRegisterLicenseKeyPack : invalid keypack type - %d\n"), 
                    pLicensePack->dwKeypackType
                );
            bSuccess = FALSE;
    }

    if(bSuccess == FALSE)
    {
        goto cleanup;
    }
    
    if(bSuccess == FALSE)
    {
        goto cleanup;
    }

    if(CompareFileTime(&pLicensePack->ActiveDate, &pLicensePack->ExpireDate) > 0)
    {
        DBGPrintf(
                DBG_ERROR,
                DBG_FACILITY_RPC,
                DBG_FACILITY_KEYPACK,
                _TEXT("LSDBRegisterLicenseKeyPack : invalid activate date and expiration date\n")
            );
        bSuccess = FALSE;
        goto cleanup;
    }

    if(pLicensePack->pbProductId == NULL || pLicensePack->cbProductId == NULL)
    {
        DBGPrintf(
                DBG_ERROR,
                DBG_FACILITY_RPC,
                DBG_FACILITY_KEYPACK,
                _TEXT("LSDBRegisterLicenseKeyPack : No product ID\n")
            );
        bSuccess = FALSE;
        goto cleanup;
    }

    if(pLicensePack->dwDescriptionCount == 0 || pLicensePack->pDescription == NULL)
    {
        DBGPrintf(
                DBG_ERROR,
                DBG_FACILITY_RPC,
                DBG_FACILITY_KEYPACK,
                _TEXT("LSDBRegisterLicenseKeyPack : No product description\n")
            );
        bSuccess = FALSE;
        goto cleanup;
    }

    if(pLicensePack->cbManufacturer == 0 || pLicensePack->pbManufacturer == NULL)
    {
        DBGPrintf(
                DBG_ERROR,
                DBG_FACILITY_RPC,
                DBG_FACILITY_KEYPACK,
                _TEXT("LSDBRegisterLicenseKeyPack : No product manufacturer\n")
            );
        bSuccess = FALSE;
    }

cleanup:
    return bSuccess;
}

//----------------------------------------------------------------------
        
DWORD
ConvertInternetLicensePackToPMLicensePack(
    License_KeyPack* pLicensePack,
    PPMREGISTERLICENSEPACK ppmLicensePack
    )
/*++

--*/
{
    DWORD dwStatus = ERROR_SUCCESS;

    memset(ppmLicensePack, 0, sizeof(PMREGISTERLICENSEPACK));

    if(VerifyInternetLicensePack(pLicensePack) == FALSE)
    {
        SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
        goto cleanup;
    }

    ppmLicensePack->SourceType = REGISTER_SOURCE_INTERNET;
    ppmLicensePack->dwKeyPackType = pLicensePack->dwKeypackType;

    ppmLicensePack->dwDistChannel = pLicensePack->dwDistChannel;
    ppmLicensePack->KeypackSerialNum = pLicensePack->KeypackSerialNum;
    ppmLicensePack->IssueDate = pLicensePack->IssueDate;
    ppmLicensePack->ActiveDate = pLicensePack->ActiveDate;
    ppmLicensePack->ExpireDate = pLicensePack->ExpireDate;
    ppmLicensePack->dwBeginSerialNum = pLicensePack->dwBeginSerialNum;
    ppmLicensePack->dwQuantity = pLicensePack->dwQuantity;
    memcpy(
            ppmLicensePack->szProductId,
            pLicensePack->pbProductId,
            min(sizeof(ppmLicensePack->szProductId) - sizeof(TCHAR), pLicensePack->cbProductId)
        );
                
    memcpy(
            ppmLicensePack->szCompanyName,
            pLicensePack->pbManufacturer,
            min(sizeof(ppmLicensePack->szCompanyName) - sizeof(TCHAR), pLicensePack->cbManufacturer)
        );

    ppmLicensePack->dwProductVersion = pLicensePack->dwProductVersion;
    ppmLicensePack->dwPlatformId = pLicensePack->dwPlatformId;
    ppmLicensePack->dwLicenseType = pLicensePack->dwLicenseType;
    ppmLicensePack->dwDescriptionCount = pLicensePack->dwDescriptionCount;

    if( pLicensePack->dwDescriptionCount != 0 )
    {
        ppmLicensePack->pDescription = (PPMREGISTERLKPDESC)AllocateMemory(sizeof(PMREGISTERLKPDESC) * ppmLicensePack->dwDescriptionCount);
        if(ppmLicensePack->pDescription != NULL)
        {
            for(DWORD dwIndex = 0; dwIndex < ppmLicensePack->dwDescriptionCount; dwIndex++)
            {
                ppmLicensePack->pDescription[dwIndex].Locale = pLicensePack->pDescription[dwIndex].Locale;

                memcpy(
                    ppmLicensePack->pDescription[dwIndex].szProductName,
                    pLicensePack->pDescription[dwIndex].pbProductName,
                    min(
                          sizeof(ppmLicensePack->pDescription[dwIndex].szProductName) - sizeof(TCHAR),
                            pLicensePack->pDescription[dwIndex].cbProductName
                        )
                );
                    
                memcpy(
                    ppmLicensePack->pDescription[dwIndex].szProductDesc,
                    pLicensePack->pDescription[dwIndex].pDescription,
                    min(
                          sizeof(ppmLicensePack->pDescription[dwIndex].szProductDesc) - sizeof(TCHAR),
                            pLicensePack->pDescription[dwIndex].cbDescription
                        )
                );
            }
        }
        else
        {
            SetLastError(dwStatus = ERROR_OUTOFMEMORY);
        }
    }

cleanup:
    return dwStatus;
}

//----------------------------------------------------------------------------
DWORD
TLSDBInstallKeyPack(
    IN PTLSDbWorkSpace pDbWkSpace, 
    IN PPMLSKEYPACK ppmLsKeyPack,
    OUT LPLSKeyPack lpInstalledKeyPack
    )
/*++

--*/
{
    DWORD dwStatus = ERROR_SUCCESS;
    LSKeyPack KeyPack;
    DWORD i;

    //
    // Policy module should leave product name/description in PPMREGISTERLKPDESC
    //
    memset(&KeyPack, 0, sizeof(LSKeyPack));
    KeyPack = ppmLsKeyPack->keypack;

    if (!FileTimeToLicenseDate(
            &ppmLsKeyPack->ActiveDate, 
            &KeyPack.dwActivateDate
            ))
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    if (!FileTimeToLicenseDate(
            &ppmLsKeyPack->ExpireDate, 
            &KeyPack.dwExpirationDate
            ))
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    //
    // Add to KeyPack and KeyPackDesc Table.
    for(i=0; i < ppmLsKeyPack->dwDescriptionCount && dwStatus == ERROR_SUCCESS; i++)
    {
        KeyPack.ucKeyPackStatus = (i) ? LSKEYPACKSTATUS_ADD_DESC : LSKEYPACKSTATUS_ACTIVE;

        KeyPack.dwLanguageId = ppmLsKeyPack->pDescription[i].Locale;
        _tcscpy(
                KeyPack.szProductName, 
                ppmLsKeyPack->pDescription[i].szProductName
            );

        _tcscpy(
                KeyPack.szProductDesc, 
                ppmLsKeyPack->pDescription[i].szProductDesc
            );

        //  Todo:

        //
        //  This is a temporary workaround to Install Whistler CALs: If registry key is set,
        //  Keypack's minor version number is set to the data in DWORD Registry value, "Whistler".
        //

        HKEY hKey = NULL;
        DWORD dwBuffer = 0;
        DWORD cbBuffer = sizeof (DWORD);
        dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WHISTLER_CAL, 0,
                                KEY_ALL_ACCESS, &hKey);

        if (dwStatus == ERROR_SUCCESS)
        {

            dwStatus = RegQueryValueEx(hKey, KP_VERSION_VALUE, NULL, NULL,
            (LPBYTE)&dwBuffer, &cbBuffer);

            if (dwStatus == ERROR_SUCCESS)
            {
                KeyPack.wMinorVersion = dwBuffer;

                _tcscpy(
                KeyPack.szProductName, L"MS Terminal Server 5.1");
                
                _tcscpy(
                KeyPack.szProductId, L"A02-5.01-S");

                _tcsncpy(
                KeyPack.szKeyPackId, L"1", 1);
               
                _tcscpy(
                KeyPack.szProductDesc, L"Windows Whistler Terminal Services Client Access License Token");
            }
            RegCloseKey(hKey);
        }


        dwStatus = TLSDBLicenseKeyPackAdd(pDbWkSpace, &KeyPack);
    }

    if(dwStatus == ERROR_SUCCESS)
    {
        KeyPack.dwNumberOfLicenses = KeyPack.dwTotalLicenseInKeyPack;

        KeyPack.ucKeyPackStatus = LSKEYPACKSTATUS_ACTIVE;

        if (!FileTimeToLicenseDate(
                &ppmLsKeyPack->ActiveDate, 
                &KeyPack.dwActivateDate
                ))
        {
            dwStatus = GetLastError();
            goto cleanup;
        }

        if (!FileTimeToLicenseDate(
                &ppmLsKeyPack->ExpireDate, 
                &KeyPack.dwExpirationDate
                ))
        {
            dwStatus = GetLastError();
            goto cleanup;
        }

        dwStatus=TLSDBLicenseKeyPackSetStatus(
                                    pDbWkSpace, 
                                    LSKEYPACK_SET_ACTIVATEDATE | LSKEYPACK_SET_KEYPACKSTATUS | LSKEYPACK_SET_EXPIREDATE | LSKEYPACK_EXSEARCH_AVAILABLE, 
                                    &KeyPack
                                );
    }        

    //
    // Post a ssync work object to all known server.
    //
    if(dwStatus == ERROR_SUCCESS)
    {
        *lpInstalledKeyPack = KeyPack;
    }

cleanup:

    return dwStatus;
}


DWORD
TLSDBRegisterLicenseKeyPack(
    IN PTLSDbWorkSpace pDbWkSpace, 
    IN License_KeyPack* pLicenseKeyPack,
    OUT LPLSKeyPack lpInstalledKeyPack
    )
/*++

Abstract:

    Add a license keypack into database.

Parameter:

    pDbWkSpace : workspace handle.
    pLicenseKeyPack : Licensed key pack to be added.

Returns:
    
*/
{
    LSKeyPack KeyPack;
    long activeDate;
    long expireDate;
    DWORD dwStatus=ERROR_SUCCESS;
    PMREGISTERLICENSEPACK pmLicensePack;
    PMLSKEYPACK pmLsKeyPack;

    CTLSPolicy* pPolicy = NULL;
    PMHANDLE hClient = NULL;

    TCHAR szTlsProductCode[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szCHProductCode[LSERVER_MAX_STRING_SIZE+1];
    DWORD dwBufSize = LSERVER_MAX_STRING_SIZE + 1;

    DWORD i;

    dwStatus = ConvertInternetLicensePackToPMLicensePack(
                                        pLicenseKeyPack,
                                        &pmLicensePack
                                    );

    if(dwStatus != ERROR_SUCCESS)
    {
        goto cleanup;
    }    

    lstrcpyn(
            szCHProductCode,
            pmLicensePack.szProductId,
            LSERVER_MAX_STRING_SIZE+1
        );

    if(TranslateCHCodeToTlsCode(
                            pmLicensePack.szCompanyName,
                            szCHProductCode,
                            szTlsProductCode,
                            &dwBufSize) == TRUE )
    {
        // if can't find a policy module to handle, use default.
        lstrcpyn(
                pmLicensePack.szProductId,
                szTlsProductCode,
                sizeof(pmLicensePack.szProductId)/sizeof(pmLicensePack.szProductId[0])
            );
    }
     
    // use default if necessary                       
    pPolicy = AcquirePolicyModule(
                            pmLicensePack.szCompanyName,
                            pmLicensePack.szProductId,
                            TRUE
                        );

    if(pPolicy == NULL)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    hClient = GenerateClientId();

    dwStatus = pPolicy->PMRegisterLicensePack(
                                        hClient,
                                        REGISTER_PROGRESS_NEW,
                                        (PVOID)&pmLicensePack,
                                        (PVOID)&pmLsKeyPack
                                    );
    if(dwStatus != ERROR_SUCCESS)
    {
        goto cleanup;
    }

    dwStatus = TLSDBInstallKeyPack(
                            pDbWkSpace, 
                            &pmLsKeyPack,
                            lpInstalledKeyPack
                        );

    if(dwStatus == ERROR_SUCCESS)
    {
        TLSResetLogLowLicenseWarning(
                            pmLicensePack.szCompanyName,
                            pmLicensePack.szProductId,
                            pmLicensePack.dwProductVersion,
                            FALSE
                        );
    }

                            
cleanup:

    if(pPolicy != NULL && hClient != NULL)
    {
        pPolicy->PMRegisterLicensePack(
                                hClient,
                                REGISTER_PROGRESS_END,
                                UlongToPtr(dwStatus),
                                NULL
                            );

        ReleasePolicyModule(pPolicy);
    }

    if(pmLicensePack.pDescription != NULL)
    {
        FreeMemory(pmLicensePack.pDescription);
    }

    return dwStatus;
}

//+--------------------------------------------------------------------
//
// TermSrv specific code...
//
// PRODUCT_INFO_COMPANY_NAME is defined in license.h
//
#define LKP_VERSION_BASE            1
#define WINDOWS_VERSION_NT5         5
#define WINDOWS_VERSION_BASE        2000

DWORD
TLSDBTelephoneRegisterLicenseKeyPack(
    IN PTLSDbWorkSpace pDbWkSpace, 
    IN LPTSTR pszPID,
    IN PBYTE pbLKP,
    IN DWORD cbLKP,
    OUT LPLSKeyPack lpInstalledKeyPack
    )
/*++

Abstract:

    Add a license keypack into database.

Parameter:

    pDbWkSpace : workspace handle.
    pLicenseKeyPack : Licensed key pack to be added.

Returns:
    
*/
{
    DWORD dwStatus;
    DWORD dwVerifyResult;
    DWORD dwQuantity;
    DWORD dwSerialNumber;
    DWORD dwExpirationMos;
    DWORD dwVersion;
    DWORD dwUpgrade;
    LSKeyPack keypack;
    DWORD dwProductVersion;

    PMKEYPACKDESCREQ kpDescReq;
    PPMKEYPACKDESC pKpDesc = NULL;
    CTLSPolicy* pPolicy=NULL;
    PMHANDLE hClient = NULL;
    DWORD dwProgramType;

    struct tm expire;
    time_t currentDate;
    time_t ExpirationDate;

    PMREGISTERLICENSEPACK pmLicensePack;
    PMLSKEYPACK pmLsKeyPack;
    LPTSTR pszLKP = NULL;

    TCHAR szTlsProductCode[LSERVER_MAX_STRING_SIZE+1];
    TCHAR szCHProductCode[LSERVER_MAX_STRING_SIZE+1];
    DWORD dwBufSize = LSERVER_MAX_STRING_SIZE + 1;

    if(pDbWkSpace == NULL || pszPID == NULL || pbLKP == NULL || cbLKP == 0)
    {
        dwStatus = ERROR_INVALID_PARAMETER;
        goto cleanup;
    }

    //
    // Make sure data passed in is NULL terminated, current LKP
    // is base 24 encoded string.
    //
    pszLKP = (LPTSTR)AllocateMemory( cbLKP + sizeof(TCHAR) );
    if(pszLKP == NULL)
    {
        dwStatus = TLS_E_ALLOCATE_MEMORY;
        goto cleanup;
    }

    memcpy(
            pszLKP,
            pbLKP,
            cbLKP
        );
    //
    // Verify LKP
    //
    dwVerifyResult = LKPLITE_LKP_VALID;
    dwStatus = LKPLiteVerifyLKP(
                            pszPID,
                            pszLKP,
                            &dwVerifyResult
                        );

    if(dwStatus != ERROR_SUCCESS || dwVerifyResult != LKPLITE_LKP_VALID)
    {
        if(dwVerifyResult == LKPLITE_LKP_INVALID)
        {
            dwStatus = TLS_E_INVALID_LKP;
        }
        else if(dwVerifyResult == LKPLITE_LKP_INVALID_SIGN)
        {
            dwStatus = TLS_E_LKP_INVALID_SIGN;
        }

        goto cleanup;
    }

    //
    // Decode LKP
    //
    dwStatus = LKPLiteCrackLKP(
                            pszPID,
                            pszLKP,
                            szCHProductCode,
                            &dwQuantity,
                            &dwSerialNumber,
                            &dwExpirationMos,
                            &dwVersion,
                            &dwUpgrade,
                            &dwProgramType
                        );

    if(dwStatus != ERROR_SUCCESS)
    {
        dwStatus = TLS_E_DECODE_LKP;
        goto cleanup;
    }

    if(TranslateCHCodeToTlsCode(
                            PRODUCT_INFO_COMPANY_NAME,
                            szCHProductCode,
                            szTlsProductCode,
                            &dwBufSize) == FALSE )
    {
        // if can't find a policy module to handle, use default.
        lstrcpyn(
                szTlsProductCode,
                szCHProductCode,
                sizeof(szTlsProductCode)/sizeof(szTlsProductCode)
            );
    }

    //
    // Current LKP does not support 1) other company, 2)
    // only register with NT5 or later
    //
    pPolicy = AcquirePolicyModule(
                                PRODUCT_INFO_COMPANY_NAME,
                                szTlsProductCode,
                                TRUE
                            );

    if(pPolicy == NULL)
    {
        dwStatus = GetLastError();
        goto cleanup;
    }

    memset(&keypack, 0, sizeof(keypack));


    memset(&pmLicensePack, 0, sizeof(pmLicensePack));
    pmLicensePack.SourceType = REGISTER_SOURCE_PHONE;

    switch(dwProgramType)
    {
        case LKPLITE_PROGRAM_SELECT:
            pmLicensePack.dwKeyPackType = LICENSE_KEYPACK_TYPE_SELECT;
            break;

        case LKPLITE_PROGRAM_MOLP:
            pmLicensePack.dwKeyPackType = LICENSE_KEYPACK_TYPE_MOLP;
            break;
        
        case LKPLITE_PROGRAM_RETAIL:
            pmLicensePack.dwKeyPackType = LICENSE_KEYPACK_TYPE_RETAIL;
            break;

        default:
            SetLastError(dwStatus = TLS_E_INVALID_DATA);
            goto cleanup;
    }

    pmLicensePack.dwDistChannel = LSKEYPACKCHANNELOFPURCHASE_RETAIL;
    GetSystemTimeAsFileTime(&pmLicensePack.IssueDate);
    pmLicensePack.ActiveDate = pmLicensePack.IssueDate;

    currentDate = time(NULL);
    expire = *gmtime( (time_t *)&currentDate );
    expire.tm_mon += dwExpirationMos;
    ExpirationDate = mktime(&expire);

    if(ExpirationDate == (time_t) -1)
    {
        //
        // expiration month is too big, 
        // set it to 2038/1/1
        //
        memset(&expire, 0, sizeof(expire));

        expire.tm_year = 2038 - 1900;
        expire.tm_mon = 0;
        expire.tm_mday = 1;

        ExpirationDate = mktime(&expire);
    }

    if(ExpirationDate == (time_t) -1)
    {
        //
        // invalid time
        //
        dwStatus = ERROR_INVALID_PARAMETER;
        goto cleanup;
    }

    UnixTimeToFileTime(ExpirationDate, &pmLicensePack.ExpireDate);   

    //
    // dwSerialNumber is license pack serial number not begin 
    // serial number in license pack.
    //
    pmLicensePack.KeypackSerialNum.Data1 = dwSerialNumber;

    //
    // Tel. registration does not have any info regarding
    // begin serial number in license pack.
    //
    pmLicensePack.dwBeginSerialNum = 0;
    pmLicensePack.dwQuantity = dwQuantity;
    _tcscpy(pmLicensePack.szProductId, szTlsProductCode);
    _tcscpy(pmLicensePack.szCompanyName, PRODUCT_INFO_COMPANY_NAME);
    if(dwVersion == 1)
    {
        pmLicensePack.dwProductVersion = MAKELONG(0, WINDOWS_VERSION_NT5);
    }
    else
    {           
        DWORD dwMajorVer = (dwVersion >> 3); 
        
        // Right most 3 bits represent Minor version and stored in LOBYTE(LOWORD)
        pmLicensePack.dwProductVersion = (DWORD)(dwVersion & 07);

        // 4 bits starting at 6th position represent Major version and stored in LOBYTE(HIWORD)
        pmLicensePack.dwProductVersion |= (DWORD)(dwMajorVer << 16);
    }

    pmLicensePack.dwPlatformId = dwUpgrade;
    pmLicensePack.dwLicenseType = LSKEYPACKLICENSETYPE_UNKNOWN;
    pmLicensePack.pbLKP = pbLKP;
    pmLicensePack.cbLKP = cbLKP;

    hClient = GenerateClientId();
    dwStatus = pPolicy->PMRegisterLicensePack(
                                        hClient,
                                        REGISTER_PROGRESS_NEW,
                                        (PVOID)&pmLicensePack,
                                        (PVOID)&pmLsKeyPack
                                    );
    if(dwStatus != ERROR_SUCCESS)
    {
        goto cleanup;
    }


    dwStatus = TLSDBInstallKeyPack(
                            pDbWkSpace, 
                            &pmLsKeyPack,
                            lpInstalledKeyPack
                        );

    if(dwStatus == ERROR_SUCCESS)
    {
        TLSResetLogLowLicenseWarning(
                            pmLicensePack.szCompanyName,
                            pmLicensePack.szProductId,
                            pmLicensePack.dwProductVersion,
                            FALSE
                        );
    }

cleanup:

    FreeMemory(pszLKP);

    //
    // Close policy module
    //
    if(pPolicy != NULL && hClient != NULL)
    {
        pPolicy->PMRegisterLicensePack(
                                hClient,
                                REGISTER_PROGRESS_END,
                                UlongToPtr(dwStatus),
                                NULL
                            );

        ReleasePolicyModule(pPolicy);
    }

    return dwStatus;
}