//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1997 - 1999
//
//  File:       chooser.cpp
//
//--------------------------------------------------------------------------

/////////////////////////////////////////////////////////////////////
//	Chooser.cpp
//
//	Dialog to choose a machine name.
//
//	PURPOSE
//	What you have to do is to copy all the files from the
//	snapin\chooser\ directory into your project (you may add
//	\nt\private\admin\snapin\chooser\ to your include directory if
//	you prefer not copying the code).
//	If you decide to copy the code to your project, please send mail
//	to Dan Morin (T-DanM) and cc to Jon Newman (JonN) so we can
//	mail you when we have updates available.  The next update will
//	be the "Browse" button to select a machine name.
//
//
//  DYNALOADED LIBRARIES
//
//	HISTORY
//	13-May-1997		t-danm		Creation.
//	23-May-1997		t-danm		Checkin into public tree. Comments updates.
//	25-May-1997		t-danm		Added MMCPropPageCallback().
//      31-Oct-1997             mattt           Added dynaload, fixed user <CANCEL> logic
//       1-Oct-1998             mattt           Removed reliance on MFC, changed default look to enable certsvr picker
//
/////////////////////////////////////////////////////////////////////

#include <stdafx.h>

#include "chooser.h"
#include "csdisp.h" // certsrv picker

#define __dwFILE__	__dwFILE_CERTMMC_CHOOSER_CPP__


#ifdef _DEBUG
#undef THIS_FILE
#define THIS_FILE __FILE__
#endif

#ifndef INOUT		
// The following defines are found in \nt\private\admin\snapin\filemgmt\stdafx.h

#define INOUT
#define	Endorse(f)		// Dummy macro
#define LENGTH(x)		(sizeof(x)/sizeof(x[0]))
#define Assert(f)		ASSERT(f)
#endif

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Replacement for BEGIN_MESSAGE_MAP
BOOL
CAutoDeletePropPage::OnCommand(
    WPARAM, // wParam
    LPARAM /* lParam */ )
{
/*
    switch(LOWORD(wParam))
    {
    }
*/
    return FALSE;
}

/////////////////////////////////////////////////////////////////////
//	Constructor
CAutoDeletePropPage::CAutoDeletePropPage(UINT uIDD) : PropertyPage(uIDD)
{
    m_prgzHelpIDs = NULL;
    m_autodeleteStuff.cWizPages = 1; // Number of pages in wizard
    m_autodeleteStuff.pfnOriginalPropSheetPageProc = m_psp.pfnCallback;

    m_psp.dwFlags |= PSP_USECALLBACK;
    m_psp.pfnCallback = S_PropSheetPageProc;
    m_psp.lParam = reinterpret_cast<LPARAM>(this);
}

CAutoDeletePropPage::~CAutoDeletePropPage()
{
}


/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::SetCaption(LPCTSTR pszCaption)
{
    m_strCaption = pszCaption;		// Copy the caption
    m_psp.pszTitle = m_strCaption;	// Set the title
    m_psp.dwFlags |= PSP_USETITLE;
}

/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::SetCaption(UINT uStringID)
{
    VERIFY(m_strCaption.LoadString(uStringID));
    SetCaption(m_strCaption);
}

/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::SetHelp(LPCTSTR szHelpFile, const DWORD rgzHelpIDs[])
{
    m_strHelpFile = szHelpFile;
    m_prgzHelpIDs = rgzHelpIDs;
}

/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::EnableDlgItem(INT nIdDlgItem, BOOL fEnable)
{
    Assert(IsWindow(::GetDlgItem(m_hWnd, nIdDlgItem)));
    ::EnableWindow(::GetDlgItem(m_hWnd, nIdDlgItem), fEnable);
}

/////////////////////////////////////////////////////////////////////
BOOL CAutoDeletePropPage::OnSetActive()
{
    HWND hwndParent = ::GetParent(m_hWnd);
    Assert(IsWindow(hwndParent));
    ::PropSheet_SetWizButtons(hwndParent, PSWIZB_FINISH);
    return PropertyPage::OnSetActive();
}

