/* Copyright (c) 1995, Microsoft Corporation, all rights reserved
**
** entryw.c
** Remote Access Common Dialog APIs
** Add Entry wizard
**
** 06/20/95 Steve Cobb
*/

#include "rasdlgp.h"
#include "entry.h"

/* Page definitions.
*/
#define AE_EnPage    0
#define AE_RsPage    1
#define AE_MaPage    2
#define AE_PaPage    3
#define AE_FpPage    4
#define AE_LoPage    5
#define AE_IaPage    6
#define AE_NaPage    7
#define AE_ApPage    8
#define AE_PageCount 9


/*----------------------------------------------------------------------------
** Local datatypes (alphabetically)
**----------------------------------------------------------------------------
*/

/* Add Entry wizard context block.  All property pages refer to the single
** context block associated with the sheet.
*/
#define AEINFO struct tagAEINFO
AEINFO
{
    /* Common input arguments.
    */
    EINFO* pArgs;

    /* Wizard and page handles.  'hwndFirstPage' is the handle of the first
    ** property page initialized.  This is the page that allocates and frees
    ** the context block.
    */
    HWND hwndDlg;
    HWND hwndFirstPage;
    HWND hwndEn;
    HWND hwndRs;
    HWND hwndMa;
    HWND hwndPa;
    HWND hwndFp;
    HWND hwndIa;
    HWND hwndNa;
    HWND hwndLo;
    HWND hwndAp;

    /* Entry Name page.
    */
    HWND hwndEbEntryName;

    /* Modem/Adapter page.
    */
    HWND hwndLv;

    /* Phone number page.
    */
    HWND hwndStCountry;
    HWND hwndLbCountry;
    HWND hwndStArea;
    HWND hwndClbArea;
    HWND hwndStNumber;
    HWND hwndEbNumber;
    HWND hwndPbAlternates;

    RECT rectStNumber;
    RECT rectEbNumber;
    RECT rectPbAlternates;
    LONG dxAdjustLeft;
    LONG dyAdjustUp;

    /* Framing page.
    */
    HWND hwndRbPpp;
    HWND hwndRbSlip;

    /* Login script page.
    */
    HWND hwndRbNone;
    HWND hwndRbTerminal;
    HWND hwndRbScript;
    HWND hwndLbScripts;
    HWND hwndPbEdit;
    HWND hwndPbRefresh;

    /* IP address page.
    */
    HWND hwndCcIp;

    /* Name server page.
    */
    HWND hwndCcDns;
    HWND hwndCcWins;

    /* The phone number stash.  This allows user to change the port to another
    ** link without losing the phone number he typed.  Initialized to empty in
    ** AeInit and saved to entry in AeFinish.
    */
    DTLLIST* pListPhoneNumbers;
    BOOL     fPromoteHuntNumbers;

    /* Checkbox options chosen by user.
    */
    BOOL fInternet;
    BOOL fClearPwOk;
    BOOL fNotNt;

    /* Set true when there is only one meaningful choice of device.
    */
    BOOL fSkipMa;

    /* Set true if the selected device is a modem or null modem.
    */
    BOOL fModem;

    /* The NB_* mask of protocols configured for RAS.
    */
    DWORD dwfConfiguredProtocols;

    /* Set true if IP is configured for RAS.
    */
    BOOL fIpConfigured;
};


/*----------------------------------------------------------------------------
** Local prototypes (alphabetically)
**----------------------------------------------------------------------------
*/

int CALLBACK
AeCallbackFunc(
    IN HWND   hwndDlg,
    IN UINT   unMsg,
    IN LPARAM lparam );

VOID
AeCancel(
    IN HWND hwndPage );

AEINFO*
AeContext(
    IN HWND hwndPage );

VOID
AeExit(
    IN AEINFO* pInfo,
    IN DWORD   dwError );

VOID
AeExitInit(
    IN HWND hwndDlg );

BOOL
AeFinish(
    IN HWND hwndPage );

AEINFO*
AeInit(
    IN HWND   hwndFirstPage,
    IN EINFO* pArgs );

VOID
AeTerm(
    IN HWND hwndPage );

BOOL
ApCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl );

BOOL CALLBACK
ApDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
ApInit(
    IN HWND hwndPage );

BOOL
ApSetActive(
    IN AEINFO* pInfo );

BOOL
EnCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl );

BOOL CALLBACK
EnDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
EnInit(
    IN     HWND   hwndPage,
    IN OUT EINFO* pArgs );

BOOL
EnKillActive(
    IN AEINFO* pInfo );

BOOL
EnSetActive(
    IN AEINFO* pInfo );

BOOL CALLBACK
FpDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
FpInit(
    IN HWND hwndPage );

BOOL
FpKillActive(
    IN AEINFO* pInfo );

BOOL
FpSetActive(
    IN AEINFO* pInfo );

BOOL CALLBACK
IaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
IaInit(
    IN HWND hwndPage );

BOOL
IaKillActive(
    IN AEINFO* pInfo );

BOOL
IaSetActive(
    IN AEINFO* pInfo );

BOOL
LoCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl );

BOOL CALLBACK
LoDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
LoInit(
    IN HWND hwndPage );

BOOL
LoKillActive(
    IN AEINFO* pInfo );

BOOL
LoSetActive(
    IN AEINFO* pInfo );

BOOL CALLBACK
MaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
MaInit(
    IN HWND hwndPage );

LVXDRAWINFO*
MaLvCallback(
    IN HWND  hwndLv,
    IN DWORD dwItem );

VOID
MaLvItemChanged(
    IN AEINFO* pInfo );

BOOL
MaSetActive(
    IN AEINFO* pInfo );

BOOL CALLBACK
NaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
NaInit(
    IN HWND hwndPage );

BOOL
NaKillActive(
    IN AEINFO* pInfo );

BOOL
NaSetActive(
    IN AEINFO* pInfo );

VOID
PaAlternates(
    IN AEINFO* pInfo );

BOOL
PaCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl );

BOOL CALLBACK
PaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
PaInit(
    IN HWND hwndPage );

BOOL
PaKillActive(
    IN AEINFO* pInfo );

VOID
PaPhoneNumberToStash(
    IN AEINFO* pInfo );

BOOL
PaSetActive(
    IN AEINFO* pInfo );

VOID
PaUpdateAreaAndCountryCode(
    IN AEINFO* pInfo );

BOOL CALLBACK
RsDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam );

BOOL
RsInit(
    IN HWND hwndPage );

BOOL
RsKillActive(
    IN AEINFO* pInfo );

BOOL
RsSetActive(
    IN AEINFO* pInfo );


/*----------------------------------------------------------------------------
** Add Entry wizard entry point
**----------------------------------------------------------------------------
*/

