//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1998 - 2002
//
//  File:       util.h
//
//--------------------------------------------------------------------------

#ifndef _UTIL_H__
#define _UTIL_H__

#include <dsclient.h>
#include "stlutil.h"
#include "dscmn.h"
///////////////////////////////////////////////////////////////////////
// MACROS


// flags to interpret the DSSEC.DAT file values (from JeffreyS)
#define IDC_CLASS_NO_CREATE     0x00000001
#define IDC_CLASS_NO_DELETE     0x00000002
#define IDC_CLASS_NO_INHERIT    0x00000004
#define IDC_PROP_NO_READ        0x00000001
#define IDC_PROP_NO_WRITE       0x00000002

// derived flags
#define IDC_CLASS_NO (IDC_CLASS_NO_CREATE | IDC_CLASS_NO_DELETE | IDC_CLASS_NO_INHERIT)
#define IDC_PROP_NO (IDC_PROP_NO_READ | IDC_PROP_NO_WRITE)

///////////////////////////////////////////////////////////////////////
// strings

// special classes

extern PWSTR g_wzRootDSE;
extern PWSTR g_wzSchemaNamingContext;
extern PWSTR g_wzLDAPAbstractSchemaFormat;


// fwd decl
class CAdsiObject;
class CErrorMessageHandlerBase;

///////////////////////////////////////////////////////////////////////
// CWString

class CWString : public wstring
{
public:
  operator LPCWSTR() { return c_str(); }
  CWString& operator=(LPCWSTR lpsz)
  {
    if (lpsz == NULL)
      lpsz = L"";
    *((wstring*)this) = lpsz;
    return *this;
  }
  BOOL LoadFromResource(UINT uID);
};


///////////////////////////////////////////////////////////////////////
// GLOBAL FUNCTIONS


BOOL LoadStringHelper(UINT uID, LPTSTR lpszBuffer, int nBufferMax);

BOOL GetStringFromHRESULTError(HRESULT hr, CWString& szErrorString, BOOL bTryADsIErrors = TRUE);
BOOL GetStringFromWin32Error(DWORD dwErr, CWString& CWString);

inline HRESULT ADsOpenObjectHelper(LPCWSTR lpszPathName, REFIID riid,DWORD dwFlags, void** ppObject)
{
  static DWORD additionalFlags = GetADsOpenObjectFlags();

  dwFlags |= additionalFlags;
  dwFlags |= ADS_SECURE_AUTHENTICATION;


  return ADsOpenObject((LPWSTR)lpszPathName,
                        NULL, //LPWSTR lpszUserName,
                        NULL, //LPWSTR lpszPassword,
                        dwFlags, //DWORD  dwReserved,
                        riid,    
                        ppObject
                        );
}



HRESULT InitCheckAccess( HWND hwndParent, LPCWSTR pszObjectLADPPath );


// functions to access DSSEC.DAT
ULONG GetClassFlags(LPCWSTR lpszClassName);
ULONG GetAttributeFlags(LPCWSTR lpszClassName, LPCWSTR lpszAttr);

void BuildLdapPathHelper(LPCWSTR lpszServerName, LPCWSTR lpszNamingContext, CWString& szLdapPath);
void BuildWin32PathHelper(LPCWSTR lpszServerName, LPCWSTR lpszNamingContext, CWString& szWin32Path);

HRESULT GetCanonicalNameFromNamingContext(LPCWSTR lpszNamingContext, CWString& szCanonicalName);

HRESULT GetGlobalNamingContexts(LPCWSTR lpszServerName, 
                                CWString& szPhysicalSchemaNamingContext,
                                CWString& szConfigurationNamingContext);


extern LPCWSTR g_lpszSummaryIdent;
extern LPCWSTR g_lpszSummaryNewLine;

void WriteSummaryTitleLine(CWString& szSummary, UINT nTitleID, LPCWSTR lpszNewLine);
void WriteSummaryLine(CWString& szSummary, LPCWSTR lpsz, LPCWSTR lpszIdent, LPCWSTR lpszNewLine);

DWORD AddObjectRightInAcl(IN      PSID pSid, 
                          IN      ULONG uAccess, 
                          IN      const GUID* pRightGUID, 
                          IN      const GUID* pInheritGUID, 
                          IN OUT  PACL* ppAcl);

///////////////////////////////////////////////////////////////////////
//////////////////////////// HELPER CLASSES ///////////////////////////



///////////////////////////////////////////////////////////////////////
// CWaitCursor

class CWaitCursor
{
public:
  CWaitCursor()
  {
    m_hCurrentCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));
  }
  ~CWaitCursor()
  {
    ::SetCursor(m_hCurrentCursor);
  }
private:
  HCURSOR m_hCurrentCursor;
};




