// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

#include "precomp.h"

// sql queries
enum eWebDirPropertiesQuery { wpqProperties = 1, wpqAccess, wpqAuthorization, wpqUser, wpqControlledPassword, wpqLogVisits, wpqIndex, wpqDefaultDoc,  wpqAspDetailedError, wpqHttpExp, wpqCCMaxAge, wpqCCCustom, wpqNoCustomError, wpqAccessSSLFlags, wpqAuthenticationProviders };

HRESULT ScaGetWebDirProperties(
    __in LPCWSTR wzProperties,
    __in WCA_WRAPQUERY_HANDLE hUserQuery,
    __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
    __inout SCA_WEB_PROPERTIES* pswp
    )
{
    Assert(*wzProperties && pswp);

    HRESULT hr = S_OK;
    MSIHANDLE hRec;
    LPWSTR pwzData = NULL;

    ExitOnNull(wzProperties, hr, E_INVALIDARG, "Failed to get web directory properties because no properties were provided to get");

    WcaFetchWrappedReset(hWebDirPropQuery);

    hr = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec);
    if (S_OK == hr)
    {
        hr = WcaGetRecordString(hRec, wpqProperties, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DirProperties");
        hr = ::StringCchCopyW(pswp->wzKey, countof(pswp->wzKey), pwzData);
        ExitOnFailure(hr, "Failed to copy key string to webdirproperties object");

        Assert(0 == lstrcmpW(pswp->wzKey, wzProperties));

        hr = WcaGetRecordInteger(hRec, wpqAccess, &pswp->iAccess);
        ExitOnFailure(hr, "Failed to get access value");

        hr = WcaGetRecordInteger(hRec, wpqAuthorization, &pswp->iAuthorization);
        ExitOnFailure(hr, "Failed to get authorization value");

        // if allow anonymous users
        if (S_OK == hr && pswp->iAuthorization & 1)
        {
            // if there is an anonymous user specified
            hr = WcaGetRecordString(hRec, wpqUser, &pwzData);
            ExitOnFailure(hr, "Failed to get AnonymousUser_");
            if (pwzData && *pwzData)
            {
                hr = WcaGetRecordInteger(hRec, wpqControlledPassword, &pswp->fIIsControlledPassword);
                ExitOnFailure(hr, "Failed to get IIsControlledPassword");
                if (S_FALSE == hr)
                {
                    pswp->fIIsControlledPassword = FALSE;
                    hr = S_OK;
                }

                hr = ScaGetUserDeferred(pwzData, hUserQuery, &pswp->scau);
                ExitOnFailure(hr, "Failed to get User information for Web");

                pswp->fHasUser = TRUE;
            }
            else
                pswp->fHasUser = FALSE;
        }

        hr = WcaGetRecordInteger(hRec, wpqLogVisits, &pswp->fLogVisits);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.LogVisits");

        hr = WcaGetRecordInteger(hRec, wpqIndex, &pswp->fIndex);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.Index");

        hr = WcaGetRecordString(hRec, wpqDefaultDoc, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.DefaultDoc");
        if (pwzData && *pwzData)
        {
            pswp->fHasDefaultDoc = TRUE;
            if (0 == lstrcmpW(L"-", pwzData))   // remove any existing default documents by setting them blank
            {
                pswp->wzDefaultDoc[0] = L'\0';
            }
            else   // set the default documents
            {
                hr = ::StringCchCopyW(pswp->wzDefaultDoc, countof(pswp->wzDefaultDoc), pwzData);
                ExitOnFailure(hr, "Failed to copy default document string to webdirproperties object");
            }
        }
        else
        {
            pswp->fHasDefaultDoc = FALSE;
        }

        hr = WcaGetRecordInteger(hRec, wpqAspDetailedError, &pswp->fAspDetailedError);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AspDetailedError");

        hr = WcaGetRecordString(hRec, wpqHttpExp, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.HttpExp");
        if (pwzData && *pwzData)
        {
            pswp->fHasHttpExp = TRUE;
            if (0 == lstrcmpW(L"-", pwzData))   // remove any existing default expiration settings by setting them blank
            {
                pswp->wzHttpExp[0] = L'\0';
            }
            else   // set the expiration setting
            {
                hr = ::StringCchCopyW(pswp->wzHttpExp, countof(pswp->wzHttpExp), pwzData);
                ExitOnFailure(hr, "Failed to copy http expiration string to webdirproperties object");
            }
        }
        else
        {
            pswp->fHasHttpExp = FALSE;
        }

        hr = WcaGetRecordInteger(hRec, wpqCCMaxAge, &pswp->iCacheControlMaxAge);
        ExitOnFailure(hr, "failed to get IIsWebDirProperties.CacheControlMaxAge");

        hr = WcaGetRecordString(hRec, wpqCCCustom, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.CacheControlCustom");
        if (pwzData && *pwzData)
        {
            pswp->fHasCacheControlCustom = TRUE;
            if (0 == lstrcmpW(L"-", pwzData))   // remove any existing default cache control custom settings by setting them blank
            {
                pswp->wzCacheControlCustom[0] = L'\0';
            }
            else   // set the custom cache control setting
            {
                hr = ::StringCchCopyW(pswp->wzCacheControlCustom, countof(pswp->wzCacheControlCustom), pwzData);
                ExitOnFailure(hr, "Failed to copy cache control custom settings to webdirproperites object");
            }
        }
        else
        {
            pswp->fHasCacheControlCustom = FALSE;
        }

        hr = WcaGetRecordInteger(hRec, wpqNoCustomError, &pswp->fNoCustomError);
        ExitOnFailure(hr, "failed to get IIsWebDirProperties.NoCustomError");
        if (MSI_NULL_INTEGER == pswp->fNoCustomError)
            pswp->fNoCustomError = FALSE;

        hr = WcaGetRecordInteger(hRec, wpqAccessSSLFlags, &pswp->iAccessSSLFlags);
        ExitOnFailure(hr, "failed to get IIsWebDirProperties.AccessSSLFlags");

        hr = WcaGetRecordString(hRec, wpqAuthenticationProviders, &pwzData);
        ExitOnFailure(hr, "Failed to get IIsWebDirProperties.AuthenticationProviders");
        if (pwzData && *pwzData)
        {
            hr = ::StringCchCopyW(pswp->wzAuthenticationProviders, countof(pswp->wzAuthenticationProviders), pwzData);
            ExitOnFailure(hr, "Failed to copy authentication providers string to webdirproperties object");
        }
        else
        {
            pswp->wzAuthenticationProviders[0] = L'\0';
        }
    }
    else if (E_NOMOREITEMS == hr)
    {
        WcaLog(LOGMSG_STANDARD, "Error: Cannot locate IIsWebDirProperties.DirProperties='%ls'", wzProperties);
        hr = E_FAIL;
    }
    else
    {
        ExitOnFailure(hr, "Error getting appropriate webdirproperty");
    }

    // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would
    HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWebDirPropQuery, 1, wzProperties, &hRec);
    if (SUCCEEDED(hrTemp))
    {
        AssertSz(E_NOMOREITEMS == hrTemp, "ScaGetWebDirProperties found more than one record");
    }

LExit:
    ReleaseStr(pwzData);

    return hr;
}


HRESULT ScaWriteWebDirProperties(
    __in IMSAdminBase* piMetabase,
    __in LPCWSTR wzRootOfWeb,
    __inout SCA_WEB_PROPERTIES* pswp
    )
{
    HRESULT hr = S_OK;
    DWORD dw = 0;
    WCHAR wz[METADATA_MAX_NAME_LEN + 1];

    // write the access permissions to the metabase
    if (MSI_NULL_INTEGER != pswp->iAccess)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccess));
        ExitOnFailure(hr, "Failed to write access permissions for Web");
    }

    if (MSI_NULL_INTEGER != pswp->iAuthorization)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAuthorization));
        ExitOnFailure(hr, "Failed to write authorization for Web");
    }

    if (pswp->fHasUser)
    {
        Assert(pswp->scau.wzName);
        // write the user name
        if (*pswp->scau.wzDomain)
        {
            hr = ::StringCchPrintfW(wz, countof(wz), L"%s\\%s", pswp->scau.wzDomain, pswp->scau.wzName);
            ExitOnFailure(hr, "Failed to format domain\\username string");
        }
        else
        {
            hr = ::StringCchCopyW(wz, countof(wz), pswp->scau.wzName);
            ExitOnFailure(hr, "Failed to copy user name");
        }
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz);
        ExitOnFailure(hr, "Failed to write anonymous user name for Web");

        // write the password
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->scau.wzPassword);
        ExitOnFailure(hr, "Failed to write anonymous user password for Web");

        // store whether IIs controls password
        dw = (pswp->fIIsControlledPassword) ? TRUE : FALSE;
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
        ExitOnFailure(hr, "Failed to write if IIs controls user password for Web");
    }

    if (MSI_NULL_INTEGER != pswp->fLogVisits)
    {
        // The sense of this boolean value is reversed - it is "don't log", not "log visits."
        dw = (pswp->fLogVisits) ? FALSE : TRUE;
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
        ExitOnFailure(hr, "Failed to write authorization for Web");
    }

    if (MSI_NULL_INTEGER != pswp->fIndex)
    {
        dw = (pswp->fIndex) ? TRUE : FALSE;
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
        ExitOnFailure(hr, "Failed to write authorization for Web");
    }

    if (pswp->fHasDefaultDoc)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzDefaultDoc);
        ExitOnFailure(hr, "Failed to write default documents for Web");
    }

    if (MSI_NULL_INTEGER != pswp->fAspDetailedError)
    {
        dw = (pswp->fAspDetailedError) ? TRUE : FALSE;
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, (LPVOID)((DWORD_PTR)dw));
        ExitOnFailure(hr, "Failed to write ASP script error for Web");
    }

    if (pswp->fHasHttpExp)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzHttpExp);
        ExitOnFailure(hr, "Failed to write HTTP Expiration for Web");
    }

    if (MSI_NULL_INTEGER != pswp->iCacheControlMaxAge)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_MAX_AGE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iCacheControlMaxAge));
        ExitOnFailure(hr, "Failed to write Cache Control Max Age for Web");
    }

    if (pswp->fHasCacheControlCustom)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CC_OTHER, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pswp->wzCacheControlCustom);
        ExitOnFailure(hr, "Failed to write Cache Control Custom for Web");
    }

    if (pswp->fNoCustomError)
    {
        memset(wz, 0, sizeof(wz));
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wz);
        ExitOnFailure(hr, "Failed to write Custom Error for Web");
    }

    if (MSI_NULL_INTEGER != pswp->iAccessSSLFlags)
    {
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)pswp->iAccessSSLFlags));
        ExitOnFailure(hr, "Failed to write AccessSSLFlags for Web");
    }

    if (*pswp->wzAuthenticationProviders)
    {
        hr = ::StringCchCopyW(wz, countof(wz), pswp->wzAuthenticationProviders);
        ExitOnFailure(hr, "Failed to copy authentication providers string");
        hr = ScaWriteMetabaseValue(piMetabase, wzRootOfWeb, NULL, MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)wz);
        ExitOnFailure(hr, "Failed to write AuthenticationProviders for Web");
    }

LExit:
    return hr;
}