//----------------------------------------------------------------------------
//
// Copyright (c) 1997-1999  Microsoft Corporation
// All rights reserved.
//
// File Name:
//      tcpipip.c
//
// Description:
//
//----------------------------------------------------------------------------

#include "pch.h"
#include "resource.h"
#include "tcpip.h"

//----------------------------------------------------------------------------
//
// Function: ChangeIPDlgProc
//
// Purpose:  Dialog procedure for allowing the user to add or edit an IP and Subnet Mask
//
// Arguments:  standard Win32 dialog proc arguments
//
// Returns:
//
//----------------------------------------------------------------------------
INT_PTR CALLBACK
ChangeIPDlgProc( IN HWND     hwnd,
                 IN UINT     uMsg,
                 IN WPARAM   wParam,
                 IN LPARAM   lParam) {

    BOOL bStatus = TRUE;
    HWND hIPEditBox = GetDlgItem( hwnd, IDC_IPADDR_ADV_CHANGEIP_IP );
    HWND hSubnetEditBox = GetDlgItem( hwnd, IDC_IPADDR_ADV_CHANGEIP_SUB );

    switch( uMsg ) {

        case WM_INITDIALOG: {

            SetWindowText( hIPEditBox, szIPString );

            SetWindowText( hSubnetEditBox, szSubnetMask );

            SetFocus( hIPEditBox );

            bStatus = FALSE;  // return FALSE, we set the keyboard focus

            break;

        }

        case WM_COMMAND: {

            int nButtonId = LOWORD( wParam );

            switch ( nButtonId ) {

                case IDOK: {

                    // return a 1 to show an IP was added
                    GetWindowText( hIPEditBox, szIPString, IPSTRINGLENGTH+1 );

                    GetWindowText( hSubnetEditBox, szSubnetMask, IPSTRINGLENGTH+1 );

                    EndDialog( hwnd, 1 );

                    break;

                }

                case IDCANCEL: {

                    // return a 0 to show no IP was added
                    EndDialog( hwnd, 0 );

                    break;
                }

            }

        }

        default:
            bStatus = FALSE;
            break;

    }

    return bStatus;

}

//----------------------------------------------------------------------------
//
// Function: SetGatewayInitialValues
//
// Purpose:  To set the initial contents of the Gateway list box
//
// Arguments:  IN HWND hwnd - handle to the dialog
//
// Returns: VOID
//
//----------------------------------------------------------------------------
VOID
SetGatewayInitialValues( IN HWND hwnd ) {

    INT i;
    INT nEntries;
    TCHAR *pString;

    nEntries = GetNameListSize( &NetSettings.pCurrentAdapter->Tcpip_GatewayAddresses );

    //
    //  Iterate over the Gateway namelist adding each one to the Gateway List box
    //
    for( i = 0; i < nEntries; i++ ) {

        pString = GetNameListName( &NetSettings.pCurrentAdapter->Tcpip_GatewayAddresses, i );

        SendDlgItemMessage( hwnd,
                            IDC_IPADDR_GATE,
                            LB_ADDSTRING,
                            0,
                            (LPARAM) pString );

    }

    //
    // select the first entry
    //
    SendDlgItemMessage( hwnd,
                        IDC_IPADDR_GATE,
                        LB_SETCURSEL,
                        0,
                        0 );

}

//----------------------------------------------------------------------------
//
// Function: InsertItemIntoTcpipListView
//
// Purpose:  hListView is the handle to the list view the IPStruct is to be
//           added to
//           position designates the position in the list view the item is to
//           be inserted in
//
// Arguments:
//
// Returns:  TRUE if the insert succeeded,
//           FALSE if it failed
//
//----------------------------------------------------------------------------
// ISSUE-2002/02/28-stelo- move this to tcpipcom.c because optional uses it too.  Should also be
//    renamed??
BOOL
InsertItemIntoTcpipListView( HWND hListView,
                             LPARAM lParam,
                             UINT position ) {

    LVITEM lvI;

    lvI.mask = LVIF_TEXT | LVIF_PARAM;

    lvI.iItem = position;
    lvI.iSubItem = 0;
    lvI.pszText = LPSTR_TEXTCALLBACK;
    lvI.cchTextMax = MAX_ITEMLEN;
    lvI.lParam = lParam;

    //
    // if ListView_InsertItem returns a non-negative value then it succeeded
    //
    if( ListView_InsertItem( hListView, &lvI ) >= 0 )
        return( TRUE ) ;

    // insertion failed
    return( FALSE ) ;

}

