// EdtBindD.cpp : implementation file
//

#include "stdafx.h"
#include "resource.h"

#include "iiscnfg.h"

#include "KeyObjs.h"
#include "wrapmb.h"
#include "cmnkey.h"
#include "mdkey.h"
#include "mdserv.h"

#include "ListRow.h"
#include "BindsDlg.h"
#include "EdtBindD.h"

#include "W3Key.h"
#include "ipdlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CEditBindingDlg dialog


//--------------------------------------------------------
CEditBindingDlg::CEditBindingDlg(WCHAR* pszw, CWnd* pParent /*=NULL*/)
    : CDialog(CEditBindingDlg::IDD, pParent),
    m_fPopulatedPortDropdown( FALSE ),
    m_pszwMachineName( pszw )
    {
    //{{AFX_DATA_INIT(CEditBindingDlg)
    m_int_ip_option = -1;
    m_int_port_option = -1;
    m_cstring_port = _T("");
    //}}AFX_DATA_INIT
    }

//--------------------------------------------------------
void CEditBindingDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CEditBindingDlg)
    DDX_Control(pDX, IDC_PORT_DROP, m_ccombobox_port);
    DDX_Radio(pDX, IDC_ANY_IP, m_int_ip_option);
    DDX_Radio(pDX, IDC_ANY_PORT, m_int_port_option);
    DDX_CBString(pDX, IDC_PORT_DROP, m_cstring_port);
    //}}AFX_DATA_MAP
    }

//--------------------------------------------------------
BEGIN_MESSAGE_MAP(CEditBindingDlg, CDialog)
    //{{AFX_MSG_MAP(CEditBindingDlg)
    ON_BN_CLICKED(IDC_RD_IP, OnRdIp)
    ON_BN_CLICKED(IDC_RD_PORT, OnRdPort)
    ON_BN_CLICKED(IDC_ANY_IP, OnAnyIp)
    ON_BN_CLICKED(IDC_ANY_PORT, OnAnyPort)
    ON_CBN_DROPDOWN(IDC_PORT_DROP, OnDropdownPortDrop)
    ON_BN_CLICKED(IDC_BTN_SELECT_IPADDRESS, OnBtnSelectIpaddress)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//--------------------------------------------------------
BOOL CEditBindingDlg::OnInitDialog()
    {
    CString szIP;
    CString szPort;
    int     iColon;

    // call the parental oninitdialog
    BOOL f = CDialog::OnInitDialog();

    // the initial values of the dialog as appropriate
    // for the string that was passed. The easiest case
    // is that of the default string - so do that first.

    // check for the default
    if ( m_szBinding == MDNAME_DEFAULT )
        {
        m_int_ip_option = OPTION_ANY_UNASSIGNED;
        m_int_port_option = OPTION_ANY_UNASSIGNED;
        m_cstring_port.Empty();
        ClearIPAddress();
        }
    else
        {
        // the first thing we are going to do is seperate the IP and PORT into seperate strings

        // look for the : and seperate
        iColon = m_szBinding.Find(':');

        // if we got the colon, we can seperate easy
        if ( iColon >= 0 )
            {
            szIP = m_szBinding.Left(iColon);
            szPort = m_szBinding.Right(m_szBinding.GetLength() - iColon - 1);
            }
        // we did not get the colon, so it is one or the other, look for a '.' to get the IP
        else
            {
            if ( m_szBinding.Find('.') >= 0 )
                szIP = m_szBinding;
            else
                szPort = m_szBinding;
            }

        // put the strings into the appropriate places
        if ( szIP.IsEmpty() )
            {
            ClearIPAddress();
            m_int_ip_option = OPTION_ANY_UNASSIGNED;
            }
        else
            {
            FSetIPAddress( szIP );
            m_int_ip_option = OPTION_SPECIFIED;
            }

        // setting the port string is a bit easier
        m_cstring_port = szPort;
        if ( szPort.IsEmpty() )
            m_int_port_option = OPTION_ANY_UNASSIGNED;
        else
            m_int_port_option = OPTION_SPECIFIED;
        }

    // update the data in the dialog
    UpdateData( FALSE );

    // enable the items as appropriate
    EnableItems();

    // return the answer
    return f;
    }

//--------------------------------------------------------
// enable the itesm as appropriate
void CEditBindingDlg::EnableItems()
    {
    // get the data so we are up-to-date
    UpdateData( TRUE );

    // handle the ip addressing items
    if ( m_int_ip_option == OPTION_ANY_UNASSIGNED )
        {
        GetDlgItem(IDC_IPA_IPADDRESS)->EnableWindow(FALSE);
//      m_cbutton_delete.EnableWindow( FALSE );
        }
    else
        {
        GetDlgItem(IDC_IPA_IPADDRESS)->EnableWindow(TRUE);
//      m_cbutton_delete.EnableWindow( TRUE );
        }

    // handle the port addressing items
    if ( m_int_port_option == OPTION_ANY_UNASSIGNED )
        {
        m_ccombobox_port.EnableWindow( FALSE );
        }
    else
        {
        m_ccombobox_port.EnableWindow( TRUE );
        }
    }