BOOL FormatStringGUID(LPWSTR lpszBuf, UINT nBufSize, const GUID* pGuid);

BOOL GuidFromString(GUID* pGuid, LPCWSTR lpszGuidString);

///////////////////////////////////////////////////////////////////////
// CFilterBase

class CFilterBase
{
public:
  virtual BOOL CanAdd(LPCWSTR lpsz, ULONG* pFilterFlags) = 0;
};

///////////////////////////////////////////////////////////////////////
// CSidHolder

class CSidHolder
{
public:
  CSidHolder()
  {
    _Init();
  }
  ~CSidHolder()
  {
    _Free();
  }
  
  PSID Get()
  {
    return m_pSID;
  }

  BOOL Copy(PSID p)
  {
    _Free();
    return _Copy(p);
  }

  void Attach(PSID p, BOOL bLocalAlloc)
  {
    _Free();
    m_pSID = p;
    m_bLocalAlloc = bLocalAlloc;
  }

private:
  void _Init()
  {
    m_pSID = NULL;
    m_bLocalAlloc = TRUE;
  }

  void _Free()
  {
    if (m_pSID != NULL)
    {
      if (m_bLocalAlloc)
        ::LocalFree(m_pSID);
      else
        ::FreeSid(m_pSID);
      _Init();
    }
  }

  BOOL _Copy(PSID p)
  {
    if ( (p == NULL) || !::IsValidSid(p) )
      return FALSE;
    DWORD dwLen = ::GetLengthSid(p);
    PSID pNew = ::LocalAlloc(LPTR, dwLen);
    if(!pNew)
        return FALSE;   
    if (!::CopySid(dwLen, pNew, p))
    {
      ::LocalFree(pNew);
      return FALSE;
    }
    m_bLocalAlloc = TRUE;
    m_pSID = pNew;
    ASSERT(dwLen == ::GetLengthSid(m_pSID));
    ASSERT(memcmp(p, m_pSID, dwLen) == 0);
    return TRUE;
  }

  PSID m_pSID;
  BOOL m_bLocalAlloc;
};




///////////////////////////////////////////////////////////////////////
// CPrincipal

class CPrincipal
{
public:
	CPrincipal() 
  { 
    m_hClassIcon = NULL;
  }

  HRESULT Initialize(PDS_SELECTION pDsSelection, HICON hClassIcon);

  HRESULT Initialize (PSID psid);

  BOOL IsEqual(CPrincipal* p);


  PSID GetSid()
  {
    return m_sidHolder.Get();
  }

  LPCWSTR GetClass()
  {
    return m_szClass;
  }

  HICON GetClassIcon()
  {
    return m_hClassIcon;
  }

  LPCWSTR GetDisplayName()
  {
    return m_szDisplayName;
  }

private:
  void _ComposeDisplayName();

  // names
  CWString m_szName; // e.g. "JoeB"
  CWString m_szADsPath; //e.g. "WINNT://FOODOM/JoeB"
  CWString m_szUPN; // e.g. "JoeB@foo.com."
  CWString m_szClass; // e.g. "user"

  CWString m_szDisplayName; // generated, to be shown into the UI

  // other data
  HICON m_hClassIcon;       // icon handle
  CSidHolder m_sidHolder;   // PSID holder
};


///////////////////////////////////////////////////////////////////////
// CPrincipalList


class CPrincipalList : public CPtrList<CPrincipal*>
{
public:
  CPrincipalList(BOOL bOwnMem = TRUE) : CPtrList<CPrincipal*>(bOwnMem) 
  {
  }
  BOOL AddIfNotPresent(CPrincipal* p);
  void WriteSummaryInfo(CWString& szSummary, LPCWSTR lpszIdent, LPCWSTR lpszNewLine);
};



///////////////////////////////////////////////////////////////////////
// CBasicRightInfo

class CBasicRightInfo
{
public:
  CBasicRightInfo()
  {
    m_fAccess = 0x0;
    m_bSelected = FALSE;
  }

  LPCWSTR GetDisplayName() { return m_szDisplayName; }
  ULONG GetAccess() { return m_fAccess; }

  BOOL IsSelected() { return m_bSelected; }
  void Select(BOOL b) { m_bSelected = b; }

protected:
  CWString m_szDisplayName;
  ULONG m_fAccess;
private:
  BOOL m_bSelected;
};


///////////////////////////////////////////////////////////////////////
// CAccessRightInfo

class CTemplateAccessPermissionsHolder; // fwd decl
class CCustomAccessPermissionsHolder; // fwd decl

class CAccessRightInfo : public CBasicRightInfo
{
  friend class CTemplateAccessPermissionsHolder;
  friend class CCustomAccessPermissionsHolder;
};

///////////////////////////////////////////////////////////////////////
// CAccessRightInfoArray


