//-- == 0-------------------------------------------------------------------------
//
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1995
//
//  File:  utilprop.cxx
//
//  Contents:
//
//
//  History:   08-28-96     shanksh    Created.
//
//----------------------------------------------------------------------------
// Notes - there are two main methods in this module:
//     - CUtilProps::GetPropertyInfo, a helper function for
//       GetProperty method on Data Source
//     - CUtilProps::GetProperties, a helper function for
//       GetProperties method on Data Source, Session and Command objects
//     - CUtilProps::SetProperties, a helper function for
//       SetProperties method on Data Source, Session and Command objects
//
//
// The implementation is very simple - we keep a global table of the
// properties we support in s_rgprop. We search this table sequentially.
// 

#include "oleds.hxx"
#pragma hdrstop

PROPSTRUCT s_rgDBInitProp[] =
{
    {DBPROP_AUTH_PASSWORD,         F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Password"},
    {DBPROP_AUTH_USERID,           F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"User ID"},
    {DBPROP_AUTH_ENCRYPT_PASSWORD, F_DBINITRW, VT_BOOL, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Encrypt Password"},
    {DBPROP_AUTH_INTEGRATED,       F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Integrated Security"},
    {DBPROP_INIT_DATASOURCE,       F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Data Source"},
    {DBPROP_INIT_LOCATION,         F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Location"},
    {DBPROP_INIT_PROVIDERSTRING,   F_DBINITRW, VT_BSTR, VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Extended Properties"},
    {DBPROP_INIT_TIMEOUT,          F_DBINITRW, VT_I4,   VARIANT_FALSE, 90,           OPT_REQ, NULL, L"Connect Timeout"},
    {DBPROP_INIT_PROMPT,           F_DBINITRW, VT_I2,   VARIANT_FALSE, DBPROMPT_NOPROMPT, OPT_REQ, NULL,  L"Prompt"},
    {DBPROP_INIT_HWND,             F_DBINITRW, VT_I4,   VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Window Handle"},
    {DBPROP_INIT_MODE,             F_DBINITRW, VT_I4,   VARIANT_FALSE, DB_MODE_READ,      OPT_REQ, NULL, L"Mode"}
#if (!defined(BUILD_FOR_NT40)) 
    ,
    {DBPROP_INIT_BINDFLAGS,        F_DBINITRW, VT_I4,   VARIANT_FALSE, 0,            OPT_REQ, NULL, L"Bind Flags"}
#endif
};

PROPSTRUCT s_rgADSIBindProp[] =
{
    // initialize this property to a reserved value. The client is not supposed
    // to set this property to the reserved value. This reserved value prevents
    // ADSIFLAG from overriding ENCRYPT_PASSWORD when VB initializes this
    // property to its default value. See IsValidValue().

    {ADSIPROP_ADSIFLAG,            F_DBINITRW, VT_I4,   VARIANT_FALSE, 
     ADS_AUTH_RESERVED, OPT_REQ, NULL, L"ADSI Flag"} 
};

PROPSTRUCT s_rgDSInfoProp[] =
{
    {DBPROP_ACTIVESESSIONS,             F_DSRO,    VT_I4,   VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"Active Sessions"},
    {DBPROP_BYREFACCESSORS,             F_DSRO,    VT_BOOL, VARIANT_FALSE, 1, OPT_REQ, NULL,                                              L"Pass By Ref Accessors"},
    {DBPROP_CATALOGLOCATION,            F_DSRO,    VT_I4,   VARIANT_FALSE, DBPROPVAL_CL_START, OPT_REQ, NULL,                             L"Catalog Location"},
    {DBPROP_CATALOGTERM,                F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"Catalog Term"},
    {DBPROP_CATALOGUSAGE,               F_DSRO,    VT_I4,   VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"Catalog Usage"},
    {DBPROP_DATASOURCENAME,             F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, L"Active Directory Service Interfaces",            L"Data Source Name"},
    {DBPROP_DATASOURCEREADONLY,         F_DSRO,    VT_BOOL, VARIANT_TRUE,  0, OPT_REQ, NULL,                                              L"Read-Only Data Source"},
//  {DBPROP_DBMSNAME,                   F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"DBMS Name"},
//  {DBPROP_DBMSVER,                    F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"DBMS Version"},
    {DBPROP_DSOTHREADMODEL,             F_DSRO,    VT_I4,   VARIANT_FALSE, DBPROPVAL_RT_FREETHREAD, OPT_REQ, NULL,                        L"Data Source Object Threading Model"},
    {DBPROP_MAXROWSIZE,                 F_DSRO,    VT_I4,   VARIANT_FALSE, 0, OPT_SIC, NULL,                                              L"Maximum Row Size"},
#if (!defined(BUILD_FOR_NT40))
    {DBPROP_OLEOBJECTS,                 F_DSRO,    VT_I4,   VARIANT_FALSE, DBPROPVAL_OO_ROWOBJECT | DBPROPVAL_OO_DIRECTBIND | DBPROPVAL_OO_SINGLETON, OPT_REQ, NULL, L"OLE Object Support"},
#endif
    {DBPROP_PERSISTENTIDTYPE,           F_DSRO,    VT_I4,   VARIANT_FALSE, DBPROPVAL_PT_NAME, OPT_SIC, NULL,                              L"Persistent ID Type"},
    {DBPROP_PROVIDERFRIENDLYNAME,       F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, L"Microsoft OLE DB Provider for ADSI",             L"Provider Friendly Name"},
    {DBPROP_PROVIDERNAME,               F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, L"ACTIVEDS.DLL",                                   L"Provider Name"},
    {DBPROP_PROVIDEROLEDBVER,           F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, L"02.50",                                          L"OLE DB Version"},
    {DBPROP_PROVIDERVER,                F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, L"02.50.0000",                                     L"Provider Version"},
    {DBPROP_SQLSUPPORT,                 F_DSRO,    VT_I4,   VARIANT_FALSE, DBPROPVAL_SQL_ODBC_MINIMUM, OPT_REQ, NULL,                     L"SQL Support"},
    {DBPROP_ROWSETCONVERSIONSONCOMMAND, F_DSRO,    VT_BOOL, VARIANT_TRUE,  0, OPT_REQ, NULL,                                              L"Rowset Conversions on Command"},
    {DBPROP_USERNAME,                   F_DSRO,    VT_BSTR, VARIANT_FALSE, 0, OPT_REQ, NULL,                                              L"User Name"}
};

PROPSTRUCT s_rgRowsetProp[] =
{
    {DBPROP_IAccessor,                       F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IAccessor"},
    {DBPROP_IColumnsInfo,                    F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IColumnsInfo"},
#if (!defined(BUILD_FOR_NT40))
    {DBPROP_IColumnsInfo2,                   F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IColumnsInfo2"},
#endif
    {DBPROP_IConvertType,                    F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IConvertType"},
#if (!defined(BUILD_FOR_NT40))
    {DBPROP_IGetSession,                     F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IGetSession"},
    {DBPROP_IRow,                            F_ROWSETRW,     VT_BOOL, VARIANT_FALSE,    0, OPT_REQ, NULL, L"IRow"},
    {DBPROP_IGetRow,                         F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IGetRow"},
#endif
    {DBPROP_IRowset,                         F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IRowset"},
    {DBPROP_IRowsetIdentity,                 F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_SIC, NULL, L"IRowsetIdentity"},
    {DBPROP_IRowsetInfo,                     F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IRowsetInfo"},
    {DBPROP_IRowsetLocate,                   F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IRowsetLocate"},
    {DBPROP_IRowsetScroll,                   F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"IRowsetScroll"},
    {DBPROP_ABORTPRESERVE,                   F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Preserve on Abort"},
    {DBPROP_BLOCKINGSTORAGEOBJECTS,          F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"Blocking Storage Objects"},
    {DBPROP_BOOKMARKS,                       F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"Use Bookmarks"},
    {DBPROP_BOOKMARKSKIPPED,                 F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Skip Deleted Bookmarks"},
    {DBPROP_BOOKMARKTYPE,                    F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   DBPROPVAL_BMK_NUMERIC, OPT_REQ, NULL, L"Bookmark Type"},
    {DBPROP_CANFETCHBACKWARDS,               F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_SIC, NULL, L"Fetch Backwards"},
    {DBPROP_CANHOLDROWS,                     F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_SIC, NULL, L"Hold Rows"},
    {DBPROP_CANSCROLLBACKWARDS,              F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_SIC, NULL, L"Scroll Backwards"},
    {DBPROP_COLUMNRESTRICT,                  F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_SIC, NULL, L"Column Privileges"},
    {DBPROP_COMMITPRESERVE,                  F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Preserve on Commit"},
    {DBPROP_IMMOBILEROWS,                    F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_SIC, NULL, L"Immobile Rows"},
    {DBPROP_LITERALBOOKMARKS,                F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_SIC, NULL, L"Literal Bookmarks"},
    {DBPROP_LITERALIDENTITY,                 F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_REQ, NULL, L"Literal Row Identity"},
    {DBPROP_MAXOPENROWS,                     F_ROWSETRW,     VT_I4,   VARIANT_FALSE,   0, OPT_SIC, NULL, L"Maximum Open Rows"},
    {DBPROP_MAXPENDINGROWS,                  F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_SIC, NULL, L"Maximum Pending Rows"},
    {DBPROP_MAXROWS,                         F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_SIC, NULL, L"Maximum Rows"},
    {DBPROP_NOTIFICATIONPHASES,              F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Notification Phases"},
//  {DBPROP_NOTIFYCOLUMNRECALCULATED,        F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"NotifyColumnRecalculated"},
    {DBPROP_NOTIFYCOLUMNSET,                 F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Column Set Notification"},
//  {DBPROP_NOTIFYROWACTIVATE,               F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"NotifyRowActivate"},
    {DBPROP_NOTIFYROWDELETE,                 F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Delete Notification"},
    {DBPROP_NOTIFYROWFIRSTCHANGE,            F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row First Change Notification"},
    {DBPROP_NOTIFYROWINSERT,                 F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Insert Notification"},
//  {DBPROP_NOTIFYROWRELEASE,                F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"NotifyRowRelease"},
    {DBPROP_NOTIFYROWRESYNCH,                F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Resynchronization Notification"},
    {DBPROP_NOTIFYROWSETRELEASE,             F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Rowset Release Notification"},
    {DBPROP_NOTIFYROWSETFETCHPOSITIONCHANGE, F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Rowset Fetch Position Change Notification"},
    {DBPROP_NOTIFYROWUNDOCHANGE,             F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Undo Change Notification"},
    {DBPROP_NOTIFYROWUNDODELETE,             F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Undo Delete Notification"},
    {DBPROP_NOTIFYROWUNDOINSERT,             F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Undo Insert Notification"},
    {DBPROP_NOTIFYROWUPDATE,                 F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Update Notification"},
    {DBPROP_ORDEREDBOOKMARKS,                F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_SIC, NULL, L"Bookmarks Ordered"},
    {DBPROP_OWNINSERT,                       F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_SIC, NULL, L"Own Inserts Visible"},
    {DBPROP_OWNUPDATEDELETE,                 F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_SIC, NULL, L"Own Changes Visible"},
    {DBPROP_QUICKRESTART,                    F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,   0, OPT_SIC, NULL, L"Quick Restart"},
    {DBPROP_REENTRANTEVENTS,                 F_ROWSETRO,     VT_BOOL, VARIANT_TRUE,    0, OPT_REQ, NULL, L"Reentrant Events"},
    {DBPROP_REMOVEDELETED,                   F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_SIC, NULL, L"Remove Deleted Rows"},
    {DBPROP_REPORTMULTIPLECHANGES,           F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Report Multiple Changes"},
    {DBPROP_ROWRESTRICT,                     F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Row Privileges"},
    {DBPROP_ROWTHREADMODEL,                  F_ROWSETRO,     VT_I4,   VARIANT_FALSE,   DBPROPVAL_RT_FREETHREAD, OPT_REQ, NULL, L"Row Threading Model"},
    {DBPROP_STRONGIDENTITY,                  F_ROWSETRO,     VT_BOOL, VARIANT_FALSE,   0, OPT_REQ, NULL, L"Strong Row Identity"},

};

PROPSTRUCT s_rgDBSessProp[] =
{
    {DBPROP_SESS_AUTOCOMMITISOLEVELS, F_SESSRO, VT_I4, VARIANT_FALSE, 0, OPT_REQ, NULL, L"Autocommit Isolation Levels"},
};


PROPSTRUCT s_rgADSISearchProp[12] =
{
    {ADSIPROP_ASYNCHRONOUS,     F_ADSIRW,    VT_BOOL,    VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Asynchronous"},
    {ADSIPROP_DEREF_ALIASES,    F_ADSIRW,    VT_I4,      VARIANT_FALSE,  ADS_DEREF_NEVER,           OPT_REQ, NULL, L"Deref Aliases"},
    {ADSIPROP_SIZE_LIMIT,       F_ADSIRW,    VT_I4,      VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Size Limit"},
    {ADSIPROP_TIME_LIMIT,       F_ADSIRW,    VT_I4,      VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Server Time Limit"},
    {ADSIPROP_ATTRIBTYPES_ONLY, F_ADSIRW,    VT_BOOL,    VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Column Names only"},
    {ADSIPROP_SEARCH_SCOPE,     F_ADSIRW,    VT_I4,      VARIANT_FALSE,  ADS_SCOPE_SUBTREE,         OPT_REQ, NULL, L"SearchScope"},
    {ADSIPROP_TIMEOUT,          F_ADSIRW,    VT_I4,      VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Timeout"},
    {ADSIPROP_PAGESIZE,         F_ADSIRW,    VT_I4,      VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Page size"},
    {ADSIPROP_PAGED_TIME_LIMIT, F_ADSIRW,    VT_I4,      VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Time limit"},
    {ADSIPROP_CHASE_REFERRALS,  F_ADSIRW,    VT_I4,      VARIANT_FALSE,  ADS_CHASE_REFERRALS_NEVER, OPT_REQ, NULL, L"Chase referrals"},
    {ADSIPROP_SORT_ON,          F_ADSIRW,    VT_BSTR,    VARIANT_FALSE,  0,                         OPT_REQ, NULL, L"Sort On"},
    {ADSIPROP_CACHE_RESULTS,    F_ADSIRW,    VT_BOOL,    VARIANT_TRUE,   0,                         OPT_REQ, NULL, L"Cache Results"}

};

// Number of supported properties per property set
#define    NUMBER_OF_SUPPORTED_PROPERTY_SETS   6

static PROPSET s_rgPropertySets[NUMBER_OF_SUPPORTED_PROPERTY_SETS] =
{
    {&DBPROPSET_DBINIT,         NUMELEM(s_rgDBInitProp),    s_rgDBInitProp},
    {&DBPROPSET_ADSIBIND,       NUMELEM(s_rgADSIBindProp),  s_rgADSIBindProp},
    {&DBPROPSET_DATASOURCEINFO, NUMELEM(s_rgDSInfoProp),    s_rgDSInfoProp},
    {&DBPROPSET_SESSION,        NUMELEM(s_rgDBSessProp),    s_rgDBSessProp},
    {&DBPROPSET_ROWSET,         NUMELEM(s_rgRowsetProp),    s_rgRowsetProp},
    {&DBPROPSET_ADSISEARCH,     NUMELEM(s_rgADSISearchProp),s_rgADSISearchProp}
};

//
// WARNING: Don't change the order. Add new property sets at the end
//
// Update: New property sets should not always be added at the end.
// Property sets which have properties in the Initialization  property group
// have to be added before DATASOURCEINFO and prop. sets with properties
// in the  data source information property groups have to be added
// before INDEX_SESSION and so on. This is for GetProperties to work correctly.
//

#define INDEX_INIT              0
#define INDEX_ADSIBIND          1
#define INDEX_DATASOURCEINFO    2
#define INDEX_SESSION           3
#define INDEX_ROWSET            4
#define INDEX_ADSISEARCH        5

//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::CUtilProp
//
//  Synopsis:  Constructor for this class
//
//  Arguments:
//
//  Returns:
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
CUtilProp::CUtilProp(
    void
    )
{
    _pIMalloc      = NULL;
    _pCredentials  = NULL;
    _prgProperties = NULL;
    _dwDescBufferLen = 0;
}


//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::FInit
//
//  Synopsis:
//
//  Arguments:
//
//  Returns:
//
//  Modifies:
//
//  History:    09-20-96   ShankSh     Created.
//
//  Update: pCredentials may be NULL if called from CRowset.
//
//----------------------------------------------------------------------------

STDMETHODIMP
CUtilProp::FInit(
    CCredentials *pCredentials
    )
{
    HRESULT hr=S_OK;
    ULONG i, j;
    ULONG c = 0;

    //
    // Get the IMalloc interface pointer
    //
    hr = CoGetMalloc(MEMCTX_TASK, &_pIMalloc);
    BAIL_ON_FAILURE( hr );

    _pCredentials = pCredentials;
    _prgProperties = (PROPSTRUCT*) AllocADsMem(sizeof(PROPSTRUCT) *
                                               (NUMELEM(s_rgDBInitProp) +
                                                NUMELEM(s_rgADSIBindProp) +
                                                NUMELEM(s_rgDSInfoProp) +
                                                NUMELEM(s_rgDBSessProp) +
                                                NUMELEM(s_rgRowsetProp) +
                                                NUMELEM(s_rgADSISearchProp)) );
    if( !_prgProperties )
        BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );

    for (i=c=0; i< NUMBER_OF_SUPPORTED_PROPERTY_SETS; i++) {
        for (j=0; j < s_rgPropertySets[i].cProperties; j++) {
            // Copy static structure
            memcpy( &_prgProperties[c],
                    &s_rgPropertySets[i].pUPropInfo[j], sizeof(PROPSTRUCT) );

            // Allocate new BSTR value
            _prgProperties[c].pwstrVal =
                    AllocADsStr(s_rgPropertySets[i].pUPropInfo[j].pwstrVal);

            // Add description length
            if( s_rgPropertySets[i].pUPropInfo[j].pwszDescription ) {
                _dwDescBufferLen += wcslen(s_rgPropertySets[i].pUPropInfo[j].pwszDescription) + 1;
            }

            c++;
        }
    }
    _dwDescBufferLen *= sizeof(WCHAR);

    ADsAssert( c == NUMELEM(s_rgDBInitProp) +
                    NUMELEM(s_rgADSIBindProp) +
                    NUMELEM(s_rgDSInfoProp) +
                    NUMELEM(s_rgDBSessProp) +
                    NUMELEM(s_rgRowsetProp) +
                    NUMELEM(s_rgADSISearchProp) );

error:

    RRETURN( hr );
}


//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::~CUtilProp
//
//  Synopsis:  Destructor for this class
//
//  Arguments:
//
//  Returns:
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------

CUtilProp:: ~CUtilProp
(
void
)
{
    ULONG c = 0;

    if( _prgProperties )
    {
        // Clear all of the String values
        for (ULONG i=c=0; i< NUMBER_OF_SUPPORTED_PROPERTY_SETS; i++) {
            for (ULONG j=0; j < s_rgPropertySets[i].cProperties; j++) {
                if( _prgProperties[c].pwstrVal )
                    FreeADsStr(_prgProperties[c].pwstrVal);
                c++;
            }
        }

        FreeADsMem(_prgProperties);
    }

    if( _pIMalloc )
        _pIMalloc->Release();

    return;
}


PROPSET *
CUtilProp::GetPropSetFromGuid (
    GUID guidPropSet
    )
{

    for (int j=0; j< NUMELEM(s_rgPropertySets); j++) {
        if (IsEqualGUID(guidPropSet,
                        *(s_rgPropertySets[j].guidPropertySet)))
            return &(s_rgPropertySets[j]);
    }
    return NULL;
}

HRESULT
CUtilProp::GetSearchPrefInfo(
    DBPROPID dwPropId,
    PADS_SEARCHPREF_INFO pSearchPrefInfo
    )
{
    PADS_SORTKEY pSortKey = NULL;
    LPWSTR pszAttrs = NULL;
    LPWSTR pszFirstAttr = NULL;
    LPWSTR pszCurrentAttr = NULL, pszNextAttr = NULL, pszOrder = NULL;
    DWORD cAttrs = 0;
    HRESULT hr = S_OK;
    DWORD index;

    if (!pSearchPrefInfo) {
        RRETURN (E_INVALIDARG);
    }

    if (dwPropId >= g_cMapDBPropToSearchPref)
        RRETURN(E_FAIL);

    pSearchPrefInfo->dwSearchPref = g_MapDBPropIdToSearchPref[dwPropId];

    //
    // Get index of where ADSI search properties begin
    //

    index = NUMELEM(s_rgDBInitProp) +
            NUMELEM(s_rgADSIBindProp) +
            NUMELEM(s_rgDSInfoProp) +
            NUMELEM(s_rgDBSessProp) +
            NUMELEM(s_rgRowsetProp);

    switch (_prgProperties[index + dwPropId].vtType) {
    case VT_BOOL:
        pSearchPrefInfo->vValue.dwType = ADSTYPE_BOOLEAN;
        pSearchPrefInfo->vValue.Boolean =
            _prgProperties[index + dwPropId].boolVal == VARIANT_TRUE ? TRUE : FALSE;
        break;

    case VT_I4:
    case VT_I2:
        pSearchPrefInfo->vValue.dwType = ADSTYPE_INTEGER;
        pSearchPrefInfo->vValue.Integer = _prgProperties[index + dwPropId].longVal;
        break;

    case VT_BSTR: {
        if (pSearchPrefInfo->dwSearchPref != ADS_SEARCHPREF_SORT_ON) {
            //
            // right now, this is the only string preference supported
            //
            RRETURN (E_FAIL);
        }
        //
        // The preference is a list of atributes to be sorted on (in that order
        // and an optional indication of whether it has to be sorted ascending
        // or not.
        // eg., "name ASC, usnchanged DESC, cn"
        //
        pSearchPrefInfo->vValue.dwType = ADSTYPE_PROV_SPECIFIC;

        if (!_prgProperties[index + dwPropId].pwstrVal ||
            !_wcsicmp(_prgProperties[index + dwPropId].pwstrVal, L"")) {

            pSearchPrefInfo->vValue.ProviderSpecific.dwLength = 0;
            pSearchPrefInfo->vValue.ProviderSpecific.lpValue = NULL;

            break;
        }

        // make a copy
        pszAttrs = AllocADsStr(_prgProperties[index + dwPropId].pwstrVal);

        pszCurrentAttr = pszFirstAttr = wcstok(pszAttrs, L",");

        for(cAttrs=0; pszCurrentAttr != NULL; cAttrs++ ) {
            pszCurrentAttr = wcstok(NULL, L",");
        }

        if(cAttrs == 0) {
           BAIL_ON_FAILURE ( hr = E_ADS_BAD_PARAMETER );
        }

        pSortKey = (PADS_SORTKEY) AllocADsMem(sizeof(ADS_SORTKEY) * cAttrs);

        if (!pSortKey) {
            BAIL_ON_FAILURE ( E_OUTOFMEMORY );
        }

        pszCurrentAttr = pszFirstAttr;

        for (DWORD i=0 ; i < cAttrs; i++) {

            pszNextAttr = pszCurrentAttr + wcslen(pszCurrentAttr) + 1;
            pszCurrentAttr = RemoveWhiteSpaces(pszCurrentAttr);

            pszOrder = wcstok(pszCurrentAttr, L" ");
            pszOrder = pszOrder ? wcstok(NULL, L" ") : NULL;

            if (pszOrder && !_wcsicmp(pszOrder, L"DESC"))
                pSortKey[i].fReverseorder = 1;
            else
                pSortKey[i].fReverseorder = 0;  // This is the default

            pSortKey[i].pszAttrType = AllocADsStr(pszCurrentAttr);
            pSortKey[i].pszReserved = NULL;

            pszCurrentAttr = pszNextAttr;

        }

        pSearchPrefInfo->vValue.ProviderSpecific.dwLength = sizeof(ADS_SORTKEY) * cAttrs;
        pSearchPrefInfo->vValue.ProviderSpecific.lpValue = (LPBYTE) pSortKey;

        break;

    }

    default:

        RRETURN (E_FAIL);
    }

error:

    if (pszAttrs) {
        FreeADsStr(pszAttrs);
    }

    RRETURN(hr);

}


HRESULT
CUtilProp::FreeSearchPrefInfo(
    PADS_SEARCHPREF_INFO pSearchPrefInfo,
    DWORD dwNumSearchPrefs
    )
{

    PADS_SORTKEY pSortKey = NULL;
    DWORD nSortKeys = 0;

    if (!pSearchPrefInfo || !dwNumSearchPrefs) {
        RRETURN (S_OK);
    }

    for (DWORD i=0; i<dwNumSearchPrefs; i++) {

        switch(pSearchPrefInfo[i].vValue.dwType) {

        case ADSTYPE_BOOLEAN:
        case ADSTYPE_INTEGER:
            // do nothing
            break;

        case ADSTYPE_PROV_SPECIFIC:

            if (pSearchPrefInfo[i].dwSearchPref == ADS_SEARCHPREF_SORT_ON) {
                //
                // delete the strings allocated for each of the attributes
                // to be sorted

                nSortKeys = pSearchPrefInfo[i].vValue.ProviderSpecific.dwLength / sizeof(ADS_SORTKEY);
                pSortKey = (PADS_SORTKEY) pSearchPrefInfo[i].vValue.ProviderSpecific.lpValue;

                for (DWORD j=0; pSortKey && j<nSortKeys; j++) {
                    FreeADsStr(pSortKey[j].pszAttrType);
                }

                if (pSortKey) {
                    FreeADsMem(pSortKey);
                }

            }

            break;
        }

    }

    RRETURN (S_OK);

}

//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::LoadDBPROPINFO
//
//  Synopsis:  Helper for GetPropertyInfo. Loads field of DBPROPINFO
//             structure.
//
//  Arguments:
//
//  Returns:        TRUE    :  Method succeeded
//                  FALSE   :  Method failed (couldn't allocate memory)
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUtilProp::LoadDBPROPINFO (
    PROPSTRUCT* pPropStruct,
    ULONG       cProperties,
    DBPROPINFO* pPropInfo
    )
{
    ULONG cCount;
    PROPSTRUCT* pProp=NULL;

    // asserts
    ADsAssert( pPropInfo );
    if( cProperties ) {
        ADsAssert( pPropStruct );
    }

    //
    // init the variant
    //
    VariantInit( &pPropInfo->vValues );

    for (cCount=0; cCount < cProperties; cCount++) {
        if(pPropInfo->dwPropertyID == pPropStruct[cCount].dwPropertyID)
            break;
    }

    if(cCount == cProperties) {
        pPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
        pPropInfo->pwszDescription = NULL;
        RRETURN (DB_S_ERRORSOCCURRED);
    }

    pProp = &(pPropStruct[cCount]);
    //
    // set the easy fields..
    //
    pPropInfo->dwPropertyID    = pProp->dwPropertyID;
    pPropInfo->dwFlags        = pProp->dwFlags;
    pPropInfo->vtType        = pProp->vtType;


    // fill in the description
    if (pPropInfo->pwszDescription)
        wcscpy(pPropInfo->pwszDescription, pProp->pwszDescription);

    RRETURN(S_OK);
}


//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::LoadDBPROP
//
//  Synopsis:  Helper for GetProperties. Loads field of DBPROP structure.
//
//  Arguments:
//
//  Returns:        TRUE    :  Method succeeded
//                  FALSE   :  Method failed (couldn't allocate memory)
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUtilProp::LoadDBPROP (
    PROPSTRUCT* pPropStruct,
    ULONG       cProperties,
    DBPROP*     pPropSupport,
    BOOL        IsDBInitPropSet
    )
{
    ULONG cCount;
    PROPSTRUCT* pProp=NULL;
    LPWSTR szUserName=NULL, szPassword=NULL;
    BOOL fAuthFlags=0;

    // asserts
    ADsAssert( pPropSupport );
    if( cProperties ) {
        ADsAssert( pPropStruct );
    }

    //
    // init the variant
    //
    VariantInit( &pPropSupport->vValue );

    for (cCount=0; cCount < cProperties; cCount++) {
        if( pPropSupport->dwPropertyID == pPropStruct[cCount].dwPropertyID )
            break;
    }

    if( cCount == cProperties ) {
        pPropSupport->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
        RRETURN ( DB_S_ERRORSOCCURRED );
    }

    pProp = &(pPropStruct[cCount]);

    pPropSupport->colid = DB_NULLID;
    pPropSupport->dwOptions = pProp->dwOptions;

    //
    // set pPropSupport->vValue based on Variant type
    //
    switch (pProp->vtType) {
        case VT_BOOL:
            V_VT( &pPropSupport->vValue ) = VT_BOOL;
            V_BOOL( &pPropSupport->vValue ) = (SHORT)pProp->boolVal;
            break;

        case VT_I4:
            V_VT( &pPropSupport->vValue ) = VT_I4;
            V_I4( &pPropSupport->vValue ) = pProp->longVal;
            break;

        case VT_I2:
            V_VT( &pPropSupport->vValue ) = VT_I2;
            V_I2( &pPropSupport->vValue ) = (short)pProp->longVal;
            break;

        case VT_BSTR:
            //
            // If requesting password, get it from the credentials structure
            // as it is not stored anywhere else
            //
            if (IsDBInitPropSet &&
                pPropSupport->dwPropertyID == DBPROP_AUTH_PASSWORD)
            {
                PWSTR pszPassword = NULL;

                if (FAILED(_pCredentials->GetPassword(&pszPassword)))
                {
                    VariantClear( &pPropSupport->vValue );
                    return DB_S_ERRORSOCCURRED;
                }

                if (pszPassword)
                {
                    V_VT(&pPropSupport->vValue)  = VT_BSTR;
                    V_BSTR(&pPropSupport->vValue)= SysAllocString(pszPassword);

                    FreeADsMem(pszPassword);

                    if( V_BSTR(&pPropSupport->vValue) == NULL ) {
                        VariantClear( &pPropSupport->vValue );
                        return DB_S_ERRORSOCCURRED;
                    }
                }
            }
            else if( pProp->pwstrVal ) {
                V_VT(&pPropSupport->vValue)  = VT_BSTR;

                V_BSTR(&pPropSupport->vValue)= SysAllocString(pProp->pwstrVal);

                if( V_BSTR(&pPropSupport->vValue) == NULL ) {
                    VariantClear( &pPropSupport->vValue );
                    return DB_S_ERRORSOCCURRED;
                }
            }
            break;

        default:
            ADsAssert( !"LoadDBPROP unknown variant type!\n\r" );
            pPropSupport->dwStatus = DBPROPSTATUS_BADVALUE;
            RRETURN (DB_S_ERRORSOCCURRED);
            break;
    }
    //
    // all went well
    //
    pPropSupport->dwStatus = DBPROPSTATUS_OK;
    RRETURN(S_OK);
}



//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::StoreDBProp
//
//  Synopsis:  Helper for SetProperties. Loads field of DBPROP structure.
//
//  Arguments:
//
//  Returns:
//
//
//  Modifies:
//
//  History:    09-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUtilProp::StoreDBPROP (
    PROPSTRUCT* pPropStruct,
    PROPSTRUCT* pStaticPropStruct,
    ULONG       cProperties,
    DBPROP*     pPropSupport,
    DWORD       dwPropIndex
)
{
    // asserts
    ADsAssert( pPropStruct );
    ADsAssert( pPropSupport );

    ULONG i;
    HRESULT hr=S_OK;

    // Initialize the status to DBPROPSTATUS_OK
    pPropSupport->dwStatus = DBPROPSTATUS_OK;

    for (i=0; i < cProperties; i++) {
        if(pPropStruct[i].dwPropertyID == pPropSupport->dwPropertyID) {

            // arg checking for the prop
            if( pPropSupport->dwOptions != DBPROPOPTIONS_OPTIONAL &&
                pPropSupport->dwOptions != DBPROPOPTIONS_REQUIRED ) {
                pPropSupport->dwStatus = DBPROPSTATUS_BADOPTION;
                hr = DB_S_ERRORSOCCURRED;
                goto error;
            }

            if( (pPropStruct[i].vtType != V_VT(&pPropSupport->vValue) &&
                 V_VT(&pPropSupport->vValue) != VT_EMPTY) ||
                (IsValidValue(pPropSupport, dwPropIndex) == S_FALSE) ) {

                pPropSupport->dwStatus = DBPROPSTATUS_BADVALUE;
                hr = DB_S_ERRORSOCCURRED;
                goto error;
            }

            //
            // If property being set is password, we get out here.
            // Reason is we have already stored it in the Credentials structure
            // in encrypted form in the function IsVaidValue above.
            // We should not store it in plain text in pPropStruct[i].
            //
            if (dwPropIndex == INDEX_INIT &&
                pPropSupport->dwPropertyID == DBPROP_AUTH_PASSWORD)
            {
                pPropSupport->dwStatus = DBPROPSTATUS_OK;
                pPropStruct[i].dwOptions = pPropSupport->dwOptions;
                goto error;
            }

            if( !(pPropStruct[i].dwFlags & DBPROPFLAGS_WRITE) ) {
                // Check the value - if they are the same, do nothing
                if ( (V_VT(&pPropSupport->vValue) == VT_EMPTY) ||
                     ((V_VT(&pPropSupport->vValue) == VT_BOOL) &&
                      (pPropStruct[i].boolVal == V_BOOL(&pPropSupport->vValue))) ||
                     ((V_VT(&pPropSupport->vValue) == VT_I4) &&
                      (pPropStruct[i].longVal == V_I4(&pPropSupport->vValue))) ||
                     ((V_VT(&pPropSupport->vValue) == VT_I2) &&
                      ((short)pPropStruct[i].longVal == V_I2(&pPropSupport->vValue))) ||
                     ((V_VT(&pPropSupport->vValue) == VT_BSTR) && pPropStruct[i].pwstrVal &&
                      (wcscmp(pPropStruct[i].pwstrVal,V_BSTR(&pPropSupport->vValue)) == 0)) )

                    goto error;

                if( pPropSupport->dwOptions != DBPROPOPTIONS_OPTIONAL )
                    pPropSupport->dwStatus = DBPROPSTATUS_NOTSETTABLE;
                else
                    pPropSupport->dwStatus = DBPROPSTATUS_NOTSET;

                hr = DB_S_ERRORSOCCURRED;
                goto error;
            }

            switch (pPropStruct[i].vtType) {
                case VT_BOOL:
                    if( V_VT(&pPropSupport->vValue) != VT_EMPTY )
                        pPropStruct[i].boolVal = V_BOOL( &pPropSupport->vValue );
                    else
                        pPropStruct[i].boolVal = pStaticPropStruct[i].boolVal;
                    break;

                case VT_I4:
                    if( V_VT(&pPropSupport->vValue) != VT_EMPTY )
                        pPropStruct[i].longVal = V_I4( &pPropSupport->vValue );
                    else
                        pPropStruct[i].longVal = pStaticPropStruct[i].longVal;
                    break;

                case VT_I2:
                    if( V_VT(&pPropSupport->vValue) != VT_EMPTY )
                        pPropStruct[i].longVal = V_I2( &pPropSupport->vValue );
                    else
                        pPropStruct[i].longVal = pStaticPropStruct[i].longVal;
                    break;

                case VT_BSTR:
                    if(pPropStruct[i].pwstrVal) {
                        FreeADsStr(pPropStruct[i].pwstrVal);
                        pPropStruct[i].pwstrVal = NULL;
                    }

                    if( V_VT(&pPropSupport->vValue) == VT_EMPTY )
                        pPropStruct[i].pwstrVal = AllocADsStr(( pStaticPropStruct[i].pwstrVal ));
                    else
                    {
                        if (V_BSTR( &pPropSupport->vValue) == NULL &&
                            pPropSupport->dwPropertyID == DBPROP_AUTH_INTEGRATED)
                        {
                            //
                            // For integrated security, NULL bstrVal implies 'use default
                            // provider', which is "SSPI" for us. The reason we don't set
                            // the defult value to SSPI in the static structure is
                            // because this property is special. Unless set, it should
                            // not be used.
                            //
                            pPropStruct[i].pwstrVal = AllocADsStr(L"SSPI");
                        }
                        else
                            pPropStruct[i].pwstrVal = AllocADsStr(V_BSTR( &pPropSupport->vValue ));
                    }

                    if( !pPropStruct[i].pwstrVal &&
                        V_VT(&pPropSupport->vValue) == VT_BSTR ) {

                        hr = E_FAIL;
                        goto error;
                    }
                    break;

                default:
                    pPropSupport->dwStatus = DBPROPSTATUS_BADVALUE;
                    hr = DB_S_ERRORSOCCURRED;
                    goto error;
            }
            pPropSupport->dwStatus = DBPROPSTATUS_OK;
            pPropStruct[i].dwOptions = pPropSupport->dwOptions;
            break;
        }

    }

    if (i == cProperties) {
        pPropSupport->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
        hr = DB_E_ERRORSOCCURRED;
        goto error;
    }

error:
    RRETURN(hr);
}


//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::IsValidValue
//
//  Synopsis:  Helper for SetProperties. Check the valid values for the Property.
//
//  Arguments:
//
//  Returns:
//
//
//  Modifies:
//
//  History:    09-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
HRESULT
CUtilProp::IsValidValue
        (
        DBPROP*         pDBProp,
        DWORD           dwPropIndex
        )
{
    // Check BOOLEAN values
    if( (pDBProp->vValue.vt == VT_BOOL) &&
        !((V_BOOL(&(pDBProp->vValue)) == VARIANT_TRUE) ||
          (V_BOOL(&(pDBProp->vValue)) == VARIANT_FALSE)) )
        return S_FALSE;

    if( pDBProp->vValue.vt != VT_EMPTY &&
        dwPropIndex == INDEX_INIT )
    {
        switch( pDBProp->dwPropertyID )
        {
        case DBPROP_INIT_PROMPT:
            // These are the only values we support (from spec).
            if (!(V_I2(&pDBProp->vValue) == DBPROMPT_PROMPT ||
                  V_I2(&pDBProp->vValue) == DBPROMPT_COMPLETE ||
                  V_I2(&pDBProp->vValue) == DBPROMPT_COMPLETEREQUIRED ||
                  V_I2(&pDBProp->vValue) == DBPROMPT_NOPROMPT))
                return S_FALSE;
                break;

        case DBPROP_INIT_TIMEOUT:
            if( (pDBProp->vValue.vt == VT_I4) &&
                (V_I4(&pDBProp->vValue) < 0) )
                return S_FALSE;

            break;

        case DBPROP_AUTH_USERID:
            if( (!_pCredentials) ||
                (S_OK != _pCredentials->SetUserName(V_BSTR(&pDBProp->vValue))) )
                return S_FALSE;

                break;

        case DBPROP_AUTH_PASSWORD:
            if( (!_pCredentials) ||
                (S_OK != _pCredentials->SetPassword(V_BSTR(&pDBProp->vValue))) )
                return S_FALSE;

                break;

        case DBPROP_AUTH_INTEGRATED:
            //
            // For integrated security, NULL bstrVal implies 'use default
            // provider', which is "SSPI" for us.
            //
            if( ((pDBProp->vValue.vt != VT_BSTR) &&
                 (pDBProp->vValue.vt != VT_NULL))    ||
                ((V_BSTR(&pDBProp->vValue) != NULL) &&
                 (wcscmp(V_BSTR(&pDBProp->vValue), L"SSPI") != 0)))
                return S_FALSE;

            break;

        case DBPROP_INIT_MODE:
            if( (pDBProp->vValue.vt != VT_I4) ||
                    (S_FALSE == IsValidInitMode(V_I4(&pDBProp->vValue))) )
                return S_FALSE;

            break;

#if (!defined(BUILD_FOR_NT40))

        case DBPROP_INIT_BINDFLAGS:
            if( (pDBProp->vValue.vt != VT_I4) ||
                    (S_FALSE == IsValidBindFlag(V_I4(&pDBProp->vValue))) )
                return S_FALSE;

            break;
#endif

        case DBPROP_AUTH_ENCRYPT_PASSWORD:
            if( !_pCredentials )
                return S_FALSE;

            if( IsADSIFlagSet() )
                // override this property if the user set the authentication
                break;

            BOOL fAuthFlags = _pCredentials->GetAuthFlags();

            if( V_BOOL(&pDBProp->vValue) )
                _pCredentials->SetAuthFlags(fAuthFlags | ADS_SECURE_AUTHENTICATION);
            else
                _pCredentials->SetAuthFlags(fAuthFlags & ~ADS_SECURE_AUTHENTICATION);

            break;

        }
    }
    else if( pDBProp->vValue.vt != VT_EMPTY &&
             dwPropIndex == INDEX_ADSIBIND )
    {
        switch( pDBProp->dwPropertyID )
        {
            case ADSIPROP_ADSIFLAG:
                if( !_pCredentials )
                    // don't think this will ever happen
                    return S_FALSE;

                // prevent default initialization by VB from setting the
                // AUTH flags. The client should not specify ADS_AUTH_RESERVED
                // for this property (this might happen if the client behaves
                // like VB i.e, does GetProperties and then SetProperties 
                // without ORing in any flags. In this case, ENCRYPT_PASSWORD
                // will not be overwritten by this property due to this check).
                if( ADS_AUTH_RESERVED == (V_I4(&pDBProp->vValue)) )
                    break;

                // the following call might overwrite ENCRYPT_PASSWORD
                _pCredentials->SetAuthFlags((V_I4(&pDBProp->vValue)) & 
                                                     (~ADS_AUTH_RESERVED) );

                break;

        }
    }
    else if( pDBProp->vValue.vt != VT_EMPTY &&
             dwPropIndex == INDEX_SESSION )
    {
        switch( pDBProp->dwPropertyID )
        {
            case DBPROP_SESS_AUTOCOMMITISOLEVELS:
                // These are the only values we support (from spec).
                if( (pDBProp->vValue.vt == VT_I4) &&
                     (V_I4(&pDBProp->vValue) != 0                            &&
                      V_I4(&pDBProp->vValue) != DBPROPVAL_TI_CHAOS           &&
                      V_I4(&pDBProp->vValue) != DBPROPVAL_TI_READUNCOMMITTED &&
                      V_I4(&pDBProp->vValue) != DBPROPVAL_TI_READCOMMITTED   &&
                      V_I4(&pDBProp->vValue) != DBPROPVAL_TI_REPEATABLEREAD  &&
                      V_I4(&pDBProp->vValue) != DBPROPVAL_TI_SERIALIZABLE) )
                    return S_FALSE;

                break;
        }
    }
    else if( pDBProp->vValue.vt != VT_EMPTY &&
             dwPropIndex == INDEX_ROWSET )
    {
        switch( pDBProp->dwPropertyID )
        {
            case DBPROP_MAXOPENROWS:
                if( (pDBProp->vValue.vt != VT_I4) || 
                    (V_I4(&pDBProp->vValue) < 0) )
                    return S_FALSE;

                    break;
        }
    }

    return S_OK;    // Is valid
}

//----------------------------------------------------------------------------
// IsValidInitMode
//
// Checks if a given value is a valid value for DBPROP_INIT_MODE
//
//----------------------------------------------------------------------------
HRESULT
CUtilProp::IsValidInitMode(
    long lVal
    )
{
    // check if any bit that shouldn't be set is actually set
    if( lVal & (~(DB_MODE_READWRITE | 
                  DB_MODE_SHARE_EXCLUSIVE | DB_MODE_SHARE_DENY_NONE)) )
        return S_FALSE;
 
    return S_OK;

}

//---------------------------------------------------------------------------
// IsValidInitBindFlag
//
// Checks if a given value is a valid value for DBPROP_INIT_BINDFLAGS
//
//---------------------------------------------------------------------------
HRESULT
CUtilProp::IsValidBindFlag(
    long lVal
    )
{
#if (!defined(BUILD_FOR_NT40))
    // check if any bit that shouldn't be set is actually set
    if( lVal & (~(DB_BINDFLAGS_DELAYFETCHCOLUMNS | 
                  DB_BINDFLAGS_DELAYFETCHSTREAM | DB_BINDFLAGS_RECURSIVE |
                  DB_BINDFLAGS_OUTPUT | DB_BINDFLAGS_COLLECTION |
                  DB_BINDFLAGS_OPENIFEXISTS | DB_BINDFLAGS_OVERWRITE |
                  DB_BINDFLAGS_ISSTRUCTUREDDOCUMENT)) )
        return S_FALSE;

    // check for mutually exclusive flags
    if( (lVal & DB_BINDFLAGS_OPENIFEXISTS) &&
            (lVal & DB_BINDFLAGS_OVERWRITE) )
        return S_FALSE;

    return S_OK;
#else
    return E_FAIL;
#endif
}

//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::GetPropertiesArgChk
//
//  Synopsis:  Initialize the buffers and check for E_INVALIDARG
//
//  Arguments:
//             cPropertyIDSets       # of restiction property IDs
//             rgPropertyIDSets[]    restriction guids
//             pcPropertySets        count of properties returned
//             prgPropertySets       property information returned
//             dwBitMask             which property group
//
//  Returns:
//             S_OK          | The method succeeded
//             E_INVALIDARG  | pcPropertyIDSets or prgPropertyInfo was NULL
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
HRESULT
CUtilProp::GetPropertiesArgChk(
        ULONG                           cPropertySets,
        const DBPROPIDSET               rgPropertySets[],
        ULONG*                          pcProperties,
        DBPROPSET**                     prgProperties,
        DWORD                           dwBitMask
    )
{
    // Initialize values
    if( pcProperties )
        *pcProperties = 0;
    if( prgProperties )
        *prgProperties = NULL;

    // Check Arguments
    if( ((cPropertySets > 0) && !rgPropertySets) ||
         !pcProperties || !prgProperties )
        RRETURN ( E_INVALIDARG );

    // New argument check for > 1 cPropertyIDs and NULL pointer for
    // array of property ids.
    for(ULONG ul=0; ul<cPropertySets; ul++)
    {
        if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) )
            RRETURN ( E_INVALIDARG );

        // Check for propper formation of DBPROPSET_PROPERTIESINERROR
        if( ((dwBitMask & PROPSET_DSO) || (dwBitMask & PROPSET_COMMAND)) &&
            (rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
        {
            if( (cPropertySets > 1) ||
                (rgPropertySets[ul].cPropertyIDs != 0) ||
                (rgPropertySets[ul].rgPropertyIDs != NULL) )
                 RRETURN ( E_INVALIDARG );
        }
    }

    RRETURN ( S_OK );
}

//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::GetPropertyInfo
//
//  Synopsis:  Returns information about rowset and data source properties
//            supported by the provider
//
//  Arguments:
//              cPropertyIDSets             # properties
//              rgPropertyIDSets[]          Array of property sets
//              pcPropertyInfoSets          # DBPROPSET structures
//              prgPropertyInfoSets         DBPROPSET structures property
//                                          information returned
//              ppDescBuffer                Property descriptions
//
//  Returns:
//             S_OK          | The method succeeded
//             E_INVALIDARG  | pcPropertyIDSets or prgPropertyInfo was NULL
//             E_OUTOFMEMORY | Out of memory
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------

STDMETHODIMP CUtilProp::GetPropertyInfo
(
    ULONG                cPropertyIDSets,
    const DBPROPIDSET    rgPropertyIDSets[],
    ULONG*               pcPropertyInfoSets,
    DBPROPINFOSET**      pprgPropertyInfoSets,
    WCHAR**              ppDescBuffer,
    BOOL                 fDSOInitialized
    )
{
    DBPROPINFO*      pPropInfo = NULL;
    DBPROPINFOSET*   pPropInfoSet = NULL;
    BOOL             fNoPropInfoGot = TRUE;
    BOOL             fWarning=FALSE;
    HRESULT          hr;
    LPWSTR           pwszDescBuffer=NULL;
    ULONG            cPropertySets=0, cProperties=0;
    ULONG            cCount, j, i;
    ULONG            cNewPropIDSets    = 0;
    BOOL             fIsSpecialGUID    = FALSE;
    BOOL             fIsNotSpecialGUID = FALSE;
    ULONG            ul;
    BOOL             fNewDescription = TRUE;

    // asserts
    ADsAssert( _pIMalloc );

    // init out params
    if( pcPropertyInfoSets )
        *pcPropertyInfoSets = 0;
    if( pprgPropertyInfoSets )
        *pprgPropertyInfoSets = NULL;
    if( ppDescBuffer )
        *ppDescBuffer = NULL;

    // Check Arguments, on failure post HRESULT to error queue
    if( (cPropertyIDSets > 0 && !rgPropertyIDSets) ||
        !pcPropertyInfoSets || !pprgPropertyInfoSets )
        RRETURN( E_INVALIDARG );

    // New argument check for > 1 cPropertyIDs and NULL pointer for
    // array of property ids.
    for(ul=0; ul<cPropertyIDSets; ul++)
    {
        if( rgPropertyIDSets[ul].cPropertyIDs &&
            !rgPropertyIDSets[ul].rgPropertyIDs )
            RRETURN( E_INVALIDARG );

        // Add 1 for the Provider Specific Rowset Properties
        if( (rgPropertyIDSets[ul].guidPropertySet == DBPROPSET_DBINITALL) ||
            (fDSOInitialized &&
            rgPropertyIDSets[ul].guidPropertySet == DBPROPSET_ROWSETALL) )
            cNewPropIDSets++;

        //
        // Special Guids for Property Sets can not be mixed with ordinary
        // Property Set Guids. Either one or the other, not both
        //
        if (IsSpecialGuid(rgPropertyIDSets[ul].guidPropertySet))
            fIsSpecialGUID = TRUE;
        else
            fIsNotSpecialGUID = TRUE;

        if( fIsSpecialGUID && fIsNotSpecialGUID )
            RRETURN( E_INVALIDARG );
    }

    // save the count of PropertyIDSets
    cNewPropIDSets += cPropertyIDSets;

    // If the consumer does not restrict the property sets
    // by specify an array of property sets and a cPropertySets
    // greater than 0, then we need to make sure we
    // have some to return
    if( cPropertyIDSets == 0 )
    {
        if( fDSOInitialized )
            cNewPropIDSets = NUMBER_OF_SUPPORTED_PROPERTY_SETS;
        else
            // we have 2 property sets in the DBINIT property group
            cNewPropIDSets = 2;
    }

    // use task memory allocater to alloc a DBPROPINFOSET struct
    pPropInfoSet = (DBPROPINFOSET*) _pIMalloc->Alloc(cNewPropIDSets *
                                                                                                sizeof( DBPROPINFOSET ));
    if( !pPropInfoSet )
        BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );

    memset( pPropInfoSet, 0, (cNewPropIDSets * sizeof( DBPROPINFOSET )));

    if( ppDescBuffer )
    {
        // Allocating more memory than actually required, since 
        // _dwDescBufferLen is th etotal for all property sets together, not
        // just for one property set 
        pwszDescBuffer = (LPWSTR) _pIMalloc->Alloc(_dwDescBufferLen * cNewPropIDSets);
        if( !pwszDescBuffer )
            BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );

        memset( pwszDescBuffer, 0, _dwDescBufferLen * cNewPropIDSets);
        *ppDescBuffer = pwszDescBuffer;
    }

    // If no restrictions return all properties from the three supported property sets
    if( cPropertyIDSets == 0 )
    {
        // Fill in all of the Providers Properties
        for (j=0; j< cNewPropIDSets; j++)
            pPropInfoSet[j].guidPropertySet = *s_rgPropertySets[j].guidPropertySet;
    }
    else
    {
        cCount = 0;

        //
        // Deal with the Special GUID's
        //
        for (j=0; j< cPropertyIDSets; j++)
        {
            if( rgPropertyIDSets[j].guidPropertySet == DBPROPSET_DBINITALL )
            {
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_DBINIT;
                // Adjust for ADSI_BIND (provider specific) property set
                cCount++;
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_ADSIBIND;
            }
            else if( fDSOInitialized &&
                     rgPropertyIDSets[j].guidPropertySet == DBPROPSET_DATASOURCEINFOALL )
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_DATASOURCEINFO;
            else if( fDSOInitialized &&
                     rgPropertyIDSets[j].guidPropertySet == DBPROPSET_SESSIONALL )
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_SESSION;
            else if( fDSOInitialized &&
                    rgPropertyIDSets[j].guidPropertySet == DBPROPSET_ROWSETALL )
            {
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_ROWSET;
                // Adjust for the Provider Specific
                cCount++;
                pPropInfoSet[cCount].guidPropertySet = DBPROPSET_ADSISEARCH;
            }
            else
            {
                pPropInfoSet[cCount].guidPropertySet = rgPropertyIDSets[j].guidPropertySet;
                pPropInfoSet[cCount].cPropertyInfos  = rgPropertyIDSets[j].cPropertyIDs;
            }

            cCount++;
        }
    }

    //
    // For each supported Property Set
    //
    for (cPropertySets=0;
        cPropertySets < cNewPropIDSets;
        cPropertySets++)
    {
        // Set cProperties to the numerber passed in
        cProperties = pPropInfoSet[cPropertySets].cPropertyInfos;
        pPropInfo = NULL;

        // Get the correct Static data. We have 2 property sets in the
        // INIT property group. Note that we assume that both these property
        // sets occur successively in s_rgPropertySets.
        for (j=0; j< (fDSOInitialized ? NUMELEM(s_rgPropertySets) : 2); j++) {
            if( IsEqualGUID(pPropInfoSet[cPropertySets].guidPropertySet,
                            *(s_rgPropertySets[j].guidPropertySet)) ) {
                if( pPropInfoSet[cPropertySets].cPropertyInfos == 0 )
                    cProperties = s_rgPropertySets[j].cProperties;
                break;
            }
        }

        if( cProperties )
        {
            //
            // use task memory allocater to alloc array of DBPROPINFO structs
            //
            pPropInfo = (DBPROPINFO*) _pIMalloc->Alloc(cProperties * sizeof( DBPROPINFO ));
            if( !pPropInfo ) {
                for (i=0; i<cNewPropIDSets; i++)
                    _pIMalloc->Free(pPropInfoSet[i].rgPropertyInfos);
                BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );
            }

            memset(pPropInfo, 0, cProperties * sizeof(DBPROPINFO));

            for (cCount=0; cCount < cProperties; cCount++)
            {
                if( pPropInfoSet[cPropertySets].cPropertyInfos == 0 )
                    pPropInfo[cCount].dwPropertyID =
                               s_rgPropertySets[j].pUPropInfo[cCount].dwPropertyID;
                else
                    pPropInfo[cCount].dwPropertyID =
                                  rgPropertyIDSets[cPropertySets].rgPropertyIDs[cCount];

                // set the description pointer. If this property was already 
                // requested in this call, then we reuse the same description
                // pointer. 
                DWORD dwTmp;
                for(dwTmp = 0; dwTmp < cCount; dwTmp++)
                    if(pPropInfo[dwTmp].dwPropertyID == 
                                   pPropInfo[cCount].dwPropertyID) 
                    // same property requested more than once
                        break;

                if(dwTmp == cCount)
                {
                    fNewDescription = TRUE;
                    pPropInfo[cCount].pwszDescription = pwszDescBuffer;
                }
                else
                {
                    fNewDescription = FALSE;
                    pPropInfo[cCount].pwszDescription = 
                                      pPropInfo[dwTmp].pwszDescription;
                }

                hr = LoadDBPROPINFO(
                        ((j < (fDSOInitialized ? NUMELEM(s_rgPropertySets) : 2)) ?
                                        s_rgPropertySets[j].pUPropInfo  : NULL),
                        ((j < (fDSOInitialized ? NUMELEM(s_rgPropertySets) : 2)) ?
                                        s_rgPropertySets[j].cProperties : 0),
                         &pPropInfo[cCount]
                         );

                if( FAILED(hr) ) {
                    ULONG ulFor;
                    //
                    // something went wrong
                    // clear all variants used so far..
                    //
                    for (ulFor = 0; ulFor < cCount; ulFor++)
                        VariantClear( &pPropInfo[ulFor].vValues );

                    //
                    // .. delete the pPropInfo array, return failure
                    //
                    for (i=0; i<cNewPropIDSets; i++)
                        _pIMalloc->Free(pPropInfoSet[i].rgPropertyInfos);

                    _pIMalloc->Free(pPropInfo);
                    BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );
                }

                if( hr != S_OK )
                    fWarning = TRUE;
                else
                    fNoPropInfoGot = FALSE;

                // move the description pointer to the next, if required
                if( pPropInfo[cCount].pwszDescription && fNewDescription)
                    pwszDescBuffer += (wcslen(pPropInfo[cCount].pwszDescription) + 1);
            }
        }
        else
            fWarning = TRUE;

        pPropInfoSet[cPropertySets].rgPropertyInfos = pPropInfo;
        pPropInfoSet[cPropertySets].cPropertyInfos = cProperties;
    }    // for each property set

    //
    // set count of properties and property information
    //
    *pcPropertyInfoSets= cNewPropIDSets;
    *pprgPropertyInfoSets = pPropInfoSet;

    if( fNoPropInfoGot ) {
        if( ppDescBuffer )
            *ppDescBuffer = NULL;
        if( pwszDescBuffer )
            _pIMalloc->Free(pwszDescBuffer);
        RRETURN ( DB_E_ERRORSOCCURRED );
    }
    else if( fWarning )
       RRETURN ( DB_S_ERRORSOCCURRED );
    else
       RRETURN ( S_OK );

error:

    if( pPropInfoSet )
        _pIMalloc->Free(pPropInfoSet);
    if( pwszDescBuffer )
        _pIMalloc->Free(pwszDescBuffer);

        RRETURN ( hr );
}

//----------------------------------------------------------------------------
// IsSpecialGuid
//
// Check if the the property set GUID is one of the special GUIDs
//
//----------------------------------------------------------------------------
BOOL CUtilProp::IsSpecialGuid(
    GUID guidPropSet
    )
{
    if( (DBPROPSET_ROWSETALL == guidPropSet) || 
        (DBPROPSET_DATASOURCEALL == guidPropSet) ||
        (DBPROPSET_DATASOURCEINFOALL == guidPropSet) ||
        (DBPROPSET_SESSIONALL == guidPropSet) ||
        (DBPROPSET_DBINITALL == guidPropSet) 

#if (!defined(BUILD_FOR_NT40)) 
                                             ||
        (DBPROPSET_COLUMNALL == guidPropSet) ||
        (DBPROPSET_CONSTRAINTALL == guidPropSet) ||
        (DBPROPSET_INDEXALL == guidPropSet) ||
        (DBPROPSET_TABLEALL == guidPropSet) ||
        (DBPROPSET_TRUSTEEALL == guidPropSet) ||
        (DBPROPSET_VIEWALL == guidPropSet) 
#endif
                                         )
        
        return TRUE;
    else
        return FALSE;
} 

//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::GetProperties
//
//  Synopsis:  Returns current settings of all properties supported
//             by the DSO/rowset
//
//  Arguments:
//
//             cPropertyIDSets       # of restiction property IDs
//             rgPropertyIDSets[]    restriction guids
//             pcPropertySets        count of properties returned
//             prgPropertySets       property information returned
//
//
//  Returns:
//             S_OK          | The method succeeded
//             E_INVALIDARG  | pcPropertyIDSets or prgPropertyInfo was NULL
//             E_OUTOFMEMORY | Out of memory
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP CUtilProp::GetProperties
(
    ULONG               cPropertyIDSets,
    const DBPROPIDSET   rgPropertyIDSets[],
    ULONG*              pcPropertySets,
    DBPROPSET**         pprgPropertySets,
    DWORD               dwBitMask
    )
{
    ULONG       cPropertySets, cProperties;
    ULONG       cNewPropIDSets = 0;
    ULONG       cCount, j, i;
    DBPROP*     pProp = NULL;
    DBPROPSET*  pPropSet = NULL;
    HRESULT     hr = E_FAIL;
    BOOL        fNoPropertyGot = TRUE;
    BOOL        fWarning = FALSE;
    BOOL        fFound = FALSE;
    ULONG       cOffset = 0;

    // asserts
    ADsAssert(_pIMalloc);

    // Assign in the count
    cNewPropIDSets = cPropertyIDSets;

    // If the consumer does not restrict the property sets
    // by specify an array of property sets and a cPropertySets
    // greater than 0, then we need to make sure we
    // have some to return
    if( cPropertyIDSets == 0 )
    {
        // Set the count of properties
        cNewPropIDSets = 1;

        if(dwBitMask & PROPSET_DSO)
        {
            if(dwBitMask & PROPSET_INIT)
                // if the data src object has been initialized, return
                // properties in the DBInit, DSInfo and ADSIBind property sets.
                cNewPropIDSets = 3;
            else
                // Return DBInit and ADSIBind property sets only. Note that we
                // are counting on ADSIBind being the second property set in
                // s_rgPropertySets, since we are leaving cOffset as 0
                cNewPropIDSets = 2;
        }

         if(dwBitMask & PROPSET_COMMAND)
            cNewPropIDSets = 2;
    }

    // Figure out the Offset
    if( dwBitMask & PROPSET_SESSION )
        cOffset = INDEX_SESSION;
    else if( dwBitMask & PROPSET_COMMAND )
        cOffset = INDEX_ROWSET;

    //
    // use task memory allocater to alloc a DBPROPSET struct
    //
    pPropSet = (DBPROPSET*) _pIMalloc->Alloc(cNewPropIDSets * sizeof( DBPROPSET ));

    if( !pPropSet )
        BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );

    memset( pPropSet, 0, (cNewPropIDSets * sizeof( DBPROPSET )));

    //
    // For each supported Property Set
    //
    for (cPropertySets=0; cPropertySets < cNewPropIDSets; cPropertySets++) {

        // Initialize variable
        ULONG cPropOffset = 0;
        int cNumDSOProps = 0;
        cProperties = 0;
        pProp = NULL;
        fFound = FALSE;

        // Setup the PropSet GUID
        if( cPropertyIDSets == 0 ) {
            pPropSet[cPropertySets].guidPropertySet =
                       *s_rgPropertySets[cPropertySets+cOffset].guidPropertySet;
        }
        else {
            cProperties = rgPropertyIDSets[cPropertySets].cPropertyIDs;
            pPropSet[cPropertySets].guidPropertySet =
                    rgPropertyIDSets[cPropertySets].guidPropertySet;
        }

        if(dwBitMask & PROPSET_DSO)
             // we have 2 property sets whose properties can be set before
             // initialization and one whose properties can be set only after
             // init. Set the count of properties accordingly.
             cNumDSOProps = 1 + !!(dwBitMask & PROPSET_INIT);

        // Setup the count of Properties for that PropSet
        for (j=0;
             j <= cOffset+ cNumDSOProps + !!(dwBitMask & PROPSET_COMMAND);
             j++) {
            if( j >= cOffset &&
                IsEqualGUID(pPropSet[cPropertySets].guidPropertySet,
                            *(s_rgPropertySets[j].guidPropertySet)) ) {
                if (rgPropertyIDSets == NULL ||
                    rgPropertyIDSets[cPropertySets].cPropertyIDs == 0)
                    cProperties = s_rgPropertySets[j].cProperties;

                fFound = TRUE;
                break;
            }

            // Move to the next PropSet
            cPropOffset += s_rgPropertySets[j].cProperties;
        }

        if( cProperties != 0 ) {
            // use task memory allocator to alloc array of DBPROP struct
            pProp = (DBPROP*) _pIMalloc->Alloc(cProperties * sizeof( DBPROP ));

            if( pProp == NULL ) {
                for (i=0; i < cPropertySets; i++)
                    _pIMalloc->Free(pPropSet[i].rgProperties);

                BAIL_ON_FAILURE ( hr=E_OUTOFMEMORY );
            }

            memset( pProp, 0, (cProperties * sizeof( DBPROP )));

            if( rgPropertyIDSets == NULL ||
                rgPropertyIDSets[cPropertySets].cPropertyIDs == 0 ) {
                for (cCount=0; cCount < cProperties; cCount++)
                    pProp[cCount].dwPropertyID =
                        s_rgPropertySets[j-!fFound].pUPropInfo[cCount].dwPropertyID;
            }
            else {
                for (cCount=0; cCount < cProperties; cCount++)
                    pProp[cCount].dwPropertyID =
                        rgPropertyIDSets[cPropertySets].rgPropertyIDs[cCount];
            }
        }
        else
            fWarning = TRUE;

        //
        // for each prop in our table..
        //
        for (cCount = 0; cCount < cProperties; cCount++) {
            hr = LoadDBPROP((fFound ? &(_prgProperties[cPropOffset]) :  NULL),
                            (fFound ? s_rgPropertySets[j-!fFound].cProperties : 0),
                            &pProp[cCount],
                            pPropSet[cPropertySets].guidPropertySet == DBPROPSET_DBINIT
                            );

            if( FAILED(hr) ) {
                // something went wrong
                // clear all variants used so far..
                for (i=0; i < cCount; i++)
                    VariantClear( &pProp[i].vValue );

                for (i=0; i < cPropertySets; i++)
                    _pIMalloc->Free(pPropSet[i].rgProperties);

                                _pIMalloc->Free(pProp);

                BAIL_ON_FAILURE( hr );
            }

            if( hr != S_OK )
                fWarning = TRUE;
            else
                fNoPropertyGot = FALSE;

        }    // for each property

        pPropSet[cPropertySets].rgProperties = pProp;
        pPropSet[cPropertySets].cProperties = cProperties;
    }    // for each property set

    // set count of properties and property informatio
    *pcPropertySets   = cNewPropIDSets;
    *pprgPropertySets = pPropSet;

    if( fNoPropertyGot )
       RRETURN( DB_E_ERRORSOCCURRED );
    else if( fWarning )
       RRETURN( DB_S_ERRORSOCCURRED );
    else
       RRETURN( S_OK );

error:
    if( pPropSet )
        _pIMalloc->Free(pPropSet);
    RRETURN( hr );
}


//+---------------------------------------------------------------------------
//
//  Function:  CUtilProp::SetProperties
//
//  Synopsis:  Set current settings of properties supported by the DSO/rowset
//
//  Arguments:
//
//             cPropertyIDSets,      # of DBPROPSET
//             rgPropertyIDSets[]    Array of property sets
//
//  Returns:
//             S_OK          | The method succeeded
//             E_INVALIDARG  | pcPropertyIDSets or prgPropertyInfo was NULL
//             E_OUTOFMEMORY | Out of memory
//
//  Modifies:
//
//  History:    08-28-96   ShankSh     Created.
//
//----------------------------------------------------------------------------
STDMETHODIMP
CUtilProp::SetProperties(
    ULONG cPropertySets,
    DBPROPSET rgPropertySets[],
    DWORD dwBitMask
    )
{
    ULONG cCount, j, k;
    HRESULT hr;
    BOOL fNoPropertySet = TRUE;
    BOOL fWarning = FALSE;

    // check params
    if( cPropertySets > 0 && !rgPropertySets )
        RRETURN ( E_INVALIDARG );

    // New argument check for > 1 cPropertyIDs and NULL pointer for
    // array of property ids.
    for(ULONG ul=0; ul<cPropertySets; ul++)
    {
        if( rgPropertySets[ul].cProperties &&
            !(rgPropertySets[ul].rgProperties) )
            RRETURN ( E_INVALIDARG );
    }

    for (cCount=0; cCount < cPropertySets; cCount++) {
        // Not legal to Set INIT or DATASOURCE properties after Initializing
        if( (dwBitMask & PROPSET_INIT) &&
            (rgPropertySets[cCount].guidPropertySet == DBPROPSET_DBINIT) ) {
            //
            // Wrong time to set these Properties
            //
            for (k=0; k < rgPropertySets[cCount].cProperties; k++) {
                rgPropertySets[cCount].rgProperties[k].dwStatus = DBPROPSTATUS_NOTSETTABLE;
                fWarning = TRUE;
            }
            continue;
        }

        // Trying to set the wrong Property Set
        if( ((dwBitMask & PROPSET_DSO) && !(dwBitMask & PROPSET_INIT) &&
             (rgPropertySets[cCount].guidPropertySet != DBPROPSET_DBINIT &&
              rgPropertySets[cCount].guidPropertySet != DBPROPSET_ADSIBIND)) ||
            ((dwBitMask & PROPSET_DSO) && (dwBitMask & PROPSET_INIT) &&
             rgPropertySets[cCount].guidPropertySet != DBPROPSET_DATASOURCEINFO) ||
            ((dwBitMask & PROPSET_SESSION) &&
             rgPropertySets[cCount].guidPropertySet != DBPROPSET_SESSION) ||
            ((dwBitMask & PROPSET_COMMAND) &&
             rgPropertySets[cCount].guidPropertySet != DBPROPSET_ROWSET &&
             rgPropertySets[cCount].guidPropertySet != DBPROPSET_ADSISEARCH) ) {

            //
            // Wrong Property Set
            //
            for (k=0; k < rgPropertySets[cCount].cProperties; k++) {
                rgPropertySets[cCount].rgProperties[k].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
                fWarning = TRUE;
            }
            continue;
        }

        ULONG cPropOffset = 0;

        for (j=0; j< NUMELEM(s_rgPropertySets); j++) {
            if (IsEqualGUID(rgPropertySets[cCount].guidPropertySet,
                            *(s_rgPropertySets[j].guidPropertySet))) {
                for (k=0; k < rgPropertySets[cCount].cProperties; k++) {
                    hr = StoreDBPROP(&(_prgProperties[cPropOffset]),
                                     s_rgPropertySets[j].pUPropInfo,
                                     s_rgPropertySets[j].cProperties,
                                     &(rgPropertySets[cCount].rgProperties[k]),
                                     j );

                    if( hr != S_OK )
                        fWarning = TRUE;
                    else
                        fNoPropertySet = FALSE;
                }
                break;
            }
            // Move to the next PropSet
            cPropOffset += s_rgPropertySets[j].cProperties;
        }
    }

    if ( fNoPropertySet && fWarning )
       RRETURN ( DB_E_ERRORSOCCURRED );
    else if (fWarning)
       RRETURN ( DB_S_ERRORSOCCURRED );
    else
       RRETURN ( S_OK );
}


BOOL
CUtilProp::IsIntegratedSecurity(
    void
    )
{
    // Check to see if SSPI is set
    for (ULONG i=0; i< s_rgPropertySets[INDEX_INIT].cProperties; i++) {
        if( _prgProperties[i].dwPropertyID == DBPROP_AUTH_INTEGRATED)
        {
            if (_prgProperties[i].pwstrVal )
                return( wcscmp(_prgProperties[i].pwstrVal, L"SSPI") == 0 );
            break;
        }
    }

    return FALSE;
}

BOOL
CUtilProp::IsADSIFlagSet()
{
    ULONG PropSetOffset = 0, i;

    for(i = 0; i < INDEX_ADSIBIND; i++)
          PropSetOffset += s_rgPropertySets[i].cProperties;

    // Check if "ADSI Flag" is set to something other than ADS_AUTH_RESERVED 
    for (i=0; i < s_rgPropertySets[INDEX_ADSIBIND].cProperties; i++)
        if(_prgProperties[i+PropSetOffset].dwPropertyID == ADSIPROP_ADSIFLAG)
             return (_prgProperties[i+PropSetOffset].longVal != 
                                                           ADS_AUTH_RESERVED);

    // we should never get here
    return FALSE;
}