//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1997.
//
//  File:       S R V R O B J . C P P
//
//  Contents:   Implementation of CSrvrcfg and helper functions.
//
//  Notes:
//
//  Author:     danielwe   5 Mar 1997
//
//----------------------------------------------------------------------------

#include "pch.h"
#pragma hdrstop
#include "srvrobj.h"
#include "ncerror.h"
#include "ncperms.h"
#include "ncreg.h"
#include "ncsetup.h"
#include "ncsvc.h"
#include "afilestr.h"

static const WCHAR c_szRegKeyServerParams[]     = L"System\\CurrentControlSet\\Services\\LanmanServer\\Parameters";
static const WCHAR c_szRegKeyServerShares[]     = L"System\\CurrentControlSet\\Services\\LanmanServer\\Shares";
static const WCHAR c_szRegKeyServerAutoTuned[]  = L"System\\CurrentControlSet\\Services\\LanmanServer\\AutotunedParameters";

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::CSrvrcfg
//
//  Purpose:    Constructs the CSrvrcfg object.
//
//  Arguments:
//      (none)
//
//  Returns:    Nothing.
//
//  Author:     danielwe   5 Mar 1997
//
//  Notes:
//
CSrvrcfg::CSrvrcfg()
:
    m_hkeyMM(NULL),
    m_fDirty(FALSE),
    m_pncc(NULL),
    m_fOneTimeInstall(FALSE),
    m_fRestoredRegistry(FALSE),
    m_fUpgradeFromWks(FALSE),
    m_fUpgrade(FALSE)
{
    ZeroMemory(&m_apspObj, sizeof(m_apspObj));
    ZeroMemory(&m_sdd, sizeof(m_sdd));
}

//
// INetCfgComponentControl
//

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::Initialize
//
//  Purpose:    Called when we are initialized.
//
//  Arguments:
//      pnccItem    [in]    Component we belong to.
//      pnc         [in]    INetCfg master object if we need it.
//      fInstalling [in]    TRUE if we are being installed, FALSE otherwise.
//
//  Returns:    HRESULT, Error code.
//
//  Author:     danielwe   22 Mar 1997
//
//  Notes:
//
STDMETHODIMP CSrvrcfg::Initialize(INetCfgComponent* pnccItem, INetCfg *pnc,
                                  BOOL fInstalling)
{
    Validate_INetCfgNotify_Initialize(pnccItem, pnc, fInstalling);

    m_pncc = pnccItem;
    AddRefObj(m_pncc);
    GetProductFlavor(NULL, &m_pf);

    HRESULT hr = HrOpenRegKeys(pnc);
    if (SUCCEEDED(hr))
    {
        hr = HrGetRegistryInfo(fInstalling);
    }

    Validate_INetCfgNotify_Initialize_Return(hr);

    TraceError("CSrvrcfg::Initialize", hr);
    return hr;
}

STDMETHODIMP CSrvrcfg::Validate()
{
    return S_OK;
}

STDMETHODIMP CSrvrcfg::CancelChanges()
{
    return S_OK;
}

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::Apply
//
//  Purpose:    Called when changes to this component should be applied.
//
//  Arguments:
//      (none)
//
//  Returns:    HRESULT, Error code.
//
//  Author:     danielwe   5 Mar 1997
//
//  Notes:
//
STDMETHODIMP CSrvrcfg::ApplyRegistryChanges()
{
    HRESULT     hr = S_OK;

    static const WCHAR c_szLicenseSvc[] = L"LicenseService";

    if (m_fUpgrade)
    {
        TraceTag(ttidSrvrCfg, "Upgrading MS_SERVER");

        if (!m_fRestoredRegistry)
        {
            TraceTag(ttidSrvrCfg, "Restoring registry");

            hr = HrRestoreRegistry();
            if (FAILED(hr))
            {
                TraceError("CSrvrcfg::ApplyRegistryChanges - HrRestoreRegistry - non-fatal",
                           hr);
                hr = S_OK;
            }
        }
    }

    if (SUCCEEDED(hr))
    {
        if (m_fDirty)
        {
            hr = HrSetRegistryInfo();
        }

        if (SUCCEEDED(hr))
        {
            if (m_fOneTimeInstall)
            {
                hr = HrChangeServiceStartTypeOptional(c_szLicenseSvc,
                                                      SERVICE_AUTO_START);
                if (SUCCEEDED(hr))
                {
                    hr = S_OK;

                    m_fDirty = FALSE;
                    m_fOneTimeInstall = FALSE;
                }
            }
        }
    }

    Validate_INetCfgNotify_Apply_Return(hr);

    TraceError("CSrvrcfg::ApplyRegistryChanges",
        (hr == S_FALSE) ? S_OK : hr);
    return hr;
}