VOID
AeWizard(
    IN OUT EINFO* pEinfo )

    /* Runs the Phonebook entry property sheet.  'PEinfo' is an input block
    ** with only caller's API arguments filled in.
    */
{
    DWORD           dwErr;
    PROPSHEETHEADER header;
    PROPSHEETPAGE   apage[ AE_PageCount ];
    PROPSHEETPAGE*  ppage;

    TRACE("AeWizard");

    ZeroMemory( &header, sizeof(header) );

    header.dwSize = sizeof(PROPSHEETHEADER);
    header.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_USECALLBACK;
    header.hwndParent = pEinfo->pApiArgs->hwndOwner;
    header.hInstance = g_hinstDll;
    header.nPages = AE_PageCount;
    header.ppsp = apage;
    header.pfnCallback = AeCallbackFunc;

    ZeroMemory( apage, sizeof(apage) );

    ppage = &apage[ AE_EnPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_EN_EntryName );
    ppage->pfnDlgProc = EnDlgProc;
    ppage->lParam = (LPARAM )pEinfo;

    ppage = &apage[ AE_RsPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_RS_RandomStuff );
    ppage->pfnDlgProc = RsDlgProc;

    ppage = &apage[ AE_MaPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_MA_ModemAdapter );
    ppage->pfnDlgProc = MaDlgProc;

    ppage = &apage[ AE_PaPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_PA_PhoneNumber );
    ppage->pfnDlgProc = PaDlgProc;

    ppage = &apage[ AE_FpPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_FP_Framing );
    ppage->pfnDlgProc = FpDlgProc;

    ppage = &apage[ AE_LoPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_LO_LoginScript );
    ppage->pfnDlgProc = LoDlgProc;

    ppage = &apage[ AE_IaPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_IA_IpAddress );
    ppage->pfnDlgProc = IaDlgProc;

    ppage = &apage[ AE_NaPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_NA_NameServers );
    ppage->pfnDlgProc = NaDlgProc;

    ppage = &apage[ AE_ApPage ];
    ppage->dwSize = sizeof(PROPSHEETPAGE);
    ppage->hInstance = g_hinstDll;
    ppage->pszTemplate = MAKEINTRESOURCE( PID_AP_Properties );
    ppage->pfnDlgProc = ApDlgProc;

    if (PropertySheet( &header ) == -1)
    {
        TRACE("PropertySheet failed");
        ErrorDlg( pEinfo->pApiArgs->hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN,
            NULL );
    }
}


/*----------------------------------------------------------------------------
** Add Entry wizard
** Listed alphabetically
**----------------------------------------------------------------------------
*/

int CALLBACK
AeCallbackFunc(
    IN HWND   hwndDlg,
    IN UINT   unMsg,
    IN LPARAM lparam )

    /* A standard Win32 commctrl PropSheetProc.  See MSDN documentation.
    **
    ** Returns 0 always.
    */
{
    TRACE2("AeCallbackFunc(m=%d,l=%08x)",unMsg,lparam);

    if (unMsg == PSCB_PRECREATE)
    {
        DLGTEMPLATE* pDlg = (DLGTEMPLATE* )lparam;
        pDlg->style &= ~(DS_CONTEXTHELP);
    }

    return 0;
}


VOID
AeCancel(
    IN HWND hwndPage )

    /* Cancel was pressed.  'HwndPage' is the handle of a wizard page.
    */
{
    TRACE("AeCancel");
}


AEINFO*
AeContext(
    IN HWND hwndPage )

    /* Retrieve the property sheet context from a wizard page handle.
    */
{
    return (AEINFO* )GetProp( GetParent( hwndPage ), g_contextId );
}


VOID
AeExit(
    IN AEINFO* pInfo,
    IN DWORD   dwError )

    /* Forces an exit from the dialog, reporting 'dwError' to the caller.
    ** 'PInfo' is the dialog context.
    **
    ** Note: This cannot be called during initialization of the first page.
    **       See AeExitInit.
    */
{
    TRACE("AeExit");

    pInfo->pArgs->pApiArgs->dwError = dwError;
    PropSheet_PressButton( pInfo->hwndDlg, PSBTN_CANCEL );
}


VOID
AeExitInit(
    IN HWND hwndDlg )

    /* Utility to report errors within AeInit and other first page
    ** initialization.  'HwndDlg' is the dialog window.
    */
{
    SetOffDesktop( hwndDlg, SOD_MoveOff, NULL );
    SetOffDesktop( hwndDlg, SOD_Free, NULL );
    PostMessage( hwndDlg, WM_COMMAND,
        MAKEWPARAM( IDCANCEL , BN_CLICKED ),
        (LPARAM )GetDlgItem( hwndDlg, IDCANCEL ) );
}


BOOL
AeFinish(
    IN HWND hwndPage )

    /* Saves the contents of the wizard.  'HwndPage is the handle of a
    ** property page.  Pops up any errors that occur.  'FPropertySheet'
    ** indicates the user chose to edit the property sheet directly.
    **
    ** Returns true is page can be dismissed, false otherwise.
    */
{
    const TCHAR* pszIp0 = TEXT("0.0.0.0");

    AEINFO*  pInfo;
    PBENTRY* pEntry;

    TRACE("AeFinish");

    pInfo = AeContext( hwndPage );
    ASSERT(pInfo);
    pEntry = pInfo->pArgs->pEntry;
    ASSERT(pEntry);

    /* Attach the stashed phone number information to the final link(s).
    */
    EuPhoneNumberStashToEntry( pInfo->pArgs, pInfo->pListPhoneNumbers,
        pInfo->fPromoteHuntNumbers, TRUE );

    /* Update some settings based on user selections.
    */
    if (pInfo->fNotNt)
    {
        pEntry->fLcpExtensions = FALSE;
        pEntry->fSwCompression = FALSE;
    }

    if (!pInfo->fClearPwOk)
        pEntry->dwAuthRestrictions = AR_AuthEncrypted;

    if (pInfo->fInternet && pEntry->dwBaseProtocol == BP_Ppp)
        pEntry->dwfExcludedProtocols |= (NP_Nbf | NP_Ipx);

    if (pEntry->pszIpAddress
        && lstrcmp( pEntry->pszIpAddress, pszIp0 ) != 0)
    {
        pEntry->dwIpAddressSource = ASRC_RequireSpecific;
    }

    if ((pEntry->pszIpDnsAddress
             && lstrcmp( pEntry->pszIpDnsAddress, pszIp0 ) != 0)
        || (pEntry->pszIpWinsAddress
             && lstrcmp( pEntry->pszIpWinsAddress, pszIp0 ) != 0))
    {
        pEntry->dwIpNameSource = ASRC_RequireSpecific;
    }

    /* It's a valid new entry and caller has not chosen to edit properties
    ** directly, so mark the entry for commitment.
    */
    if (!pInfo->pArgs->fChainPropertySheet)
        pInfo->pArgs->fCommit = TRUE;

    return TRUE;
}


