// Copyright (c) 1996, Microsoft Corporation, all rights reserved
//
// phonenum.c
// Phone number helper library
// Listed alphabetically
//
// 03/06/96 Steve Cobb


#include <windows.h>  // Win32 root
#include <nouiutil.h> // No-HWND utilities
#include <tapiutil.h> // TAPI wrappers
#include <phonenum.h> // Our public header
#include <debug.h>    // Trace/Assert library


TCHAR*
LinkPhoneNumberFromParts(
    IN HINSTANCE hInst,
    IN OUT HLINEAPP* pHlineapp,
    IN PBUSER* pUser,
    IN PBENTRY* pEntry,
    IN PBLINK* pLink,
    IN DWORD iPhoneNumber,
    IN TCHAR* pszOverrideNumber,
    IN BOOL fDialable )

    // Like PhoneNumberFromParts but takes a link and hunt group index as
    // input instead of a base number, and handles not modifying the number
    // associated with non-modem/ISDN links.  If 'pszOverrideNumber' is
    // non-NULL and non-"" it is used instead of the derived number.
    //
{
    DTLNODE* pNode;
    TCHAR* pszBaseNumber;
    PBPHONE* pPhone;

    if (pszOverrideNumber && *pszOverrideNumber)
    {
        // So, this is useful?  RaoS?
        //
        return StrDup( pszOverrideNumber );
    }

    pNode = DtlNodeFromIndex( pLink->pdtllistPhones, iPhoneNumber );
    if (!pNode)
    {
        ASSERT( FALSE );
        return NULL;
    }

    pPhone = (PBPHONE *) DtlGetData(pNode);
    ASSERT( pPhone );

    if (pLink->pbport.pbdevicetype == PBDT_Modem
        || pLink->pbport.pbdevicetype == PBDT_Isdn)
    {
        BOOL fDownLevelIsdn;

        fDownLevelIsdn =
            (pLink->pbport.pbdevicetype == PBDT_Isdn
             && pLink->fProprietaryIsdn);

        return PhoneNumberFromParts(
            hInst, pHlineapp, pUser, pPhone, fDownLevelIsdn, fDialable );
    }
    else
    {
        return StrDup( pPhone->pszPhoneNumber );
    }
}


TCHAR*
PhoneNumberFromParts(
    IN HINSTANCE hInst,
    IN OUT HLINEAPP* pHlineapp,
    IN PBUSER* pUser,
    IN PBPHONE* pPhone,
    IN BOOL fDownLevelIsdn,
    IN BOOL fDialable )

    // Returns a heap block containing the composite phone number using the
    // rules of 'pPhone' and 'pUser'.  'HInst' is the module handle.
    // 'PHlineapp' is the TAPI context.  'FDialable' indicates the dialable
    // string, instead of the displayable string, should be returned.
    //
    // It is caller's responsibility to Free the returned string.
    //
{
    TCHAR* pszResult;
    TCHAR* pszBaseNumber;

    TRACE( "PhoneNumberFromParts" );

    pszBaseNumber = pPhone->pszPhoneNumber;
    if (!pszBaseNumber)
    {
        pszBaseNumber = TEXT("");
    }

    if (pPhone->fUseDialingRules)
    {
        pszResult =
            PhoneNumberFromTapiPartsEx( hInst, pszBaseNumber,
                pPhone->pszAreaCode, pPhone->dwCountryCode, fDownLevelIsdn,
                pHlineapp, fDialable );
    }
    else
    {
        TCHAR* pszPrefix;
        TCHAR* pszSuffix;

        PrefixSuffixFromLocationId( pUser,
            GetCurrentLocation( hInst, pHlineapp ),
            &pszPrefix, &pszSuffix );

        pszResult =
            PhoneNumberFromPrefixSuffixEx(
                pszBaseNumber, pszPrefix, pszSuffix, fDownLevelIsdn );

        Free0( pszPrefix );
        Free0( pszSuffix );
    }

    if (!pszResult)
    {
        TRACE( "!Phone#" );
        pszResult = StrDup( pszBaseNumber );
    }

    return pszResult;
}


TCHAR*
PhoneNumberFromPrefixSuffix(
    IN TCHAR* pszBaseNumber,
    IN TCHAR* pszPrefix,
    IN TCHAR* pszSuffix )

    // Returns a heap block containing the composite phone number comprised of
    // prefix 'pszPrefix', base phone number 'pszBaseNumber', and suffix
    // 'pszSuffix', or NULL if the composite number is too long or on a memory
    // error.
    //
    // It is caller's responsibility to Free the returned string.
    //
{
    TCHAR* pszResult;
    DWORD  cch;

    TRACE( "PhoneNumberFromPrefixSuffix" );

    pszResult = NULL;

    if (!pszBaseNumber)
    {
        pszBaseNumber = TEXT("");
    }
    if (!pszPrefix)
    {
        pszPrefix = TEXT("");
    }
    if (!pszSuffix)
    {
        pszSuffix = TEXT("");
    }

    cch = lstrlen( pszPrefix ) + lstrlen( pszBaseNumber ) + lstrlen( pszSuffix );
    if (cch > RAS_MaxPhoneNumber)
    {
        return NULL;
    }

    pszResult = Malloc( (cch + 1) * sizeof(TCHAR) );
    if (pszResult)
    {
        *pszResult = TEXT('\0');
        lstrcat( pszResult, pszPrefix );
        lstrcat( pszResult, pszBaseNumber );
        lstrcat( pszResult, pszSuffix );
    }

    return pszResult;
}


