windows-nt/Source/XPSP1/NT/admin/snapin/adsiedit/attredit.cpp
2020-09-26 16:20:57 +08:00

1452 lines
32 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: attredit.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#include <SnapBase.h>
#include "resource.h"
#include "common.h"
#include "attredit.h"
#include "connection.h"
#include "attrqry.h"
#ifdef DEBUG_ALLOCATOR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
////////////////////////////////////////////////////////////////////////////
// this is used to fill in the attributes for RootDSE
//
typedef struct tagRootDSEAttr
{
LPCWSTR lpszAttr;
LPCWSTR lpszSyntax;
BOOL bMulti;
} SYNTAXMAP;
extern SYNTAXMAP g_ldapRootDSESyntax[];
extern LPCWSTR g_lpszGC;
extern LPCWSTR g_lpszRootDSE;
///////////////////////////////////////////////////////////////////////////
// CAttrList
POSITION CAttrList::FindProperty(LPCWSTR lpszAttr)
{
CADSIAttr* pAttr;
for (POSITION p = GetHeadPosition(); p != NULL; GetNext(p))
{
// I use GetAt here because I don't want to advance the POSITION
// because it is returned if they are equal
//
pAttr = GetAt(p);
CString sName;
pAttr->GetProperty(sName);
if (wcscmp(sName, lpszAttr) == 0)
{
break;
}
}
return p;
}
BOOL CAttrList::HasProperty(LPCWSTR lpszAttr)
{
POSITION pos = FindProperty(lpszAttr);
return pos != NULL;
}
// Searches through the cache for the attribute
// ppAttr will point to the CADSIAttr if found, NULL if not
//
void CAttrList::GetNextDirty(POSITION& pos, CADSIAttr** ppAttr)
{
*ppAttr = GetNext(pos);
if (pos == NULL && !(*ppAttr)->IsDirty())
{
*ppAttr = NULL;
return;
}
while (!(*ppAttr)->IsDirty() && pos != NULL)
{
*ppAttr = GetNext(pos);
if (!(*ppAttr)->IsDirty() && pos == NULL)
{
*ppAttr = NULL;
break;
}
}
}
BOOL CAttrList::HasDirty()
{
POSITION pos = GetHeadPosition();
while (pos != NULL)
{
CADSIAttr* pAttr = GetNext(pos);
if (pAttr->IsDirty())
{
return TRUE;
}
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////
// CDNSManageButtonTextHelper
CDNSManageButtonTextHelper::CDNSManageButtonTextHelper(int nStates)
{
m_nID = 0;
m_pParentWnd = NULL;
m_nStates = nStates;
m_lpszText = NULL;
m_lpszArr = (LPWSTR*)malloc(sizeof(LPWSTR*)*m_nStates);
if (m_lpszArr != NULL)
{
memset(m_lpszArr, 0x0, sizeof(LPWSTR*)*m_nStates);
}
}
CDNSManageButtonTextHelper::~CDNSManageButtonTextHelper()
{
for (int k = 0; k < m_nStates; k++)
{
if (m_lpszArr[k] != NULL)
free(m_lpszArr[k]);
}
free(m_lpszArr);
}
void CDNSManageButtonTextHelper::SetStateX(int nIndex)
{
CWnd* pWnd = m_pParentWnd->GetDlgItem(m_nID);
ASSERT(pWnd != NULL);
ASSERT( (nIndex >0) || (nIndex < m_nStates));
pWnd->SetWindowText(m_lpszArr[nIndex]);
}
BOOL CDNSManageButtonTextHelper::Init(CWnd* pParentWnd, UINT nButtonID, UINT* nStrArray)
{
ASSERT(m_pParentWnd == NULL);
ASSERT(pParentWnd != NULL);
m_pParentWnd = pParentWnd;
m_nID = nButtonID;
CWnd* pWnd = m_pParentWnd->GetDlgItem(m_nID);
if (pWnd == NULL)
return FALSE;
// get the text for the window
int nSuccessEntries;
LoadStringArrayFromResource(m_lpszArr, nStrArray, m_nStates, &nSuccessEntries);
ASSERT(nSuccessEntries == m_nStates);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////
// CDNSButtonToggleTextHelper
CDNSButtonToggleTextHelper::CDNSButtonToggleTextHelper()
: CDNSManageButtonTextHelper(2)
{
}
///////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CADSIEditBox, CEdit)
ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
END_MESSAGE_MAP()
void CADSIEditBox::OnChange()
{
m_pEditor->OnEditChange();
}
////////////////////////////////////////////////////////////////
// CADSIValueBox
BEGIN_MESSAGE_MAP(CADSIValueBox, CEdit)
// ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////
// CADSIValueList
BEGIN_MESSAGE_MAP(CADSIValueList, CListBox)
ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelChange)
END_MESSAGE_MAP()
void CADSIValueList::OnSelChange()
{
m_pEditor->OnValueSelChange();
}
////////////////////////////////////////////////////////////////
// CADSIAddButton
BEGIN_MESSAGE_MAP(CADSIAddButton, CButton)
ON_CONTROL_REFLECT(BN_CLICKED, OnAdd)
END_MESSAGE_MAP()
void CADSIAddButton::OnAdd()
{
m_pEditor->OnAddValue();
}
////////////////////////////////////////////////////////////////
// CADSIRemoveButton
BEGIN_MESSAGE_MAP(CADSIRemoveButton, CButton)
ON_CONTROL_REFLECT(BN_CLICKED, OnRemove)
END_MESSAGE_MAP()
void CADSIRemoveButton::OnRemove()
{
m_pEditor->OnRemoveValue();
}
////////////////////////////////////////////////////////////////
// CAttrEditor
CAttrEditor::CAttrEditor() : m_AttrEditBox(this),
m_SyntaxBox(this),
m_ValueBox(this),
m_ValueList(this),
m_AddButton(this),
m_RemoveButton(this),
m_AddButtonHelper(),
m_RemoveButtonHelper()
{
m_bExisting = TRUE;
m_ptouchedAttr = NULL;
}
BOOL CAttrEditor::Initialize(CPropertyPageBase* pParentWnd, CTreeNode* pTreeNode,
LPCWSTR lpszServer,
UINT nIDEdit, UINT nIDSyntax,
UINT nIDValueBox, UINT nIDValueList,
UINT nIDAddButton, UINT nIDRemoveButton,
BOOL bComplete)
{
ASSERT(pParentWnd != NULL);
if (pParentWnd == NULL)
return FALSE;
m_pParentWnd = pParentWnd;
m_ptouchedAttr = new CAttrList();
ASSERT(m_ptouchedAttr != NULL);
if (pTreeNode == NULL)
{
m_bExisting = FALSE;
}
else
{
m_bExisting = TRUE;
}
m_sServer = lpszServer;
if (m_bExisting)
{
// This gets the CConnectionData from the ConnectionNode by finding a valid treenode and using its
// CADsObject to get the ConnectionNode and then the CConnectionData
//
m_pTreeNode = pTreeNode;
CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(m_pTreeNode);
if (pContNode == NULL)
{
CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(m_pTreeNode);
ASSERT(pLeafNode != NULL);
m_pConnectData = pLeafNode->GetADsObject()->GetConnectionNode()->GetConnectionData();
}
else
{
m_pConnectData = pContNode->GetADsObject()->GetConnectionNode()->GetConnectionData();
}
}
// sublclass controls
//
BOOL bRes = m_AttrEditBox.SubclassDlgItem(nIDEdit, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_SyntaxBox.SubclassDlgItem(nIDSyntax, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_ValueBox.SubclassDlgItem(nIDValueBox, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_ValueList.SubclassDlgItem(nIDValueList, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_AddButton.SubclassDlgItem(nIDAddButton, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
UINT nAddButtonTextIDs[2] = { IDS_BUTTON_TEXT_ADD, IDS_BUTTON_TEXT_SET };
m_AddButtonHelper.Init(m_pParentWnd,
nIDAddButton,
nAddButtonTextIDs);
bRes = m_RemoveButton.SubclassDlgItem(nIDRemoveButton, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
UINT nRemoveButtonTextIDs[2] = { IDS_BUTTON_TEXT_REMOVE, IDS_BUTTON_TEXT_CLEAR };
m_RemoveButtonHelper.Init(m_pParentWnd,
nIDRemoveButton,
nRemoveButtonTextIDs);
if (!m_sNotSet.LoadString(IDS_NOT_SET))
{
return FALSE;
}
if ( bComplete)
{
// Show property values as single and without the ability to set or clear
//
SetPropertyUI(0, FALSE, TRUE);
}
else
{
m_AttrEditBox.ShowWindow(SW_HIDE);
m_SyntaxBox.ShowWindow(SW_HIDE);
m_ValueBox.ShowWindow(SW_HIDE);
m_ValueList.ShowWindow(SW_HIDE);
m_AddButton.ShowWindow(SW_HIDE);
m_RemoveButton.ShowWindow(SW_HIDE);
}
return bRes;
}
BOOL CAttrEditor::Initialize(CPropertyPageBase* pParentWnd, CConnectionData* pConnectData,
LPCWSTR lpszServer,
UINT nIDEdit, UINT nIDSyntax,
UINT nIDValueBox, UINT nIDValueList,
UINT nIDAddButton, UINT nIDRemoveButton,
BOOL bComplete, CAttrList* pAttrList)
{
ASSERT(pParentWnd != NULL);
if (pParentWnd == NULL)
return FALSE;
m_pParentWnd = pParentWnd;
m_bExisting = FALSE;
m_sServer = lpszServer;
m_pConnectData = pConnectData;
ASSERT(pAttrList != NULL);
m_ptouchedAttr = pAttrList;
// sublclass controls
//
BOOL bRes = m_AttrEditBox.SubclassDlgItem(nIDEdit, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_SyntaxBox.SubclassDlgItem(nIDSyntax, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_ValueBox.SubclassDlgItem(nIDValueBox, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_ValueList.SubclassDlgItem(nIDValueList, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
bRes = m_AddButton.SubclassDlgItem(nIDAddButton, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
UINT nAddButtonTextIDs[2] = { IDS_BUTTON_TEXT_ADD, IDS_BUTTON_TEXT_SET };
m_AddButtonHelper.Init(m_pParentWnd,
nIDAddButton,
nAddButtonTextIDs);
bRes = m_RemoveButton.SubclassDlgItem(nIDRemoveButton, m_pParentWnd);
ASSERT(bRes);
if (!bRes) return FALSE;
UINT nRemoveButtonTextIDs[2] = { IDS_BUTTON_TEXT_REMOVE, IDS_BUTTON_TEXT_CLEAR };
m_RemoveButtonHelper.Init(m_pParentWnd,
nIDRemoveButton,
nRemoveButtonTextIDs);
if (!m_sNotSet.LoadString(IDS_NOT_SET))
{
return FALSE;
}
if ( bComplete)
{
// Show property values as single and without the ability to set or clear
//
SetPropertyUI(0, FALSE, TRUE);
}
else
{
m_AttrEditBox.ShowWindow(SW_HIDE);
m_SyntaxBox.ShowWindow(SW_HIDE);
m_ValueBox.ShowWindow(SW_HIDE);
m_ValueList.ShowWindow(SW_HIDE);
m_AddButton.ShowWindow(SW_HIDE);
m_RemoveButton.ShowWindow(SW_HIDE);
}
return bRes;
}
void CAttrEditor::SetAttribute(LPCWSTR lpszAttr, LPCWSTR lpszPath)
{
m_sAttr = lpszAttr;
m_sPath = lpszPath;
DisplayAttribute();
}
BOOL CAttrEditor::OnApply()
{
if (m_bExisting && m_ptouchedAttr->HasDirty() &&
!m_pConnectData->IsRootDSE() &&
!m_pConnectData->IsGC())
{
CComPtr<IDirectoryObject> pDirObject;
// bind to object with authentication
//
HRESULT hr, hCredResult;
hr = OpenObjectWithCredentials(
m_pConnectData,
m_pConnectData->GetCredentialObject()->UseCredentials(),
(LPWSTR)(LPCWSTR)m_sPath,
IID_IDirectoryObject,
(LPVOID*) &pDirObject,
NULL,
hCredResult
);
if (FAILED(hr))
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
m_pParentWnd->SetModified(FALSE);
}
// Need to change the focus or we will not be able to navigate with the keyboard
m_AttrEditBox.SetFocus();
return FALSE;
}
// Change or add values to ADSI cache that have changed
//
hr = CADSIAttr::SetValuesInDS(m_ptouchedAttr, pDirObject);
if (FAILED(hr))
{
//Format Error message and pop up a dialog
ADSIEditErrorMessage(hr);
m_ptouchedAttr->RemoveAllAttr();
DisplayAttribute();
m_pParentWnd->SetModified(FALSE);
// Need to change the focus or we will not be able to navigate with the keyboard
m_AttrEditBox.SetFocus();
return FALSE;
}
}
m_pParentWnd->SetModified(FALSE);
return TRUE;
}
void CAttrEditor::OnAddValue()
{
ASSERT(!m_pConnectData->IsRootDSE());
ASSERT(!m_pConnectData->IsGC());
CString s;
m_AttrEditBox.GetWindowText(s);
CStringList sList;
m_pAttr->GetValues(sList);
if (m_pAttr->GetMultivalued())
{
// if it is the first value to be added we need to get rid of the "<not set>"
//
CString sNotSet;
m_ValueList.GetText(0, sNotSet);
if (sNotSet == m_sNotSet)
{
m_ValueList.ResetContent();
}
// then add the new value
//
sList.AddTail(s);
}
else
{
// since it is single valued, remove the old one and add the new one
//
sList.RemoveAll();
sList.AddTail(s);
}
HRESULT hr = m_pAttr->SetValues(sList);
if (FAILED(hr))
{
DisplayFormatError();
}
else
{
if ( m_pAttr->GetMultivalued())
{
m_ValueList.AddString(s);
}
else
{
m_ValueBox.SetWindowText(s);
}
m_AttrEditBox.SetWindowText(_T(""));
m_pAttr->SetDirty(TRUE);
m_pParentWnd->SetModified(TRUE);
// Make the UI reflect the new data
//
m_AttrEditBox.SetFocus();
SetPropertyUI(~TN_FLAG_ENABLE_ADD, TRUE);
// Enable the clear button if the attribute is not multivalued
//
if ( !m_pAttr->GetMultivalued())
{
SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE);
}
}
}
void CAttrEditor::DisplayFormatError()
{
switch (m_pAttr->GetADsType())
{
case ADSTYPE_DN_STRING :
case ADSTYPE_CASE_EXACT_STRING :
case ADSTYPE_CASE_IGNORE_STRING :
case ADSTYPE_PRINTABLE_STRING :
case ADSTYPE_NUMERIC_STRING :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
case ADSTYPE_BOOLEAN :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_BOOLEAN, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
case ADSTYPE_INTEGER :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
case ADSTYPE_OCTET_STRING :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_OCTET, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
case ADSTYPE_UTC_TIME :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT_TIME, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
case ADSTYPE_LARGE_INTEGER :
case ADSTYPE_OBJECT_CLASS :
case ADSTYPE_UNKNOWN :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
default :
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
if (m_pAttr->GetMultivalued())
{
if (m_ValueList.GetCount() < 1)
{
m_ValueList.AddString(m_sNotSet);
}
}
break;
}
}
}
void CAttrEditor::OnRemoveValue()
{
if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC())
{
CStringList sList;
m_pAttr->GetValues(sList);
DWORD dwNumVals = m_pAttr->GetNumValues();
if (m_pAttr->GetMultivalued())
{
CString s, sVal;
int iCount = m_ValueList.GetCurSel();
m_ValueList.GetText(iCount, sVal);
m_AttrEditBox.SetWindowText(sVal);
m_ValueList.DeleteString(iCount);
// Add "<not set>" to the UI if this is the last value being removed
//
if (m_ValueList.GetCount() == 0)
{
m_AttrEditBox.SetFocus();
SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE);
m_ValueList.AddString(m_sNotSet);
if (!m_bExisting)
{
m_pAttr->SetDirty(FALSE);
}
}
POSITION pos = sList.FindIndex(iCount);
sList.RemoveAt(pos);
HRESULT hr = m_pAttr->SetValues(sList);
if (FAILED(hr))
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
}
if (m_bExisting || m_ValueList.GetCount() > 0)
{
m_pAttr->SetDirty(TRUE);
}
}
else
{
CString sVal;
m_ValueBox.GetWindowText(sVal);
m_AttrEditBox.SetWindowText(sVal);
m_ValueBox.SetWindowText( m_sNotSet);
sList.RemoveAll();
HRESULT hr = m_pAttr->SetValues(sList);
if (FAILED(hr))
{
ADSIEditMessageBox(IDS_MSG_INCORRECT_FORMAT, MB_OK);
}
if (!m_bExisting)
{
m_pAttr->SetDirty(FALSE);
}
else
{
m_pAttr->SetDirty(TRUE);
}
}
m_AttrEditBox.SetFocus();
SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE);
dwNumVals--;
m_pParentWnd->SetModified(TRUE);
}
}
void CAttrEditor::OnEditChange()
{
if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC())
{
CString s;
m_AttrEditBox.GetWindowText(s);
if (s != _T(""))
{
SetPropertyUI(TN_FLAG_ENABLE_ADD, FALSE);
}
else
{
SetPropertyUI(~TN_FLAG_ENABLE_ADD, TRUE);
}
}
}
void CAttrEditor::OnValueSelChange()
{
if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC())
{
SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE);
}
}
void CAttrEditor::GetAttrFailed()
{
CString sSyntax;
GetSyntax(m_sAttr, sSyntax);
m_SyntaxBox.SetWindowText(sSyntax);
m_ValueList.ResetContent();
m_ValueList.AddString(m_sNotSet);
m_ValueBox.SetWindowText(m_sNotSet);
SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE);
}
void CAttrEditor::FillWithExisting()
{
CString s;
m_pAttr = m_ptouchedAttr->GetAt(m_ptouchedAttr->FindProperty(m_sAttr));
ASSERT(m_pAttr != NULL);
CStringList slValues;
m_pAttr->GetValues(slValues);
if (m_pAttr->GetMultivalued())
{
m_ValueList.ResetContent();
POSITION pos;
if (slValues.GetCount() == 0)
{
slValues.AddTail(m_sNotSet);
}
for (pos = slValues.GetHeadPosition(); pos != NULL; slValues.GetNext(pos) )
{
s = slValues.GetAt(pos);
m_ValueList.AddString(s);
}
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
}
else
{
if (slValues.GetCount() > 0)
{
s = slValues.GetAt(slValues.GetHeadPosition());
m_ValueBox.SetWindowText(s);
if (!m_pConnectData->IsRootDSE() && !m_pConnectData->IsGC())
{
SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE);
}
}
else
{
m_ValueBox.SetWindowText(m_sNotSet);
SetPropertyUI(~TN_FLAG_ENABLE_REMOVE, TRUE);
}
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
}
}
void CAttrEditor::DisplayAttribute()
{
int iCount;
HRESULT hr, hCredResult;
if (m_ptouchedAttr->HasProperty(m_sAttr))
{
FillWithExisting();
}
else
{
if (m_pConnectData->IsRootDSE())
{
DisplayRootDSE();
}
else if (!m_bExisting)
{
ADS_ATTR_INFO *pAttrInfo = NULL;
GetAttrFailed();
m_pAttr = TouchAttr(m_sAttr);
ASSERT(m_pAttr != NULL);
if (m_pAttr != NULL)
{
if (m_pAttr->GetMultivalued())
{
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
}
else
{
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
}
}
return;
}
else
{
CComPtr<IDirectoryObject> pDirObject;
hr = OpenObjectWithCredentials(
m_pConnectData,
m_pConnectData->GetCredentialObject()->UseCredentials(),
(LPWSTR)(LPCWSTR)m_sPath,
IID_IDirectoryObject,
(LPVOID*) &pDirObject,
NULL,
hCredResult
);
if ( FAILED(hr) )
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
}
return;
}
ASSERT(pDirObject != NULL);
// Get attribute
//
CString szAttrName;
szAttrName = m_sAttr + _T(";range=0-*");
CString szFormat = m_sAttr + _T(";range=%ld-*");
DWORD dwReturn = 0;
DWORD dwNumAttr = 1;
ADS_ATTR_INFO *pAttrInfo;
const WCHAR wcSep = L'-';
const WCHAR wcEnd = L'*';
BOOL fMoreRemain = FALSE;
CStringList sList;
do
{
LPWSTR lpszAttrs[] = {(LPWSTR)(LPCWSTR)szAttrName};
hr = pDirObject->GetObjectAttributes(lpszAttrs, dwNumAttr, &pAttrInfo, &dwReturn);
if (FAILED(hr))
{
ADSIEditErrorMessage(hr);
return;
}
if (pAttrInfo == NULL)
{
GetAttrFailed();
m_pAttr = TouchAttr(m_sAttr);
ASSERT(m_pAttr != NULL);
if (m_pAttr != NULL)
{
if (m_pAttr->GetMultivalued())
{
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
}
else
{
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
}
}
return;
}
if (dwReturn > 0)
{
GetStringFromADs(pAttrInfo, sList);
}
//
// Check to see if there is more data. If the last char of the
// attribute name string is an asterisk, then we have everything.
//
int cchEnd = wcslen(pAttrInfo->pszAttrName);
fMoreRemain = pAttrInfo->pszAttrName[cchEnd - 1] != wcEnd;
if (fMoreRemain)
{
PWSTR pwz = wcsrchr(pAttrInfo->pszAttrName, wcSep);
if (!pwz)
{
ASSERT(FALSE && pAttrInfo->pszAttrName);
fMoreRemain = FALSE;
}
else
{
pwz++; // move past the hyphen to the range end value.
ASSERT(*pwz);
long lEnd = _wtol(pwz);
lEnd++; // start with the next value.
szAttrName.Format(szFormat, lEnd);
TRACE(L"Range returned is %ws, now asking for %ws\n",
pAttrInfo->pszAttrName, szAttrName);
}
}
} while (fMoreRemain);
BOOL bMulti = FALSE;
if (m_pConnectData->IsGC())
{
bMulti = IsMultiValued(pAttrInfo);
}
else
{
bMulti = IsMultiValued(m_sAttr);
}
if (pAttrInfo != NULL)
{
if (bMulti)
{
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
m_ValueList.ResetContent();
POSITION pos = sList.GetHeadPosition();
while (pos != NULL)
{
CString sValue = sList.GetNext(pos);
m_ValueList.AddString(sValue);
}
}
else
{
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
if (sList.GetCount() > 0)
{
m_ValueBox.SetWindowText(sList.GetHead());
}
if (!m_pConnectData->IsGC())
{
SetPropertyUI(TN_FLAG_ENABLE_REMOVE, FALSE);
}
}
}
else
{
GetAttrFailed();
CStringList sTempList;
m_pAttr = TouchAttr(pAttrInfo, bMulti);
if (bMulti)
{
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE, TRUE);
}
else
{
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
}
return;
}
m_pAttr = TouchAttr(pAttrInfo, bMulti);
}
}
CString sSyntax;
GetSyntax(m_sAttr, sSyntax);
m_SyntaxBox.SetWindowText(sSyntax);
}
void CAttrEditor::DisplayRootDSE()
{
CString s = m_sPath;
CComPtr<IADs> pADs;
HRESULT hr, hCredResult;
hr = OpenObjectWithCredentials(
m_pConnectData,
m_pConnectData->GetCredentialObject()->UseCredentials(),
(LPWSTR)(LPCWSTR)s,
IID_IADs,
(LPVOID*)&pADs,
NULL,
hCredResult
);
if ( FAILED(hr) )
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
}
return;
}
// This is to insure that the ADSI cache is current
//
hr = pADs->GetInfo();
VARIANT var;
hr = pADs->GetEx( (LPWSTR)(LPCWSTR)m_sAttr , &var );
if ( FAILED(hr) )
{
GetAttrFailed();
m_pAttr = TouchAttr(m_sAttr);
return;
}
/////////////////////////////////////////
// Convert and populate
///////////////////////////////////////////
CStringList sList;
hr = VariantToStringList( var, sList );
if ( FAILED(hr) )
{
GetAttrFailed();
VariantClear(&var);
CStringList sTempList;
m_pAttr = TouchAttr(m_sAttr);
return;
}
VariantClear( &var );
if ( IsRootDSEAttrMultiValued(m_sAttr) )
{
SetPropertyUI(TN_FLAG_SHOW_MULTI, FALSE);
m_ValueList.ResetContent();
POSITION pos = sList.GetHeadPosition();
while (pos != NULL)
{
CString sValue = sList.GetNext(pos);
m_ValueList.AddString(sValue);
}
}
else
{
SetPropertyUI(~TN_FLAG_SHOW_MULTI, TRUE);
s = sList.GetHead();
m_ValueBox.SetWindowText(s);
}
// m_pAttr = TouchAttr(m_sAttr);
CString sSyntax;
GetSyntax(m_sAttr, sSyntax);
m_SyntaxBox.SetWindowText(sSyntax);
// REVEIW : this is the only occurrance of "UTCTime", if there
// becomes more we may need to make a global string or something
//
if (sSyntax == _T("UTCTime"))
{
CString sFormatted, sRemainder;
CString sYear, sMonth, sDay, sHour, sMinute, sSecond;
int iCount = 0;
sYear = s.Left(4);
iCount = s.GetLength();
sRemainder = s.Right(iCount - 4);
sMonth = sRemainder.Left(2);
iCount = sRemainder.GetLength();
sRemainder = sRemainder.Right(iCount - 2);
sDay = sRemainder.Left(2);
iCount = sRemainder.GetLength();
sRemainder = sRemainder.Right(iCount - 2);
sHour = sRemainder.Left(2);
iCount = sRemainder.GetLength();
sRemainder = sRemainder.Right(iCount - 2);
sMinute = sRemainder.Left(2);
iCount = sRemainder.GetLength();
sRemainder = sRemainder.Right(iCount - 2);
sSecond = sRemainder.Left(2);
sFormatted = sMonth + _T("/") + sDay + _T("/") + sYear + _T(" ")
+ sHour + _T(":") + sMinute + _T(":") + sSecond;
m_ValueBox.SetWindowText(sFormatted);
}
}
BOOL CAttrEditor::IsRootDSEAttrMultiValued(LPCWSTR lpszAttr)
{
int idx=0, iCount = 0;
iCount = wcslen(lpszAttr);
while( g_ldapRootDSESyntax[idx].lpszAttr)
{
if ( _wcsnicmp(g_ldapRootDSESyntax[idx].lpszAttr, lpszAttr, iCount) == 0)
{
return g_ldapRootDSESyntax[idx].bMulti;
}
idx++;
}
return FALSE;
}
// TODO : This is extremely ugly, redo it
//
void CAttrEditor::SetPropertyUI(DWORD dwFlags, BOOL bAnd, BOOL bReset)
{
if (bReset)
{
m_dwMultiFlags = dwFlags;
}
if (bAnd)
{
m_dwMultiFlags &= dwFlags;
}
else
{
m_dwMultiFlags |= dwFlags;
}
if (m_dwMultiFlags & TN_FLAG_SHOW_MULTI)
{
m_AddButtonHelper.SetToggleState(TRUE);
m_RemoveButtonHelper.SetToggleState(TRUE);
m_ValueList.ShowWindow(SW_SHOW);
m_ValueBox.ShowWindow(SW_HIDE);
}
else
{
m_AddButtonHelper.SetToggleState(FALSE);
m_RemoveButtonHelper.SetToggleState(FALSE);
m_ValueList.ShowWindow(SW_HIDE);
m_ValueBox.ShowWindow(SW_SHOW);
}
if (m_dwMultiFlags & TN_FLAG_ENABLE_REMOVE)
{
m_RemoveButton.EnableWindow(TRUE);
}
else
{
m_RemoveButton.EnableWindow(FALSE);
}
if (m_dwMultiFlags & TN_FLAG_ENABLE_ADD)
{
m_AddButton.EnableWindow(TRUE);
}
else
{
m_AddButton.EnableWindow(FALSE);
}
if (m_bExisting && (m_pConnectData->IsGC() || m_pConnectData->IsRootDSE()))
{
m_AttrEditBox.EnableWindow(FALSE);
}
else
{
m_AttrEditBox.EnableWindow(TRUE);
}
}
void CAttrEditor::GetSyntax(LPCWSTR lpszProp, CString& sSyntax)
{
if (m_bExisting && m_pConnectData->IsRootDSE())
{
int idx=0;
while( g_ldapRootDSESyntax[idx].lpszAttr )
{
if ( wcscmp(lpszProp, g_ldapRootDSESyntax[idx].lpszAttr) == 0 )
{
sSyntax = g_ldapRootDSESyntax[idx].lpszSyntax;
return;
}
idx++;
}
}
else
{
CComPtr<IADsProperty> pProp;
HRESULT hr, hCredResult;
CString schema;
m_pConnectData->GetAbstractSchemaPath(schema);
schema = schema + lpszProp;
hr = OpenObjectWithCredentials(
m_pConnectData,
m_pConnectData->GetCredentialObject()->UseCredentials(),
(LPWSTR)(LPCWSTR)schema,
IID_IADsProperty,
(LPVOID*) &pProp,
NULL,
hCredResult
);
if ( FAILED(hr) )
{
if (SUCCEEDED(hCredResult))
{
ADSIEditErrorMessage(hr);
}
return;
}
///////////////////////////////////////////////////
// Create a new cached attribute and populate
//////////////////////////////////////////////////
BSTR bstr;
hr = pProp->get_Syntax( &bstr );
if ( SUCCEEDED(hr) )
{
sSyntax = bstr;
}
SysFreeString(bstr);
}
}
BOOL CAttrEditor::IsMultiValued(ADS_ATTR_INFO* pAttrInfo)
{
return (pAttrInfo->dwNumValues > 1) ? TRUE : FALSE;
}
BOOL CAttrEditor::IsMultiValued(LPCWSTR lpszProp)
{
CString schema;
BOOL bResult = FALSE;
CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(m_pTreeNode);
if (pContNode == NULL)
{
CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(m_pTreeNode);
ASSERT(pLeafNode != NULL);
bResult = pLeafNode->BuildSchemaPath(schema);
}
else
{
bResult = pContNode->BuildSchemaPath(schema);
}
if (!bResult)
{
return FALSE;
}
CADSIQueryObject schemaSearch;
// Initialize search object with path, username and password
//
HRESULT hr = schemaSearch.Init(schema, m_pConnectData->GetCredentialObject());
if (FAILED(hr))
{
ADSIEditErrorMessage(hr);
return FALSE;
}
int cCols = 1;
LPWSTR pszAttributes[] = {L"isSingleValued"};
LPWSTR pszDesiredAttr = L"attributeSyntax";
ADS_SEARCH_COLUMN ColumnData;
hr = schemaSearch.SetSearchPrefs(ADS_SCOPE_ONELEVEL);
if (FAILED(hr))
{
ADSIEditErrorMessage(hr);
return FALSE;
}
BOOL bMulti = FALSE;
CString csFilter;
csFilter.Format(L"(&(objectClass=attributeSchema)(lDAPDisplayName=%s))", lpszProp);
schemaSearch.SetFilterString((LPWSTR)(LPCWSTR)csFilter);
schemaSearch.SetAttributeList (pszAttributes, cCols);
hr = schemaSearch.DoQuery ();
if (SUCCEEDED(hr))
{
hr = schemaSearch.GetNextRow();
if (SUCCEEDED(hr))
{
hr = schemaSearch.GetColumn(pszAttributes[0], &ColumnData);
if (SUCCEEDED(hr))
{
TRACE(_T("\t\tisSingleValued: %d\n"),
ColumnData.pADsValues->Boolean);
bMulti = !ColumnData.pADsValues->Boolean;
}
}
}
return bMulti;
}
// NOTE : this is only called for the RootDSE or if we failed to get
// values for the attribute. An empty ADS_ATTR_INFO object is
// created but should not be modified. If values are to be changed
// or set for this object a new ADS_ATTR_INFO should be created
// with the desired block of memory allocated for the values
//
CADSIAttr* CAttrEditor::TouchAttr(LPCWSTR lpszAttr)
{
POSITION pos = m_ptouchedAttr->FindProperty(lpszAttr);
if (pos == NULL)
{
ADS_ATTR_INFO* pADsInfo = new ADS_ATTR_INFO;
if (!pADsInfo)
{
return 0;
}
memset(pADsInfo, 0, sizeof(ADS_ATTR_INFO));
int iLength = wcslen(lpszAttr);
pADsInfo->pszAttrName = new WCHAR[iLength + 1];
wcscpy(pADsInfo->pszAttrName, lpszAttr);
CADSIQueryObject schemaSearch;
BOOL bResult;
CString schema;
CADSIEditContainerNode* pContNode = m_pConnectData->GetConnectionNode();
bResult = pContNode->BuildSchemaPath(schema);
if (!bResult)
{
return NULL;
}
// Initialize search object with path, username and password
//
HRESULT hr = schemaSearch.Init(schema, m_pConnectData->GetCredentialObject());
if (FAILED(hr))
{
ADSIEditErrorMessage(hr);
return NULL;
}
int cCols = 3;
LPWSTR pszAttributes[] = {L"lDAPDisplayName", L"attributeSyntax", L"isSingleValued"};
LPWSTR pszDesiredAttr = _T("attributeSyntax");
ADS_SEARCH_COLUMN ColumnData;
hr = schemaSearch.SetSearchPrefs(ADS_SCOPE_ONELEVEL);
if (FAILED(hr))
{
ADSIEditErrorMessage(hr);
return NULL;
}
BOOL bMulti = FALSE;
CString szSyntax;
CString csFilter;
csFilter.Format(L"(&(objectClass=attributeSchema)(lDAPDisplayName=%s))", lpszAttr);
schemaSearch.SetFilterString((LPWSTR)(LPCWSTR)csFilter);
schemaSearch.SetAttributeList (pszAttributes, cCols);
hr = schemaSearch.DoQuery ();
if (SUCCEEDED(hr))
{
hr = schemaSearch.GetNextRow();
if (SUCCEEDED(hr))
{
hr = schemaSearch.GetColumn(pszDesiredAttr,
&ColumnData);
if (SUCCEEDED(hr))
{
TRACE(_T("\t\tattributeSyntax: %s\n"),
ColumnData.pADsValues->CaseIgnoreString);
ADSTYPE dwType;
dwType = GetADsTypeFromString(ColumnData.pADsValues->CaseIgnoreString, szSyntax);
pADsInfo->dwADsType = dwType;
}
hr = schemaSearch.GetColumn(pszAttributes[2], &ColumnData);
if (SUCCEEDED(hr))
{
TRACE(_T("\t\tisSingleValued: %d\n"),
ColumnData.pADsValues->Boolean);
pADsInfo->dwNumValues = 0;
bMulti = !ColumnData.pADsValues->Boolean;
}
}
}
CADSIAttr* pAttr = new CADSIAttr(pADsInfo, bMulti, szSyntax, FALSE);
m_ptouchedAttr->AddTail(pAttr);
return pAttr;
}
return m_ptouchedAttr->GetAt(pos);
}
CADSIAttr* CAttrEditor::TouchAttr(ADS_ATTR_INFO* pADsInfo, BOOL bMulti)
{
POSITION pos = m_ptouchedAttr->FindProperty(pADsInfo->pszAttrName);
if (pos == NULL)
{
CADSIAttr* pAttr = new CADSIAttr(pADsInfo, bMulti, L"");
m_ptouchedAttr->AddTail(pAttr);
return pAttr;
}
return m_ptouchedAttr->GetAt(pos);
}