#ifndef _W3METADATA_HXX_
#define _W3METADATA_HXX_

#include "customerror.hxx"
#include "usercache.hxx"

// forward declaration
class W3_CONTEXT;

enum GATEWAY_TYPE
{
    GATEWAY_UNKNOWN,
    GATEWAY_STATIC_FILE,
    GATEWAY_CGI,
    GATEWAY_ISAPI,
    GATEWAY_MAP
};

class META_SCRIPT_MAP_ENTRY
{
    //
    // CODEWORK
    // 1. Add missing members and accsessors
    // 2. Handle initialization errors
    //

    friend class META_SCRIPT_MAP;

public:

    META_SCRIPT_MAP_ENTRY()
      : m_fIsStarScriptMapEntry (FALSE)
    {
        InitializeListHead( &m_ListEntry );
    }

    ~META_SCRIPT_MAP_ENTRY()
    {
    }

    // actual ctor
    HRESULT
    Create(
        IN const WCHAR * szExtension,
        IN const WCHAR * szExecutable,
        IN DWORD         Flags,
        IN const WCHAR * szVerbs,
        IN DWORD         cbVerbs
        );

    BOOL
    IsVerbAllowed(
        IN const STRA & strVerb
        )
    {
        return m_Verbs.IsEmpty() || m_Verbs.FindString( strVerb.QueryStr() );
    }

    STRU *
    QueryExecutable()
    {
        return &m_strExecutable;
    }

    GATEWAY_TYPE
    QueryGateway()
    {
        return m_Gateway;
    }

    BOOL
    QueryIsStarScriptMap()
    {
        return m_fIsStarScriptMapEntry;
    }

    MULTISZA *
    QueryAllowedVerbs()
    {
        return &m_Verbs;
    }    
    
    BOOL
    QueryCheckPathInfoExists()
    {
        return !!( m_Flags & MD_SCRIPTMAPFLAG_CHECK_PATH_INFO );
    }
    
    BOOL
    QueryAllowScriptAccess()
    {
        return !!( m_Flags & MD_SCRIPTMAPFLAG_SCRIPT );
    }

private:
    //
    // Avoid c++ errors
    //
    META_SCRIPT_MAP_ENTRY( const META_SCRIPT_MAP_ENTRY & ) 
    {}
    META_SCRIPT_MAP_ENTRY & operator = ( const META_SCRIPT_MAP_ENTRY & ) 
    { return *this; }


    //
    // Data Members
    //
    
    //
    // META_SCRIPT_MAP maintains a list of us
    //
    LIST_ENTRY      m_ListEntry;

    //
    // Data from the script map stored in the metabase
    //
    STRU            m_strExtension;
    STRU            m_strExecutable;
    DWORD           m_Flags;
    MULTISZA        m_Verbs;
    GATEWAY_TYPE    m_Gateway;
    BOOL            m_fIsStarScriptMapEntry;
};


class META_SCRIPT_MAP
{
public:

    META_SCRIPT_MAP()
    {
        InitializeListHead( &m_ListHead );
        InitializeListHead( &m_StarScriptMapListHead );
    }

    ~META_SCRIPT_MAP()
    {
        Terminate();
    }

    HRESULT
    Initialize( 
        IN WCHAR * szScriptMapData
        );

    VOID
    Terminate( VOID );

    BOOL
    FindEntry(
        IN  const STRU &              strExtension,
        OUT META_SCRIPT_MAP_ENTRY * * ppScriptMapEntry
        );

    META_SCRIPT_MAP_ENTRY *
    QueryStarScriptMap(DWORD index)
    {
        LIST_ENTRY *pEntry = m_StarScriptMapListHead.Flink;
        DWORD       i      = 0;

        while (pEntry != &m_StarScriptMapListHead)
        {
            if (i == index)
            {
                return CONTAINING_RECORD(pEntry,
                                         META_SCRIPT_MAP_ENTRY,
                                         m_ListEntry);
            }

            i++;
            pEntry = pEntry->Flink;
        }

        return NULL;
    }

private:
    //
    // Avoid c++ errors
    //
    META_SCRIPT_MAP( const META_SCRIPT_MAP & ) 
    {}
    META_SCRIPT_MAP & operator = ( const META_SCRIPT_MAP & ) 
    { return *this; }

private:

