// MapWPge.cpp : implementation file
//

#include "stdafx.h"
#include <iadmw.h>
#include "certmap.h"

extern "C"
    {
    #include <wincrypt.h>
    #include <sslsp.h>
    }

#include "Iismap.hxx"
#include "Iiscmr.hxx"

#include "brwsdlg.h"
#include "ListRow.h"
#include "ChkLstCt.h"

#include "MapWPge.h"
#include "Ed11Maps.h"
#include "EdWldRul.h"

#include <iiscnfgp.h>
#include "wrapmb.h"

#include "WWzOne.h"
#include "WWzTwo.h"
#include "WWzThree.h"

#include <lmcons.h>

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


#define COL_NUM_ENABLED                 0
#define COL_NUM_DESCRIPTION             1
#define COL_NUM_NTACCOUNT               2


#define MB_EXTEND_KEY   "CertW"

/////////////////////////////////////////////////////////////////////////////
// CMapWildcardsPge property page

IMPLEMENT_DYNCREATE(CMapWildcardsPge, CPropertyPage)

//---------------------------------------------------------------------------
CMapWildcardsPge::CMapWildcardsPge() : CPropertyPage(CMapWildcardsPge::IDD),
    m_fDirty(FALSE)
    {
    //{{AFX_DATA_INIT(CMapWildcardsPge)
    m_bool_enable = FALSE;
    //}}AFX_DATA_INIT
    }

//---------------------------------------------------------------------------
CMapWildcardsPge::~CMapWildcardsPge()
    {
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::DoDataExchange(CDataExchange* pDX)
    {
    CPropertyPage::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CMapWildcardsPge)
    DDX_Control(pDX, IDC_LIST, m_clistctrl_list);
    DDX_Control(pDX, IDC_MOVE_UP, m_cbutton_up);
    DDX_Control(pDX, IDC_MOVE_DOWN, m_cbutton_down);
    DDX_Control(pDX, IDC_ADD, m_cbutton_add);
    DDX_Control(pDX, IDC_DELETE, m_cbutton_delete);
    DDX_Control(pDX, IDC_EDIT, m_cbutton_editrule);
    DDX_Check(pDX, IDC_ENABLE, m_bool_enable);
    //}}AFX_DATA_MAP
    }


//---------------------------------------------------------------------------
BEGIN_MESSAGE_MAP(CMapWildcardsPge, CPropertyPage)
    //{{AFX_MSG_MAP(CMapWildcardsPge)
    ON_BN_CLICKED(IDC_MOVE_DOWN, OnMoveDown)
    ON_BN_CLICKED(IDC_MOVE_UP, OnMoveUp)
    ON_BN_CLICKED(IDC_ADD, OnAdd)
    ON_BN_CLICKED(IDC_DELETE, OnDelete)
    ON_BN_CLICKED(IDC_EDIT, OnEdit)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnItemchangedList)
    ON_NOTIFY(NM_DBLCLK, IDC_LIST, OnDblclkList)
    ON_BN_CLICKED(IDC_ENABLE, OnEnable)
    //}}AFX_MSG_MAP
    ON_COMMAND(ID_HELP_FINDER,  DoHelp)
    ON_COMMAND(ID_HELP,         DoHelp)
    ON_COMMAND(ID_CONTEXT_HELP, DoHelp)
    ON_COMMAND(ID_DEFAULT_HELP, DoHelp)
END_MESSAGE_MAP()

//---------------------------------------------------------------------------
void CMapWildcardsPge::DoHelp()
    {
    WinHelp( HIDD_CERTMAP_MAIN_ADVANCED );
    }

/////////////////////////////////////////////////////////////////////////////
// initialization routines