//----------------------------------------------------------------------------
//
// Function: SetIPandSubnetMaskInitialValues
//
// Purpose:
//
// Arguments:
//
// Returns:
//
//----------------------------------------------------------------------------
VOID
SetIPandSubnetMaskInitialValues( IN HWND hwnd ) {

    INT i;
    INT nEntries;
    LPTSTR pszIPAddress;
    LPTSTR pszSubnetMask;
    HWND hTcpipListView;

    hTcpipListView = GetDlgItem( hwnd, IDC_IPADDR_ADVIP );

    if( NetSettings.pCurrentAdapter->bObtainIPAddressAutomatically == TRUE ) {

        //
        //  allocate space for the IP struct
        //
        IPStruct = malloc( sizeof(IP_STRUCT) );
        if (IPStruct == NULL)
        {
            TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
        }
        lstrcpyn( IPStruct->szIPString, StrDhcpEnabled, AS(IPStruct->szIPString) );

        //  force the subnet mask field to be blank
        lstrcpyn( IPStruct->szSubnetMask, _T(""), AS(IPStruct->szSubnetMask) );

        //
        //  use an IP_STRUCT to pass the data, the name is somewhat misleading
        //  because we are not passing in an IP address in this case
        //
        InsertItemIntoTcpipListView( hTcpipListView,
                                     (LPARAM) IPStruct, 0 );

        //
        //  Grey-out the Add, Edit and Remove buttons since none of these are
        //  available to the user when DHCP is enabled
        //
        EnableWindow( GetDlgItem( hwnd, IDC_IPADDR_ADDIP ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_IPADDR_EDITIP ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_IPADDR_REMOVEIP ), FALSE );

    }
    else {

        nEntries = GetNameListSize( &NetSettings.pCurrentAdapter->Tcpip_IpAddresses );

        if( nEntries == 0 ) {

            //
            //  Grey-out the Edit and Remove buttons since these are not
            //  available when there are no items in the ListView
            //
            EnableWindow( GetDlgItem( hwnd, IDC_IPADDR_EDITIP ), FALSE );
            EnableWindow( GetDlgItem( hwnd, IDC_IPADDR_REMOVEIP ), FALSE );

        }

        for( i = 0; i < nEntries; i = i++ ) {

            // allocate space for the IP struct
            IPStruct = malloc( sizeof(IP_STRUCT) );
            if ( IPStruct == NULL ) {
	        TerminateTheWizard( IDS_ERROR_OUTOFMEMORY );
            }

            pszIPAddress = GetNameListName(
                &NetSettings.pCurrentAdapter->Tcpip_IpAddresses, i );

            lstrcpyn( IPStruct->szIPString, pszIPAddress, AS(IPStruct->szIPString) );

            pszSubnetMask = GetNameListName(
                &NetSettings.pCurrentAdapter->Tcpip_SubnetMaskAddresses, i );

            lstrcpyn( IPStruct->szSubnetMask, pszSubnetMask, AS(IPStruct->szSubnetMask) );

            InsertItemIntoTcpipListView( hTcpipListView, (LPARAM) IPStruct, i );

        }

    }

}