    //
    // List of META_SCRIPT_MAP_ENTRY
    //
    LIST_ENTRY             m_ListHead;

    //
    // List of *-ScriptMap entries
    //
    LIST_ENTRY             m_StarScriptMapListHead;
};

class REDIRECTION_BLOB;

#define EXPIRE_MODE_NONE                0
#define EXPIRE_MODE_STATIC              1
#define EXPIRE_MODE_DYNAMIC             2
#define EXPIRE_MODE_OFF                 3

//
// This is the maximum we allow the global expires value to be set to.
// This is 1 year in seconds
//
#define MAX_GLOBAL_EXPIRE                   0x1e13380

#define W3MD_CREATE_PROCESS_AS_USER         0x00000001
#define W3MD_CREATE_PROCESS_NEW_CONSOLE     0x00000002

#define DEFAULT_SCRIPT_TIMEOUT              (15 * 60)

#define DEFAULT_ENTITY_READ_AHEAD           (48 * 1024)
#define DEFAULT_MAX_REQUEST_ENTITY_ALLOWED  0xffffffff


//
// W3_METADATA elements are stored in the metadata cache
//

class W3_METADATA_KEY : public CACHE_KEY
{
public:
    
    W3_METADATA_KEY()
    {
        _dwDataSetNumber = 0;
    }
    
    VOID
    SetDataSetNumber(
        DWORD           dwDataSet
    )
    {
        DBG_ASSERT( dwDataSet != 0 );
        _dwDataSetNumber = dwDataSet;
    }
    
    DWORD
    QueryKeyHash(
        VOID
    ) const
    {
        return _dwDataSetNumber;
    }
    
    BOOL
    QueryIsEqual(
        const CACHE_KEY *     pCacheCompareKey
    ) const
    {
        W3_METADATA_KEY *   pMetaKey = (W3_METADATA_KEY*) pCacheCompareKey;
        
        return pMetaKey->_dwDataSetNumber == _dwDataSetNumber;
    }
    
private:
    DWORD               _dwDataSetNumber;
};

class W3_METADATA : public CACHE_ENTRY
{
public:

    W3_METADATA( OBJECT_CACHE * pObjectCache );
    
    virtual 
    ~W3_METADATA();

    CACHE_KEY *
    QueryCacheKey(
        VOID
    ) const
    {
        return (CACHE_KEY*) &_cacheKey;
    }
    
    STRU *
    QueryMetadataPath(
        VOID
    )
    {
        return &_strFullMetadataPath;
    }
    
    BOOL
    QueryIsOkToFlushDirmon(
        WCHAR *,
        DWORD
    )
    {
        DBG_ASSERT( FALSE );
        return FALSE;
    }

    VOID * 
    operator new( 
#if DBG
        size_t            size
#else
        size_t
#endif
    )
    {
        DBG_ASSERT( size == sizeof( W3_METADATA ) );
        DBG_ASSERT( sm_pachW3MetaData != NULL );
        return sm_pachW3MetaData->Alloc();
    }

    VOID
    operator delete(
        VOID *              pW3MetaData
    )
    {
        DBG_ASSERT( pW3MetaData != NULL );
        DBG_ASSERT( sm_pachW3MetaData != NULL );
        
        DBG_REQUIRE( sm_pachW3MetaData->Free( pW3MetaData ) );
    }

    HRESULT
    ReadMetaData(
        const STRU & strMetabasePath,
        const STRU & strURL
    );
    
    HRESULT
    BuildPhysicalPath(
        STRU &          strUrl,
        STRU *          pstrPhysicalPath
    );

    HRESULT
    BuildProviderList(
        IN WCHAR      * pszProviders
    );

