/*++

   Copyright    (c)    1994-1999    Microsoft Corporation

   Module  Name :

        fservic.cpp

   Abstract:

        FTP Service Property Page

   Author:

        Ronald Meijer (ronaldm)

   Project:

        Internet Services Manager

   Revision History:

--*/

//
// Include Files
//
#include "stdafx.h"
#include "common.h"
#include "inetprop.h"
#include "InetMgrApp.h"
#include "shts.h"
#include "ftpsht.h"
#include "fservic.h"
#include "usersess.h"
#include "iisobj.h"


#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif



//
// Some sanity values on max connections
//
#define MAX_MAX_CONNECTIONS      (1999999999L)
#define INITIAL_MAX_CONNECTIONS  (      1000L)
#define UNLIMITED_CONNECTIONS    (2000000000L)

#define MAX_TIMEOUT              (0x7FFFFFFF)

#define LIMITED_CONNECTIONS_MIN    (10)
#define LIMITED_CONNECTIONS_MAX    (40)



IMPLEMENT_DYNCREATE(CFtpServicePage, CInetPropertyPage)



CFtpServicePage::CFtpServicePage(
    IN CInetPropertySheet * pSheet
    )
/*++

Routine Description:

    Constructor for FTP service property page

Arguments:

    CInetPropertySheet * pSheet : Associated property sheet

Return Value:

    N/A

--*/
    : CInetPropertyPage(CFtpServicePage::IDD, pSheet)
{
#ifdef _DEBUG

    afxMemDF |= checkAlwaysMemDF;

#endif // _DEBUG

#if 0 // Keep Class Wizard happy

    //{{AFX_DATA_INIT(CFtpServicePage)
    m_strComment = _T("");
    m_nTCPPort = 20;
    m_nUnlimited = RADIO_LIMITED;
    m_nIpAddressSel = -1;
    m_fEnableLogging = FALSE;
    //}}AFX_DATA_INIT

    m_nMaxConnections = 50;
    m_nVisibleMaxConnections = 50;
    m_nConnectionTimeOut = 600;
    m_iaIpAddress = (LONG)0L;
    m_strDomainName = _T("");

#endif // 0
}



CFtpServicePage::~CFtpServicePage()
/*++

Routine Description:

    Destructor

Arguments:

    N/A

Return Value:

    N/A

--*/
{
}



void
CFtpServicePage::DoDataExchange(
    IN CDataExchange * pDX
    )
/*++

Routine Description:

    Initialise/Store control data

Arguments:

    CDataExchange * pDX - DDX/DDV control structure

Return Value:

    None

--*/
{
    CInetPropertyPage::DoDataExchange(pDX);

    if (!pDX->m_bSaveAndValidate)
    {
        m_fEnableLogging = LoggingEnabled(m_dwLogType);
    }

    //{{AFX_DATA_MAP(CFtpServicePage)
    DDX_Radio(pDX, IDC_RADIO_UNLIMITED, m_nUnlimited);
    DDX_Check(pDX, IDC_CHECK_ENABLE_LOGGING, m_fEnableLogging);
    DDX_Text(pDX, IDC_EDIT_COMMENT, m_strComment);
    DDV_MinMaxChars(pDX, m_strComment, 0, MAX_PATH);
    DDX_Control(pDX, IDC_EDIT_MAX_CONNECTIONS, m_edit_MaxConnections);
    DDX_Control(pDX, IDC_STATIC_LOG_PROMPT, m_static_LogPrompt);
    DDX_Control(pDX, IDC_STATIC_CONNECTIONS, m_static_Connections);
    DDX_Control(pDX, IDC_BUTTON_PROPERTIES, m_button_LogProperties);
    DDX_Control(pDX, IDC_COMBO_IP_ADDRESS, m_combo_IpAddresses);
    DDX_Control(pDX, IDC_COMBO_LOG_FORMATS, m_combo_LogFormats);
    //}}AFX_DATA_MAP

    DDX_Text(pDX, IDC_EDIT_TCP_PORT, m_nTCPPort);

    if (!IsMasterInstance())
    {
        DDV_MinMaxUInt(pDX, m_nTCPPort, 1, 65535);
    }

    if (pDX->m_bSaveAndValidate && !FetchIpAddressFromCombo(
        m_combo_IpAddresses,
        m_oblIpAddresses,
        m_iaIpAddress
        ))
    {
        pDX->Fail();
    }

    //
    // Private DDX/DDV Routines
    //
    int nMin = IsMasterInstance() ? 0 : 1;

    if (!pDX->m_bSaveAndValidate || !m_fUnlimitedConnections )
    {
        DDX_Text(pDX, IDC_EDIT_MAX_CONNECTIONS, m_nVisibleMaxConnections);
    }

    if (m_f10ConnectionLimit)
    {
        //
        // Special validation for unlimited connections.  We use a bogus
        // numeric check for data validation.  Number adjustment happens 
        // later.
        //
        if (pDX->m_bSaveAndValidate && 
            (m_nVisibleMaxConnections < 0 || 
             m_nVisibleMaxConnections > UNLIMITED_CONNECTIONS))
        {
            TCHAR szMin[32];
            TCHAR szMax[32];
            wsprintf(szMin, _T("%ld"), 0);
            wsprintf(szMax, _T("%ld"), 40);
            CString prompt;
            AfxFormatString2(prompt, AFX_IDP_PARSE_INT_RANGE, szMin, szMax);
            AfxMessageBox(prompt, MB_ICONEXCLAMATION);
            prompt.Empty(); // exception prep
            pDX->Fail();
        }
    }
    else
    {
        DDV_MinMaxLong(pDX, m_nVisibleMaxConnections, 0, UNLIMITED_CONNECTIONS);
    }

    DDX_Text(pDX, IDC_EDIT_CONNECTION_TIMEOUT, m_nConnectionTimeOut);
    DDV_MinMaxLong(pDX, m_nConnectionTimeOut, nMin, MAX_TIMEOUT);

    if (pDX->m_bSaveAndValidate)
    {
        EnableLogging(m_dwLogType, m_fEnableLogging);
    }
}