//----------------------------------------------------------------------------
//
// Function: OnTcpipIpInitDialog
//
// Purpose:  loads button bitmaps from resources and initializes the list view
//
// Arguments: IN HWND hwnd - handle to the dialog
//
// Returns:  VOID
//
//----------------------------------------------------------------------------
VOID
OnTcpipIpInitDialog( IN HWND hwnd ) {

    LV_COLUMN lvCol;        // list view column structure
    INT iIndex;
    INT iNewItem;
    INT nEntries;
    INT colWidth;
    RECT rect;
    HWND hGatewayEditButton;
    HWND hGatewayRemoveButton;
    HWND hTcpipListView;

    //
    //  Load strings from resources
    //

    StrDhcpEnabled = MyLoadString( IDS_DHCP_ENABLED );

    StrIpAddress = MyLoadString( IDS_IP_ADDRESS );
    StrSubnetMask = MyLoadString( IDS_SUBNET_MASK );

    hTcpipListView = GetDlgItem( hwnd, IDC_IPADDR_ADVIP );

    //
    //    This will always be the first page of the property sheet
    //  displayed so load the up and down icons and store the handles
    //  in global variables
    //
    if ( ! g_hIconUpArrow && ! g_hIconDownArrow ) {

        g_hIconUpArrow = (HICON)LoadImage(FixedGlobals.hInstance,
                                      MAKEINTRESOURCE(IDI_UP_ARROW),
                                      IMAGE_ICON, 16, 16, 0);

        g_hIconDownArrow = (HICON)LoadImage(FixedGlobals.hInstance,
                                      MAKEINTRESOURCE(IDI_DOWN_ARROW),
                                      IMAGE_ICON, 16, 16, 0);

    }

    // Place up/down arrow icons on buttons
    SendDlgItemMessage( hwnd,
                        IDC_IPADDR_UP,
                        BM_SETIMAGE,
                        (WPARAM)IMAGE_ICON,
                        (LPARAM)g_hIconUpArrow );

    SendDlgItemMessage( hwnd,
                        IDC_IPADDR_DOWN,
                        BM_SETIMAGE,
                        (WPARAM)IMAGE_ICON,
                        (LPARAM)g_hIconDownArrow );

    // Calculate column width
    GetClientRect( hTcpipListView, &rect );

    colWidth = ( rect.right / cIPSettingsColumns );

    for( iIndex = 0; iIndex < cIPSettingsColumns; iIndex++ ) {

        ListView_SetColumnWidth( hTcpipListView, iIndex, colWidth );

    }

    // The mask specifies that the fmt, width and pszText members
    // of the structure are valid
    lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT ;
    lvCol.fmt = LVCFMT_LEFT;   // left-align column
    lvCol.cx = colWidth;       // width of column in pixels

    //  Add the two columns and header text
    for( iIndex = 0; iIndex < cIPSettingsColumns; iIndex++ ) {

        //  column header text
        if ( iIndex == 0 ) // first column
            lvCol.pszText = (LPTSTR) StrIpAddress;
        else
            lvCol.pszText = (LPTSTR) StrSubnetMask;

        iNewItem = ListView_InsertColumn( hTcpipListView, iIndex, &lvCol );

    }

    //  fill the IP and Subnet mask list box with the appropriate
    //  initial value(s)
    SetIPandSubnetMaskInitialValues( hwnd );

    //  fill the gateway list box with the appropriate initial value(s)
    SetGatewayInitialValues( hwnd );

    hGatewayEditButton = GetDlgItem( hwnd, IDC_IPADDR_EDITGATE );
    hGatewayRemoveButton = GetDlgItem( hwnd, IDC_IPADDR_REMOVEGATE );

    SetButtons( GetDlgItem( hwnd, IDC_IPADDR_GATE ),
                hGatewayEditButton,
                hGatewayRemoveButton );

    SetArrows( hwnd,
               IDC_IPADDR_GATE,
               IDC_IPADDR_UP,
               IDC_IPADDR_DOWN );

}

