/*++

   Copyright    (c)    1994-1998    Microsoft Corporation

   Module  Name :

        mmmdlg.cpp

   Abstract:

        Multi-multi-multi dialog editor

   Author:

        Ronald Meijer (ronaldm)

   Project:

        Internet Services Manager

   Revision History:

--*/

//
// Include Files
//
#include "stdafx.h"
#include "common.h"
#include "inetmgrapp.h"
#include "mmmdlg.h"
#include "inetprop.h"
#include "w3sht.h"

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

//
// Registry key name for this dialog
//
const TCHAR g_szRegKeyIP[] = _T("MMMIpBindings");
const TCHAR g_szRegKeySSL[] = _T("MMMSSLBindings");

//
// IP Bindings Listbox Column Definitions
//
static const ODL_COLUMN_DEF g_aIPColumns[] =
{
// ===============================================
// Weight   Label
// ===============================================
    {  6,   IDS_MMM_IP_ADDRESS,         },
    {  3,   IDS_MMM_TCP_PORT,           },
    { 10,   IDS_MMM_DOMAIN_NAME,        },
};

//
// SSL Bindings Listbox Column Definitions
//
static const ODL_COLUMN_DEF g_aSSLColumns[] =
{
// ===============================================
// Weight   Label
// ===============================================
    {  2,   IDS_MMM_IP_ADDRESS,         },
    {  1,   IDS_MMM_SSL_PORT,           },
};

#define NUM_COLUMNS(cols) (sizeof(cols) / sizeof(cols[0]))

IMPLEMENT_DYNAMIC(CMMMListBox, CRMCListBox);

//
// Bitmap indices
//
enum
{
    BMPID_BINDING,

    //
    // Don't move this one
    //
    BMPID_TOTAL
};


const int CMMMListBox::nBitmaps = BMPID_TOTAL;


CMMMListBox::CMMMListBox(
    IN LPCTSTR lpszRegKey,
    IN int cColumns,
    IN const ODL_COLUMN_DEF * pColumns
    )
/*++

Routine Description:

    Constructor

Arguments:

    None

Return Value:

    N/A

--*/
    : CHeaderListBox(HLS_STRETCH, lpszRegKey),
      m_cColumns(cColumns),
      m_pColumns(pColumns)
{
    VERIFY(m_strDefaultIP.LoadString(IDS_DEFAULT));
    VERIFY(m_strNoPort.LoadString(IDS_MMM_NA));
}



void
CMMMListBox::DrawItemEx(
    IN CRMCListBoxDrawStruct & ds
    )
/*++

Routine Description:

    Draw item in the listbox

Arguments:

    CRMCListBoxDrawStruct & ds : Draw item structure

Return Value:

    None

--*/
{
    CString & strBinding = *(CString *)ds.m_ItemData;

    TRACEEOLID(strBinding);

    UINT nPort;
    LPCTSTR lp;
    CString strHostHeader;
    CString strPort;
    CString strIP;
    CIPAddress iaIpAddress;

    CInstanceProps::CrackBinding(
        strBinding, 
        iaIpAddress, 
        nPort, 
        strHostHeader
        );

    //
    // Display Granted/Denied with appropriate bitmap
    //
    DrawBitmap(ds, 0, BMPID_BINDING);

    if (iaIpAddress.IsZeroValue())
    {
        lp = m_strDefaultIP;
    }
    else
    {
        lp = iaIpAddress.QueryIPAddress(strIP);
    }

    ColumnText(ds, 0, TRUE, lp);

    if (nPort > 0)
    {
        strPort.Format(_T("%u"), nPort);
        lp = strPort;
    }
    else
    {
        lp = m_strNoPort;
    }

    ColumnText(ds, 1, FALSE, lp);
    ColumnText(ds, 2, FALSE, strHostHeader);
}