AEINFO*
AeInit(
    IN HWND   hwndFirstPage,
    IN EINFO* pArgs )

    /* Wizard level initialization.  'HwndPage' is the handle of the first
    ** page.  'PArgs' is the common entry input argument block.
    **
    ** Returns address of the context block if successful, NULL otherwise.  If
    ** NULL is returned, an appropriate message has been displayed, and the
    ** wizard has been cancelled.
    */
{
    DWORD   dwErr;
    DWORD   dwOp;
    AEINFO* pInfo;
    HWND    hwndDlg;

    TRACE("AeInit");

    hwndDlg = GetParent( hwndFirstPage );

    /* Allocate the context information block.  Initialize it enough so that
    ** it can be destroyed properly, and associate the context with the
    ** window.
    */
    {
        pInfo = Malloc( sizeof(*pInfo) );
        if (!pInfo)
        {
            TRACE("Context NOT allocated");
            ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
            pArgs->pApiArgs->dwError = ERROR_NOT_ENOUGH_MEMORY;
            AeExitInit( hwndDlg );
            return NULL;
        }

        ZeroMemory( pInfo, sizeof(AEINFO) );
        pInfo->pArgs = pArgs;
        pInfo->hwndDlg = hwndDlg;
        pInfo->hwndFirstPage = hwndFirstPage;

        if (!SetProp( hwndDlg, g_contextId, pInfo ))
        {
            TRACE("Context NOT set");
            ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
            pArgs->pApiArgs->dwError = ERROR_UNKNOWN;
            Free( pInfo );
            AeExitInit( hwndDlg );
            return NULL;
        }

        TRACE("Context set");
    }

    /* Position the dialog per caller's instructions.
    */
    PositionDlg( hwndDlg,
        pArgs->pApiArgs->dwFlags & RASDDFLAG_PositionDlg,
        pArgs->pApiArgs->xDlg, pArgs->pApiArgs->yDlg );

    /* Mess with the title bar gadgets.
    */
    TweakTitleBar( hwndDlg );

    /* Load RAS DLL entrypoints which starts RASMAN, if necessary.
    */
    dwErr = LoadRas( g_hinstDll, hwndDlg );
    if (dwErr != 0)
    {
        ErrorDlg( hwndDlg, SID_OP_LoadRas, dwErr, NULL );
        pArgs->pApiArgs->dwError = dwErr;
        AeExitInit( hwndDlg );
        return NULL;
    }

    /* Load the common entry information.  This must happen after RasLoad,
    ** which must happen after the dialog has been positioned so that the
    ** "Waiting for services" appears where the dialog will eventually popup.
    ** Note that EuInit assues that EuInit0 has previously been called.
    */
    dwErr = EuInit( pArgs, &dwOp );
    if (dwErr != 0)
    {
        ErrorDlg( hwndDlg, dwOp, dwErr, NULL );
        pArgs->pApiArgs->dwError = dwErr;
        AeExitInit( hwndDlg );
        return NULL;
    }

    /* Initialize these meta-flags that are not actually stored.
    */
    pInfo->fNotNt = FALSE;
    pInfo->fSkipMa = FALSE;
    pInfo->fModem = FALSE;
    pInfo->dwfConfiguredProtocols = GetInstalledProtocols();
    pInfo->fIpConfigured = (pInfo->dwfConfiguredProtocols & NP_Ip);

    /* Initialize the phone number stash to from the entry, i.e. set it to
    ** empty default.  The stash list is edited rather than the list in the
    ** entry so user can change active links without losing the phone number
    ** he entered.
    */
    EuPhoneNumberStashFromEntry( pArgs, &pInfo->pListPhoneNumbers,
        &pInfo->fPromoteHuntNumbers );

    return pInfo;
}


VOID
AeTerm(
    IN HWND hwndPage )

    /* Wizard level termination.  Releases the context block.  'HwndPage' is
    ** the handle of a property page.
    */
{
    AEINFO* pInfo;

    TRACE("AeTerm");

    pInfo = AeContext( hwndPage );
    if (pInfo)
    {
        DtlDestroyList( pInfo->pListPhoneNumbers, DestroyPszNode );

        Free( pInfo );
        TRACE("Context freed");
    }

    RemoveProp( GetParent( hwndPage ), g_contextId );
}


/*----------------------------------------------------------------------------
** Entry Name property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
EnDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Entry Name page of the wizard.  Parameters
    ** and return value are as described for standard windows 'DialogProc's.
    */
{
#if 0
    TRACE4("EnDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
        {
            return
                EnInit( hwnd, (EINFO* )(((PROPSHEETPAGE* )lparam)->lParam) );
        }

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_RESET:
                {
                    TRACE("EnRESET");
                    AeCancel( hwnd );
                    SetWindowLong( hwnd, DWL_MSGRESULT, FALSE );
                    return TRUE;
                }

                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("EnSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = EnSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("EnKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = EnKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }

                case PSN_WIZFINISH:
                {
                    AEINFO* pInfo;

                    TRACE("EnWIZFINISH");

                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);

                    /* You'd think pressing Finish would trigger a KILLACTIVE
                    ** event, but it doesn't, so we do it ourselves.
                    */
                    EnKillActive( pInfo );

                    /* Set "no wizard" user preference, per user's check.
                    */
                    pInfo->pArgs->pUser->fNewEntryWizard = FALSE;
                    pInfo->pArgs->pUser->fDirty = TRUE;
                    SetUserPreferences(
                        pInfo->pArgs->pUser, pInfo->pArgs->fNoUser );

                    pInfo->pArgs->fChainPropertySheet = TRUE;
                    AeFinish( hwnd );
                    SetWindowLong( hwnd, DWL_MSGRESULT, 0 );
                    return TRUE;
                }
            }
            break;
        }

        case WM_COMMAND:
        {
            AEINFO* pInfo = AeContext( hwnd );
            ASSERT(pInfo);

            return EnCommand(
                pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
        }

        case WM_DESTROY:
        {
            AeTerm( hwnd );
            break;
        }
    }

    return FALSE;
}


BOOL
EnCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl )

    /* Called on WM_COMMAND.  'PInfo' is the dialog context.  'WNotification'
    ** is the notification code of the command.  'wId' is the control/menu
    ** identifier of the command.  'HwndCtrl' is the control window handle of
    ** the command.
    **
    ** Returns true if processed message, false otherwise.
    */
{
    TRACE3("EnCommand(n=%d,i=%d,c=$%x)",
        (DWORD)wNotification,(DWORD)wId,(DWORD)hwndCtrl);

    switch (wId)
    {
        case CID_EN_CB_SkipWizard:
        {
            if (IsDlgButtonChecked( pInfo->hwndEn, CID_EN_CB_SkipWizard ))
                PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_FINISH );
            else
                PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_NEXT );
            return TRUE;
        }
    }

    return FALSE;
}


BOOL
EnInit(
    IN     HWND   hwndPage,
    IN OUT EINFO* pArgs )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.  'PArgs' is the arguments from the PropertySheet caller.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    DWORD    dwErr;
    AEINFO*  pInfo;
    PBENTRY* pEntry;

    TRACE("EnInit");

    /* We're first page, so initialize the wizard.
    */
    pInfo = AeInit( hwndPage, pArgs );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndEn = hwndPage;
    pInfo->hwndEbEntryName = GetDlgItem( hwndPage, CID_EN_EB_EntryName );
    ASSERT(pInfo->hwndEbEntryName);

    /* Initialize the entry name field.
    */
    pEntry = pInfo->pArgs->pEntry;
    if (!pEntry->pszEntryName)
    {
        /* No entry name, so think up a default.
        */
        dwErr = GetDefaultEntryName(
            pInfo->pArgs->pFile->pdtllistEntries, &pEntry->pszEntryName );
        if (dwErr != 0)
        {
            ErrorDlg( pInfo->hwndDlg, SID_OP_LoadPage, dwErr, NULL );
            AeExit( pInfo, dwErr );
            return TRUE;
        }
    }

    Edit_LimitText( pInfo->hwndEbEntryName, RAS_MaxEntryName );
    SetWindowText( pInfo->hwndEbEntryName, pEntry->pszEntryName );

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return TRUE;
}