    HRESULT
    BuildDefaultProviderList(
        VOID
    );
    
    BOOL 
    CheckAuthProvider(
        IN const CHAR * pszPkgName
    ); 

    HRESULT
    CreateUNCVrToken( 
        IN LPWSTR       pszUserName,
        IN LPWSTR       pszPasswd
        );

    HRESULT
    CreateAnonymousToken( 
        IN LPWSTR       pszUserName,
        IN LPWSTR       pszPasswd
        );   

    HRESULT
    ReadCustomFooter(
        WCHAR *         pszFooter
        );

    HRESULT
    GetMetadataProperty(
        IN W3_CONTEXT *    pW3Context,
        IN DWORD           dwPropertyId,
        OUT BYTE *         pbBuffer,
        IN DWORD           cbBuffer,
        OUT DWORD *        pcbBufferRequired
        );

    //
    //  Query Methods
    //

    STRU *
    QueryWamClsId(
        VOID
    )
    {
        return &_strWamClsId;
    }
    
    DWORD
    QueryAppIsolated(
        VOID
    ) const
    {
        return _dwAppIsolated;
    }
    
    BOOL
    QueryNoCache(
        VOID
    ) const
    {
        return _fNoCache;
    }
    
    DWORD QueryVrLen(
        VOID
    ) const
    {
        return _dwVrLen;
    }

    HRESULT
    GetAndRefVrAccessToken(
        OUT TOKEN_CACHE_ENTRY ** ppCachedToken
    );

    HRESULT
    GetAndRefAnonymousToken(
        OUT TOKEN_CACHE_ENTRY ** ppCachedToken
    );

    DWORD 
    QueryAccessPerms( 
        VOID 
    ) const
    {
        return _dwAccessPerm | _dwSslAccessPerm;
    }
    
    DWORD
    QueryRequireMapping(
        VOID
    ) const
    {
        return _dwRequireMapping;
    }

    DWORD 
    QuerySslAccessPerms( 
        VOID 
    ) const
    {
        return _dwSslAccessPerm; 
    }
    
    BOOL
    QueryAppPoolMatches(
        VOID
    ) const
    {
        return _fAppPoolMatches;
    }

    DWORD
    QueryDirBrowseFlags(
        VOID
    ) const
    {
        return _dwDirBrowseFlags;
    }

    WCHAR *
    QueryDomainName(
        VOID
    )
    {
        return _strDomainName.QueryStr();
    }

    STRA *
    QueryCustomHeaders(
        VOID
    ) 
    {
        return &_strCustomHeaders;
    }

    HRESULT
    GetTrueRedirectionSource(
        LPWSTR                  pszURL,
        LPCWSTR                 pszMetabasePath,
        OUT STRU *              pstrTrueSource
    );
    
    STRU *
    QueryDefaultLoadFiles(
        VOID
    ) 
    {
        return &_strDefaultLoad;
    }

    STRU *
    QueryVrPath(
        VOID
    )
    {
        return &_strVrPath;
    }
    
    HRESULT
    FindCustomError(
        USHORT              StatusCode,
        USHORT              SubError,
        BOOL *              pfIsFile,
        STRU *              pstrFile
    )
    {
        return _customErrorTable.FindCustomError( StatusCode,
                                                  SubError,
                                                  pfIsFile,
                                                  pstrFile );
    }
    
    DIRMON_CONFIG *
    QueryDirmonConfig(
        VOID
    )
    {
        return &_dirmonConfig;
    }
    
    STRA *
    QueryRedirectHeaders(
        VOID
    ) 
    {
        return &_strRedirectHeaders;
    }

    REDIRECTION_BLOB *
    QueryRedirectionBlob()
    {
        return _pRedirectBlob;
    }

    DWORD
    QueryAuthentication(
        VOID
    ) 
    {
        return _dwAuthentication;
    }
    