/* virtual */
BOOL
CMMMListBox::Initialize()
/*++

Routine Description:

    Initialize the listbox.  Insert the columns as requested, and lay
    them out appropriately

Arguments:

    None

Return Value:

    TRUE for succesful initialisation, FALSE otherwise

--*/
{
    if (!CHeaderListBox::Initialize())
    {
        return FALSE;
    }

    //
    // Build all columns
    //
    HINSTANCE hInst = AfxGetResourceHandle();
    for (int nCol = 0; nCol < m_cColumns; ++nCol)
    {
        InsertColumn(nCol, m_pColumns[nCol].nWeight, m_pColumns[nCol].nLabelID, hInst);
    }

    //
    // Try to set the widths from the stored registry value,
    // otherwise distribute according to column weights specified
    //
//    if (!SetWidthsFromReg())
//    {
        DistributeColumns();
//    }

    return TRUE;
}



void AFXAPI
DDXV_UINT(
    IN CDataExchange * pDX,
    IN UINT nID,
    IN OUT UINT & uValue,
    IN UINT uMin,
    IN UINT uMax,
    IN UINT nEmptyErrorMsg  OPTIONAL
    )
/*++

Routine Description:

    DDX/DDV Function that uses a space to denote a 0 value

Arguments:

    CDataExchange * pDX     : Data exchange object
    UINT nID                : Resource ID
    OUT UINT & uValue       : Value
    UINT uMin               : Minimum value
    UINT uMax               : Maximum value
    UINT nEmptyErrorMsg     : Error message ID for empty unit, or 0 if empty OK

Return Value:

    None.

--*/
{
    ASSERT(uMin <= uMax);

    CWnd * pWnd = CWnd::FromHandle(pDX->PrepareEditCtrl(nID));
    ASSERT(pWnd != NULL);

    if (pDX->m_bSaveAndValidate)
    {
        if (pWnd->GetWindowTextLength() > 0)
        {
            DDX_Text(pDX, nID, uValue);
            DDV_MinMaxUInt(pDX, uValue, uMin, uMax);
        }
        else
        {
            uValue = 0;
            if (nEmptyErrorMsg)
            {
                ::AfxMessageBox(nEmptyErrorMsg);
                pDX->Fail();
            }
        }
    }
    else
    {
        if (uValue != 0)
        {
            DDX_Text(pDX, nID, uValue);
        }    
        else
        {
            pWnd->SetWindowText(_T(""));
        }
    }
}



BOOL
IsBindingUnique(
    IN CString & strBinding,
    IN CStringList & strlBindings,
    IN int iCurrent                 OPTIONAL
    )
/*++

Routine Description:

    Helper function to determine if a binding is unique.

Arguments:

    CString & strBinding            : Binding string
    CStringList & strlBindings      : List of bindings
    int iCurrent                    : Index of "current" item.  
                                      Not used for uniqueness checking.

Return Value:

    TRUE if the binding is unique, FALSE otherwise.

--*/
{
    int iItem = 0;
        
    for(POSITION pos = strlBindings.GetHeadPosition(); pos != NULL; /**/ )
    {
        CString & str = strlBindings.GetNext(pos);
        if (iItem != iCurrent && &str != &strBinding && str == strBinding)
        {
            //
            // Not unique!
            //
            return FALSE;
        }

        ++iItem;
    }

    //
    // Unique
    //
    return TRUE;
}


//
// Multi-multi-multi editing dialog
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



CMMMEditDlg::CMMMEditDlg(
    IN CString & strServerName,
    IN CStringList & strlBindings,
    IN CStringList & strlOtherBindings,
    IN OUT CString & entry,
    IN BOOL fIPBinding,
    IN CWnd * pParent OPTIONAL
    )