//
// Message Map
//
BEGIN_MESSAGE_MAP(CFtpServicePage, CInetPropertyPage)
    //{{AFX_MSG_MAP(CFtpServicePage)
    ON_BN_CLICKED(IDC_CHECK_ENABLE_LOGGING, OnCheckEnableLogging)
    ON_BN_CLICKED(IDC_RADIO_LIMITED, OnRadioLimited)
    ON_BN_CLICKED(IDC_RADIO_UNLIMITED, OnRadioUnlimited)
    ON_BN_CLICKED(IDC_BUTTON_CURRENT_SESSIONS, OnButtonCurrentSessions)
    ON_BN_CLICKED(IDC_BUTTON_PROPERTIES, OnButtonProperties)
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP

    ON_EN_CHANGE(IDC_EDIT_TCP_PORT, OnItemChanged)
    ON_EN_CHANGE(IDC_EDIT_COMMENT, OnItemChanged)
    ON_EN_CHANGE(IDC_EDIT_MAX_CONNECTIONS, OnItemChanged)
    ON_EN_CHANGE(IDC_EDIT_CONNECTION_TIMEOUT, OnItemChanged)
    ON_CBN_EDITCHANGE(IDC_COMBO_IP_ADDRESS, OnItemChanged)
    ON_CBN_SELCHANGE(IDC_COMBO_IP_ADDRESS, OnItemChanged)
    ON_CBN_SELCHANGE(IDC_COMBO_LOG_FORMATS, OnItemChanged)

END_MESSAGE_MAP()



void
CFtpServicePage::SetControlStates()
/*++

Routine Description:

    Set the states of the dialog control depending on its current
    values.

Arguments:

    None

Return Value:

    None

--*/
{
    if (m_edit_MaxConnections.m_hWnd)
    {
        m_edit_MaxConnections.EnableWindow(!m_fUnlimitedConnections);
        m_static_Connections.EnableWindow(!m_fUnlimitedConnections);
    }
}



void
CFtpServicePage::PopulateKnownIpAddresses()
/*++

Routine Description:

    Fill the combo box with known ip addresses

Arguments:

    None

Return Value:

    None

--*/
{
    BeginWaitCursor();
    PopulateComboWithKnownIpAddresses(
        QueryServerName(),
        m_combo_IpAddresses,
        m_iaIpAddress,
        m_oblIpAddresses,
        m_nIpAddressSel 
        );
    EndWaitCursor();
}



//
// Message Handlers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