//------------------------------------------------------------------------------
// Set and get the ip STRING from the ip edit control
BOOL CEditBindingDlg::FSetIPAddress( CString& szAddress )
    {
    DWORD   dword, b1, b2, b3, b4;

    // break the string into 4 numerical bytes (reading left to right)
    dword = sscanf( szAddress, "%d.%d.%d.%d", &b1, &b2, &b3, &b4 );

    // if we didn't get all four, fail
    if ( dword != 4 )
        return FALSE;

    // make the numerical ip address out of the bytes
    dword = (DWORD)MAKEIPADDRESS(b1,b2,b3,b4);

    // set the ip address into the control
    SendDlgItemMessage( IDC_IPA_IPADDRESS, IPM_SETADDRESS, 0, dword );

#ifdef _DEBUG
    dword = 0;
//  dword = SendDlgItemMessage( IDC_IPA_IPADDRESS, IPM_GETADDRESS, 0, 0 );
#endif

    // return success
    return TRUE;
    }

//------------------------------------------------------------------------------
CString CEditBindingDlg::GetIPAddress()
    {
    CString szAnswer;
    DWORD   dword, b1, b2, b3, b4;

    // get the ip address from the control
    SendDlgItemMessage( IDC_IPA_IPADDRESS, IPM_GETADDRESS, 0, (LPARAM)&dword );


    // get the constituent parts
    b1 = FIRST_IPADDRESS( dword );
    b2 = SECOND_IPADDRESS( dword );
    b3 = THIRD_IPADDRESS( dword );
    b4 = FOURTH_IPADDRESS( dword );

    // format the string
    if ( dword )
        szAnswer.Format( "%d.%d.%d.%d", b1, b2, b3, b4 );
    else
        szAnswer.Empty();

    return szAnswer;
    }

//------------------------------------------------------------------------------
// Set and get the ip STRING from the ip edit control
void CEditBindingDlg::ClearIPAddress()
    {
    // clear the ip address control
    SendDlgItemMessage( IDC_IPA_IPADDRESS, IPM_CLEARADDRESS, 0, 0 );
    }

//------------------------------------------------------------------------------
BOOL CEditBindingDlg::FIsBindingSafeToUse( CString szBinding )
    {

    // start by testing the binding in the current dialog - uses
    // the localized version of "Default"
    if ( m_pBindingsDlg->FContainsBinding(szBinding) )
        {
        AfxMessageBox( IDS_THIS_KEY_HAS_BINDING, MB_OK );
        return FALSE;
        }

    // now we check to see if any other keys have the specified binding. If
    // they do, we ask the user if they want to give the binding to this key.
    // but first we have to find the key. This means scanning the list of
    // keys and asking each - but not this key - if they have the binding.
    CMDKey* pKeyLocal = m_pBindingsDlg->m_pKey;
    CMDKey* pKey;

    if ( !pKeyLocal->m_pService )
        return FALSE;

    // get the first key in the service list
    pKey = pKeyLocal->m_pService->GetFirstMDKey();

    // loop the keys, testing each in turn
    while ( pKey )
        {
        // if this is not the local key, test it
        if ( pKey != pKeyLocal )
            {
            // test it
            if ( pKey->FContainsBinding( szBinding ) )
                {
                // prepare the message for the user
                CString szMessage;
                AfxFormatString1( szMessage, IDS_ANOTHER_KEY_HAS_BINDING, pKey->m_szName );
                // ask the user what to do
                if ( AfxMessageBox( szMessage, MB_YESNO ) == IDYES )
                    {
                    // create a new removal object
                    CBingingRemoval* pRemoval = new CBingingRemoval( pKey, szBinding );
                    // add it to the queue
                    m_pBindingsDlg->rgbRemovals.Add( pRemoval );
                    // the key is safe use
                    return TRUE;
                    }
                else
                    {
                    // the user has thought better of this
                    return FALSE;
                    }
                }
            }

        // get the next key in the list
        pKey = pKeyLocal->m_pService->GetNextMDKey( pKey );
        }

    // no one else is using the binding. It is safe.
    return TRUE;
    }

/////////////////////////////////////////////////////////////////////////////
// CEditBindingDlg message handlers