class CAccessRightInfoArray : public CGrowableArr<CAccessRightInfo>
{
};
  

///////////////////////////////////////////////////////////////////////
// CControlRightInfo

class CControlRightInfoArray; //fwd decl

class CControlRightInfo : public CBasicRightInfo
{
public:
  CControlRightInfo()
  {
    ZeroMemory(&m_rightsGUID, sizeof (GUID));
  }

  const GUID* GetRightsGUID() { return &m_rightsGUID;}
  LPCWSTR GetLdapDisplayName() { return m_szLdapDisplayName; }
  LPCWSTR GetLocalizedName() { return m_szLocalizedName; }

  BOOL IsPropertySet() 
  { 
    return ((m_fAccess & (ACTRL_DS_READ_PROP | ACTRL_DS_WRITE_PROP)) != 0);
  }

  void SetLocalizedName(UINT nLocalizationDisplayId, HMODULE hModule);

private:
  GUID m_rightsGUID;
  CWString m_szLdapDisplayName; // this is from the schema, not localized
  CWString m_szLocalizedName;   // this is obtained from NTMARTA

  friend class CControlRightInfoArray;
};

///////////////////////////////////////////////////////////////////////
// CControlRightInfoArray 

class CControlRightInfoArray : public CGrowableArr<CControlRightInfo>
{
public:
  HRESULT InitFromDS(CAdsiObject* pADSIObj,
                         const GUID* pSchemaIDGUID);
};


///////////////////////////////////////////////////////////////////////
// CSchemaObjectInfo

class CSchemaObjectInfo
{
public:
	CSchemaObjectInfo(LPCWSTR lpszName)
	{
        m_bFilter = FALSE;
        if (lpszName != NULL)
        m_szName = lpszName;

        ZeroMemory(&m_schemaIDGUID, sizeof(GUID));
    }
	virtual ~CSchemaObjectInfo()
	{ 
	}

  void SetDisplayName(LPCWSTR lpszDisplayName) 
  { 
    //TRACE(_T("SetDisplayName(%s)\n"),lpszDisplayName); 
    m_szDisplayName = (lpszDisplayName != NULL) ? lpszDisplayName : m_szName;
    //TRACE(_T("m_szDisplayName = (%s)\n"),m_szDisplayName.c_str()); 
  }
  LPCWSTR GetName()
  { 
    return (m_szName.data()[0] == NULL) ? NULL : m_szName.c_str();
  }
  LPCWSTR GetDisplayName() 
  { 
    //TRACE(_T("GetDisplayName() m_szName = (%s) m_szDisplayName = (%s)\n"),
    //  m_szName.c_str(), m_szDisplayName.c_str()); 
    return (m_szDisplayName.data()[0] == NULL) ? NULL : m_szDisplayName.c_str();
  }

  const GUID* GetSchemaGUID()
  {
    return &m_schemaIDGUID;
  }

  bool operator<(CSchemaObjectInfo& x) 
  { 
    if ((GetDisplayName() == NULL) || (x.GetDisplayName() == NULL))
      return false;
    return (_wcsicmp(GetDisplayName(), x.GetDisplayName()) < 0);
  }

  void SetFiltered() { m_bFilter = TRUE;}
  BOOL IsFiltered() { return m_bFilter;}

protected:
  BOOL m_bFilter;
  CWString m_szName;
  CWString m_szDisplayName;
  GUID m_schemaIDGUID;

};

//////////////////////////////////////////////////////////////////////
// CPropertyRightInfo

class CPropertyRightInfoArray; // fwd decl

class CPropertyRightInfo : public CSchemaObjectInfo
{
public:
  CPropertyRightInfo(ULONG filterFlags, LPCWSTR lpszName) 
    : CSchemaObjectInfo(lpszName)
  {
    //TRACE(_T("CPropertyRightInfo(0x%x, %s)\n"),filterFlags, lpszName);
    m_FilterFlags = filterFlags;
    m_nRightCount = m_nRightCountMax;
    if (m_FilterFlags & IDC_PROP_NO_READ)
      m_nRightCount--;
    if (m_FilterFlags & IDC_PROP_NO_WRITE)
      m_nRightCount--;

    ASSERT(m_nRightCount > 0);
    m_Access = 0x0;
  }
  ~CPropertyRightInfo() {}

  static const ULONG m_nRightCountMax;
  static const ULONG m_nReadIndex;
  static const ULONG m_nWriteIndex;

  LPCWSTR GetRightDisplayString(ULONG iRight);
  void SetRight(ULONG iRight, BOOL b);
  ULONG GetRight(ULONG iRight);
  BOOL IsRightSelected(ULONG iRight);
  ULONG GetAccess() { return m_Access;}
  void AddAccessRight(ULONG uRight) { m_Access |= uRight;}
  ULONG GetRightCount() { return m_nRightCount;}

private:
  ULONG m_nRightCount;
  ULONG m_FilterFlags;
  ULONG m_Access;