TCHAR*
PhoneNumberFromPrefixSuffixEx(
    IN TCHAR* pszBaseNumber,
    IN TCHAR* pszPrefix,
    IN TCHAR* pszSuffix,
    IN BOOL fDownLevelIsdn )

    // Returns a heap block containing the composite phone number comprised of
    // prefix 'pszPrefix', base phone number 'pszBaseNumber', and suffix
    // 'pszSuffix', or NULL if the composite number is too long or on a memory
    // error.
    //
    // If 'fDownLevelIsdn' is set colons are recognized as separaters with
    // each colon separated token built treated separately.
    //
    // It is caller's responsibility to Free the returned string.
    //
{
    TCHAR* psz;
    TCHAR* pszResult;
    INT cchResult;

    TRACE( "PhoneNumberFromPrefixSuffixEx" );

    if (fDownLevelIsdn)
    {
        TCHAR* pszNum;
        TCHAR* pszS;
        TCHAR* pszE;

        pszResult = StrDup( TEXT("") );

        for (pszS = pszE = pszBaseNumber;
             *pszE != TEXT('\0');
             pszE = CharNext( pszE ))
        {
            if (*pszE == TEXT(':'))
            {
                *pszE = TEXT('\0');

                pszNum =
                    PhoneNumberFromPrefixSuffix(
                        pszS, pszPrefix, pszSuffix );

                *pszE = TEXT(':');

                if (pszNum)
                {
                    if (pszResult)
                        cchResult = lstrlen( pszResult );

                    psz = Realloc( pszResult,
                        (cchResult + lstrlen( pszNum ) + 2) * sizeof(TCHAR) );

                    if (!psz)
                    {
                        Free0( pszResult );
                        Free( pszNum );
                        return NULL;
                    }

                    pszResult = psz;
                    lstrcat( pszResult, pszNum );
                    lstrcat( pszResult, TEXT(":") );
                    Free( pszNum );
                }

                pszS = CharNext( pszE );
            }
        }

        {
            pszNum =
                PhoneNumberFromPrefixSuffix(
                    pszS, pszPrefix, pszSuffix );

            if (pszNum)
            {
                if (pszResult)
                    cchResult = lstrlen( pszResult );

                psz = Realloc( pszResult,
                    (cchResult + lstrlen( pszNum ) + 1) * sizeof(TCHAR) );

                if (!psz)
                {
                    Free0( pszResult );
                    Free( pszNum );
                    return NULL;
                }

                pszResult = psz;
                lstrcat( pszResult, pszNum );
                Free( pszNum );
            }
        }
    }
    else
    {
        pszResult =
            PhoneNumberFromPrefixSuffix(
                pszBaseNumber, pszPrefix, pszSuffix );
    }

    if (pszResult && (lstrlen( pszResult ) > RAS_MaxPhoneNumber ))
    {
        Free( pszResult );
        return NULL;
    }

    return pszResult;
}


TCHAR*
PhoneNumberFromTapiParts(
    IN HINSTANCE hInst,
    IN TCHAR* pszBaseNumber,
    IN TCHAR* pszAreaCode,
    IN DWORD dwCountryCode,
    IN OUT HLINEAPP* pHlineapp,
    IN BOOL fDialable )

    // Returns a heap block containing the composite phone number comprised of
    // base phone number 'pszBaseNumber', area code 'pszAreaCode', and country
    // code 'dwCountryCode, or NULL if the composite number is too long or on
    // a memory error.  'HInst' is the module instance handle.  '*PHlineapp'
    // is the address of the TAPI context.  'FDialable' indicates the dialable
    // string, as opposed to the displayable string, should be returned.
    //
    // It is caller's responsibility to Free the returned string.
    //
{
    TCHAR* pszResult;

    TRACE( "PhoneNumberFromTapiParts" );

    pszResult = NULL;

    TapiTranslateAddress(
        hInst, pHlineapp, dwCountryCode, pszAreaCode, pszBaseNumber,
        0, fDialable, &pszResult );

    return pszResult;
}