BOOL
CFtpServicePage::OnInitDialog()
/*++

Routine Description:

    WM_INITDIALOG handler.  Initialize the dialog.

Arguments:

    None.

Return Value:

    TRUE if no focus is to be set automatically, FALSE if the focus
    is already set.

--*/
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());

    CInetPropertyPage::OnInitDialog();

    //
    // Take our direction from a phony button
    //
    CRect rc(0, 0, 0, 0);
    m_ocx_LogProperties.Create(
        _T("LogUI"),
        WS_BORDER,
        rc,
        this,
        IDC_LOGUICTRL
        );

    //
    // Initialize the logging ocx; pass it the metabase path of the 
    // virtual server.
    // TODO: Rewrite this crappy logui control to make it more predictable.
    // Here metabase path should not contain leading / and trailing Root
    //
    CString path_inst = QueryMetaPath();
    CString path;
    if (IsMasterInstance())
    {
       CMetabasePath::GetServicePath(path_inst, path);
    }
    else
    {
       CMetabasePath::GetInstancePath(path_inst, path);
    }
    if (path[0] == _T('/'))
    {
        path = path.Right(path.GetLength() - 1);
    }
    m_ocx_LogProperties.SetAdminTarget(QueryServerName(), path);
    m_ocx_LogProperties.SetComboBox(m_combo_LogFormats.m_hWnd);

    GetDlgItem(IDC_RADIO_UNLIMITED)->EnableWindow(!m_f10ConnectionLimit);

    if (IsMasterInstance() || !HasAdminAccess())
    {
        GetDlgItem(IDC_STATIC_IPADDRESS)->EnableWindow(FALSE);
        GetDlgItem(IDC_STATIC_TCP_PORT)->EnableWindow(FALSE);
        GetDlgItem(IDC_EDIT_TCP_PORT)->EnableWindow(FALSE);
        m_combo_IpAddresses.EnableWindow(FALSE);
		GetDlgItem(IDC_STATIC_DESCRIPTION)->EnableWindow(FALSE);
		GetDlgItem(IDC_EDIT_COMMENT)->EnableWindow(FALSE);
    }

    PopulateKnownIpAddresses();
    SetControlStates();
    SetLogState();

    GetDlgItem(IDC_BUTTON_CURRENT_SESSIONS)->EnableWindow(!IsMasterInstance());

    return TRUE;
}



/* virtual */
HRESULT
CFtpServicePage::FetchLoadedValues()
/*++

Routine Description:
    
    Move configuration data from sheet to dialog controls

Arguments:

    None

Return Value:

    HRESULT

--*/
{
    CError err;

    m_f10ConnectionLimit = Has10ConnectionLimit();

    BEGIN_META_INST_READ(CFtpSheet)
        FETCH_INST_DATA_FROM_SHEET(m_nMaxConnections);
        FETCH_INST_DATA_FROM_SHEET(m_nConnectionTimeOut);
        FETCH_INST_DATA_FROM_SHEET(m_iaIpAddress);
        FETCH_INST_DATA_FROM_SHEET(m_nTCPPort);
        FETCH_INST_DATA_FROM_SHEET(m_strDomainName);
        FETCH_INST_DATA_FROM_SHEET(m_strComment);
        FETCH_INST_DATA_FROM_SHEET(m_dwLogType);
        
        m_fUnlimitedConnections = m_nMaxConnections >= MAX_MAX_CONNECTIONS;

        if (m_f10ConnectionLimit)
        {
            m_fUnlimitedConnections = FALSE;
            if ((LONG)m_nMaxConnections > LIMITED_CONNECTIONS_MAX)
            {
                m_nMaxConnections = LIMITED_CONNECTIONS_MAX;
            }
        }

        m_nVisibleMaxConnections = m_fUnlimitedConnections
            ? INITIAL_MAX_CONNECTIONS
            : m_nMaxConnections;

        //
        // Set radio value
        //
        m_nUnlimited = m_fUnlimitedConnections ? RADIO_UNLIMITED : RADIO_LIMITED;

        m_nOldTCPPort = m_nTCPPort;
    END_META_INST_READ(err)

    return err;
}