/*++

Routine Description:

    Constructor

Arguments:

    CString & strServerName          : Server name
    CStringList & strlBindings       : bindings
    CStringList & strlOtherBindings  : "other" bindings list
    CString & entry                  : Entry being edited
    BOOL fIPBinding                  : TRUE for IP, FALSE for SSL
    CWnd * pParent                   : Optional parent window

Return Value:

    N/A

--*/
    : CDialog(CMMMEditDlg::IDD, pParent),
      m_strServerName(strServerName),
      m_strlBindings(strlBindings),
      m_strlOtherBindings(strlOtherBindings),
      m_entry(entry),
      m_fIPBinding(fIPBinding),
      m_nIpAddressSel(-1)
{

#if 0 // Keep class wizard happy

    //{{AFX_DATA_INIT(CMMMEditDlg)
    m_nIpAddressSel = -1;
    //}}AFX_DATA_INIT

#endif // 0

    CInstanceProps::CrackBinding(
        m_entry, 
        m_iaIpAddress, 
        m_nPort, 
        m_strDomainName
        );
}

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

Routine Description:

    Initialise/Store control data

Arguments:

    CDataExchange * pDX - DDX/DDV control structure

Return Value:

    None

--*/
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CMMMEditDlg)
    DDX_Text(pDX, IDC_EDIT_DOMAIN_NAME, m_strDomainName);
    DDV_MaxChars(pDX, m_strDomainName, MAX_PATH);
    DDX_Control(pDX, IDC_COMBO_IP_ADDRESSES, m_combo_IpAddresses);
    DDX_Control(pDX, IDC_STATIC_PORT, m_static_Port);
    //}}AFX_DATA_MAP

    DDXV_UINT(pDX, IDC_EDIT_PORT, m_nPort, 1, 65535);

    DDX_CBIndex(pDX, IDC_COMBO_IP_ADDRESSES, m_nIpAddressSel);

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

    // Currently IIS support in domain names only A-Z,a-z,0-9,.-
    if (pDX->m_bSaveAndValidate)
    {
        LPCTSTR p = m_strDomainName;
        while (p != NULL && *p != 0)
        {
            TCHAR c = towupper(*p);
            if (    (c >= _T('A') && c <= _T('Z')) 
                ||  (c >= _T('0') && c <= _T('9'))
                ||  (c == _T('.') || c == _T('-'))
                )
            {
                p++;
                continue;
            }
            else
            {
                AfxMessageBox(IDS_WARNING_DOMAIN_NAME);
                pDX->PrepareEditCtrl(IDC_EDIT_DOMAIN_NAME);
                pDX->Fail();
            }
        }
    }
}

//
// Message Map
//
BEGIN_MESSAGE_MAP(CMMMEditDlg, CDialog)
    //{{AFX_MSG_MAP(CMMMEditDlg)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

