1452 lines
32 KiB
C++
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);
|
|
}
|
|
|
|
|