HRESULT
CFtpServicePage::SaveInfo()
/*++

Routine Description:

    Save the information on this property page

Arguments:

    None

Return Value:

    Error return code

--*/
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());
    ASSERT(IsDirty());

    TRACEEOLID("Saving FTP service page now...");

    CError err;

    m_nMaxConnections = m_fUnlimitedConnections 
        ? UNLIMITED_CONNECTIONS
        : m_nVisibleMaxConnections;

    //
    // Check to make sure we're not violating the license
    // agreement
    //
    if (m_f10ConnectionLimit)
    {
        if (m_nMaxConnections > LIMITED_CONNECTIONS_MAX)
        {
            ::AfxMessageBox(IDS_CONNECTION_LIMIT);
            m_nMaxConnections = LIMITED_CONNECTIONS_MIN;
        }
        else if (m_nMaxConnections >  LIMITED_CONNECTIONS_MIN
              && m_nMaxConnections <= LIMITED_CONNECTIONS_MAX)
        {
            ::AfxMessageBox(IDS_WRN_CONNECTION_LIMIT);
        }
    }

    CString strBinding;
    CStringListEx m_strlBindings;

    CInstanceProps::BuildBinding(
        strBinding, 
        m_iaIpAddress, 
        m_nTCPPort, 
        m_strDomainName
        );
    m_strlBindings.AddTail(strBinding);
    m_ocx_LogProperties.ApplyLogSelection();

    BeginWaitCursor();
    BEGIN_META_INST_WRITE(CFtpSheet)
        STORE_INST_DATA_ON_SHEET(m_nMaxConnections);
        STORE_INST_DATA_ON_SHEET(m_nMaxConnections);
        STORE_INST_DATA_ON_SHEET(m_nConnectionTimeOut);
        STORE_INST_DATA_ON_SHEET(m_dwLogType);
        STORE_INST_DATA_ON_SHEET(m_strComment);
        STORE_INST_DATA_ON_SHEET(m_strlBindings);
    END_META_INST_WRITE(err)
    EndWaitCursor();

    if (err.Succeeded())
    {
		CIISMBNode * pNode = (CIISMBNode *)GetSheet()->GetParameter();
		ASSERT(pNode != NULL);
		pNode->Refresh(FALSE);
    }

    return err;
}



void
CFtpServicePage::OnRadioLimited()
/*++

Routine Description:

    'limited' radio button handler

Arguments:

    None

Return Value:

    None

--*/
{
    m_fUnlimitedConnections = FALSE;
    SetControlStates();
    m_edit_MaxConnections.SetSel(0, -1);
    m_edit_MaxConnections.SetFocus();
    OnItemChanged();
}



void
CFtpServicePage::OnRadioUnlimited()
/*++

Routine Description:

    'unlimited' radio button handler

Arguments:

    None

Return Value:

    None

--*/
{
    m_fUnlimitedConnections = TRUE;
    OnItemChanged();
}



void
CFtpServicePage::OnItemChanged()
/*++

Routine Description:

    Register a change in control value on this page.  Mark the page as dirty.
    All change messages map to this function

Arguments:

    None

Return Value:

    None

--*/
{
    SetControlStates();
    SetModified(TRUE);
}



void
CFtpServicePage::SetLogState()
/*++

Routine Description:

    Set the enabled state of the logging controls depending on
    whether logging is currently enabled

Arguments:

    None

Return Value:

    None

--*/
{
    m_static_LogPrompt.EnableWindow(m_fEnableLogging);
    m_combo_LogFormats.EnableWindow(m_fEnableLogging);
    m_button_LogProperties.EnableWindow(m_fEnableLogging);
}



void
CFtpServicePage::OnCheckEnableLogging()
/*++

Routine Description:

    'Enable logging' checkbox has been toggled.  Reset the state
    of the dialog

Arguments:

    None

Return Value:

    None

--*/
{
    m_fEnableLogging = !m_fEnableLogging;
    SetLogState();
    OnItemChanged();
}



void 
CFtpServicePage::OnButtonProperties() 
/*++

Routine Description:

    Pass on "log properties" button click to the ocx.

Arguments:

    None

Return Value:

    None

--*/
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());
    m_ocx_LogProperties.DoClick();
}



void
CFtpServicePage::OnButtonCurrentSessions()
/*++

Routine Description:

    'Current Sessions' button has been pressed.  Bring up the current
    sessions dialog

Arguments:

    None

Return Value:

    None

-*/
{
    CComAuthInfo * pAuth = GetSheet()->QueryAuthInfo();
    ASSERT(pAuth != NULL);
    CUserSessionsDlg dlg(
        pAuth->QueryServerName(), 
        QueryInstance(), 
        pAuth->QueryUserName(),
        pAuth->QueryPassword(),
        this);
    dlg.DoModal();
}



void 
CFtpServicePage::OnDestroy() 
/*++

Routine Description:

    WM_DESTROY handler.  Clean up internal data

Arguments:

    None

Return Value:

    None

--*/
{
    CInetPropertyPage::OnDestroy();
    
    if (m_ocx_LogProperties.m_hWnd)
    {
        m_ocx_LogProperties.Terminate();
    }
}