//---------------------------------------------------------------------------
// FInitMapper is called by the routine instantiating this page. After the object
// is first created is when it is called. It allows us to fail gracefully.
BOOL CMapWildcardsPge::FInit(IMSAdminBase* pMB)
    {
    BOOL            fAnswer = FALSE;
    PVOID           pData = NULL;
    DWORD           cbData = 0;
    BOOL            f;

    m_pMB = pMB;

    // before messing with the metabase, prepare the strings we will need
    CString         szBasePath = m_szMBPath;
    CString         szRelativePath = MB_EXTEND_KEY;
    CString         szObjectPath = m_szMBPath + _T('/') + szRelativePath;

    // prepare the metabase wrapper
    CWrapMetaBase   mbWrap;
    f = mbWrap.FInit(m_pMB);
    if ( !f ) return FALSE;

    // attempt to open the object we want to store into
    f = mbWrap.Open( szObjectPath, METADATA_PERMISSION_READ );

    // if that worked, load the data
    if ( f )
        {
        // first, get the size of the data that we are looking for
        pData = mbWrap.GetData( _T(""), MD_SERIAL_CERTW, IIS_MD_UT_SERVER, BINARY_METADATA, &cbData );

        // if we successfully got the data, unserialize it
        // WARNING: m_mapper.Unserialize changes the value of the pointer that is passed in. Pass
        // in a copy of the pointer
        PUCHAR  pDataCopy = (PUCHAR)pData;
        if ( pData )
            fAnswer = m_mapper.Unserialize( (PUCHAR*)&pDataCopy, &cbData );

        // close the object
        f = mbWrap.Close();

        // cleanup
        if ( pData )
            mbWrap.FreeWrapData( pData );
        }

    // return the answer
    return fAnswer;
    }

//---------------------------------------------------------------------------
BOOL CMapWildcardsPge::OnInitDialog()
    {
    //call the parental oninitdialog
    BOOL f = CPropertyPage::OnInitDialog();

    // if the initinalization (sp?) succeeded, init the list and other items
    if ( f )
        {
        // init the contents of the list
        FInitRulesList();

        // Fill the mapping list with the stored items
        FillRulesList();

        // set the initial button states
        EnableDependantButtons();
        }

    // set the initial state of the enable button
    // get the globals object
    CCertGlobalRuleInfo* pGlob = m_mapper.GetGlobalRulesInfo();
    m_bool_enable = pGlob->GetRulesEnabled();

    // set any changes in the info into place
    UpdateData(FALSE);

    // return the answer
    return f;
    }

//---------------------------------------------------------------------------
BOOL CMapWildcardsPge::FInitRulesList()
    {
    CString sz;
    int             i;

    // setup the friendly name column
    sz.Empty();
    i = m_clistctrl_list.InsertColumn( COL_NUM_ENABLED, sz, LVCFMT_LEFT, 20 );

    // setup the description column
    sz.LoadString( IDS_WILD_DESCRIPTION );
    i = m_clistctrl_list.InsertColumn( COL_NUM_DESCRIPTION, sz, LVCFMT_LEFT, 238 );

    // setup the account column
    sz.LoadString( IDS_WILD_ACCOUNT );
    i = m_clistctrl_list.InsertColumn( COL_NUM_NTACCOUNT, sz, LVCFMT_LEFT, 220 );

    return TRUE;
    }

//---------------------------------------------------------------------------
// fill in the rules. Get the order for the rules from the globals object. That
// way there is no need to sort them later
BOOL CMapWildcardsPge::FillRulesList()
    {
    // get the globals object
    CCertGlobalRuleInfo* pGlob = m_mapper.GetGlobalRulesInfo();

    // get the number of rules (actually its a number of rule order - but they are the same thing)
    DWORD   cbRules = m_mapper.GetRuleCount();

    // get the pointer to the order array
    DWORD*  pOrder = pGlob->GetRuleOrderArray();

    // for each item in the mapper object, add it to the list control
    for ( DWORD j = 0; j < cbRules; j++ )
        {
        CCertMapRule*   pRule;
        DWORD                   iRule = pOrder[j];

        // get the mapping
        pRule = m_mapper.GetRule( iRule );

        // if that worked, add it to the list
        if ( pRule )
            {
            // add it to the list
            AddRuleToList( pRule, iRule, 0xffffffff );
            }
        }

    // it worked - so ok.
    return TRUE;
    }

//---------------------------------------------------------------------------
int CMapWildcardsPge::AddRuleToList( CCertMapRule* pRule, DWORD iRule, int iInsert )
    {
    CString sz;
    int             i;

    if ( !pRule )
        return -1;

    // if the item to be inserted is to be the last, set it up
    if ( iInsert == 0xffffffff )
        iInsert = m_clistctrl_list.GetItemCount();

    // get the appropriate "enabled" string
    BOOL fEnabled = pRule->GetRuleEnabled();
    if ( fEnabled )
        sz.LoadString( IDS_ENABLED );
    else
        sz.Empty();

    // add the friendly name of the mapping
    // create the new entry in the list box. Do not sort on this entry - yet
    i = m_clistctrl_list.InsertItem( iInsert, sz );

    // add the friendly name of the rule
    sz = pRule->GetRuleName();
    // create the new entry in the list box. Do not sort on this entry - yet
    m_clistctrl_list.SetItemText( i, COL_NUM_DESCRIPTION, sz );

    // add the account name of the mapping
    if ( pRule->GetRuleDenyAccess() )
        sz.LoadString( IDS_DENYACCESS );
    else
        sz = pRule->GetRuleAccount();
    m_clistctrl_list.SetItemText( i, COL_NUM_NTACCOUNT, sz );

    // attach the mapper index to the item in the list - it may have a different
    // list index after the list has been sorted.
    m_clistctrl_list.SetItemData( i, iRule );

    // return whether or not the insertion succeeded
    return i;
    }