//
// INetCfgComponentSetup
//

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::Install
//
//  Purpose:    Called when this component is being installed
//
//  Arguments:
//      dwSetupFlags [in]   Flags that describe the type of setup
//
//  Returns:    HRESULT, Error code.
//
//  Author:     danielwe   5 Mar 1997
//
//  Notes:
//
STDMETHODIMP CSrvrcfg::Install(DWORD dwSetupFlags)
{
    m_fDirty = TRUE;
    m_fOneTimeInstall = TRUE;

    if (dwSetupFlags & NSF_WINNT_WKS_UPGRADE)
    {
        m_fUpgrade = TRUE;
        m_fUpgradeFromWks = TRUE;
    }
    else if ((dwSetupFlags & NSF_WINNT_SVR_UPGRADE) ||
             (dwSetupFlags & NSF_WINNT_SBS_UPGRADE))
    {
        m_fUpgrade = TRUE;
    }

    return S_OK;
}

STDMETHODIMP CSrvrcfg::Upgrade(DWORD dwSetupFlags,
                               DWORD dwUpgradeFomBuildNo)
{
    return S_FALSE;
}

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::ReadAnswerFile
//
//  Purpose:    Reads the appropriate fields from the given answer file into
//              our in-memory state.
//
//  Arguments:
//      pszAnswerFile     [in] File name of answer file
//      pszAnswerSection [in] Section of answer file to look in
//
//  Returns:    S_OK if successful, OLE or Win32 error otherwise
//
//  Author:     danielwe   30 Oct 1997
//
//  Notes:
//
STDMETHODIMP CSrvrcfg::ReadAnswerFile(PCWSTR pszAnswerFile,
                                      PCWSTR pszAnswerSection)
{
    HRESULT     hr = S_OK;

    if (pszAnswerSection && pszAnswerFile)
    {
        // There's an answer file. We must process it now.
        hr = HrProcessAnswerFile(pszAnswerFile, pszAnswerSection);
        if (FAILED(hr))
        {
            TraceError("CSrvrcfg::ReadAnswerFile- Answer file has "
                       "errors. Defaulting all information as if "
                       "answer file did not exist.",
                       NETSETUP_E_ANS_FILE_ERROR);
            hr = S_OK;
        }
    }

    TraceError("CSrvrcfg::ReadAnswerFile", hr);
    return hr;
}