BOOL
EnKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    TCHAR* psz;

    psz = GetText( pInfo->hwndEbEntryName );
    if (psz)
    {
        /* Update the entry name from the editbox.
        */
        Free0( pInfo->pArgs->pEntry->pszEntryName );
        pInfo->pArgs->pEntry->pszEntryName = psz;

        /* Validate the entry name.
        */
        if (!EuValidateName( pInfo->hwndDlg, pInfo->pArgs ))
        {
            SetFocus( pInfo->hwndEbEntryName );
            Edit_SetSel( pInfo->hwndEbEntryName, 0, -1 );
            return TRUE;
        }
    }

    return FALSE;
}


BOOL
EnSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Random stuff property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
RsDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the 3 random checkboxes page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("RsDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return RsInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("RsSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = RsSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("RsKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = RsKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }
    }

    return FALSE;
}


BOOL
RsInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("NeInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndRs = hwndPage;

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
RsKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    pInfo->fInternet =
        IsDlgButtonChecked( pInfo->hwndRs, CID_RS_CB_Internet );
    pInfo->fClearPwOk =
        IsDlgButtonChecked( pInfo->hwndRs, CID_RS_CB_PlainPw );
    pInfo->fNotNt =
        IsDlgButtonChecked( pInfo->hwndRs, CID_RS_CB_NotNt );

    if (pInfo->fInternet && !pInfo->fIpConfigured)
    {
        MsgDlg( pInfo->hwndDlg, SID_InternetWithoutIp, NULL );
        SetFocus( GetDlgItem( pInfo->hwndRs, CID_RS_CB_Internet ) );
        return TRUE;
    }

    return FALSE;
}


BOOL
RsSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Modem/Adapter property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
MaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Modem/Adapter page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("MaDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    if (ListView_OwnerHandler(
            hwnd, unMsg, wparam, lparam, MaLvCallback ))
    {
        return TRUE;
    }

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return MaInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("MaSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = MaSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case LVN_ITEMCHANGED:
                {
                    AEINFO* pInfo;

                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    MaLvItemChanged( pInfo );
                    return TRUE;
                }
            }
            break;
        }
    }

    return FALSE;
}