  friend class CPropertyRightInfoArray;
};

//////////////////////////////////////////////////////////////////////
// CPropertyRightInfoArray

class CPropertyRightInfoFilter : public CFilterBase
{
public:
  virtual BOOL CanAdd(LPCWSTR lpsz, ULONG* pFilterFlags)
  {
    *pFilterFlags = ::GetAttributeFlags(m_szClassName, lpsz);
    if (*pFilterFlags == 0)
      return TRUE; // have no info, so add anyway
    if ((*pFilterFlags & IDC_PROP_NO) == IDC_PROP_NO)
      return FALSE; // have all the hide flags set
    return TRUE; // some of the hide flags not set

  }
  void SetClassName(LPCWSTR lpszClassName)
  {
    if (lpszClassName == NULL)
      m_szClassName = L"";
    else
      m_szClassName = lpszClassName;
  }
private:
  CWString m_szClassName;
};


class CPropertyRightInfoArray : public CGrowableArr<CPropertyRightInfo>
{
public:
  HRESULT InitFromSchema(CAdsiObject* pADSIObj, IADsClass* pDsSchemaClass, 
                         LPCWSTR lpszClassName, BOOL bUseFilter);
};

//////////////////////////////////////////////////////////////////////
// CClassRightInfo

class CClassRightInfoArray; // fwd decl.

class CClassRightInfo : public CSchemaObjectInfo
{
public:
  CClassRightInfo(ULONG filterFlags, LPCWSTR lpszName)
    : CSchemaObjectInfo(lpszName)
  {
    //TRACE(_T("CClassRightInfo(0x%x, %s)\n"),filterFlags, lpszName);

    m_FilterFlags = filterFlags;
    m_nRightCount = m_nRightCountMax;
    if (m_FilterFlags & IDC_CLASS_NO_CREATE)
      m_nRightCount--;
    if (m_FilterFlags & IDC_CLASS_NO_DELETE)
      m_nRightCount--;

    // REVIEW_MARCOC: do we need this?
    //if (m_FilterFlags & IDC_CLASS_NO_INHERIT)
    //  m_nRightCount--;

    ASSERT(m_nRightCount > 0);
    m_Access = 0x0;
  }
  ~CClassRightInfo() {}

  static const ULONG m_nRightCountMax;
  static const ULONG m_nCreateIndex;
  static const ULONG m_nDeleteIndex;

  LPCWSTR GetRightDisplayString(ULONG iRight);
  void SetRight(ULONG iRight, BOOL b);
  ULONG GetRight(ULONG iRight);
  BOOL IsRightSelected(ULONG iRight);
  ULONG GetAccess() { return m_Access;}
  void AddAccessRight(ULONG uRight) { m_Access |= uRight;}
  ULONG GetRightCount() { return m_nRightCount;}

private:
  ULONG m_nRightCount;
  ULONG m_FilterFlags;
  ULONG m_Access;

  friend class CClassRightInfoArray;

};

//////////////////////////////////////////////////////////////////////
// CClassRightInfoArray

class CClassRightInfoFilter : public CFilterBase
{
public:
  virtual BOOL CanAdd(LPCWSTR lpsz, ULONG* pFilterFlags)
  {
    *pFilterFlags = ::GetClassFlags(lpsz);
    if (*pFilterFlags == 0)
      return TRUE; // have no info, so add anyway
    if ((*pFilterFlags & IDC_CLASS_NO) == IDC_CLASS_NO)
      return FALSE; // have all the hide flags set
    return TRUE; // some of the hide flags not set
  }
};

class CClassRightInfoArray : public CGrowableArr<CClassRightInfo>
{
public:
  HRESULT InitFromSchema(CAdsiObject* pADSIObj, IADsClass* pDsSchemaClass, BOOL bUseFilter);
};


///////////////////////////////////////////////////////////////////////
// CSchemaClassInfo
#define CHILD_CLASS_NOT_EXIST   1
#define CHILD_CLASS_EXIST       2
#define CHILD_CLASS_NOT_CALCULATED  3

class CSchemaClassInfo : public CSchemaObjectInfo
{
public:
  CSchemaClassInfo(LPCWSTR lpszName, LPCWSTR lpszSchemaClassName,
                                     const GUID* pSchemaIDGUID)
                  : CSchemaObjectInfo(lpszName)
  { 
    m_szSchemaClassName = lpszSchemaClassName;
    m_schemaIDGUID = *pSchemaIDGUID;
    m_dwChildClass = CHILD_CLASS_NOT_CALCULATED;
    m_bSelected = FALSE;
	m_bAux = FALSE;
  }