STDMETHODIMP CSrvrcfg::Removing()
{
    return S_OK;
}

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::HrRestoreRegistry
//
//  Purpose:    Restores the contents of the registry for this component
//
//  Arguments:
//      (none)
//
//  Returns:    Win32 error if failed, otherwise S_OK
//
//  Author:     danielwe   8 Aug 1997
//
//  Notes:
//
HRESULT CSrvrcfg::HrRestoreRegistry()
{
    HRESULT             hr = S_OK;
    HKEY                hkey;
    TOKEN_PRIVILEGES *  ptpRestore = NULL;
    BOOL                fRestoreSucceeded = FALSE;

    if (!m_strParamsRestoreFile.empty() ||
        !m_strSharesRestoreFile.empty() ||
        !m_strAutoTunedRestoreFile.empty())
    {
        hr = HrEnableAllPrivileges(&ptpRestore);
        if (SUCCEEDED(hr))
        {
            if (!m_strParamsRestoreFile.empty())
            {
                hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyServerParams,
                                      KEY_ALL_ACCESS, &hkey);
                if (SUCCEEDED(hr))
                {
                    hr = HrRegRestoreKey(hkey, m_strParamsRestoreFile.c_str(),
                                         0);
                    if (FAILED(hr))
                    {
                        TraceError("CSrvrcfg::HrRestoreRegistry - HrRestoreRegistry for "
                                   "Parameters", hr);
                        hr = S_OK;
                    }
                    else
                    {
                        fRestoreSucceeded = TRUE;
                    }

                    RegCloseKey(hkey);
                }
            }

            if (fRestoreSucceeded)
            {
                // if the restore succeeded, rewrite the values that were blown
                // away by the restore

                static const WCHAR c_szSvcDLLName[]     = L"%SystemRoot%\\System32\\srvsvc.dll";
                static const WCHAR c_szServiceDll[]     = L"ServiceDll";

                HKEY hkResult = NULL;
                hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyServerParams, KEY_ALL_ACCESS, &hkResult);
                if SUCCEEDED(hr)
                {
                    hr = HrRegSetValueEx(hkResult, c_szServiceDll, REG_EXPAND_SZ, (const BYTE *)c_szSvcDLLName, CbOfMultiSzAndTermSafe(c_szSvcDLLName));
                    RegSafeCloseKey(hkResult);
                }

                if FAILED(hr)
                {
                    TraceError("CSrvrcfg::HrRestoreRegistry - HrRestoreRegistry for "
                            "ServiceDll", hr);
                    hr = S_OK;
                }

                static const WCHAR c_szTrkWks[]         = L"TrkWks";
                static const WCHAR c_szTrkSrv[]         = L"TrkSrv";
                static const WCHAR c_szNullSession[]    = L"NullSessionPipes";

                hr = HrRegAddStringToMultiSz(c_szTrkWks,
                                             HKEY_LOCAL_MACHINE,
                                             c_szRegKeyServerParams,
                                             c_szNullSession,
                                             STRING_FLAG_ENSURE_AT_END,
                                             0);
                if (SUCCEEDED(hr))
                {
                    hr = HrRegAddStringToMultiSz(c_szTrkSrv,
                                                 HKEY_LOCAL_MACHINE,
                                                 c_szRegKeyServerParams,
                                                 c_szNullSession,
                                                 STRING_FLAG_ENSURE_AT_END,
                                                 0);
                }

                if (FAILED(hr))
                {
                    TraceError("CSrvrcfg::HrRestoreRegistry - Error replacing "
                               "values for Parameters", hr);
                    hr = S_OK;
                }
            }

            if (!m_strSharesRestoreFile.empty())
            {
                hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyServerShares,
                                    KEY_ALL_ACCESS, &hkey);
                if (SUCCEEDED(hr))
                {
                    hr = HrRegRestoreKey(hkey, m_strSharesRestoreFile.c_str(),
                                         0);
                    if (FAILED(hr))
                    {
                        TraceError("CSrvrcfg::HrRestoreRegistry - HrRestoreRegistry for "
                                   "Shares", hr);
                        hr = S_OK;
                    }

                    RegCloseKey(hkey);
                }
            }

            if (!m_strAutoTunedRestoreFile.empty())
            {
                hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyServerAutoTuned,
                                    KEY_ALL_ACCESS, &hkey);
                if (SUCCEEDED(hr))
                {
                    hr = HrRegRestoreKey(hkey, m_strAutoTunedRestoreFile.c_str(),
                                         0);
                    if (FAILED(hr))
                    {
                        TraceError("CSrvrcfg::HrRestoreRegistry - HrRestoreRegistry for "
                                   "AutotunedParameters", hr);
                        hr = S_OK;
                    }

                    RegCloseKey(hkey);
                }
            }

            hr = HrRestorePrivileges(ptpRestore);

            delete [] reinterpret_cast<BYTE *>(ptpRestore);

            // Set a flag so we don't do this again if we are applied again
            m_fRestoredRegistry = TRUE;
        }
    }
    else
    {
        TraceTag(ttidSrvrCfg, "WARNING: HrRestoreRegistry() was called without"
                 " ReadAnswerFile() being called!");
    }

    TraceError("CSrvrcfg::HrRestoreRegistry", hr);
    return hr;
}

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::HrProcessAnswerFile
//
//  Purpose:    Handles necessary processing of contents of the answer file.
//
//  Arguments:
//      pszAnswerFile       [in]   Filename of answer file for upgrade.
//      pszAnswerSection   [in]   Comma-separated list of sections in the
//                                  file appropriate to this component.
//
//  Returns:    S_OK if successful, setup API error otherwise.
//
//  Author:     danielwe   8 May 1997
//
//  Notes:
//
HRESULT CSrvrcfg::HrProcessAnswerFile(PCWSTR pszAnswerFile,
                                      PCWSTR pszAnswerSection)
{
    HRESULT         hr = S_OK;
    tstring         strOpt;
    PCWSTR         szOptDefault;
    CSetupInfFile   csif;

    if (m_pf == PF_SERVER)
    {
        szOptDefault = c_szAfMaxthroughputforfilesharing;
    }
    else
    {
        szOptDefault = c_szAfMinmemoryused;
    }

    // Open the answer file.
    hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
    if (FAILED(hr))
    {
        hr = S_OK;
        goto err;
    }

    if (m_fUpgrade)
    {
        // Restore portions of the registry based on file names from the answer
        // file

        // Get restore file for "Parameters" key
        hr = csif.HrGetString(pszAnswerSection, c_szAfLmServerParameters,
                              &m_strParamsRestoreFile);
        if (FAILED(hr))
        {
            TraceError("CSrvrcfg::HrProcessAnswerFile - Error restoring "
                       "Parameters key", hr);

            // oh well, just continue
            hr = S_OK;
        }

        // Get restore file for "Shares" key
        hr = csif.HrGetString(pszAnswerSection, c_szAfLmServerShares,
                              &m_strSharesRestoreFile);
        if (FAILED(hr))
        {
            TraceError("CSrvrcfg::HrProcessAnswerFile - Error restoring "
                       "Shares key", hr);

            // oh well, just continue
            hr = S_OK;
        }

        // Get restore file for "AutotunedParameters" key
        hr = csif.HrGetString(pszAnswerSection,
                              c_szAfLmServerAutotunedParameters,
                              &m_strAutoTunedRestoreFile);
        if (FAILED(hr))
        {
            TraceError("CSrvrcfg::HrProcessAnswerFile - Error restoring "
                       "AutotunedParameters key", hr);

            // oh well, just continue
            hr = S_OK;
        }
    }

    // Read contents Opimitzation key
    hr = csif.HrGetString(pszAnswerSection, c_szAfLmServerOptimization,
                          &strOpt);
    if (SUCCEEDED(hr))
    {
		m_fDirty = TRUE;

        if (!lstrcmpiW(strOpt.c_str(), c_szAfMinmemoryused))
        {
            m_sdd.dwSize = 1;
        }
        else if (!lstrcmpiW(strOpt.c_str(), c_szAfBalance))
        {
            m_sdd.dwSize = 2;
        }
        else if (!lstrcmpiW(strOpt.c_str(), c_szAfMaxthroughputforfilesharing))
        {
            m_sdd.dwSize = 3;
            m_sdd.fLargeCache = TRUE;
        }
        else if (!lstrcmpiW(strOpt.c_str(), c_szAfMaxthrouputfornetworkapps))
        {
            m_sdd.dwSize = 3;
            m_sdd.fLargeCache = FALSE;
        }
#ifdef DBG
        else
        {
            // NOTE: Default values for dwSize and fLargeCache will have been set
            // already by registry reading function.

            TraceTag(ttidSrvrCfg, "Unknown Optimization value '%S'. Using default "
                     "'%S'.", strOpt.c_str(), szOptDefault);
        }
#endif
    }

    // Read contents of BroadcastsToLanman2Clients key.
    hr = csif.HrGetStringAsBool(pszAnswerSection, c_szAfBroadcastToClients,
                                &m_sdd.fAnnounce);
    if (FAILED(hr))
    {
        TraceError("CSrvrcfg::HrProcessAnswerFile - Error restoring "
                   "BroadcastsToLanman2Clients key. Using default value"
                   " of FALSE.", hr);

        // oh well, just continue
        hr = S_OK;
    }

err:
    TraceError("CSrvrcfg::HrProcessAnswerFile", hr);
    return hr;
}