BOOL
MaInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    DWORD   dwErr;
    AEINFO* pInfo;

    TRACE("MaInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndMa = hwndPage;
    pInfo->hwndLv = GetDlgItem( hwndPage, CID_MA_LV_Devices );
    ASSERT(pInfo->hwndLv);

    ListView_DeleteAllItems( pInfo->hwndLv );

    /* Add the modem and adapter images.
    */
    ListView_SetDeviceImageList( pInfo->hwndLv, g_hinstDll );

    /* Fill the list of devices and select the first item.
    */
    {
        TCHAR*   psz;
        DTLNODE* pNode;
        DWORD    cMultilinkableIsdn;
        INT      iItem;

        iItem = 1;
        cMultilinkableIsdn = 0;
        for (pNode = DtlGetFirstNode( pInfo->pArgs->pEntry->pdtllistLinks );
             pNode;
             pNode = DtlGetNextNode( pNode ))
        {
            PBLINK* pLink;

            pLink = (PBLINK* )DtlGetData( pNode );
            ASSERT(pLink);

            if (pLink->pbport.pbdevicetype == PBDT_Isdn
                && !pLink->fProprietaryIsdn)
            {
                ++cMultilinkableIsdn;
            }

            psz = DisplayPszFromDeviceAndPort(
                pLink->pbport.pszDevice, pLink->pbport.pszPort );
            if (psz)
            {
                PBLINK* pLink;
                LV_ITEM item;

                pLink = (PBLINK* )DtlGetData( pNode );

                ZeroMemory( &item, sizeof(item) );
                item.mask = LVIF_TEXT + LVIF_IMAGE + LVIF_PARAM;
                item.iItem = iItem++;
                item.pszText = psz;

                item.iImage =
                    (pLink->pbport.pbdevicetype == PBDT_Modem)
                        ? DI_Modem : DI_Adapter;

                item.lParam = (LPARAM )pNode;

                ListView_InsertItem( pInfo->hwndLv, &item );
                Free( psz );
            }
        }

        if (cMultilinkableIsdn > 1)
        {
            psz = PszFromId( g_hinstDll, SID_IsdnAdapter );
            if (psz)
            {
                LONG    lStyle;
                LV_ITEM item;

                /* Turn off sorting so the special ISDN-multilink item appears
                ** at the top of the list.
                */
                lStyle = GetWindowLong( pInfo->hwndLv, GWL_STYLE );
                SetWindowLong( pInfo->hwndLv, GWL_STYLE,
                    (lStyle & ~(LVS_SORTASCENDING)) );

                ZeroMemory( &item, sizeof(item) );
                item.mask = LVIF_TEXT + LVIF_IMAGE + LVIF_PARAM;
                item.iItem = 0;
                item.pszText = psz;
                item.iImage = DI_Adapter;
                item.lParam = (LPARAM )NULL;

                ListView_InsertItem( pInfo->hwndLv, &item );
                Free( psz );
            }
        }

        /* Select the first item.
        */
        ListView_SetItemState( pInfo->hwndLv, 0, LVIS_SELECTED, LVIS_SELECTED );

        /* Add a single column exactly wide enough to fully display the
        ** widest member of the list.
        */
        {
            LV_COLUMN col;

            ZeroMemory( &col, sizeof(col) );
            col.mask = LVCF_FMT;
            col.fmt = LVCFMT_LEFT;
            ListView_InsertColumn( pInfo->hwndLv, 0, &col );
            ListView_SetColumnWidth(
                pInfo->hwndLv, 0, LVSCW_AUTOSIZE_USEHEADER );
        }
    }

    /* Don't bother with this page if there's only one device, not counting
    ** the bogus "uninstalled" standard modem that's added by EuInit so
    ** entries can be edited when there are no ports.
    */
    if (!pInfo->pArgs->fNoPortsConfigured
        && ListView_GetItemCount( pInfo->hwndLv ) == 1)
    {
        pInfo->fSkipMa = TRUE;
    }

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


LVXDRAWINFO*
MaLvCallback(
    IN HWND  hwndLv,
    IN DWORD dwItem )

    /* Enhanced list view callback to report drawing information.  'HwndLv' is
    ** the handle of the list view control.  'DwItem' is the index of the item
    ** being drawn.
    **
    ** Returns the address of the column information.
    */
{
    /* Use "wide selection bar" feature and the other recommended options.
    **
    ** Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'.
    */
    static LVXDRAWINFO info =
        { 1, 0, LVXDI_DxFill, { 0, 0 } };

    return &info;
}


VOID
MaLvItemChanged(
    IN AEINFO* pInfo )

    /* Called when the combobox selection changes.  'PInfo' is the wizard
    ** context.
    */
{
    INT      iSel;
    DTLNODE* pNode;
    DTLLIST* pList;

    TRACE("MaLvSelChange");

    pList = pInfo->pArgs->pEntry->pdtllistLinks;
    ASSERT(pList);
    pNode = (DTLNODE* )ListView_GetSelectedParamPtr( pInfo->hwndLv );

    if (pNode)
    {
        PBLINK* pLink;

        /* Single device selected.  Enable it, move it to the head of the list
        ** of links, and disable all the other links.
        */
        pLink = (PBLINK* )DtlGetData( pNode );
        pLink->fEnabled = TRUE;

        pInfo->fModem =
            (pLink->pbport.pbdevicetype == PBDT_Modem
             || pLink->pbport.pbdevicetype == PBDT_Null);

        DtlRemoveNode( pList, pNode );
        DtlAddNodeFirst( pList, pNode );

        for (pNode = DtlGetNextNode( pNode );
             pNode;
             pNode = DtlGetNextNode( pNode ))
        {
            PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
            ASSERT(pLink);
            pLink->fEnabled = FALSE;
        }
    }
    else
    {
        DTLNODE* pNextNode;
        DTLNODE* pAfterNode;

        pInfo->fModem = FALSE;

        /* ISDN multi-link selected.  Enable the ISDN multi-link nodes, move
        ** them to the head of the list, and disable all the other links.
        */
        pAfterNode = NULL;
        for (pNode = DtlGetFirstNode( pList );
             pNode;
             pNode = pNextNode)
        {
            PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
            ASSERT(pLink);

            pNextNode = DtlGetNextNode( pNode );

            if (pLink->pbport.pbdevicetype == PBDT_Isdn
                && !pLink->fProprietaryIsdn)
            {
                pLink->fEnabled = TRUE;

                DtlRemoveNode( pList, pNode );
                if (pAfterNode)
                    DtlAddNodeAfter( pList, pAfterNode, pNode );
                else
                    DtlAddNodeFirst( pList, pNode );
                pAfterNode = pNode;
            }
            else
            {
                pLink->fEnabled = FALSE;
            }
        }
    }
}


BOOL
MaSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    INT cDevices;

    if (pInfo->fSkipMa)
        return FALSE;

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Phone Number property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
PaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Phone Number page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("PaDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return PaInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("PaSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = PaSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("PaKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = PaKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }

        case WM_COMMAND:
        {
            AEINFO* pInfo = AeContext( hwnd );
            ASSERT(pInfo);

            return PaCommand(
                pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
        }
    }

    return FALSE;
}


VOID
PaAlternates(
    IN AEINFO* pInfo )

    /* Popup the Alternate Phone Numbers dialog.  'PInfo' is the property
    ** sheet context.
    */
{
    PaPhoneNumberToStash( pInfo );

    if (PhoneNumberDlg(
            pInfo->hwndPa,
            pInfo->pListPhoneNumbers,
            &pInfo->fPromoteHuntNumbers ))
    {
        TCHAR* pszPhoneNumber;

        pszPhoneNumber = FirstPszFromList( pInfo->pListPhoneNumbers );
        SetWindowText( pInfo->hwndEbNumber, pszPhoneNumber );
    }
}


BOOL
PaCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl )

    /* Called on WM_COMMAND.  'PInfo' is the dialog context.  'WNotification'
    ** is the notification code of the command.  'wId' is the control/menu
    ** identifier of the command.  'HwndCtrl' is the control window handle of
    ** the command.
    **
    ** Returns true if processed message, false otherwise.
    */
{
    TRACE3("PaCommand(n=%d,i=%d,c=$%x)",
        (DWORD)wNotification,(DWORD)wId,(DWORD)hwndCtrl);

    switch (wId)
    {
        case CID_PA_PB_Alternates:
            PaAlternates( pInfo );
            return TRUE;

        case CID_PA_CB_UseAreaCountry:
            PaUpdateAreaAndCountryCode( pInfo );
            return TRUE;

        case CID_PA_LB_Country:
        {
            switch (wNotification)
            {
                case CBN_DROPDOWN:
                    EuFillCountryCodeList(
                        pInfo->pArgs, pInfo->hwndLbCountry, TRUE );
                    return TRUE;

                case CBN_SELCHANGE:
                    EuLbCountryCodeSelChange(
                        pInfo->pArgs, pInfo->hwndLbCountry );
                    return TRUE;
            }
        }
    }

    return FALSE;
}


BOOL
PaInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("PaInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndPa = hwndPage;
    pInfo->hwndStCountry = GetDlgItem( hwndPage, CID_PA_ST_Country );
    ASSERT(pInfo->hwndStCountry);
    pInfo->hwndLbCountry = GetDlgItem( hwndPage, CID_PA_LB_Country );
    ASSERT(pInfo->hwndLbCountry);
    pInfo->hwndStArea = GetDlgItem( hwndPage, CID_PA_ST_Area );
    ASSERT(pInfo->hwndStArea);
    pInfo->hwndClbArea = GetDlgItem( hwndPage, CID_PA_CLB_Area );
    ASSERT(pInfo->hwndClbArea);
    pInfo->hwndStNumber = GetDlgItem( hwndPage, CID_PA_ST_Number );
    ASSERT(pInfo->hwndStNumber);
    pInfo->hwndEbNumber = GetDlgItem( hwndPage, CID_PA_EB_Number );
    ASSERT(pInfo->hwndEbNumber);
    pInfo->hwndPbAlternates = GetDlgItem( hwndPage, CID_PA_PB_Alternates );
    ASSERT(pInfo->hwndPbAlternates);

    /* Calculate the client coordinates of the phone number controls and the
    ** offsets they move left and up when "use country and area code" is off.
    */
    {
        RECT rectLbCountry;

        GetWindowRect( pInfo->hwndLbCountry, &rectLbCountry );
        GetWindowRect( pInfo->hwndStNumber, &pInfo->rectStNumber );
        GetWindowRect( pInfo->hwndEbNumber, &pInfo->rectEbNumber );
        GetWindowRect( pInfo->hwndPbAlternates, &pInfo->rectPbAlternates );

        pInfo->dxAdjustLeft = pInfo->rectEbNumber.left - rectLbCountry.left;
        pInfo->dyAdjustUp = pInfo->rectEbNumber.top - rectLbCountry.top;

        ScreenToClientRect( hwndPage, &pInfo->rectStNumber );
        ScreenToClientRect( hwndPage, &pInfo->rectEbNumber );
        ScreenToClientRect( hwndPage, &pInfo->rectPbAlternates );
    }

    /* Fill the phone number field from the stash created earlier.
    */
    Edit_LimitText( pInfo->hwndEbNumber, RAS_MaxPhoneNumber );
    SetWindowText( pInfo->hwndEbNumber,
        FirstPszFromList( pInfo->pListPhoneNumbers ) );

    /* Set "Use country code and area code" checkbox and jockey the fields
    ** according to the setting.  This will trigger filling of the area code
    ** and country code lists, if necessary.
    */
    CheckDlgButton( pInfo->hwndPa, CID_PA_CB_UseAreaCountry,
        (pInfo->pArgs->pEntry->fUseCountryAndAreaCode)
            ? BST_CHECKED : BST_UNCHECKED );
    PaUpdateAreaAndCountryCode( pInfo );

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
PaKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    DWORD    dwErr;
    PBENTRY* pEntry;
    TCHAR*   psz;

    pEntry = pInfo->pArgs->pEntry;
    ASSERT(pEntry);

    /* Update the stashed phone number from the editbox.
    */
    PaPhoneNumberToStash( pInfo );

    /* Store the area/country checkbox.
    */
    pEntry->fUseCountryAndAreaCode =
        IsDlgButtonChecked( pInfo->hwndPa, CID_PA_CB_UseAreaCountry );

    /* Store the country code and ID.
    */
    EuSaveCountryInfo( pInfo->pArgs, pInfo->hwndLbCountry );

    /* Store the area code.
    */
    Free0( pEntry->pszAreaCode );
    pEntry->pszAreaCode = GetText( pInfo->hwndClbArea );
    if (!pEntry->pszAreaCode)
    {
        dwErr = ERROR_NOT_ENOUGH_MEMORY;
        ErrorDlg( pInfo->hwndDlg, SID_OP_RetrievingData, dwErr, NULL );
        AeExit( pInfo, dwErr );
        return FALSE;
    }

    /* Validate area code.
    */
    if (!EuValidateAreaCode( pInfo->hwndDlg, pInfo->pArgs ))
    {
        SetFocus( pInfo->hwndClbArea );
        ComboBox_SetEditSel( pInfo->hwndClbArea, 0, -1 );
        return TRUE;
    }

    return FALSE;
}


VOID
PaPhoneNumberToStash(
    IN AEINFO* pInfo )

    /* Replace the first phone number in the stashed list with the contents of
    ** the phone number field.  'pInfo' is the property sheet context.
    */
{
    DWORD  dwErr;
    TCHAR* pszPhoneNumber;

    TRACE("PaPhoneNumberToStash");

    pszPhoneNumber = GetText( pInfo->hwndEbNumber );
    if (pszPhoneNumber)
    {
        dwErr = FirstPszToList( pInfo->pListPhoneNumbers, pszPhoneNumber );
        Free( pszPhoneNumber );
    }
    else
        dwErr = ERROR_NOT_ENOUGH_MEMORY;

    if (dwErr != 0)
    {
        ErrorDlg( pInfo->hwndDlg, SID_OP_RetrievingData, dwErr, NULL );
        AeExit( pInfo, dwErr );
    }
}


BOOL
PaSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


VOID
PaUpdateAreaAndCountryCode(
    IN AEINFO* pInfo )

    /* Handles enabling/disabling of the Area Code and Country Code controls
    ** and moving/sizing of the Phone Number control based on the "use area
    ** code and country code" checkbox.  'PInfo' is the dialog context.
    */
{
    HWND hwndFocus;
    BOOL fEnable;

    TRACE("PaUpdateAreaAndCountryCode");

    fEnable = IsDlgButtonChecked(
        pInfo->hwndPa, CID_PA_CB_UseAreaCountry );

    if (fEnable)
    {
        /* The area code and country code lists are being activated, so fill
        ** the lists if they aren't already.
        */
        EuFillCountryCodeList( pInfo->pArgs, pInfo->hwndLbCountry, FALSE );
        EuFillAreaCodeList( pInfo->pArgs, pInfo->hwndClbArea );
    }
    else
    {
        /* If the focus is on one of the controls we're about to disable, move
        ** it to the entry phone number editbox.  Otherwise, keyboard user is
        ** stuck.
        */
        hwndFocus = GetFocus();

        if (hwndFocus == pInfo->hwndLbCountry
            || hwndFocus == pInfo->hwndClbArea)
        {
            SetFocus( pInfo->hwndEbNumber );
        }
    }

    /* Enable/disable show/hide the country code and area code controls as
    ** indicated by user.
    */
    {
        int nCmdShow = (fEnable) ? SW_SHOW : SW_HIDE;

        EnableWindow( pInfo->hwndStCountry, fEnable );
        ShowWindow( pInfo->hwndStCountry, nCmdShow );
        EnableWindow( pInfo->hwndLbCountry, fEnable );
        ShowWindow( pInfo->hwndLbCountry, nCmdShow );

        EnableWindow( pInfo->hwndStArea, fEnable );
        ShowWindow( pInfo->hwndStArea, nCmdShow );
        EnableWindow( pInfo->hwndClbArea, fEnable );
        ShowWindow( pInfo->hwndClbArea, nCmdShow );
    }

    /* Move/size the phone number controls depending on whether the area code
    ** and country code controls are visible.
    */
    {
        RECT rectStNumber;
        RECT rectEbNumber;
        RECT rectPbAlternates;

        rectStNumber = pInfo->rectStNumber;
        rectEbNumber = pInfo->rectEbNumber;
        rectPbAlternates = pInfo->rectPbAlternates;

        if (!fEnable)
        {
            rectStNumber.left -= pInfo->dxAdjustLeft;
            rectStNumber.top -= pInfo->dyAdjustUp;
            rectStNumber.bottom -= pInfo->dyAdjustUp;

            rectEbNumber.left -= pInfo->dxAdjustLeft;
            rectEbNumber.top -= pInfo->dyAdjustUp;
            rectEbNumber.bottom -= pInfo->dyAdjustUp;

            rectPbAlternates.top -= pInfo->dyAdjustUp;
        }

        SetWindowPos( pInfo->hwndStNumber, NULL,
            rectStNumber.left,
            rectStNumber.top,
            rectStNumber.right - rectStNumber.left,
            rectStNumber.bottom - rectStNumber.top,
            SWP_NOZORDER | SWP_NOCOPYBITS );

        SetWindowPos( pInfo->hwndEbNumber, NULL,
            rectEbNumber.left,
            rectEbNumber.top,
            rectEbNumber.right - rectEbNumber.left,
            rectEbNumber.bottom - rectEbNumber.top,
            SWP_NOZORDER + SWP_NOCOPYBITS );

        SetWindowPos( pInfo->hwndPbAlternates, NULL,
            pInfo->rectPbAlternates.left, rectPbAlternates.top, 0, 0,
            SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS );
    }
}


/*----------------------------------------------------------------------------
** Framing Protocol property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
FpDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Framing Protocol page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("FpDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return FpInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("FpSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = FpSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("FpKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = FpKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }
    }

    return FALSE;
}


BOOL
FpInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("FpInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndFp = hwndPage;
    pInfo->hwndRbPpp = GetDlgItem( hwndPage, CID_FP_RB_Ppp );
    ASSERT(pInfo->hwndRbPpp);
    pInfo->hwndRbSlip = GetDlgItem( hwndPage, CID_FP_RB_Slip );
    ASSERT(pInfo->hwndRbSlip);

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
FpKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    if (Button_GetCheck( pInfo->hwndRbPpp ))
        pInfo->pArgs->pEntry->dwBaseProtocol = BP_Ppp;
    else
        pInfo->pArgs->pEntry->dwBaseProtocol = BP_Slip;

    return FALSE;
}


BOOL
FpSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    HWND hwndRb;

    if (!pInfo->fNotNt || !pInfo->fModem || !pInfo->fIpConfigured)
        return FALSE;

    /* Set the radio buttons.
    */
    if (pInfo->pArgs->pEntry->dwBaseProtocol == BP_Ppp)
        hwndRb = pInfo->hwndRbPpp;
    else
    {
        ASSERT(pInfo->pArgs->pEntry->dwBaseProtocol==BP_Slip);
        hwndRb = pInfo->hwndRbSlip;
    }
    SendMessage( hwndRb, BM_CLICK, 0, 0 );

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Logon Script property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
LoDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Logon Script page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("LoDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return LoInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("LoSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = LoSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("LoKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = LoKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }

        case WM_COMMAND:
        {
            AEINFO* pInfo = AeContext( hwnd );
            ASSERT(pInfo);

            return LoCommand(
                pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
        }
    }

    return FALSE;
}


BOOL
LoCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl )

    /* Called on WM_COMMAND.  'PInfo' is the dialog context.  'WNotification'
    ** is the notification code of the command.  'wId' is the control/menu
    ** identifier of the command.  'HwndCtrl' is the control window handle of
    ** the command.
    **
    ** Returns true if processed message, false otherwise.
    */
{
    TRACE3("LoCommand(n=%d,i=%d,c=$%x)",
        (DWORD)wNotification,(DWORD)wId,(DWORD)hwndCtrl);

    switch (wId)
    {
        case CID_LO_PB_Refresh:
        {
            INT    iSel;
            TCHAR* pszSel;

            iSel = ComboBox_GetCurSel( pInfo->hwndLbScripts );
            if (iSel > 0)
                pszSel = ComboBox_GetPsz( pInfo->hwndLbScripts, iSel );
            else
                pszSel = NULL;

            EuFillDoubleScriptsList(
                pInfo->pArgs, pInfo->hwndLbScripts, pszSel );
            Free0( pszSel );
            return TRUE;
        }

        case CID_LO_PB_Edit:
        {
            TCHAR* psz;

            psz = GetText( pInfo->hwndLbScripts );
            if (psz)
            {
                if (FileExists( psz ))
                    EuEditScpScript( pInfo->hwndDlg, psz );
                else
                    EuEditSwitchInf( pInfo->hwndDlg );

                Free( psz );
            }

            return TRUE;
        }

        case CID_LO_RB_None:
        case CID_LO_RB_Terminal:
        case CID_LO_RB_Script:
        {
            /* Scripts listbox is gray unless script mode is selected.
            */
            if (wNotification == BN_CLICKED)
            {
                EnableWindow( pInfo->hwndLbScripts,
                    (wId == CID_LO_RB_Script) );
            }
            break;
        }
    }

    return FALSE;
}


BOOL
LoInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("LoInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndLo = hwndPage;
    pInfo->hwndRbNone = GetDlgItem( hwndPage, CID_LO_RB_None );
    ASSERT(pInfo->hwndRbNone);
    pInfo->hwndRbTerminal = GetDlgItem( hwndPage, CID_LO_RB_Terminal );
    ASSERT(pInfo->hwndRbTerminal);
    pInfo->hwndRbScript = GetDlgItem( hwndPage, CID_LO_RB_Script );
    ASSERT(pInfo->hwndRbScript);
    pInfo->hwndLbScripts = GetDlgItem( hwndPage, CID_LO_LB_Scripts );
    ASSERT(pInfo->hwndLbScripts);
    pInfo->hwndPbEdit = GetDlgItem( hwndPage, CID_LO_PB_Edit );
    ASSERT(pInfo->hwndPbEdit);
    pInfo->hwndPbRefresh = GetDlgItem( hwndPage, CID_LO_PB_Refresh );
    ASSERT(pInfo->hwndPbRefresh);

    /* Fill the script list and select "(none)".
    */
    EuFillDoubleScriptsList( pInfo->pArgs, pInfo->hwndLbScripts, NULL );

    /* Default mode depends on framing chosen.
    */
    pInfo->pArgs->pEntry->dwScriptModeAfter =
        (pInfo->pArgs->pEntry->dwBaseProtocol == BP_Slip)
            ? SM_Terminal : SM_None;

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
LoKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    INT      iSel;
    PBENTRY* pEntry;

    pEntry = pInfo->pArgs->pEntry;

    if (IsDlgButtonChecked( pInfo->hwndLo, CID_LO_RB_None ))
        pEntry->dwScriptModeAfter = SM_None;
    else if (IsDlgButtonChecked( pInfo->hwndLo, CID_LO_RB_Terminal ))
        pEntry->dwScriptModeAfter = SM_Terminal;
    else
        pEntry->dwScriptModeAfter = SM_Script;

    iSel = ComboBox_GetCurSel( pInfo->hwndLbScripts );
    Free0( pEntry->pszScriptAfter );
    if (iSel > 0)
        pEntry->pszScriptAfter = ComboBox_GetPsz( pInfo->hwndLbScripts, iSel );
    else
        pEntry->pszScriptAfter = NULL;

    /* Silently fix-up "no script specified" error.
    */
    if (pEntry->dwScriptModeAfter == SM_Script && !pEntry->pszScriptAfter)
        pEntry->dwScriptModeAfter = SM_None;

    return FALSE;
}


BOOL
LoSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    HWND hwndRb;

    if (!pInfo->fNotNt || !pInfo->fModem)
        return FALSE;

    /* Select the correct mode.
    */
    {
        HWND  hwndRb;
        DWORD dwScriptMode;

        dwScriptMode = pInfo->pArgs->pEntry->dwScriptModeAfter;
        if (dwScriptMode == SM_Terminal)
            hwndRb = pInfo->hwndRbTerminal;
        else if (dwScriptMode == SM_Script)
            hwndRb = pInfo->hwndRbScript;
        else
        {
            ASSERT(dwScriptMode==SM_None);
            hwndRb = pInfo->hwndRbNone;
        }

        SendMessage( hwndRb, BM_CLICK, 0, 0 );
    }

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** IP Address property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
IaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the IP Address page of the wizard.  Parameters
    ** and return value are as described for standard windows 'DialogProc's.
    */
{
#if 0
    TRACE4("IaDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return IaInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("IaSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = IaSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("IaKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = IaKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }
    }

    return FALSE;
}


BOOL
IaInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("IaInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndIa = hwndPage;
    pInfo->hwndCcIp = GetDlgItem( hwndPage, CID_IA_CC_Ip );
    ASSERT(pInfo->hwndCcIp);

    /* Set the IP address field to '0.0.0.0'.
    */
    SetWindowText( pInfo->hwndCcIp, pInfo->pArgs->pEntry->pszIpAddress );

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
IaKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    TCHAR* psz;

    psz = GetText( pInfo->hwndCcIp );
    if (psz)
    {
        PBENTRY* pEntry = pInfo->pArgs->pEntry;

        Free0( pEntry->pszIpAddress );
        pEntry->pszIpAddress = psz;
    }

    return FALSE;
}


BOOL
IaSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    PBENTRY* pEntry;

    pEntry = pInfo->pArgs->pEntry;

    if (!pInfo->fNotNt || !pInfo->fIpConfigured
        || (pEntry->dwBaseProtocol == BP_Slip
            && pEntry->dwScriptModeAfter == SM_Terminal))
    {
        return FALSE;
    }

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Name Server property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
NaDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Name Server page of the wizard.  Parameters
    ** and return value are as described for standard windows 'DialogProc's.
    */
{
#if 0
    TRACE4("NaDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return NaInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("NaSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = NaSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_KILLACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fInvalid;

                    TRACE("NaKILLACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fInvalid = NaKillActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, fInvalid );
                    return TRUE;
                }
            }
            break;
        }
    }

    return FALSE;
}