//------------------------------------------------------------------------------
void CEditBindingDlg::OnOK()
    {
    CString szIP;
    CString szPort;

    // start by building the final binding string
    CString szBinding;

    // use the current data
    UpdateData( TRUE );


    // first things first. We need to make sure that, if used, the
    // custom fields actually have something in them

    // check the IP address first
    if ( m_int_ip_option == OPTION_SPECIFIED )
        {
        szIP = GetIPAddress();
        if ( szIP.IsEmpty() )
            {
            // tell the user about it
            AfxMessageBox( IDS_INVALID_IP );

            // hilight the IP box
            GetDlgItem( IDC_IPA_IPADDRESS )->SetFocus();

            // return without closing the dialog
            return;
            }
        }

    // check the port address second
    if ( m_int_port_option == OPTION_SPECIFIED )
        {
        if ( m_cstring_port.IsEmpty() )
            {
            // tell the user about it
            AfxMessageBox( IDS_INVALID_PORT );

            // hilight the port box
            m_ccombobox_port.SetFocus();
            m_ccombobox_port.SetEditSel(0,-1);

            // return without closing the dialog
            return;
            }
        }


    // the total default case is the easiest
    if ( m_int_ip_option == OPTION_ANY_UNASSIGNED &&
            m_int_port_option == OPTION_ANY_UNASSIGNED )
        {
        szBinding = MDNAME_DEFAULT;
        }
    else
        {
        // build from the ip and port pieces
        if ( m_int_ip_option == OPTION_SPECIFIED )
            szIP = GetIPAddress();
        if ( m_int_port_option == OPTION_SPECIFIED )
            szPort = m_cstring_port;

        // build the string start with the IP
        szBinding = szIP;

        // if both are there, add a colon
        if ( m_int_ip_option == OPTION_SPECIFIED &&
                m_int_port_option == OPTION_SPECIFIED )
            szBinding += ':';

        // finish with the port
        szBinding += szPort;
        }

    // finally, if the binding is safe to use, we can set the data and
    // close the dialog
    if ( FIsBindingSafeToUse(szBinding) )
        {
        // set the data
        m_szBinding = szBinding;

        // tell the dialog to close
        CDialog::OnOK();
        }
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnRdIp()
    {
    EnableItems();
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnRdPort()
    {
    EnableItems();
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnAnyIp()
    {
    EnableItems();
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnAnyPort()
    {
    EnableItems();
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnDropdownPortDrop()
    {
    CString     sz;
    DWORD       dwPort;

    // if we have already been here, don't do anything
    if ( m_fPopulatedPortDropdown )
        return;

    // get the metabase going
    if ( !FInitMetabaseWrapper(m_pszwMachineName) )
        return;

    // create the metabase wrapper object
    CWrapMetaBase   mbWrap;
    if ( !mbWrap.FInit() )
        {
        ASSERT( FALSE );
        return;     // can't get to metabase
        }

    // we are now to populate the drop down menu
    m_fPopulatedPortDropdown = TRUE;

    // scan the available virtual servers and populate the drop down with
    // their secure port numbers
    for ( DWORD i = 1; TRUE; i++ )
        {
        // build the object name
        sz.Format( "%s%d", MD_W3BASE, i );

        // attempt to open the object in the metabase
        if ( !mbWrap.Open( sz, METADATA_PERMISSION_READ ) )
            break;      // can't open - leave the loop

        // load the string representing the bindings
        DWORD   cbData;
        PVOID   pData;

        // extract the secure port address from the secure bindings stringlist
        pData = mbWrap.GetData( "", MD_SECURE_BINDINGS, IIS_MD_UT_SERVER, MULTISZ_METADATA, &cbData );
        if ( pData )
            {
            PTCHAR pBinding = (PTCHAR)pData;

            // walk the bindings in the list
            while ( TRUE )
                {
                sz = (PCHAR)pBinding;
                if ( sz.IsEmpty() )
                    break;

                // get the port address
                sz = sz.Right( sz.GetLength() - sz.Find(':') - 1 );
                if ( sz.Find(':') )
                sz = sz.Left( sz.Find(':') );
                if ( !sz.IsEmpty() )
                    {
                    // append the string to the dropdown
                    // but only if it isn't already there
                    if ( m_ccombobox_port.FindStringExact(-1,sz) == CB_ERR )
                        m_ccombobox_port.AddString( sz );
                    }

                // advance the binding pointer
                pBinding += strlen(pBinding)+1;
                }

            // free the buffer
            mbWrap.FreeWrapData( pData );
            }

        // close the object
        mbWrap.Close();
        }

    // now close the metabase again. We will open it when we need it
    FCloseMetabaseWrapper();
    }

//------------------------------------------------------------------------------
void CEditBindingDlg::OnBtnSelectIpaddress()
    {
    // get the metabase going
    if ( !FInitMetabaseWrapper(m_pszwMachineName) )
        return;

    // run the choose ip dialog here
    CChooseIPDlg    dlg;

    // set up the ip dialog member variables
    dlg.m_szIPAddress = GetIPAddress();

    // run the dialog
    if ( dlg.DoModal() == IDOK )
        {
        FSetIPAddress( dlg.m_szIPAddress );
        }

    // now close the metabase again. We will open it when we need it
    FCloseMetabaseWrapper();
    }