//---------------------------------------------------------------------------
// Note: supposedly, the order of the items in the list and the odrder
// of the items in the globals object should be the same
void CMapWildcardsPge::UpdateRuleInDispList( DWORD iList, CCertMapRule* pRule )
    {
    CString sz;

    // get the appropriate "enabled" string
    BOOL fEnabled = pRule->GetRuleEnabled();
    if ( fEnabled )
        sz.LoadString( IDS_ENABLED );
    else
        sz.Empty();

    // update the "Enabled" indicator
    m_clistctrl_list.SetItemText( iList, COL_NUM_ENABLED, sz );

    // update the mapping name
    sz = pRule->GetRuleName();
    m_clistctrl_list.SetItemText( iList, COL_NUM_DESCRIPTION, sz );

    // update the account name
    if ( pRule->GetRuleDenyAccess() )
        sz.LoadString( IDS_DENYACCESS );
    else
        sz = pRule->GetRuleAccount();
    m_clistctrl_list.SetItemText( iList, COL_NUM_NTACCOUNT, sz );
    }


//---------------------------------------------------------------------------
// editing a wildcard rule is rather complex, thus I am seperating that code
// out into that for the dialog itself. All we do is pass in the rule pointer
// and let it go at that.
BOOL CMapWildcardsPge::EditOneRule( CCertMapRule* pRule, BOOL fAsWizard )
    {
    // edit the item using a tabbed dialog / wizard
    CPropertySheet  propSheet;
    CWildWizOne     wwOne;
    CWildWizTwo     wwTwo;
    CWildWizThree   wwThree;

    // set the params
    wwOne.m_pMB = m_pMB;

    // fill in the data for the pages
    wwOne.m_pRule = pRule;
    wwOne.m_szMBPath = m_szMBPath;
    wwOne.m_fIsWizard = fAsWizard;
    wwOne.m_pPropSheet = &propSheet;

    wwTwo.m_pRule = pRule;
    wwTwo.m_szMBPath = m_szMBPath;
    wwTwo.m_fIsWizard = fAsWizard;
    wwTwo.m_pPropSheet = &propSheet;

    wwThree.m_pRule = pRule;
    wwThree.m_szMBPath = m_szMBPath;
    wwThree.m_fIsWizard = fAsWizard;
    wwThree.m_pPropSheet = &propSheet;

    // add the pages
    propSheet.AddPage( &wwOne );
    propSheet.AddPage( &wwTwo );
    propSheet.AddPage( &wwThree );

    // turn it into a wizard if necessary
    if ( fAsWizard )
        propSheet.SetWizardMode();

    // set the title of the wizard/tabbed dialog thing
    CString   szTitle;

    szTitle.LoadString( IDS_WILDWIZ_TITLE );

    propSheet.SetTitle( szTitle );

    // turn on help
    propSheet.m_psh.dwFlags |= PSH_HASHELP;
    wwOne.m_psp.dwFlags |= PSP_HASHELP;
    wwTwo.m_psp.dwFlags |= PSP_HASHELP;
    wwThree.m_psp.dwFlags |= PSP_HASHELP;

    // run the wizard and return if it ended with IDOK
    INT_PTR id = propSheet.DoModal();
    return ( (id == IDOK) || (id == ID_WIZFINISH) );

 /*
   CEditWildcardRule       ruleDlg;

    // prepare
    ruleDlg.m_pRule = pRule;
    ruleDlg.m_szMBPath = m_szMBPath;

    // run the dialog and return if it ended with IDOK
    return (ruleDlg.DoModal() == IDOK);
*/
    }