BOOL 
CMMMEditDlg::OnInitDialog() 
/*++

Routine Description:

    WM_INITDIALOG handler.  Initialize the dialog.

Arguments:

    None.

Return Value:

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

--*/
{
    CDialog::OnInitDialog();

    BeginWaitCursor();
    PopulateComboWithKnownIpAddresses(
        m_strServerName,
        m_combo_IpAddresses,
        m_iaIpAddress,
        m_oblIpAddresses,
        m_nIpAddressSel
        );
    EndWaitCursor();

    //
    // Configure dialog for either SSL or IP binding editing
    //
    CString str;
    VERIFY(str.LoadString(m_fIPBinding 
        ? IDS_EDIT_MMM_TITLE
        : IDS_EDIT_SSL_MMM_TITLE));
    SetWindowText(str);

    VERIFY(str.LoadString(m_fIPBinding 
        ? IDS_TCP_PORT
        : IDS_SSL_PORT));
    m_static_Port.SetWindowText(str);

    ActivateControl(*GetDlgItem(IDC_STATIC_HEADER_NAME), m_fIPBinding);
    ActivateControl(*GetDlgItem(IDC_EDIT_DOMAIN_NAME),   m_fIPBinding);
#if 0
    CHARFORMAT cf;
    ZeroMemory(&cf, sizeof(cf));
    cf.cbSize = sizeof(cf);
    cf.dwMask = CFM_FACE;
    cf.bPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
    lstrcpyn((LPTSTR)cf.szFaceName, _T("Courier"), LF_FACESIZE);

    SendDlgItemMessage(IDC_EDIT_DOMAIN_NAME, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
#endif
    DWORD event = (DWORD)SendDlgItemMessage(IDC_EDIT_DOMAIN_NAME, EM_GETEVENTMASK, 0, 0);
    event |= ENM_CHANGE;
    SendDlgItemMessage(IDC_EDIT_DOMAIN_NAME, EM_SETEVENTMASK, 0, (LPARAM)event);

    return TRUE;  
}



void 
CMMMEditDlg::OnOK() 
/*++

Routine Description:

    OK button handler.  Verify values are acceptable, and change

Arguments:

    None

Return Value:

    None

--*/
{
    if (!UpdateData(TRUE))
    {
        return;
    }

    if (m_nPort == 0)
    {
        ::AfxMessageBox(IDS_NO_PORT);
        return;
    }

    CString strOldBinding(m_entry);
    CInstanceProps::BuildBinding(m_entry, m_iaIpAddress, m_nPort, m_strDomainName);

    //
    // Ensure the ip/address doesn't exist in the "other" binding list
    //
    if (CInstanceProps::IsPortInUse(m_strlOtherBindings, m_iaIpAddress, m_nPort))
    {
        //
        // Restore the old binding
        //
        m_entry = strOldBinding;
        ::AfxMessageBox(m_fIPBinding 
            ? IDS_ERR_PORT_IN_USE_SSL 
            : IDS_ERR_PORT_IN_USE_TCP);
        return; 
    }
    

    if (!IsBindingUnique(m_entry, m_strlBindings))
    {
        //
        // Restore the old binding
        //
        m_entry = strOldBinding;
        ::AfxMessageBox(IDS_ERR_BINDING);
        return; 
    }

    CDialog::OnOK();
}

//
// Multi-multi-multi list dialog
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

CMMMDlg::CMMMDlg(
    IN LPCTSTR lpServerName,
    IN DWORD   dwInstance,
    IN CComAuthInfo * pAuthInfo,
    IN LPCTSTR lpMetaPath,
    IN OUT CStringList & strlBindings,
    IN OUT CStringList & strlSecureBindings,
    IN CWnd * pParent OPTIONAL
    )
/*++

Routine Description:

    Constructor

Arguments:

    CStringList & strlBindings          : Service bindings
    CStringList & strlSecureBindings    : SSL port bindings
    CWnd * pParent                      : Optional parent window

Return Value:

    N/A

--*/
    : CDialog(CMMMDlg::IDD, pParent),
      m_ListBoxRes(
        IDB_BINDINGS,
        CMMMListBox::nBitmaps
        ),
      m_list_Bindings(g_szRegKeyIP, NUM_COLUMNS(g_aIPColumns), g_aIPColumns),
      m_list_SSLBindings(g_szRegKeySSL, NUM_COLUMNS(g_aSSLColumns), g_aSSLColumns),
      m_strlBindings(),
      m_strlSecureBindings(),
      m_strServerName(lpServerName),
      m_strMetaPath(lpMetaPath),
      m_pAuthInfo(pAuthInfo),
      m_fDirty(FALSE)
{
    //{{AFX_DATA_INIT(CMMMDlg)
    //}}AFX_DATA_INIT
    
    m_fCertInstalled = ::IsCertInstalledOnServer(m_pAuthInfo, lpMetaPath),
    m_strlBindings.AddTail(&strlBindings);
    m_strlSecureBindings.AddTail(&strlSecureBindings);
    m_list_Bindings.AttachResources(&m_ListBoxRes);
    m_list_SSLBindings.AttachResources(&m_ListBoxRes);
}


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

Routine Description:

    Initialise/Store control data

Arguments:

    CDataExchange * pDX - DDX/DDV control structure

Return Value:

    None

--*/
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CMMMDlg)
    DDX_Control(pDX, IDC_BUTTON_ADD, m_button_Add);
    DDX_Control(pDX, IDC_BUTTON_REMOVE, m_button_Remove);
    DDX_Control(pDX, IDC_BUTTON_EDIT, m_button_Edit);
    DDX_Control(pDX, IDC_BUTTON_ADD_SSL, m_button_AddSSL);
    DDX_Control(pDX, IDC_BUTTON_REMOVE_SSL, m_button_RemoveSSL);
    DDX_Control(pDX, IDC_BUTTON_EDIT_SSL, m_button_EditSSL);
    DDX_Control(pDX, IDOK, m_button_OK);
    //}}AFX_DATA_MAP

    DDX_Control(pDX, IDC_LIST_MMM, m_list_Bindings);
    DDX_Control(pDX, IDC_LIST_SSL_MMM, m_list_SSLBindings);
}