  ~CSchemaClassInfo()
  {
  }

  VOID SetAux(){m_bAux=TRUE;}
  BOOL IsAux(){return m_bAux;}
  BOOL	m_bSelected;
  DWORD m_dwChildClass;
  LPCWSTR GetSchemaClassName() { return m_szSchemaClassName; }
private:
  CWString m_szSchemaClassName;
   BOOL  m_bAux;
};


////////////////////////////////////////////////////////////////////////
// CRigthsListViewItem

class CRigthsListViewItem
{
public:
  enum rightType { access, ctrl, prop, subobj };

  CRigthsListViewItem(ULONG iIndex, ULONG iRight, rightType type)
  {
    m_type = type;
    m_iIndex = iIndex;
    m_iRight = iRight;
  }

public:
  rightType m_type;
  ULONG m_iIndex;
  ULONG m_iRight;
};

typedef CGrowableArr<CRigthsListViewItem> CRigthsListViewItemArray;




///////////////////////////////////////////////////////////////////////
// CAccessPermissionsHolderBase

class CAccessPermissionsHolderBase
{
public:
  CAccessPermissionsHolderBase(BOOL bUseFilter);
  virtual ~CAccessPermissionsHolderBase();

  void Clear();

  // entry manipulation functions
  size_t GetTotalCount() 
  { 
    return m_accessRightInfoArr.GetCount() + m_controlRightInfoArr.GetCount()
      + m_propertyRightInfoArray.GetCount() + m_classRightInfoArray.GetCount();
  }

  BOOL HasPermissionSelected();
  
  // backend DS operations
  HRESULT ReadDataFromDS(CAdsiObject* pADSIObj,
                       LPCWSTR lpszObjectNamingContext,
                       LPCWSTR lpszClassName,
                       const GUID* pSchemaIDGUID,
                       BOOL bChildClass,
					   BOOL bHideListObject = FALSE);

  DWORD UpdateAccessList( CPrincipal* pPrincipal,
								          CSchemaClassInfo* pClassInfo,
                          LPCWSTR lpszServerName,
                          LPCWSTR lpszPhysicalSchemaNamingContext,
								          PACL* ppAcl);
protected:

  // standard access rigths
  CAccessRightInfoArray m_accessRightInfoArr; 
  virtual HRESULT _LoadAccessRightInfoArrayFromTable( BOOL bCreateDeleteChild,BOOL bHideListObject) = 0;

  // extended access rigths
  CControlRightInfoArray m_controlRightInfoArr;  


  // array of property rights
  CPropertyRightInfoArray	m_propertyRightInfoArray;

  // array of class rights
  CClassRightInfoArray	m_classRightInfoArray;

  // array of selections in the UI
  BOOL* m_pbSelectedArr;                // selected?

private:

  BOOL m_bUseFilter;

  HRESULT _ReadClassInfoFromDS(CAdsiObject* pADSIObj, LPCWSTR lpszClassName);
  
  DWORD _UpdateAccessListHelper(PSID pSid,
                         const GUID* pClassGUID,
                         PACL *ppAcl,
                         BOOL bChildClass);

};




///////////////////////////////////////////////////////////////////////
// CCustomAccessPermissionsHolder


// bitfields to keep track of the filtering state
#define FILTER_EXP_GEN    0x1
#define FILTER_EXP_PROP   0x2
#define FILTER_EXP_SUBOBJ 0x4
#define FILTER_EXP_GEN_DISABLED 0x8


class CCheckListViewHelper; // fwd decl

class CCustomAccessPermissionsHolder : public CAccessPermissionsHolderBase
{
public:
  CCustomAccessPermissionsHolder();
  virtual ~CCustomAccessPermissionsHolder();

  void Clear();

  // entry manipulation functions

  void Select(IN CRigthsListViewItem* pItem,
              IN BOOL bSelect,
              OUT ULONG* pnNewFilterState);

  void FillAccessRightsListView(
                       CCheckListViewHelper* pListViewHelper, 
                       ULONG nFilterState);

  void UpdateAccessRightsListViewSelection(
                       CCheckListViewHelper* pListViewHelper, 
                       ULONG nFilterState);

  // display finish page summary info
  void WriteSummary(CWString& szSummary, LPCWSTR lpszIdent, LPCWSTR lpszNewLine);

protected:
  virtual HRESULT _LoadAccessRightInfoArrayFromTable(BOOL bCreateDeleteChild,BOOL bHideListObject);

private:
  
  // helper functions to do selection and deselection
  void _SelectAllRigths();
  void _SelectAllPropertyRigths(ULONG fAccessPermission);
  void _SelectAllSubObjectRigths(ULONG fAccessPermission);
  void _DeselectAssociatedRights(ULONG fAccessPermission);