/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::OnHelp(LPHELPINFO pHelpInfo)
{
    if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
        return;
    if (pHelpInfo != NULL && 
        pHelpInfo->iContextType == HELPINFO_WINDOW &&
        HasContextHelp(pHelpInfo->iCtrlId))
    {
        // Display context help for a control
        ::WinHelp((HWND)pHelpInfo->hItemHandle, m_strHelpFile,
            HELP_WM_HELP, (ULONG_PTR)(LPVOID)m_prgzHelpIDs);
    }
    return;
}

/////////////////////////////////////////////////////////////////////
void CAutoDeletePropPage::OnContextHelp(HWND hwnd)
{
    if (m_prgzHelpIDs == NULL || m_strHelpFile.IsEmpty())
        return;
    Assert(IsWindow(hwnd));

    if(HasContextHelp(GetDlgCtrlID(hwnd)))
    {
        ::WinHelp(
            hwnd, 
            m_strHelpFile, 
            HELP_CONTEXTMENU, 
            (ULONG_PTR)(LPVOID)m_prgzHelpIDs);
    }
    return;
}

/////////////////////////////////////////////////////////////////////
bool CAutoDeletePropPage::HasContextHelp(int nDlgItem)
{
    const DWORD * pdwHelpIDs;

    for(pdwHelpIDs = m_prgzHelpIDs; 
        *pdwHelpIDs; 
        pdwHelpIDs += 2)
    {
        if(nDlgItem == (int) *pdwHelpIDs)
            return true;
    }
    return false;
}


/////////////////////////////////////////////////////////////////////
//	S_PropSheetPageProc()
//
//	Static member function used to delete the CAutoDeletePropPage object
//	when wizard terminates
//

UINT CALLBACK
CAutoDeletePropPage::S_PropSheetPageProc(
    HWND hwnd,	
    UINT uMsg,	
    LPPROPSHEETPAGE ppsp)
{
    Assert(ppsp != NULL);
    CAutoDeletePropPage * pThis;
    pThis = reinterpret_cast<CAutoDeletePropPage*>(ppsp->lParam);
    Assert(pThis != NULL);

    BOOL fDefaultRet;

    fDefaultRet = FALSE;
    switch (uMsg)
    {
    case PSPCB_RELEASE:

        if (--(pThis->m_autodeleteStuff.cWizPages) <= 0)
        {
            // Remember callback on stack since "this" will be deleted
            LPFNPSPCALLBACK pfnOrig = pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc;
            delete pThis;

            if (pfnOrig)
                return (pfnOrig)(hwnd, uMsg, ppsp);
            else
                return fDefaultRet;
        }
        break;
    case PSPCB_CREATE:
        fDefaultRet = TRUE;
        // do not increase refcount, PSPCB_CREATE may or may not be called
        // depending on whether the page was created.  PSPCB_RELEASE can be
        // depended upon to be called exactly once per page however.
        break;

    } // switch

    if (pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc)
        return (pThis->m_autodeleteStuff.pfnOriginalPropSheetPageProc)(hwnd, uMsg, ppsp);
    else
        return fDefaultRet;
} // CAutoDeletePropPage::S_PropSheetPageProc()





/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Replacement for BEGIN_MESSAGE_MAP
BOOL
CChooseMachinePropPage::OnCommand(
    WPARAM wParam,
    LPARAM /* lParam */ )
{
    switch(LOWORD(wParam))
    {
    case IDC_CHOOSER_RADIO_LOCAL_MACHINE:
        OnRadioLocalMachine();
        break;
    case IDC_CHOOSER_RADIO_SPECIFIC_MACHINE:
        OnRadioSpecificMachine();
        break;
    case IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES:
        OnBrowse();
        break;
    default:
        return FALSE;
        break;
    }
    return TRUE;
}