//----------------------------------------------------------------------------
//
// Function: OnTcpipIpApply
//
// Purpose:  stores the contents on the TCP/IP advanced IP address page into
//           the global variables
//
// Arguments: IN HWND hwnd - handle to the dialog
//
// Returns:  VOID
//
//----------------------------------------------------------------------------
VOID
OnTcpipIpApply( IN HWND hwnd ) {

    INT_PTR i;
    INT_PTR iCount;
    LV_ITEM lvI;
    TCHAR szIP[IPSTRINGLENGTH + 1];

    //
    //  delete any old settings in the Namelists
    //
    ResetNameList( &NetSettings.pCurrentAdapter->Tcpip_IpAddresses );

    ResetNameList( &NetSettings.pCurrentAdapter->Tcpip_SubnetMaskAddresses );

    iCount = ListView_GetItemCount( GetDlgItem( hwnd, IDC_IPADDR_ADVIP ) );

    for( i = 0; i < iCount; i++ ) {

        memset( &lvI, 0, sizeof(LV_ITEM) );

        lvI.iItem = (int)i;
        lvI.mask = LVIF_PARAM;

        ListView_GetItem( GetDlgItem( hwnd, IDC_IPADDR_ADVIP ), &lvI );

        IPStruct = (IP_STRUCT*) lvI.lParam;

        //  store the IP string into the Namelist
          TcpipAddNameToNameList( &NetSettings.pCurrentAdapter->Tcpip_IpAddresses,
                                IPStruct->szIPString);

        //  store the Subnet Mask string into the Namelist
          TcpipAddNameToNameList( &NetSettings.pCurrentAdapter->Tcpip_SubnetMaskAddresses,
                                IPStruct->szSubnetMask );

    }

    ResetNameList( &NetSettings.pCurrentAdapter->Tcpip_GatewayAddresses );

    //
    //  pull the IP address out of the Gateway list box and put them in the
    //  Gateway Namelist
    //
    iCount = SendDlgItemMessage( hwnd,
                                 IDC_IPADDR_GATE,
                                 LB_GETCOUNT,
                                 0,
                                 0 );

    for( i = 0; i < iCount; i++ ) {

        //
        // get the IP string from the list box
        //
        SendDlgItemMessage( hwnd,
                            IDC_IPADDR_GATE,
                            LB_GETTEXT,
                            i,
                            (LPARAM) szIP );

        //
        // store the IP string in to the Namelist
        //
        TcpipAddNameToNameList( &NetSettings.pCurrentAdapter->Tcpip_GatewayAddresses, szIP );

    }

}

//----------------------------------------------------------------------------
//
// Function: TCPIP_IPSettingsPageProc
//
// Purpose:  Required function for the property sheet page to function properly.
//             The important thing is to give the return value of 1 to the
//           message PSPCB_CREATE and 0 for PSPCB_RELEASE
//
// Arguments:
//
// Returns:
//
//----------------------------------------------------------------------------
UINT CALLBACK
TCPIP_IPSettingsPageProc( HWND  hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp ) {

    switch ( uMsg ) {

        case PSPCB_CREATE :
            return 1 ;  // needed for property sheet page to initialize correctly

        case PSPCB_RELEASE :
            return 0;

        default:
            return -1;

    }

}