    BOOL
    QueryAuthTypeSupported(
        DWORD               dwType
    )
    {
        if ( _dwAuthentication & dwType )
        {
            return TRUE;
        }
        else
        {
            if ( dwType == MD_ACCESS_MAP_CERT )
            {
                return !!( _dwSslAccessPerm & MD_ACCESS_MAP_CERT );
            }
        }
        return FALSE;
    }

    BOOL
    IsOnlyAnonymousAuthSupported(
        VOID
    )
    {
        return ( ( _dwAuthentication == MD_AUTH_ANONYMOUS ) &&  
                 ( ( _dwSslAccessPerm & MD_ACCESS_MAP_CERT ) == 0 ) );
    }



    META_SCRIPT_MAP *
    QueryScriptMap( VOID )
    {
        return &_ScriptMap;
    }

    DWORD 
    QueryAuthPersistence(
        VOID
        )
    {
        return _dwAuthPersistence;
    }

    DWORD 
    QueryLogonMethod(  
        VOID
        )
    {
        return _dwLogonMethod;
    }
    
    BOOL
    QueryUNCUserInvalid(
        VOID
    ) const
    {
        return _fUNCUserInvalid;
    }

    WCHAR * 
    QueryRealm(  
        VOID
        )
    {
        return _strRealm.IsEmpty() ? NULL : _strRealm.QueryStr();
    }
    
    MULTISZA *
    QueryAuthProviders(
        VOID
        )
    {
        return &_mstrAuthProviders;
    }

    BYTE *
    QueryIpAccessCheckBuffer(
        VOID
    ) const
    { 
        if ( _cbIpAccessCheck != 0 )
        {
            return (BYTE*) _buffIpAccessCheck.QueryPtr();
        }
        else
        {
            return NULL;
        }
    }

    DWORD 
    QueryIpAccessCheckSize(
        VOID
    ) const
    {
        return _cbIpAccessCheck;
    }

    BOOL
    QueryCreateProcessAsUser(
        VOID
    ) const
    {
        return _fCreateProcessAsUser;
    }

    BOOL
    QueryCreateProcessNewConsole(
        VOID
    ) const
    {
        return _fCreateProcessNewConsole;
    }

    DWORD 
    QueryScriptTimeout(
        VOID
    ) const
    {
        return _dwCGIScriptTimeout;
    }
    
    MIME_MAP *
    QueryMimeMap(
        VOID
    ) const
    {
        return _pMimeMap;
    }

    BOOL 
    QueryDoStaticCompression(
        VOID
    ) const
    {
        return _fDoStaticCompression;
    }

    BOOL 
    QueryDoDynamicCompression(
        VOID
    ) const
    {
        return _fDoDynamicCompression;
    }

    STRU *
    QueryAppMetaPath(
        VOID
    )
    {
        return &_strAppMetaPath;
    }

    BOOL  
    QuerySSIExecDisabled(
        VOID
    ) const
    { 
        return _fSSIExecDisabled; 
    }
    
    BOOL
    QueryDoReverseDNS(
        VOID
    ) const
    {
        return _fDoReverseDNS;
    }

    BOOL 
    QueryDontLog(
        VOID
    )
    {
        return _fDontLog;
    }

    BOOL 
    QueryIsFooterEnabled(
        VOID
    )
    {
        return _fFooterEnabled;
    }

    STRA *
    QueryFooterString(
        VOID
    )
    {
        return &_strFooterString;
    }
    
    STRU *
    QueryFooterDocument(
        VOID
    )
    {
        return &_strFooterDocument;
    }

    DWORD 
    QueryExpireMode(
        VOID
    ) const
    {
        return _dwExpireMode;
    }

    STRA *
    QueryCacheControlHeader(
        VOID
    )
    {
        return &_strCacheControlHeader;
    }

    STRA *
    QueryExpireHeader(
        VOID
    )
    {
        return &_strExpireHeader;
    }
    
    DWORD 
    QueryEntityReadAhead(
        VOID
    ) const
    {
        return _cbEntityReadAhead;
    }