  // array of listview items, for indexing
  CRigthsListViewItemArray m_listViewItemArr;

};



///////////////////////////////////////////////////////////////////////
// CCheckListViewHelper

class CCheckListViewHelper
{
public:
	static BOOL CheckChanged(NM_LISTVIEW* pNMListView);
	static BOOL IsChecked(NM_LISTVIEW* pNMListView);

	CCheckListViewHelper()
	{
		m_hWnd = NULL;
	}

	BOOL Initialize(UINT nID, HWND hParent);
	int InsertItem(int iItem, LPCTSTR lpszText, LPARAM lParam, BOOL bCheck);
	BOOL SetItemCheck(int iItem, BOOL bCheck);
	void SetCheckAll(BOOL bCheck);
	LPARAM GetItemData(int iItem);
  BOOL IsItemChecked(int iItem);
	int GetCheckCount();
	void GetCheckedItems(int nCheckCount, int* nCheckArray);

	BOOL GetCheckState(int iItem)
	{
		return ListView_GetCheckState(m_hWnd,iItem);
	}
	int GetItemCount()
	{
		return ListView_GetItemCount(m_hWnd);
	}

	BOOL DeleteAllItems()
	{
		return ListView_DeleteAllItems(m_hWnd);
	}
	void EnableWindow(BOOL bEnable)
	{
		::EnableWindow(m_hWnd, bEnable);
	}
private:
	HWND m_hWnd;
};

////////////////////////////////////////////////////////////////////////////
// CNamedSecurityInfo
/*
class CNamedSecurityInfo
{
public:
  CNamedSecurityInfo()
  {
    m_pAuditList = NULL;
    m_pOwner = NULL;
    m_pGroup = NULL;

    m_pAccessList = NULL;
  }
  ~CNamedSecurityInfo()
  {
    Reset();
  }

  DWORD Get();
  DWORD Set();
  void Reset();

private:
  CWString m_szObjectName; // name of the object

 	// the following varables are just read and written back
	// i.e. no modification
  PACTRL_AUDIT m_pAuditList;
  LPWSTR m_pOwner;
  LPWSTR m_pGroup;

  // list to be edited and written back
  PACTRL_ACCESS m_pAccessList;

};
*/

////////////////////////////////////////////////////////////////////////////
// CAdsPathNameObj

class CAdsPathNameObj
{
public:
  CAdsPathNameObj(){}
  ~CAdsPathNameObj(){ m_spADsPath = NULL;}

  HRESULT SkipPrefix(LPCWSTR pwzObj, BSTR* pBstr)
  {
    HRESULT hr = _Create();
    if (FAILED(hr))
  	  return hr;

    hr = m_spADsPath->Set(CComBSTR (pwzObj), ADS_SETTYPE_FULL);
    if (FAILED(hr))
  	  return hr;

    hr = m_spADsPath->Retrieve(ADS_FORMAT_X500_DN, pBstr);
    return hr;
  }
  HRESULT SkipPrefix(LPCWSTR pwzObj, CWString& str)
  {
    CComBSTR b;
    HRESULT hr = SkipPrefix(pwzObj, &b);
    if (FAILED(hr))
    {
      str = L"";
    }
    else
    {
      str = b;
    }
    return hr;
  }
  HRESULT GetProvider(LPCWSTR pwzObj, BSTR* pBstr)
  {
    HRESULT hr = _Create();
    if (FAILED(hr))
  	  return hr;

    hr = m_spADsPath->Set(CComBSTR (pwzObj), ADS_SETTYPE_FULL);
    if (FAILED(hr))
  	  return hr;

    hr = m_spADsPath->Retrieve(ADS_FORMAT_PROVIDER, pBstr);
    return hr;
  }

private:
  CComPtr<IADsPathname>		m_spADsPath;

  HRESULT _Create()
  {
    HRESULT hr = S_OK;
    if (m_spADsPath == NULL)
    {
      hr = ::CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
                            IID_IADsPathname, (PVOID *)&m_spADsPath);
    }
    return hr;
  }

};








////////////////////////////////////////////////////////////////////////////
// CAdsiObject

class CAdsiObject
{
public:
	CAdsiObject():m_iListObjectEnforced(-1)
	{ _Clear(); }
  virtual ~CAdsiObject(){}

  virtual HRESULT Bind(LPCWSTR lpszLdapPath);
  BOOL IsBound() { return m_spIADs != NULL; }
  HRESULT QuerySchemaClasses(CGrowableArr<CSchemaClassInfo>*	pSchemaClassesInfoArray,
                             BOOL bGetAttributes = FALSE);