//----------------------------------------------------------------------------
//
// Function: TCPIP_IPSettingsDlgProc
//
// Purpose:  Dialog procedure for the IP Settings page of the property sheet
//             handles all the messages sent to this window
//
// Arguments:
//
// Returns:
//
//----------------------------------------------------------------------------
INT_PTR CALLBACK
TCPIP_IPSettingsDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) {

    switch( uMsg ) {

        case WM_INITDIALOG: {

            OnTcpipIpInitDialog( hwndDlg );

            return TRUE ;

        }

        case WM_DESTROY: {

            // deallocate space for all items still in the List View
            INT i;
            INT iCount;
            LV_ITEM lvI;

            //
            //  iterate through the ListView getting each item and
            //  deallocating the space for it
            //
            iCount = ListView_GetItemCount( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ) );
            for( i = 0; i < iCount; i++ ) {

                memset( &lvI, 0, sizeof(LV_ITEM) );

                lvI.iItem = i;
                lvI.mask = LVIF_PARAM;

                ListView_GetItem( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ),
                                  &lvI );

                free( (IP_STRUCT*) lvI.lParam );

            }

            return TRUE ;

        }

        case WM_COMMAND: {

            WORD wNotifyCode = HIWORD( wParam ) ;
            WORD wButtonId = LOWORD( wParam ) ;

            if( wNotifyCode == LBN_SELCHANGE ) {

                SetArrows( hwndDlg,
                           IDC_IPADDR_GATE,
                           IDC_IPADDR_UP,
                           IDC_IPADDR_DOWN );

            }

            switch ( wButtonId ) {

                //
                //  IP Address Buttons
                //
                case IDC_IPADDR_ADDIP: {

                    //  make the string blank since we will be adding a
                    //  new IP address
                    szIPString[0] = _T('\0');
                    //  and a new subnet mask
                    szSubnetMask[0] = _T('\0');

                    if( DialogBox( FixedGlobals.hInstance,
                                   (LPCTSTR) IDD_IPADDR_ADV_CHANGEIP,
                                   hwndDlg,
                                   ChangeIPDlgProc ) ) {

                        HWND hEditButton = GetDlgItem( hwndDlg,
                                                       IDC_IPADDR_EDITIP );

                        HWND hRemoveButton = GetDlgItem( hwndDlg,
                                                         IDC_IPADDR_REMOVEIP );

                        //  allocate space for the IP struct
                        IPStruct = malloc( sizeof(IP_STRUCT) );
                        if (IPStruct == NULL)
                        {
                            TerminateTheWizard(IDS_ERROR_OUTOFMEMORY);
                        }


                        //  copy the strings that the user entered from the Dialog
                        //  Box into the IP struct so it can be added to
                        //  the list view
                        lstrcpyn( IPStruct->szIPString, szIPString, AS(IPStruct->szIPString) );
                        lstrcpyn( IPStruct->szSubnetMask, szSubnetMask, AS(IPStruct->szSubnetMask) );

                        InsertItemIntoTcpipListView( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ),
                                                     (LPARAM) IPStruct,
                                                     0 );

                        // an entry was just added so make sure the edit and remove buttons are enabled
                        EnableWindow( hEditButton, TRUE );
                        EnableWindow( hRemoveButton, TRUE );

                    }

                    return TRUE ;

                }

                case IDC_IPADDR_EDITIP: {

                    LV_ITEM lvI;
                    BOOL bIsItemSelected = FALSE;

                    bIsItemSelected = GetSelectedItemFromListView( hwndDlg,
                                                               IDC_IPADDR_ADVIP,
                                                               &lvI );

                    if( bIsItemSelected ) {
                        IPStruct = (IP_STRUCT*) lvI.lParam;

                        lstrcpyn( szIPString, IPStruct->szIPString, AS(szIPString) );

                        lstrcpyn( szSubnetMask, IPStruct->szSubnetMask, AS(szSubnetMask) );

                        if( DialogBox( FixedGlobals.hInstance,
                                       (LPCTSTR) IDD_IPADDR_ADV_CHANGEIP,
                                       hwndDlg,
                                       ChangeIPDlgProc ) ) {

                            lstrcpyn( IPStruct->szIPString, szIPString, AS(IPStruct->szIPString) );
                            lstrcpyn( IPStruct->szSubnetMask, szSubnetMask, AS(IPStruct->szSubnetMask) );

                            // delete the old item and insert the new one
                            ListView_DeleteItem( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ),
                                                 lvI.iItem );

                            InsertItemIntoTcpipListView( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ),
                                                         (LPARAM) IPStruct, lvI.iItem );

                        }

                    }

                    return TRUE ;

                }

                case IDC_IPADDR_REMOVEIP: {

                    LV_ITEM lvI;
                    BOOL bIsItemSelected = FALSE;

                    bIsItemSelected = GetSelectedItemFromListView( hwndDlg,
                                                                   IDC_IPADDR_ADVIP,
                                                                   &lvI );

                    //
                    //    if there is an item selected, then free its memory and
                    //  delete the item from the ListView
                    //
                    if( bIsItemSelected ) {

                        free( (IP_STRUCT*) lvI.lParam );

                        ListView_DeleteItem( GetDlgItem( hwndDlg, IDC_IPADDR_ADVIP ),
                                             lvI.iItem );

                    }

                    return TRUE ;

                }

                //
                //  Gateway Buttons
                //
                case IDC_IPADDR_ADDGATE:

                    g_CurrentEditBox = GATEWAY_EDITBOX;

                    OnAddButtonPressed( hwndDlg,
                                        IDC_IPADDR_GATE,
                                        IDC_IPADDR_EDITGATE,
                                        IDC_IPADDR_REMOVEGATE,
                                        (LPCTSTR) IDD_IPADDR_ADV_CHANGEGATE,
                                        GenericIPDlgProc );

                    SetArrows( hwndDlg,
                               IDC_IPADDR_GATE,
                               IDC_IPADDR_UP,
                               IDC_IPADDR_DOWN );

                    return TRUE ;

                case IDC_IPADDR_EDITGATE:

                    g_CurrentEditBox = GATEWAY_EDITBOX;

                    OnEditButtonPressed( hwndDlg,
                                         IDC_IPADDR_GATE,
                                        (LPCTSTR) IDD_IPADDR_ADV_CHANGEGATE,
                                       GenericIPDlgProc );

                    SetArrows( hwndDlg,
                               IDC_IPADDR_GATE,
                               IDC_IPADDR_UP,
                               IDC_IPADDR_DOWN );

                    return TRUE ;

                case IDC_IPADDR_REMOVEGATE:

                    OnRemoveButtonPressed( hwndDlg,
                                           IDC_IPADDR_GATE,
                                           IDC_IPADDR_EDITGATE,
                                           IDC_IPADDR_REMOVEGATE );

                    SetArrows( hwndDlg,
                               IDC_IPADDR_GATE,
                               IDC_IPADDR_UP,
                               IDC_IPADDR_DOWN );

                    return TRUE ;

                case IDC_IPADDR_UP:

                    OnUpButtonPressed( hwndDlg, IDC_IPADDR_GATE );

                    SetArrows( hwndDlg,
                               IDC_IPADDR_GATE,
                               IDC_IPADDR_UP,
                               IDC_IPADDR_DOWN );

                    return TRUE ;

                case IDC_IPADDR_DOWN:

                    OnDownButtonPressed( hwndDlg, IDC_IPADDR_GATE );

                    SetArrows( hwndDlg,
                               IDC_IPADDR_GATE,
                               IDC_IPADDR_UP,
                               IDC_IPADDR_DOWN );

                    return TRUE ;

            }  // end switch

            return FALSE ;

        }

        case WM_NOTIFY: {

            LPNMHDR pnmh = (LPNMHDR) lParam;
            LV_DISPINFO *pLvdi = (LV_DISPINFO *) lParam;
            IP_STRUCT *pListViewEntry = (IP_STRUCT *) (pLvdi->item.lParam);

            if( wParam == IDC_IPADDR_ADVIP ) {

                if( pLvdi->hdr.code == LVN_GETDISPINFO ) {

                    switch( pLvdi->item.iSubItem ) {

                        case 0:
                            pLvdi->item.pszText = pListViewEntry->szIPString;
                            break;
                        case 1:
                            pLvdi->item.pszText = pListViewEntry->szSubnetMask;
                            break;

                    }

                }

            }

            switch( pnmh->code ) {

                case PSN_APPLY: {

                    //
                    //  user clicked the OK button on the property sheet
                    //
                    OnTcpipIpApply( hwndDlg );

                    return TRUE ;

                }

            }

            default :
                return FALSE ;

        }

    }

}

//
//  ISSUE-2002/02/28-stelo- this function is for debugging purposes only, remove for final product
//   it is meant to be called from the debugger to show what the contents of a
//   namelist is
//
VOID DumpNameList( NAMELIST *pNameList ) {

#if DBG

    INT i;
    INT nEntries;
    TCHAR *szNameListEntry;

    nEntries = GetNameListSize( pNameList );

    for(i = 0; i < nEntries; i++ ) {

        szNameListEntry = GetNameListName( pNameList, i );

        OutputDebugString( szNameListEntry );

    }

#endif

}