BOOL
CMMMDlg::OnItemChanged()
/*++

Routine Description:

    Mark that the dialog as dirty

Arguments:

    None

Return Value:

    TRUE if the remove button is enabled

--*/
{
    m_fDirty = TRUE;

    return SetControlStates();
}



BOOL
CMMMDlg::SetControlStates()
/*++

Routine Description:

    Set the enabled state of the controls depending on the current
    values in the dialog

Arguments:

    None

Return Value:

    TRUE if the remove button is enabled

--*/
{
    BOOL fSel = m_list_Bindings.GetSelCount() > 0;

    m_button_Remove.EnableWindow(fSel);
    m_button_Edit.EnableWindow(m_list_Bindings.GetSelCount() == 1);
    m_button_RemoveSSL.EnableWindow(m_list_SSLBindings.GetSelCount() > 0);
    m_button_EditSSL.EnableWindow(m_list_SSLBindings.GetSelCount() == 1);

    m_button_OK.EnableWindow(m_fDirty && m_list_Bindings.GetCount() > 0);

    return fSel;
}



void
CMMMDlg::AddBindings(
    IN CMMMListBox & list, 
    IN CStringList & strlBindings
    )
/*++

Routine Description:

    Add bindings information to the specified listbox

Arguments:

    CMMMListBox & list              : MMM Listbox (SSL or IP)
    CStringList & strlBindings      : SSL or IP bindings

Return Value:

    None

--*/
{
    for (POSITION pos = strlBindings.GetHeadPosition(); pos != NULL; /**/)
    {
        CString & strBinding = strlBindings.GetNext(pos);
        list.AddItem(strBinding);
    }
}


//
// Message Map
//
BEGIN_MESSAGE_MAP(CMMMDlg, CDialog)
    //{{AFX_MSG_MAP(CMMMDlg)
    ON_BN_CLICKED(IDC_BUTTON_ADD, OnButtonAdd)
    ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
    ON_BN_CLICKED(IDC_BUTTON_REMOVE, OnButtonRemove)
    ON_BN_CLICKED(IDC_BUTTON_ADD_SSL, OnButtonAddSsl)
    ON_BN_CLICKED(IDC_BUTTON_EDIT_SSL, OnButtonEditSsl)
    ON_BN_CLICKED(IDC_BUTTON_REMOVE_SSL, OnButtonRemoveSsl)
    ON_LBN_DBLCLK(IDC_LIST_MMM, OnDblclkListMmm)
    ON_LBN_DBLCLK(IDC_LIST_SSL_MMM, OnDblclkListSslMmm)
    ON_LBN_SELCHANGE(IDC_LIST_MMM, OnSelchangeListMmm)
    ON_LBN_SELCHANGE(IDC_LIST_SSL_MMM, OnSelchangeListSslMmm)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