  // accessor functions
  LPCWSTR GetLdapPath() { return m_szLdapPath; }
  LPCWSTR GetServerName() { return m_szServerName; }
  LPCWSTR GetNamingContext() { return m_szNamingContext; }
  LPCWSTR GetCanonicalName() { return m_szCanonicalName; }
  LPCWSTR GetClass() { return m_szClass; }
  LPCWSTR GetPhysicalSchemaNamingContext() { return m_szPhysicalSchemaNamingContext;}
  LPCWSTR GetConfigurationNamingContext() { return m_szConfigurationNamingContext;}

  // methods to access display specifiers
  HICON   GetClassIcon(LPCWSTR lpszObjectClass);
  HRESULT GetFriendlyClassName(LPCWSTR lpszObjectClass, 
                               LPWSTR lpszBuffer, int cchBuffer);
  HRESULT GetFriendlyAttributeName(LPCWSTR lpszObjectClass, 
                                   LPCWSTR lpszAttributeName,
                                   LPWSTR lpszBuffer, int cchBuffer);


  HRESULT GetClassGuid(LPCWSTR lpszClassLdapDisplayName, BOOL bGetAttribute, GUID& guid);

  CAdsPathNameObj* GetPathNameObject()
  {
    return &m_pathNameObject;
  }

  bool GetListObjectEnforced();

protected:
  CComPtr<IADs>                     m_spIADs;                 // pointer to ADSI object

private:

  int m_iListObjectEnforced;			
  CComPtr<IDsDisplaySpecifier>      m_spIDsDisplaySpecifier;  // pointer to Display Specifier Cache
  CAdsPathNameObj                   m_pathNameObject;         // path cracker object wrapper

  // cached naming strings
  CWString           m_szServerName;     // DNS name the object is bound to ("foo.bar.com.")
  CWString           m_szNamingContext;  // naming context (X500) ("cn=xyz,...");
	CWString						m_szLdapPath;		    // full LDAP path ("LDAP://foo.bar.com.\cn=xyz,...")
  CWString           m_szCanonicalName;  // name in canonical form
  CWString           m_szClass;          // class name in abstract schema, corresponding to 
                                        // LDAPDisplayName attribute in physical schema, 
                                        // (e.g. "organizationalUnit")

  // commonly used naming contexts
  CWString           m_szPhysicalSchemaNamingContext;
  CWString           m_szConfigurationNamingContext;

  void _Clear()
  {
    m_spIADs = NULL;
    m_spIDsDisplaySpecifier = NULL;
    m_szServerName = L"";
    m_szLdapPath = L"";
    m_szCanonicalName = L"";
    m_szClass = L"";

    m_szPhysicalSchemaNamingContext = L"";
    m_szConfigurationNamingContext = L"";
  }

  HRESULT _QueryDNSServerName();
  HRESULT _InitGlobalNamingContexts();

  HRESULT _GetFriendlyClassNames(CGrowableArr<CSchemaClassInfo>*	pSchemaClassesInfoArray);
  

};

////////////////////////////////////////////////////////////////////////////////////////
// CAdsiSearch

class CAdsiSearch
{
public:
  CAdsiSearch()
  {
    m_SearchHandle = NULL;
  }
  ~CAdsiSearch()
  {
    Reset();
  }

  HRESULT Init(LPCWSTR lpszObjectPath)
  {
    Reset();
    return ::ADsOpenObjectHelper(lpszObjectPath, IID_IDirectorySearch,0,
                    (void**)&m_spSearchObj);
  }

  void Reset()
  {
    if (m_spSearchObj != NULL) 
    {
      if (m_SearchHandle != NULL) 
      {
        m_spSearchObj->CloseSearchHandle(m_SearchHandle);
        m_SearchHandle = NULL;
      }
    }
    m_spSearchObj = NULL;
  }

  HRESULT SetSearchScope(ADS_SCOPEENUM scope)
  {
    if (m_spSearchObj == NULL)
      return E_ADS_BAD_PATHNAME;

    ADS_SEARCHPREF_INFO aSearchPref;
    aSearchPref.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
    aSearchPref.vValue.dwType = ADSTYPE_INTEGER;
    aSearchPref.vValue.Integer = scope;
    return m_spSearchObj->SetSearchPreference(&aSearchPref, 1);
  }

  HRESULT DoQuery(LPCWSTR lpszFilter, LPCWSTR* pszAttribsArr, const int cAttrs);

  HRESULT GetNextRow()
  {
    if (m_spSearchObj == NULL)
      return E_ADS_BAD_PATHNAME;
    return m_spSearchObj->GetNextRow(m_SearchHandle);
  }