#ifdef _DEBUG
static void AssertValidDialogTemplate(HWND hwnd)
{
    ASSERT(::IsWindow(hwnd));
    // Mandatory controls for a valid dialog template
    static const UINT rgzidDialogControl[] =
    {
        IDC_CHOOSER_RADIO_LOCAL_MACHINE,
            IDC_CHOOSER_RADIO_SPECIFIC_MACHINE,
            IDC_CHOOSER_EDIT_MACHINE_NAME,
            0
    };

    for (int i = 0; rgzidDialogControl[i] != 0; i++)
    {
        ASSERT(NULL != GetDlgItem(hwnd, rgzidDialogControl[i]) &&
            "Control ID not found in dialog template.");
    }
} // AssertValidDialogTemplate()
#else
#define AssertValidDialogTemplate(hwnd)
#endif	// ~_DEBUG

/////////////////////////////////////////////////////////////////////
//	Constructor
CChooseMachinePropPage::CChooseMachinePropPage(UINT uIDD) : CAutoDeletePropPage(uIDD)
{
    m_fIsRadioLocalMachine = TRUE;
    m_fEnableMachineBrowse = FALSE;

    m_pstrMachineNameOut = NULL;
    m_pstrMachineNameEffectiveOut = NULL;
    m_pdwFlags = NULL;
}

/////////////////////////////////////////////////////////////////////
CChooseMachinePropPage::~CChooseMachinePropPage()
{
}

/////////////////////////////////////////////////////////////////////
//	Load the initial state of CChooseMachinePropPage
void CChooseMachinePropPage::InitMachineName(LPCTSTR pszMachineName)
{
    m_strMachineName = pszMachineName;
    m_fIsRadioLocalMachine = m_strMachineName.IsEmpty();
}

/////////////////////////////////////////////////////////////////////
//	SetOutputBuffers()
//
//	- Set the pointer to the CString object to store the machine name.
//	- Set the pointer to the boolean flag for command line override.
//	- Set the pointer pointer to store the overriden machine name.
//
void CChooseMachinePropPage::SetOutputBuffers(
                                              OUT CString * pstrMachineNamePersist,	// Machine name the user typed.  Empty string == local machine.
                                              OUT CString * pstrMachineNameEffective,
                                              OUT DWORD*    pdwFlags)
{
    Assert(pstrMachineNamePersist != NULL && "Invalid output buffer");

    // point members at params
    m_pstrMachineNameOut = pstrMachineNamePersist;
    m_pstrMachineNameEffectiveOut = pstrMachineNameEffective;
    m_pdwFlags = pdwFlags;
    *m_pdwFlags = 0;
}

/////////////////////////////////////////////////////////////////////
// Replacement for DoDataExchange
BOOL CChooseMachinePropPage::UpdateData(BOOL fSuckFromDlg /*= TRUE*/)
{
    if (fSuckFromDlg)
    {
        m_strMachineName.FromWindow(GetDlgItem(m_hWnd, IDC_CHOOSER_EDIT_MACHINE_NAME));

        int iCheck = (int)SendMessage(GetDlgItem(m_hWnd, IDC_CHOOSER_MACHINE_OVERRIDE), BM_GETCHECK, 0, 0);
        if (iCheck == BST_CHECKED)
            *m_pdwFlags |= CCOMPDATAIMPL_FLAGS_ALLOW_MACHINE_OVERRIDE;
        else
            *m_pdwFlags &= ~CCOMPDATAIMPL_FLAGS_ALLOW_MACHINE_OVERRIDE;
    }
    else
    {
        m_strMachineName.ToWindow(GetDlgItem(m_hWnd, IDC_CHOOSER_EDIT_MACHINE_NAME));

        int iCheck;
        iCheck = (*m_pdwFlags & CCOMPDATAIMPL_FLAGS_ALLOW_MACHINE_OVERRIDE) ? BST_CHECKED : BST_UNCHECKED;
        SendMessage(GetDlgItem(m_hWnd, IDC_CHOOSER_MACHINE_OVERRIDE), BM_SETCHECK, iCheck, 0);
    }
    return TRUE;
}