TCHAR*
PhoneNumberFromTapiPartsEx(
    IN HINSTANCE hInst,
    IN TCHAR* pszBaseNumber,
    IN TCHAR* pszAreaCode,
    IN DWORD dwCountryCode,
    IN BOOL fDownLevelIsdn,
    IN OUT HLINEAPP* pHlineapp,
    IN BOOL fDialable )

    // Returns  heap block containing the composite phone number comprised of
    // base phone number 'pszBaseNumber', area code 'pszAreaCode', and country
    // code 'dwCountryCode or NULL if the composite number is too long or on a
    // memory error.  'HInst' is the module instance handle.  '*PHlineapp' is
    // the address of the TAPI context.  'FDialable' indicates the dialable
    // string, as opposed to the displayable string, should be returned.
    //
    // If 'fDownLevelIsdn' is set colons are recognized as separaters with
    // each colon separated token built treated separately.
    //
    // It is caller's responsibility to Free the returned string.
    //
{
    TCHAR* psz;
    TCHAR* pszResult;
    INT cchResult;

    TRACE( "PhoneNumberFromTapiPartsEx" );

    if (fDownLevelIsdn)
    {
        TCHAR* pszNum;
        TCHAR* pszS;
        TCHAR* pszE;

        pszResult = StrDup( TEXT("") );

        for (pszS = pszE = pszBaseNumber;
             *pszE != TEXT('\0');
             pszE = CharNext( pszE ))
        {
            if (*pszE == TEXT(':'))
            {
                *pszE = TEXT('\0');

                pszNum = PhoneNumberFromTapiParts(
                    hInst, pszS, pszAreaCode, dwCountryCode, pHlineapp, fDialable );

                *pszE = TEXT(':');

                if (pszNum)
                {
                    if (pszResult)
                    {
                        cchResult = lstrlen( pszResult );
                    }

                    psz = Realloc( pszResult,
                        (cchResult + lstrlen( pszNum ) + 2) * sizeof(TCHAR) );

                    if (!psz)
                    {
                        Free0( pszResult );
                        Free( pszNum );
                        return NULL;
                    }

                    pszResult = psz;
                    lstrcat( pszResult, pszNum );
                    lstrcat( pszResult, TEXT(":") );
                    Free( pszNum );
                }

                pszS = CharNext( pszE );
            }
        }

        {
            pszNum = PhoneNumberFromTapiParts(
                hInst, pszS, pszAreaCode, dwCountryCode, pHlineapp, fDialable );

            if (pszNum)
            {
                if (pszResult)
                {
                    cchResult = lstrlen( pszResult );
                }

                psz = Realloc( pszResult,
                    (cchResult + lstrlen( pszNum ) + 1) * sizeof(TCHAR) );

                if (!psz)
                {
                    Free0( pszResult );
                    Free( pszNum );
                    return NULL;
                }

                pszResult = psz;
                lstrcat( pszResult, pszNum );
                Free( pszNum );
            }
        }
    }
    else
    {
        pszResult = PhoneNumberFromTapiParts(
            hInst, pszBaseNumber, pszAreaCode, dwCountryCode, pHlineapp,
            fDialable );
    }

    if (pszResult && (lstrlen( pszResult ) > RAS_MaxPhoneNumber ))
    {
        Free( pszResult );
        return NULL;
    }

    return pszResult;
}


VOID
PrefixSuffixFromLocationId(
    IN PBUSER* pUser,
    IN DWORD dwLocationId,
    OUT TCHAR** ppszPrefix,
    OUT TCHAR** ppszSuffix )

    // Retrieve the prefix and suffix strings, '*ppszPrefix' and '*ppszSuffix'
    // associated with TAPI location 'dwLocationId'.  'PUser' is the user
    // preferences from which to retrieve.
    //
    // It is caller's responsibility to Free the returned strings.
    //
{
#if 0 // NT4-style

    DTLNODE* pNode;
    INT iPrefix;
    INT iSuffix;

    TRACE( "PrefixSuffixFromLocationId" );

    iPrefix = iSuffix = 0;
    for (pNode = DtlGetFirstNode( pUser->pdtllistLocations );
         pNode;
         pNode = DtlGetNextNode( pNode ))
    {
        LOCATIONINFO* p = (LOCATIONINFO* )DtlGetData( pNode );
        ASSERT( p );

        if (p->dwLocationId == dwLocationId)
        {
            iPrefix = p->iPrefix;
            iSuffix = p->iSuffix;
            break;
        }
    }

    *ppszPrefix = NULL;
    if (iPrefix != 0)
    {
        pNode = DtlNodeFromIndex( pUser->pdtllistPrefixes, iPrefix - 1 );
        if (pNode)
        {
            *ppszPrefix = StrDup( (TCHAR* )DtlGetData( pNode ) );
        }
    }

    *ppszSuffix = NULL;
    if (iSuffix != 0)
    {
        pNode = DtlNodeFromIndex( pUser->pdtllistSuffixes, iSuffix - 1 );
        if (pNode)
        {
            *ppszSuffix = StrDup( (TCHAR* )DtlGetData( pNode ) );
        }
    }

#else // Stubbed in NT5/Connections

    *ppszPrefix = StrDup( TEXT("") );
    *ppszSuffix = StrDup( TEXT("") );

#endif
}