  HRESULT GetColumn(LPCWSTR lpszAttribute,
                     PADS_SEARCH_COLUMN pColumnData)
  {
    if (m_spSearchObj == NULL)
      return E_ADS_BAD_PATHNAME;

    return m_spSearchObj->GetColumn(m_SearchHandle,
                              (LPWSTR)lpszAttribute,
                              pColumnData);
  }
  HRESULT FreeColumn(PADS_SEARCH_COLUMN pColumnData)
  {
    if (m_spSearchObj == NULL)
      return E_ADS_BAD_PATHNAME;
    return m_spSearchObj->FreeColumn(pColumnData);
  }

  HRESULT GetColumnString(LPCWSTR lpszAttribute,
                     CWString& szData)
  {
    ADS_SEARCH_COLUMN ColumnData;
    ::ZeroMemory (&ColumnData, sizeof (ADS_SEARCH_COLUMN));
    HRESULT hr = GetColumn(lpszAttribute, &ColumnData);
    if (SUCCEEDED(hr))
    {
      if (ColumnData.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
        szData = ColumnData.pADsValues->CaseIgnoreString;
      else
      {
        szData = L"";
        hr = E_INVALIDARG;
      }
      FreeColumn(&ColumnData);
    }
    return hr;
  }

  HRESULT GetColumnOctectStringGUID(LPCWSTR lpszAttribute,
                     GUID& guid)
  {
    ADS_SEARCH_COLUMN ColumnData;
    ::ZeroMemory (&ColumnData, sizeof (ADS_SEARCH_COLUMN));
    HRESULT hr = GetColumn(lpszAttribute, &ColumnData);
    if (SUCCEEDED(hr))
    {
      if ( (ColumnData.dwADsType == ADSTYPE_OCTET_STRING) &&
            (ColumnData.pADsValues->OctetString.dwLength == 16) )
      {
        // we have a blob containing a GUID in binary form
        memcpy(&guid, ColumnData.pADsValues->OctetString.lpValue, sizeof(GUID));
      }
      else
      {
        guid = GUID_NULL;
        hr = E_INVALIDARG;
      }
      FreeColumn(&ColumnData);
    }
    return hr;
  }

  HRESULT GetColumnOctectStringGUID(LPCWSTR lpszAttribute,
                     CWString& szData)
  {
    GUID guid;
    szData = L"";
    HRESULT hr = GetColumnOctectStringGUID(lpszAttribute, guid);
    if (SUCCEEDED(hr))
    {
      WCHAR szBuf[128];
      if (FormatStringGUID(szBuf, 128, &guid))
      {
        szData = szBuf;
      }
      else
      {
        szData = L"";
        hr = E_INVALIDARG;
      }
    }
    return hr;
  }

  HRESULT GetColumnInteger(LPCWSTR lpszAttribute,
                        ULONG& uVal)
  {
    ADS_SEARCH_COLUMN ColumnData;
    ::ZeroMemory (&ColumnData, sizeof (ADS_SEARCH_COLUMN));
    HRESULT hr = GetColumn(lpszAttribute, &ColumnData);
    if (SUCCEEDED(hr))
    {
      if (ColumnData.dwADsType == ADSTYPE_INTEGER)
        uVal = ColumnData.pADsValues->Integer;
      else
        hr = E_INVALIDARG;
      FreeColumn(&ColumnData);
    }
    return hr;
  }

private:
  CComPtr<IDirectorySearch> m_spSearchObj;
  ADS_SEARCH_HANDLE  m_SearchHandle;

};

///////////////////////////////////////////////////////////////////////
// CErrorMessageHandlerBase

class CErrorMessageHandlerBase
{
public:
  CErrorMessageHandlerBase() {}
  virtual ~CErrorMessageHandlerBase() {}

  virtual void ReportHRESULTError(LPCWSTR lpszMsg, HRESULT hr) 
  {
      UNREFERENCED_PARAMETER (lpszMsg);
      UNREFERENCED_PARAMETER (hr);
  }
  virtual void ReportHRESULTError(UINT nStringID, HRESULT hr) 
  {
      UNREFERENCED_PARAMETER (nStringID);
      UNREFERENCED_PARAMETER (hr);
  }
};


DWORD
FormatStringID(LPTSTR *ppszResult, UINT idStr , ...);

   HRESULT
   SetSecInfoMask(LPUNKNOWN punk, SECURITY_INFORMATION si);

   HRESULT GetSDForDsObject(IDirectoryObject* pDsObject,
                           PACL* ppDACL,
                           PSECURITY_DESCRIPTOR* ppSD);

   HRESULT GetSDForDsObjectPath(LPCWSTR pszObjectPath,
                              PACL* ppDACL,
                              PSECURITY_DESCRIPTOR* ppSecurityDescriptor);

   HRESULT SetDaclForDsObject(IDirectoryObject* pDsObject,
                              PACL pDACL);

   HRESULT SetDaclForDsObjectPath(LPCWSTR pszObjectPath,
                                 PACL pDACL);


#endif // _UTIL_H__