//
// INetCfgProperties
//

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::MergePropPages
//
//  Purpose:    Called when this component's properties are about to be
//              brought up.
//
//  Arguments:
//      pdwDefPages   [out] Number of default pages to show.
//      pahpspPrivate [out] Array of property sheet handles to pages that this
//                          component will show.
//      pcPrivate     [out] Number of pages in array.
//      hwndParent    [in]  Parent window for any UI.
//      pszStartPage  [out] Pointer to start page.
//
//  Returns:    HRESULT, Error code.
//
//  Author:     danielwe   22 Feb 1997
//
//  Notes:
//
STDMETHODIMP CSrvrcfg::MergePropPages(DWORD *pdwDefPages,
                                      LPBYTE *pahpspPrivate,
                                      UINT *pcPrivate, HWND hwndParent,
                                      PCWSTR *pszStartPage)
{
    HRESULT         hr = S_OK;
    HPROPSHEETPAGE *ahpsp = NULL;

    Validate_INetCfgProperties_MergePropPages(pdwDefPages, pahpspPrivate,
                                              pcPrivate, hwndParent,
                                              pszStartPage);

    // We don't want any default pages to be shown
    *pdwDefPages = 0;

    if (m_pf == PF_WORKSTATION)
    {
        // On workstation product, UI is not shown.
        *pcPrivate = 0;
    }
    else
    {
        hr = HrSetupPropSheets(&ahpsp, c_cPages);
        if (SUCCEEDED(hr))
        {
            *pahpspPrivate = (LPBYTE)ahpsp;
            *pcPrivate = c_cPages;
        }
    }

    Validate_INetCfgProperties_MergePropPages_Return(hr);

    TraceError("CSrvrcfg::MergePropPages", hr);
    return hr;
}

STDMETHODIMP CSrvrcfg::ValidateProperties(HWND hwndSheet)
{
    return S_OK;
}

STDMETHODIMP CSrvrcfg::CancelProperties()
{
    return S_OK;
}

STDMETHODIMP CSrvrcfg::ApplyProperties()
{
    return S_OK;
}

//+---------------------------------------------------------------------------
//
//  Member:     CSrvrcfg::~CSrvrcfg
//
//  Purpose:    Destroys the CSrvrcfg object.
//
//  Arguments:
//      (none)
//
//  Returns:    Nothing.
//
//  Author:     danielwe   5 Mar 1997
//
//  Notes:
//
CSrvrcfg::~CSrvrcfg()
{
    ReleaseObj(m_pncc);

    RegSafeCloseKey(m_hkeyMM);

    CleanupPropPages();

#ifdef DBG
    {
        INT     ipage;

        for (ipage = 0; ipage < c_cPages; ipage++)
        {
            AssertSz(!m_apspObj[ipage], "Prop page object should be NULL!");
        }
    }
#endif

}