    BOOL
    QueryKeepAliveEnabled(
        VOID
    ) const
    {
        return _fKeepAliveEnabled;
    }

    DWORD
    QueryMaxRequestEntityAllowed(
        VOID
    ) const
    {
        return _dwMaxRequestEntityAllowed;
    }

    STRA *
    QueryMatchingUrlA(
        VOID
        )
    {
        return &_strMatchingUrlA;
    }

    STRA *
    QueryMatchingPathA(
        VOID
        )
    {
        return &_strMatchingPathA;
    }

    DWORD
    QueryCBMatchingUrlA(
        VOID
        )
    {
        return _cbMatchingUrlA;
    }

    DWORD
    QueryCBMatchingPathA(
        VOID
        )
    {
        return _cbMatchingPathA;
    }

    static 
    HRESULT
    Initialize(
        VOID
    );
    
    static
    VOID
    Terminate(
        VOID
    );

private:

    HRESULT 
    EncryptMemoryPassword(
        IN OUT STRU * strPassword
    );
    
    HRESULT 
    DecryptMemoryPassword(
        IN  STRU   * strProtectedPassword,
        OUT BUFFER * bufDecryptedPassword
    );
    
    //
    // Set methods
    //

    HRESULT 
    SetRedirectionBlob(
        STRU &              strSource,
        STRU &              strDestination
    );

    HRESULT
    SetExpire(
        WCHAR *             pszExpire
    );

    HRESULT
    SetCacheControlHeader(
        VOID
    );

    HRESULT
    SetIpAccessCheck( 
        LPVOID              pMDData, 
        DWORD               dwDataLen
    );

    W3_METADATA_KEY         _cacheKey;
    STRU                    _strVrPath;
    WCHAR                   _rgVrUserName[ UNLEN + 1 ];
    STRU                    _strVrUserName;
    WCHAR                   _rgVrPasswd[ PWLEN ];
    STRU                    _strVrPasswd;
    DWORD                   _dwAccessPerm;
    DWORD                   _dwSslAccessPerm;
    DWORD                   _dwVrLevel;
    DWORD                   _dwVrLen;
    REDIRECTION_BLOB *      _pRedirectBlob;
    DWORD                   _dwDirBrowseFlags;
    STRU                    _strDefaultLoad;
    DWORD                   _dwAuthentication;
    DWORD                   _dwAuthPersistence;
    WCHAR                   _rgUserName[ UNLEN + 1 ];
    STRU                    _strUserName;
    WCHAR                   _rgPasswd[ PWLEN ];
    STRU                    _strPasswd;
    WCHAR                   _rgDomainName[ DNLEN + 1 ];
    STRU                    _strDomainName;
    STRA                    _strCustomHeaders;
    STRA                    _strRedirectHeaders;
    DWORD                   _dwLogonMethod;
    WCHAR                   _rgRealm[ DNLEN + 1 ];
    STRU                    _strRealm;
    MULTISZA                _mstrAuthProviders;
    BOOL                    _fCreateProcessAsUser;
    BOOL                    _fCreateProcessNewConsole;
    BOOL                    _fDoStaticCompression;
    BOOL                    _fDoDynamicCompression;
    DWORD                   _dwCGIScriptTimeout;
    BOOL                    _fDontLog;
    BOOL                    _fFooterEnabled;
    STRA                    _strFooterString;
    STRU                    _strFooterDocument;
    DWORD                   _dwExpireMode;
    STRA                    _strExpireHeader;
    LARGE_INTEGER           _liExpireTime;
    DWORD                   _dwExpireDelta;
    BOOL                    _fHaveNoCache;
    DWORD                   _dwMaxAge;
    BOOL                    _fHaveMaxAge;
    STRA                    _strCacheControlHeader;
    BOOL                    _fKeepAliveEnabled;
    DWORD                   _dwRequireMapping;

    //
    // Script mappings defined for this metadata entry
    //
    META_SCRIPT_MAP         _ScriptMap;