BOOL
NaInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("NaInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndNa = hwndPage;
    pInfo->hwndCcDns = GetDlgItem( hwndPage, CID_NA_CC_Dns );
    ASSERT(pInfo->hwndCcDns);
    pInfo->hwndCcWins = GetDlgItem( hwndPage, CID_NA_CC_Wins );
    ASSERT(pInfo->hwndCcWins);

    /* Set the IP address fields to '0.0.0.0'.
    */
    SetWindowText( pInfo->hwndCcDns, pInfo->pArgs->pEntry->pszIpDnsAddress );
    SetWindowText( pInfo->hwndCcWins, pInfo->pArgs->pEntry->pszIpWinsAddress );

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

    return FALSE;
}


BOOL
NaKillActive(
    IN AEINFO* pInfo )

    /* Called when PSN_KILLACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true if the page is invalid, false is it can be dismissed.
    */
{
    PBENTRY* pEntry;
    TCHAR*   psz;

    pEntry = pInfo->pArgs->pEntry;

    psz = GetText( pInfo->hwndCcDns );
    if (psz)
    {
        Free0( pEntry->pszIpDnsAddress );
        pEntry->pszIpDnsAddress = psz;
    }

    psz = GetText( pInfo->hwndCcWins );
    if (psz)
    {
        Free0( pEntry->pszIpWinsAddress );
        pEntry->pszIpWinsAddress = psz;
    }

    return FALSE;
}


