// plhelp.cpp: Provider List Helpers

#include "pch.h"

// Caller responsible for freeing returned memory
LONG GetProviderList(
    LINEPROVIDERLIST**  ppd)
{
    // Load tapi32.dll explictly. This won't matter
    // for clients that already have tapi32.dll loaded,
    // but makes all the difference if they don't.
    HINSTANCE   hinstDll = 0;
    LONG        (WINAPI* pfnGetProviderList)(DWORD, LINEPROVIDERLIST*) = 0;

    if( hinstDll = LoadLibrary("tapi32.dll") )
    {
        *(FARPROC*)&pfnGetProviderList = GetProcAddress(hinstDll, "lineGetProviderList");

        if( !pfnGetProviderList )
        {
            FreeLibrary(hinstDll);
            return LINEERR_OPERATIONFAILED;
        }
    }
    else
    {
        return LINEERR_OPERATIONFAILED;
    }

    // Fill LINEPROVIDERLIST
    DWORD dwNeededSize = sizeof(LINEPROVIDERLIST);
    LONG  tr = 0;

    do
    {
        // Get some more memory if we don't have enough
        if( !*ppd || (*ppd)->dwTotalSize < dwNeededSize )
        {
            *ppd = (LINEPROVIDERLIST*)::realloc(*ppd, dwNeededSize);
            if( *ppd )
            {
                (*ppd)->dwTotalSize = dwNeededSize;
            }
            else
            {
                return LINEERR_NOMEM;
            }
        }

        // Fill in the buffer
        tr = pfnGetProviderList(TAPI_CURRENT_VERSION, *ppd);

        // Check how much memory we need
        // (some TSPs succeed even if the
        //  data size is too small)
        if( tr == LINEERR_STRUCTURETOOSMALL ||
            (tr == 0 &&
             (*ppd)->dwTotalSize < (*ppd)->dwNeededSize) )
        {
            dwNeededSize = (*ppd)->dwNeededSize;
            tr = LINEERR_STRUCTURETOOSMALL;
        }
    }
    while( tr == LINEERR_STRUCTURETOOSMALL );

    // Unload tapi32.dll (or just release our reference to it)
    FreeLibrary(hinstDll);

    return tr;
}

bool GetPermanentProviderID(LPCSTR pszProvider, DWORD* pdwID)
{
    bool    bSucceeded = false;

    LINEPROVIDERLIST*   ppl = 0;
    if( GetProviderList(&ppl) == 0 )
    {
        LPLINEPROVIDERENTRY rglpe = (LPLINEPROVIDERENTRY)((BYTE*)ppl + ppl->dwProviderListOffset);
        for( DWORD i = 0; i < ppl->dwNumProviders; i++ )
        {
            LPCSTR pszProviderFilename = (LPCSTR)((BYTE*)ppl + rglpe[i].dwProviderFilenameOffset);

            if( strcmpi(pszProviderFilename, pszProvider) == 0 )
            {
                *pdwID = rglpe[i].dwPermanentProviderID;
                bSucceeded = true;
                break;
            }
        }

        free(ppl);
    }

    return bSucceeded;
}