//---------------------------------------------------------------------------
// Yeah! the CEdit11Mappings works equally well for multiple rules! - just
// some modifications in this routine!
BOOL CMapWildcardsPge::EditMultipleRules()
    {
    CEdit11Mappings mapdlg;
    CCertMapRule*   pRule;
    BOOL                    fSetInitialState = FALSE;
    BOOL                    fEnable;


    // scan the list of seleted items for the proper initial enable button state
    // loop through the selected items, setting each one's mapping
    int     iList = -1;
    while( (iList = m_clistctrl_list.GetNextItem( iList, LVNI_SELECTED )) >= 0 )
        {
        // get the mapper index for the item
        // IA64 - this is OK to cast to DWORD as it is just an index
        DWORD iMapper = (DWORD)m_clistctrl_list.GetItemData( iList );

        // get the mapping item for updating purposes
        pRule = m_mapper.GetRule( iMapper );
        if ( !pRule )
            {
            AfxMessageBox( IDS_ERR_ACCESS_MAPPING );
            break;
            }

        // get the enable state of the mapping
        fEnable = pRule->GetRuleEnabled();

        // if this is the first time, just set the initial state
        if ( !fSetInitialState )
            {
            mapdlg.m_int_enable = fEnable;
            fSetInitialState = TRUE;
            }
        else
            {
            // if it is different, then go indeterminate and break
            if ( fEnable != mapdlg.m_int_enable )
                {
                mapdlg.m_int_enable = 2;
                break;
                }
            }
        }

    //
    // ANSI/UNICODE conversion - RonaldM
    //
    USES_CONVERSION;

    // run the mapping dialog
    if ( mapdlg.DoModal() == IDOK )
        {
        // loop through the selected items, setting each one's mapping
        int     iList = -1;
        while( (iList = m_clistctrl_list.GetNextItem( iList, LVNI_SELECTED )) >= 0 )
            {
            // get the mapper index for the item
            // IA64 - this is OK to cast to DWORD as it is just an index
            DWORD iMapper = (DWORD)m_clistctrl_list.GetItemData( iList );

            // get the mapping item for updating purposes
            pRule = m_mapper.GetRule( iMapper );
            if ( !pRule )
                {
                AfxMessageBox( IDS_ERR_ACCESS_MAPPING );
                break;
                }

            // set the enable flag if requested
            switch ( mapdlg.m_int_enable )
                {
                case 0:         // disable
                    pRule->SetRuleEnabled( FALSE );
                    break;
                case 1:         // enable
                    pRule->SetRuleEnabled( TRUE );
                    break;
                }

            // set the NT account field of the mapping object
            pRule->SetRuleAccount( T2A ((LPTSTR)(LPCTSTR)mapdlg.m_sz_accountname) );

            // update it in the list control too
            UpdateRuleInDispList( iList, pRule );
            }

        // activate the apply button
        SetModified();
        m_fDirty = TRUE;

        // return true because the user said "OK"
        return TRUE;
        }

    // return FALSE because the user did not say "OK"
    return FALSE;
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::EnableDependantButtons()
    {
    // the whole purpose of this routine is to gray or activate
    // the edit and delete buttons depending on whether or not anything
    // is selected. So start by getting the selection count
    UINT    cItemsSel = m_clistctrl_list.GetSelectedCount();

    // if there is only one item selected, then possibly activate the up/down buttons
    if ( cItemsSel == 1 )
        {
        m_cbutton_up.EnableWindow( TRUE );
        m_cbutton_down.EnableWindow( TRUE );
        }
    else
        {
        m_cbutton_up.EnableWindow( FALSE );
        m_cbutton_down.EnableWindow( FALSE );
        }

    // now the more general case of multiple selections
    if ( cItemsSel > 0 )
        {
        // there are items selected
        m_cbutton_editrule.EnableWindow( TRUE );
        m_cbutton_delete.EnableWindow( TRUE );
        }
    else
        {
        // nope. Nothing selected
        m_cbutton_editrule.EnableWindow( FALSE );
        m_cbutton_delete.EnableWindow( FALSE );
        }

    // always enable the add button
    m_cbutton_add.EnableWindow( TRUE );
    }


/////////////////////////////////////////////////////////////////////////////
// CMapWildcardsPge message handlers

//---------------------------------------------------------------------------
BOOL CMapWildcardsPge::OnApply()
    {
    BOOL                            f;
    CStoreXBF                       xbf;
    METADATA_HANDLE         hm;

    // if no changes have been made, then don't do anything
    if ( !m_fDirty )
        return TRUE;

    UpdateData( TRUE );

    CWaitCursor wait;

    // set the current value of enable into place
    // get the globals object
    CCertGlobalRuleInfo* pGlob = m_mapper.GetGlobalRulesInfo();
    pGlob->SetRulesEnabled( m_bool_enable );

    // serialize the reference to the mapper itself
    f = m_mapper.Serialize( &xbf );

    // before messing with the metabase, prepare the strings we will need
    CString         szBasePath = m_szMBPath;
    CString         szRelativePath = MB_EXTEND_KEY;
    CString         szObjectPath = m_szMBPath + _T('/') + szRelativePath;

    // prepare the metabase wrapper
    CWrapMetaBase   mbWrap;
    f = mbWrap.FInit(m_pMB);

    // attempt to open the object we want to store into
    f = mbWrap.Open( szObjectPath, METADATA_PERMISSION_WRITE );

    // if that did not work, we need to add the object
    if ( !f )
        {
        // need a slash after the namespace extention now
        szBasePath += _T('/');

        // open the base object
        f = mbWrap.Open( szBasePath, METADATA_PERMISSION_WRITE );
        if ( !f )
            {
            AfxMessageBox(IDS_ERR_ACCESS_MAPPING);
            return FALSE;
            }

        // add the object we want
        f = mbWrap.AddObject( szRelativePath );
        if ( !f )
            {
            AfxMessageBox(IDS_ERR_ACCESS_MAPPING);
            mbWrap.Close();
            return FALSE;
            }

        // close the base object
        f = mbWrap.Close();

        // attempt to open the object we want to store into
        f = mbWrap.Open( szObjectPath, METADATA_PERMISSION_WRITE );
        }

    // set the data into place in the object - IF we were ablt to open it
    if ( f )
        mbWrap.SetData( _T(""), MD_SERIAL_CERTW, IIS_MD_UT_SERVER, BINARY_METADATA, xbf.GetBuff(), xbf.GetUsed(), METADATA_SECURE );

    // close the object
    f = mbWrap.Close();

    // save the changes to the metabase
    f = mbWrap.Save();

    // tell the persistence object to tuck away the reference so that we may find it later
    // f = m_persist.FSave( xbf.GetBuff(), xbf.GetUsed() );

    // deactivate the apply button
    SetModified( FALSE );
    m_fDirty = FALSE;

    //  return f;
    return TRUE;
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnMove( int delta )
    {
    int    iList;

    ASSERT( delta != 0 );

    // make sure there is only one item selected
    ASSERT( m_clistctrl_list.GetSelectedCount() == 1 );

    // Get the list index of the item in question.
    // this is also the index into the rule order array
    iList = m_clistctrl_list.GetNextItem( -1, LVNI_SELECTED );

    // get the globals object
    CCertGlobalRuleInfo* pGlob = m_mapper.GetGlobalRulesInfo();

    // get the number of rules (actually its a number of rule order - but they are the same thing)
    int     cbRules = pGlob->GetRuleOrderCount();

    // test against the edge conditions
    if ( ((iList == 0) && (delta < 0)) | ((iList == (cbRules - 1)) && (delta > 0)) )
        return;

    // get the pointer to the order array
    DWORD * pOrder = pGlob->GetRuleOrderArray();

    // calculate the new position in the array
    int iNewPosition = iList + delta;

    // store away the mapper's iIndex (not the position) of the item
    UINT iIndex = pOrder[iList];

    // swap the positions
    DWORD itemp = pOrder[iNewPosition];
    pOrder[iNewPosition] = pOrder[iList];
    pOrder[iList] = itemp;

    ASSERT( pOrder[iNewPosition] == iIndex );

    // unfortunately, we can't just do that with the display list. We have to remove the
    // the item, then re-insert it. Its a flaw in the CListCtrl object. Arg.
    // we have to get the item too
    CCertMapRule* pRule = m_mapper.GetRule( iIndex );

    // delete the item from the display list
    m_clistctrl_list.DeleteItem( iList );

    // re-insert it
    int iNew = AddRuleToList( pRule, iIndex, iNewPosition );

    // make sure it is visible in the list
    m_clistctrl_list.EnsureVisible( iNew, FALSE );

    // finally, because its been removed and re-inserted, we need to
    // re-select it as well - CListCtrl is such a pain at this
    LV_ITEM         lv;
    ZeroMemory( &lv, sizeof(lv) );
    lv.mask = LVIF_STATE;
    lv.iItem = iNew;
    lv.state = LVIS_SELECTED;
    lv.stateMask = LVIS_SELECTED;
    m_clistctrl_list.SetItem( &lv );

    // activate the apply button
    SetModified();
    m_fDirty = TRUE;
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnMoveDown()
    {
    OnMove( 1 );
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnMoveUp()
    {
    OnMove( -1 );
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnAdd()
    {
    CHAR sz[256];

    // create the new rule
    CCertMapRule * pNewRule = new CCertMapRule();

    if (pNewRule == NULL)
        return;

    // give the new rule some defaults
    LoadStringA(::AfxGetInstanceHandle(), IDS_DEFAULT_RULE, sz, 255 );

    pNewRule->SetRuleName( sz );
    pNewRule->SetRuleEnabled( TRUE );

    // Edit the rule. If it fails, remove it from the list
    if ( !EditOneRule( pNewRule, TRUE ) )
        {
        // kill the rule and return
        delete pNewRule;
        return;
        }

    // make a new mapper & get its index
    DWORD iNewRule = m_mapper.AddRule( pNewRule );

    // add the rule to the end of the display list. - It is added to the
    // end of the rule list by default
    AddRuleToList( pNewRule, iNewRule );

    // make sure it is visible in the list
    m_clistctrl_list.EnsureVisible( iNewRule, FALSE );

    // activate the apply button
    SetModified();
    m_fDirty = TRUE;
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnDelete()
    {
    // ask the user to confirm this decision
    if ( AfxMessageBox(IDS_CONFIRM_DELETE, MB_OKCANCEL) != IDOK )
        return;

    CWaitCursor wait;

    // loop through the selected items, setting each one's mapping
    int     iList = -1;
    while( (iList = m_clistctrl_list.GetNextItem( -1, LVNI_SELECTED )) >= 0 )
        {
        // get the mapper index for the item
        // IA64 - this is OK to cast to DWORD as it is just an index
        DWORD iMapper = (DWORD)m_clistctrl_list.GetItemData( iList );

        // delete the mapping from the mapper
        m_mapper.DeleteRule( iMapper );

        // delete the entry from the list box
        m_clistctrl_list.DeleteItem( iList );


        // because the index in the mapper for all the items below this
        // one changes when it is deleted, we must go and fix them all.
        DWORD numItems = m_clistctrl_list.GetItemCount();
        for ( DWORD iFix = iList; iFix < numItems; iFix++ )
            {
            // get the mapper index for the item to be fixed
            // IA64 - this is OK to cast to DWORD as it is just an index
            iMapper = (DWORD)m_clistctrl_list.GetItemData( iFix );

            // decrement it to reflect the change
            iMapper--;

            // put it back.
            m_clistctrl_list.SetItemData( iFix, iMapper );
            }
        }

    // activate the apply button
    SetModified();
    m_fDirty = TRUE;
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnEdit()
    {
    int             iList;
    DWORD           iRule;
    CCertMapRule*   pUpdateRule;

    // what happens here depends on if just one mapping is selected, or many
    switch( m_clistctrl_list.GetSelectedCount() )
        {
        case 0:         // do nothing - should not get here because button grays out
            ASSERT( FALSE );
            break;

        case 1:         // get the mapping for update and run single edit dialog
            // get index of the selected list item
            iList = m_clistctrl_list.GetNextItem( -1, LVNI_SELECTED );
            ASSERT( iList >= 0 );

            // get the mapper index for the item
            // IA64 - this is OK to cast to DWORD as it is just an index
            iRule = (DWORD)m_clistctrl_list.GetItemData( iList );

            // get the mapping item for updating purposes
            pUpdateRule = m_mapper.GetRule( iRule );

            if ( !pUpdateRule )
                {
                AfxMessageBox( IDS_ERR_ACCESS_MAPPING );
                break;
                }

            // edit the mapping, update it if successful, delete if not
            if ( EditOneRule(pUpdateRule) )
                {
                UpdateRuleInDispList( iList, pUpdateRule );
                // activate the apply button
                SetModified();
                m_fDirty = TRUE;
                }
            break;

        default:        // run the multi edit dialog
            EditMultipleRules();
            break;
        }
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnItemchangedList(NMHDR* pNMHDR, LRESULT* pResult)
    {
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    *pResult = 0;

    // enable the correct items
    EnableDependantButtons();
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnDblclkList(NMHDR* pNMHDR, LRESULT* pResult)
    {
    *pResult = 0;

    // if something in the list was double clicked, edit it
    if ( m_clistctrl_list.GetSelectedCount() > 0 )
       OnEdit();
    }

//---------------------------------------------------------------------------
void CMapWildcardsPge::OnEnable()
    {
    // activate the apply button
    SetModified();
    m_fDirty = TRUE;
    }