/////////////////////////////////////////////////////////////////////
BOOL CChooseMachinePropPage::OnInitDialog()
{
    AssertValidDialogTemplate(m_hWnd);
    CAutoDeletePropPage::OnInitDialog();
    InitChooserControls();

    PropSheet_SetWizButtons(GetParent(), PSWIZB_FINISH);

    return TRUE;
}

/////////////////////////////////////////////////////////////////////
BOOL CChooseMachinePropPage::OnWizardFinish()
{
    if (!UpdateData())		// Do the data exchange to collect data
        return FALSE;       // don't destroy on error

    if (m_fIsRadioLocalMachine)
        m_strMachineName.Empty();
    else
        if (m_strMachineName.IsEmpty())
        {
            DisplayCertSrvErrorWithContext(m_hWnd, S_OK, IDS_MUST_CHOOSE_MACHINE);
            return FALSE;
        }

    if (m_pstrMachineNameOut != NULL)
    {
        // Store the machine name into its output buffer
        *m_pstrMachineNameOut = m_strMachineName;
        if (m_pstrMachineNameEffectiveOut != NULL)
        {
            *m_pstrMachineNameEffectiveOut = m_strMachineName;
        } // if
    }
    else
        Assert(FALSE && "FYI: You have not specified any output buffer to store the machine name.");

    return CAutoDeletePropPage::OnWizardFinish();
}

void CChooseMachinePropPage::InitChooserControls()
{
    SendDlgItemMessage(IDC_CHOOSER_RADIO_LOCAL_MACHINE, BM_SETCHECK, m_fIsRadioLocalMachine);
    SendDlgItemMessage(IDC_CHOOSER_RADIO_SPECIFIC_MACHINE, BM_SETCHECK, !m_fIsRadioLocalMachine);
    EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, !m_fIsRadioLocalMachine);

    PCCRYPTUI_CA_CONTEXT  pCAContext = NULL;
    DWORD dwCACount;
    HRESULT hr = myGetConfigFromPicker(
              m_hWnd,
              NULL, //sub title
              NULL, //title
              NULL,
	      GCFPF_USEDS,
              TRUE, // count only
              &dwCACount,
              &pCAContext);
    if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
    {
        _PrintError(hr, "myGetConfigFromPicker");
        goto done;
    }
    m_fEnableMachineBrowse = (0 == dwCACount) ? FALSE : TRUE;
    if (NULL != pCAContext)
    {
        CryptUIDlgFreeCAContext(pCAContext);
    }

done:
    EnableDlgItem(IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES,
                  !m_fIsRadioLocalMachine && m_fEnableMachineBrowse);
}

void CChooseMachinePropPage::OnRadioLocalMachine()
{
    m_fIsRadioLocalMachine = TRUE;
    EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, FALSE);
    EnableDlgItem(IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, FALSE);
}

void CChooseMachinePropPage::OnRadioSpecificMachine()
{
    m_fIsRadioLocalMachine = FALSE;
    EnableDlgItem(IDC_CHOOSER_EDIT_MACHINE_NAME, TRUE);
    EnableDlgItem(IDC_CHOOSER_BUTTON_BROWSE_MACHINENAMES, m_fEnableMachineBrowse);
}

void CChooseMachinePropPage::OnBrowse()
{
    HRESULT hr;
    WCHAR *szConfig = NULL;
    CWaitCursor cwait;

    // UNDONE: expand config picker to non-published (DS chooser dlg)
    hr = myGetConfigStringFromPicker(m_hWnd,
        NULL, //use default prompt
        NULL, //use default title
        NULL, //use default shared folder
        GCFPF_USEDS,
        &szConfig);
    if (hr == S_OK)
    {
        LPWSTR szWhack = wcschr(szConfig, L'\\');
        if (szWhack != NULL)
            szWhack[0] = L'\0';
        m_strMachineName = szConfig;

        LocalFree(szConfig);
    }

    // push result back to ui
    UpdateData(FALSE);
}