void 
CMMMDlg::OnButtonAdd() 
/*++

Routine Description:

    Add button handler

Arguments:

    None

Return Value:

    None

--*/
{
    //
    // Add entry
    //
    CString strEntry;

    CMMMEditDlg dlg(
        m_strServerName, 
        m_strlBindings,
        m_strlSecureBindings,
        strEntry, 
        TRUE, /* IP binding */
        this
        );

    if (dlg.DoModal() == IDOK)
    {
        POSITION pos = m_strlBindings.AddTail(strEntry);
        int nSel = m_list_Bindings.AddItem(m_strlBindings.GetAt(pos));
        m_list_Bindings.SetCurSel(nSel);
        OnItemChanged();
    }
}

void 
CMMMDlg::OnButtonEdit() 
/*++

Routine Description:

    Edit button handler

Arguments:

    None

Return Value:

    None

--*/
{
    //
    // Edit entry
    //
    int nCurSel = m_list_Bindings.GetCurSel();
    if (nCurSel != LB_ERR)
    {
        CString & strEntry = m_list_Bindings.GetItem(nCurSel);
        CMMMEditDlg dlg(
            m_strServerName, 
            m_strlBindings,
            m_strlSecureBindings,
            strEntry, 
            TRUE, /* IP binding */
            this
            );

        if (dlg.DoModal() == IDOK)
        {
            m_list_Bindings.InvalidateSelection(nCurSel);
            OnItemChanged();
        }
    }
}

void 
CMMMDlg::OnButtonRemove() 
/*++

Routine Description:

    Remove button handler

Arguments:

    None

Return Value:

    None

--*/
{
    int nCurSel = m_list_Bindings.GetCurSel();
    int nSel = 0;
    int cChanges = 0;
    while (nSel < m_list_Bindings.GetCount())
    {
        //
        // Remove Selected entry
        //
        if (m_list_Bindings.GetSel(nSel))
        {
            m_strlBindings.RemoveAt(m_strlBindings.FindIndex(nSel));
            m_list_Bindings.DeleteString(nSel);
            ++cChanges;
            continue;
        }

        ++nSel;
    }

    if (cChanges)
    {
        m_list_Bindings.SetCurSel(nCurSel);
        if (!OnItemChanged())
        {
            m_button_Add.SetFocus();
        }
    }
/*
    //
    // Remove Selected entry
    //
    int nCurSel = m_list_Bindings.GetCurSel();
    if (nCurSel != LB_ERR)
    {
        m_strlBindings.RemoveAt(m_strlBindings.FindIndex(nCurSel));
        m_list_Bindings.DeleteString(nCurSel);
        if (nCurSel >= m_list_Bindings.GetCount())
        {
            --nCurSel;
        }
        m_list_Bindings.SetCurSel(nCurSel);

        if (!OnItemChanged())
        {
            m_button_Add.SetFocus();
        }
    }
*/
}


void 
CMMMDlg::OnDblclkListMmm() 
/*++

Routine Description:

    Double click notification handler

Arguments:

    None

Return Value:

    None

--*/
{
    OnButtonEdit();
}


void 
CMMMDlg::OnSelchangeListMmm() 
/*++

Routine Description:

    selection change notification handler

Arguments:

    None

Return Value:

    None

--*/
{
    SetControlStates();
}



void 
CMMMDlg::OnButtonAddSsl() 
/*++

Routine Description:

    'Add SSL' button handler

Arguments:

    None

Return Value:

    None

--*/
{
    //
    // Add entry
    //
    CString strEntry;

    CMMMEditDlg dlg(
        m_strServerName, 
        m_strlSecureBindings,
        m_strlBindings,
        strEntry, 
        FALSE, /* SSL binding */
        this
        );

    if (dlg.DoModal() == IDOK)
    {
        POSITION pos = m_strlSecureBindings.AddTail(strEntry);
        int nSel = m_list_SSLBindings.AddItem(m_strlSecureBindings.GetAt(pos));
        m_list_SSLBindings.SetCurSel(nSel);
        OnItemChanged();
    }
}