BOOL
NaSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    if (!pInfo->fNotNt || !pInfo->fIpConfigured)
        return FALSE;

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_NEXT );
    return TRUE;
}


/*----------------------------------------------------------------------------
** Advanced Properties property page
** Listed alphabetically following dialog proc
**----------------------------------------------------------------------------
*/

BOOL CALLBACK
ApDlgProc(
    IN HWND   hwnd,
    IN UINT   unMsg,
    IN WPARAM wparam,
    IN LPARAM lparam )

    /* DialogProc callback for the Advanced Properties page of the wizard.
    ** Parameters and return value are as described for standard windows
    ** 'DialogProc's.
    */
{
#if 0
    TRACE4("ApDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
        (DWORD)hwnd,(DWORD)unMsg,(DWORD)wparam,(DWORD)lparam);
#endif

    switch (unMsg)
    {
        case WM_INITDIALOG:
            return ApInit( hwnd );

        case WM_NOTIFY:
        {
            switch (((NMHDR* )lparam)->code)
            {
                case PSN_SETACTIVE:
                {
                    AEINFO* pInfo;
                    BOOL    fDisplay;

                    TRACE("ApSETACTIVE");
                    pInfo = AeContext( hwnd );
                    ASSERT(pInfo);
                    fDisplay = ApSetActive( pInfo );
                    SetWindowLong( hwnd, DWL_MSGRESULT, (fDisplay) ? 0 : -1 );
                    return TRUE;
                }

                case PSN_WIZFINISH:
                {
                    TRACE("ApWIZFINISH");
                    AeFinish( hwnd );
                    SetWindowLong( hwnd, DWL_MSGRESULT, 0 );
                    return TRUE;
                }
            }
            break;
        }

        case WM_COMMAND:
        {
            AEINFO* pInfo = AeContext( hwnd );
            ASSERT(pInfo);

            return ApCommand(
                pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
        }
    }

    return FALSE;
}


BOOL
ApCommand(
    IN AEINFO* pInfo,
    IN WORD    wNotification,
    IN WORD    wId,
    IN HWND    hwndCtrl )

    /* Called on WM_COMMAND.  'PInfo' is the dialog context.  'WNotification'
    ** is the notification code of the command.  'wId' is the control/menu
    ** identifier of the command.  'HwndCtrl' is the control window handle of
    ** the command.
    **
    ** Returns true if processed message, false otherwise.
    */
{
    TRACE3("ApCommand(n=%d,i=%d,c=$%x)",
        (DWORD)wNotification,(DWORD)wId,(DWORD)hwndCtrl);

    switch (wId)
    {
        case CID_AP_PB_Properties:
        {
            pInfo->pArgs->fChainPropertySheet = TRUE;
            PropSheet_PressButton( pInfo->hwndDlg, PSBTN_FINISH );
            return TRUE;
        }
    }

    return FALSE;
}


BOOL
ApInit(
    IN HWND hwndPage )

    /* Called on WM_INITDIALOG.  'hwndPage' is the handle of the property
    ** page.
    **
    ** Return false if focus was set, true otherwise.
    */
{
    AEINFO* pInfo;

    TRACE("ApInit");

    pInfo = AeContext( hwndPage );
    if (!pInfo)
        return TRUE;

    /* Initialize page-specific context information.
    */
    pInfo->hwndAp = hwndPage;

    /* Create and display the wizard bitmap.
    */
    CreateWizardBitmap( hwndPage, TRUE );

#if 0 // Disables AP page display

    SetOffDesktop( pInfo->hwndDlg, SOD_MoveOff, NULL );
    SetOffDesktop( pInfo->hwndDlg, SOD_Free, NULL );
    PostMessage( pInfo->hwndDlg, PSM_PRESSBUTTON, PSBTN_FINISH, 0 );

#endif

    return FALSE;
}


BOOL
ApSetActive(
    IN AEINFO* pInfo )

    /* Called when PSN_SETACTIVE is received.  'PInfo' is the wizard context.
    **
    ** Returns true to display the page, false to skip it.
    */
{
    TCHAR* psz;

    /* Fill in the entry name.
    */
    psz = PszFromId( g_hinstDll, SID_FinishWizard );
    if (psz)
    {
        MSGARGS msgargs;

        ZeroMemory( &msgargs, sizeof(msgargs) );
        msgargs.apszArgs[ 0 ] = pInfo->pArgs->pEntry->pszEntryName;
        msgargs.fStringOutput = TRUE;
        msgargs.pszString = psz;

        MsgDlgUtil( NULL, 0, &msgargs, g_hinstDll, 0 );

        if (msgargs.pszOutput)
        {
            SetDlgItemText( pInfo->hwndAp, CID_AP_ST_Entry, msgargs.pszOutput );
            Free( msgargs.pszOutput );
        }

        Free( psz );
    }

    PropSheet_SetWizButtons( pInfo->hwndDlg, PSWIZB_BACK | PSWIZB_FINISH );
    return TRUE;
}