    //
    // The metabase path for the application that controls this url.
    // Corresponds to MD_APP_ROOT
    //
    STRU                    _strAppMetaPath;

    //
    // IP address restriction info
    //
    
    BUFFER                  _buffIpAccessCheck;
    DWORD                   _cbIpAccessCheck;

    //
    // Use IIS subauthenticator to logon the anonymous use
    //

    BOOL                    _fUseAnonSubAuth;
    
    //
    // Access token for UNC case 
    //
    TOKEN_CACHE_ENTRY *     _pctVrToken;
    
    //
    // Anonymous user token (if account valid)
    //
    TOKEN_CACHE_ENTRY *     _pctAnonymousToken;
    
    //
    // Lock for managing associated tokens
    //
    CReaderWriterLock3      _TokenLock;
    
    //
    // Custom Error Table
    //
    CUSTOM_ERROR_TABLE      _customErrorTable;

    //
    // Mime Map lookup table
    //
    MIME_MAP               *_pMimeMap;

    //
    // SSI execution disable flag
    //
    BOOL                    _fSSIExecDisabled;
    
    //
    // Do a DNS lookup (for logging/server-variable purposes)
    //
    BOOL                    _fDoReverseDNS;

    //
    // Entity read ahead size
    //
    DWORD                   _cbEntityReadAhead;
    DWORD                   _dwMaxRequestEntityAllowed;

    //
    // Dir monitor configuration
    //
    DIRMON_CONFIG           _dirmonConfig;
    
    //
    // Does the AppPoolId match the current process
    //
    BOOL                    _fAppPoolMatches;
   
    //
    // Should we disable caching for this path
    //
    
    BOOL                    _fNoCache;

    //
    // Cached WAM app info stuff
    //
    
    DWORD                   _dwAppIsolated;
    DWORD                   _dwAppOopRecoverLimit;
    STRU                    _strWamClsId;
   
    //
    // Full metadata path for flushing purposes
    //
    
    STRU                    _strFullMetadataPath;
   
    //
    // GETALL structure used for retrieving metabase properties thru GSV
    //
    
    BUFFER *                _pGetAllBuffer;
    DWORD                   _cGetAllRecords;
    
    //
    // Is the UNC user invalid
    //
    
    BOOL                    _fUNCUserInvalid;

    //
    // Matching URL and path info for HTTP_FILTER_URL_MAP_EX and
    // HSE_URL_MAPEX_INFO
    //

    STRA                    _strMatchingUrlA;
    STRA                    _strMatchingPathA;
    DWORD                   _cbMatchingUrlA;
    DWORD                   _cbMatchingPathA;

    //
    // Allocation cache for W3_URL_INFO's
    //

    static ALLOC_CACHE_HANDLER * sm_pachW3MetaData;
};

//
// W3_METADATA cache
//

#define DEFAULT_W3_METADATA_CACHE_TTL       (5*60)

class W3_METADATA_CACHE : public OBJECT_CACHE
{
public:

    W3_METADATA_CACHE()
    {
    }
    
    HRESULT
    GetMetaData(
        W3_CONTEXT *            pW3Context,
        STRU &                  strUrl,
        W3_METADATA **          ppMetaData
    );
    
    WCHAR *
    QueryName(
        VOID
    ) const 
    {
        return L"W3_METADATA_CACHE";
    }

    HRESULT
    Initialize(
        VOID
    );
    
    VOID
    Terminate(
        VOID
    )
    {
        return W3_METADATA::Terminate();
    }

private:

    W3_METADATA_CACHE(const W3_METADATA_CACHE &);
    void operator=(const W3_METADATA_CACHE &);

    HRESULT
    GetFullMetadataPath( 
        W3_CONTEXT *            pW3Context,
        STRU &                  strUrl,
        STRU *                  pstrFullPath
    );

    HRESULT
    CreateNewMetaData(
        W3_CONTEXT *            pW3Context,
        STRU &                  strUrl,
        STRU &                  strFullMetadataPath,
        W3_METADATA **          ppMetaData
    );
};

#endif