void 
CMMMDlg::OnButtonEditSsl() 
/*++

Routine Description:

    'Edit SSL' button handler

Arguments:

    None

Return Value:

    None

--*/
{
    //
    // Edit entry
    //
    int nCurSel = m_list_SSLBindings.GetCurSel();
    if (nCurSel != LB_ERR)
    {
        CString & strEntry = m_list_SSLBindings.GetItem(nCurSel);
        CMMMEditDlg dlg(
            m_strServerName, 
            m_strlSecureBindings,
            m_strlBindings,
            strEntry, 
            FALSE, /* SSL binding */
            this
            );

        if (dlg.DoModal() == IDOK)
        {
            m_list_SSLBindings.InvalidateSelection(nCurSel);
            OnItemChanged();
        }
    }
}



void 
CMMMDlg::OnButtonRemoveSsl() 
/*++

Routine Description:

    'Remove SSL' button handler

Arguments:

    None

Return Value:

    None

--*/
{
    int nCurSel = m_list_SSLBindings.GetCurSel();
    int nSel = 0;
    int cChanges = 0;
    while (nSel < m_list_SSLBindings.GetCount())
    {
        //
        // Remove Selected entry
        //
        if (m_list_SSLBindings.GetSel(nSel))
        {
            m_strlSecureBindings.RemoveAt(m_strlSecureBindings.FindIndex(nSel));
            m_list_SSLBindings.DeleteString(nSel);
            ++cChanges;
            continue;
        }

        ++nSel;
    }

    if (cChanges)
    {
        m_list_SSLBindings.SetCurSel(nCurSel);
        OnItemChanged();
        if (m_list_SSLBindings.GetSelCount() == 0)
        {
            //
            // Remove will be disabled
            //
            m_button_AddSSL.SetFocus();
        }
    }

/*
    //
    // Remove Selected entry
    //
    int nCurSel = m_list_SSLBindings.GetCurSel();
    if (nCurSel != LB_ERR)
    {
        m_strlSecureBindings.RemoveAt(m_strlSecureBindings.FindIndex(nCurSel));
        m_list_SSLBindings.DeleteString(nCurSel);
        if (nCurSel >= m_list_SSLBindings.GetCount())
        {
            --nCurSel;
        }
        m_list_SSLBindings.SetCurSel(nCurSel);

        OnItemChanged();
        if (m_list_SSLBindings.GetCurSel() == LB_ERR)
        {
            //
            // Remove will be disabled
            //
            m_button_AddSSL.SetFocus();
        }
    }
*/
}



void 
CMMMDlg::OnDblclkListSslMmm() 
/*++

Routine Description:

    SSL List 'double click' handler

Arguments:

    None

Return Value:

    None

--*/
{
    OnButtonEditSsl();
}



void 
CMMMDlg::OnSelchangeListSslMmm() 
/*++

Routine Description:

    SSL List 'selection change' handler

Arguments:

    None

Return Value:

    None

--*/
{
    SetControlStates();
}



BOOL 
CMMMDlg::OnInitDialog() 
/*++

Routine Description:

    WM_INITDIALOG handler.  Initialize the dialog.

Arguments:

    None.

Return Value:

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

--*/
{
    CDialog::OnInitDialog();

    m_list_Bindings.Initialize();
    m_list_SSLBindings.Initialize();

    AddBindings(m_list_Bindings, m_strlBindings);
    AddBindings(m_list_SSLBindings, m_strlSecureBindings);

    //
    // No certificates, no SSL
    //
    GetDlgItem(IDC_GROUP_SSL)->EnableWindow(m_fCertInstalled);
    m_list_SSLBindings.EnableWindow(m_fCertInstalled);
    m_button_AddSSL.EnableWindow(m_fCertInstalled);
    m_button_RemoveSSL.EnableWindow(m_fCertInstalled);
    m_button_EditSSL.EnableWindow(m_fCertInstalled);

    SetControlStates();
    
    return TRUE; 
}