//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: connection.cpp // //-------------------------------------------------------------------------- #include "pch.h" #include #include "resource.h" #include "createwiz.h" #include "connection.h" #include "connectionui.h" #include "editorui.h" #include "filterui.h" #include "credui.h" #include "queryui.h" #ifdef DEBUG_ALLOCATOR #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif /////////////////////////////////////////////////////////////////////////////// extern LPCWSTR g_lpszRootDSE; /////////////////////////////////////////////////////////////////////////////// // {5C225203-CFF7-11d2-8801-00C04F72ED31} const GUID CADSIEditConnectionNode::NodeTypeGUID = { 0x5c225203, 0xcff7, 0x11d2, { 0x88, 0x1, 0x0, 0xc0, 0x4f, 0x72, 0xed, 0x31 } }; CADSIEditConnectionNode::~CADSIEditConnectionNode() { RemoveAndDeleteAllQueriesFromList(); delete m_pConnectData; HRESULT hr = m_SchemaCache.Destroy(); ASSERT(SUCCEEDED(hr)); } bool CADSIEditConnectionNode::IsClassAContainer(CCredentialObject* pCredObject, PCWSTR pszClass, PCWSTR pszSchemaPath) { bool bContainer = false; do // false loop { if (!pCredObject || !pszClass || !pszSchemaPath) { ASSERT(pCredObject); ASSERT(pszClass); ASSERT(pszSchemaPath); bContainer = false; break; } CADSIEditClassCacheItemBase* pSchemaCacheItem = m_SchemaCache.FindClassCacheItem(pCredObject, pszClass, pszSchemaPath); if (pSchemaCacheItem) { bContainer = pSchemaCacheItem->IsContainer(); } } while (false); return bContainer; } BOOL CADSIEditConnectionNode::OnEnumerate(CComponentDataObject* pComponentData, BOOL bAsync) { CString path, basePath; GetADsObject()->GetPath(path); m_pConnectData->GetBasePath(basePath); CComPtr spDirectoryObject; HRESULT hr, hCredResult; CADsObject* pObject = new CADsObject(); if (pObject) { if (m_pConnectData->IsRootDSE()) { pObject->SetContainer(TRUE); pObject->SetName(g_lpszRootDSE); pObject->SetPath(path); pObject->SetClass(g_lpszRootDSE); pObject->SetConnectionNode(this); pObject->SetIntermediateNode(TRUE); pObject->SetComplete(TRUE); CADSIEditContainerNode *pNewContNode = new CADSIEditContainerNode(pObject); if (pNewContNode) { pNewContNode->SetDisplayName(g_lpszRootDSE); VERIFY(AddChildToList(pNewContNode)); } pComponentData->SetDescriptionBarText(this); } else { hr = OpenObjectWithCredentials( m_pConnectData, m_pConnectData->GetCredentialObject()->UseCredentials(), path, IID_IDirectoryObject, (LPVOID*) &spDirectoryObject, NULL, hCredResult ); if ( FAILED(hr) ) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); } if (pObject) { delete pObject; pObject = 0; } return FALSE; } ADS_OBJECT_INFO* pInfo = 0; hr = spDirectoryObject->GetObjectInformation(&pInfo); if (FAILED(hr)) { ADSIEditErrorMessage(hr); if (pObject) { delete pObject; pObject = 0; } return FALSE; } // Name pObject->SetName(basePath); pObject->SetDN(basePath); pObject->SetPath(path); // Make sure the prefix is uppercase CString sBasePath(basePath); int idx = sBasePath.Find(L'='); if (idx != -1) { CString sPrefix, sRemaining; sPrefix = sBasePath.Left(idx); sPrefix.MakeUpper(); int iCount = sBasePath.GetLength(); sRemaining = sBasePath.Right(iCount - idx); sBasePath = sPrefix + sRemaining; } // Class pObject->SetClass(pInfo->pszClassName); pObject->SetIntermediateNode(TRUE); pObject->SetContainer(TRUE); pObject->SetComplete(TRUE); CADSIEditContainerNode *pNewContNode = new CADSIEditContainerNode(pObject); if (pNewContNode) { CString sName; pNewContNode->SetDisplayName(sBasePath); GetConnectionData()->SetIDirectoryInterface(spDirectoryObject); pNewContNode->GetADsObject()->SetConnectionNode(this); VERIFY(AddChildToList(pNewContNode)); pComponentData->SetDescriptionBarText(this); FreeADsMem(pInfo); } } EnumerateQueries(); } return TRUE; } void CADSIEditConnectionNode::EnumerateQueries() { POSITION pos = m_queryList.GetHeadPosition(); while(pos != NULL) { CADSIEditQueryData* pQueryData = m_queryList.GetNext(pos); CADsObject* pObject = new CADsObject(); if (pObject) { CString sPath, sName; pQueryData->GetName(sName); pObject->SetName(sName); pQueryData->GetRootPath(sPath); pObject->SetPath(sPath); pObject->SetComplete(TRUE); pObject->SetConnectionNode(this); pObject->SetContainer(TRUE); pObject->SetIntermediateNode(TRUE); CADSIEditQueryNode* pNewQuery = new CADSIEditQueryNode(pObject, pQueryData); if (pNewQuery) { CString sDisplayName; pQueryData->GetDisplayName(sDisplayName); pNewQuery->SetDisplayName(sDisplayName); VERIFY(AddChildToList(pNewQuery)); } } } } BOOL CADSIEditConnectionNode::HasPropertyPages(DATA_OBJECT_TYPES type, BOOL* pbHideVerb, CNodeList* pNodeList) { *pbHideVerb = TRUE; // always hide the verb return FALSE; } BOOL CADSIEditConnectionNode::FindNode(LPCWSTR lpszPath, CList& foundNodeList) { // NOTICE-NTRAID#NTBUG9-561513-2002/03/01-artm Validate lpszPath before using. if (!lpszPath) { // This should never happen. ASSERT(false); return FALSE; } CString szPath; GetADsObject()->GetPath(szPath); if (wcscmp(lpszPath, (LPCWSTR)szPath) == 0) { foundNodeList.AddHead(this); return TRUE; } BOOL bFound = FALSE; POSITION pos; for (pos = m_containerChildList.GetHeadPosition(); pos != NULL; ) { CTreeNode* pNode = m_containerChildList.GetNext(pos); CADSIEditContainerNode* pContNode = dynamic_cast(pNode); if (pContNode != NULL) { BOOL bTemp; bTemp = pContNode->FindNode(lpszPath, foundNodeList); if (!bFound) { bFound = bTemp; } } } return bFound; } int CADSIEditConnectionNode::GetImageIndex(BOOL bOpenImage) { int nIndex = 0; switch (m_nState) { case notLoaded: nIndex = SERVER_IMAGE_NOT_LOADED; break; case loading: nIndex = SERVER_IMAGE_LOADING; break; case loaded: nIndex = SERVER_IMAGE_LOADED; break; case unableToLoad: nIndex = SERVER_IMAGE_UNABLE_TO_LOAD; break; case accessDenied: nIndex = SERVER_IMAGE_ACCESS_DENIED; break; default: ASSERT(FALSE); } return nIndex; } void CADSIEditConnectionNode::OnChangeState(CComponentDataObject* pComponentDataObject) { switch (m_nState) { case notLoaded: case loaded: case unableToLoad: case accessDenied: { m_nState = loading; m_dwErr = 0; } break; case loading: { if (m_dwErr == 0) m_nState = loaded; else if (m_dwErr == ERROR_ACCESS_DENIED) m_nState = accessDenied; else m_nState = unableToLoad; } break; default: ASSERT(FALSE); } VERIFY(SUCCEEDED(pComponentDataObject->ChangeNode(this, CHANGE_RESULT_ITEM_ICON))); VERIFY(SUCCEEDED(pComponentDataObject->UpdateVerbState(this))); } BOOL CADSIEditConnectionNode::OnRefresh(CComponentDataObject* pComponentData, CNodeList* pNodeList) { BOOL bRet = FALSE; DWORD dwCount = 0; if (pNodeList == NULL) { dwCount = 1; } else { dwCount = pNodeList->GetCount(); } if (dwCount > 1) // multiple selection { POSITION pos = pNodeList->GetHeadPosition(); while (pos != NULL) { CTreeNode* pNode = pNodeList->GetNext(pos); ASSERT(pNode != NULL); CNodeList nodeList; nodeList.AddTail(pNode); if (!pNode->OnRefresh(pComponentData, &nodeList)) { bRet = FALSE; } } } else if (dwCount == 1) // single selection { if(CContainerNode::OnRefresh(pComponentData, pNodeList)) { CADSIEditContainerNode * pNextNode; POSITION pos = m_containerChildList.GetHeadPosition(); while (pos != NULL) { pNextNode = dynamic_cast(m_containerChildList.GetNext(pos)); ASSERT(pNextNode != NULL); CNodeList nodeList; nodeList.AddTail(pNextNode); pNextNode->OnRefresh(pComponentData, &nodeList); } return TRUE; } } return FALSE; } HRESULT CADSIEditConnectionNode::OnCommand(long nCommandID, DATA_OBJECT_TYPES type, CComponentDataObject* pComponentData, CNodeList* pNodeList) { ASSERT (pNodeList->GetCount() == 1); // should only be a single selection switch (nCommandID) { case IDM_SETTINGS_CONNECTION : OnSettings(pComponentData); break; case IDM_REMOVE_CONNECTION : OnRemove(pComponentData); break; case IDM_NEW_OBJECT : OnCreate(pComponentData); break; case IDM_FILTER : OnFilter(pComponentData); break; case IDM_UPDATE_SCHEMA : OnUpdateSchema(); break; case IDM_NEW_QUERY : OnNewQuery(pComponentData); break; default: ASSERT(FALSE); // Unknown command! return E_FAIL; } return S_OK; } void CADSIEditConnectionNode::OnUpdateSchema() { // Force an update of the schema cache CString szRootDSE; CConnectionData* pConnectData = GetConnectionData(); CComPtr spDirObject; HRESULT hr = GetRootDSEObject(pConnectData, &spDirObject); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return; } VARIANT var; var.vt = VT_I4; var.lVal = 1; hr = spDirObject->Put(CComBSTR(L"updateSchemaNow"), var); if (FAILED(hr)) { ADSIEditErrorMessage(hr); return; } CString szSchema; pConnectData->GetAbstractSchemaPath(szSchema); szSchema = szSchema.Left(szSchema.GetLength()- 1); CComPtr spSchemaObject; HRESULT hCredResult; hr = OpenObjectWithCredentials( pConnectData, pConnectData->GetCredentialObject()->UseCredentials(), szSchema, IID_IADs, (LPVOID*) &spSchemaObject, NULL, hCredResult ); if ( FAILED(hr) ) { if (SUCCEEDED(hCredResult)) { ADSIEditErrorMessage(hr); } return; } hr = spSchemaObject->GetInfo(); if (FAILED(hr)) { ADSIEditErrorMessage(hr); } // // Now clear the schema cache // m_SchemaCache.Clear(); ADSIEditMessageBox(IDS_SCHEMA_UPDATE_SUCCESSFUL, MB_OK); } void CADSIEditConnectionNode::OnNewQuery(CComponentDataObject* pComponentData) { CThemeContextActivator activator; CString sConnectPath; GetADsObject()->GetPath(sConnectPath); CConnectionData* pConnectData = GetConnectionData(); CCredentialObject* pCredObject = pConnectData->GetCredentialObject(); CString szServer; pConnectData->GetDomainServer(szServer); CADSIEditQueryDialog queryDialog(szServer, sConnectPath, pCredObject); if (queryDialog.DoModal() == IDOK) { BOOL bOneLevel; CString sQueryString, sName, sPath; queryDialog.GetResults(sName, sQueryString, sPath, &bOneLevel); CADSIEditConnectionNode* pConnectNode = GetADsObject()->GetConnectionNode(); CADsObject* pObject = new CADsObject(); if (pObject) { CADSIEditQueryData *pQueryData = new CADSIEditQueryData(); if (pQueryData) { // Name pObject->SetName(sName); pQueryData->SetName(sName); // Set the root path of the query string pObject->SetPath(sPath); pQueryData->SetRootPath(sPath); // Set the query string pQueryData->SetFilter(sQueryString); pObject->SetIntermediateNode(TRUE); pObject->SetContainer(TRUE); pObject->SetComplete(TRUE); pObject->SetConnectionNode(pConnectNode); // Set the scope of the query ADS_SCOPEENUM scope; scope = (bOneLevel) ? ADS_SCOPE_ONELEVEL : ADS_SCOPE_SUBTREE; pQueryData->SetScope(scope); // Create the query node with imbedded objects CADSIEditQueryNode* pNewQueryNode = new CADSIEditQueryNode(pObject, pQueryData); if (pNewQueryNode) { // // Set the display name // CString sDisplayName; pQueryData->GetDisplayName(sDisplayName); pNewQueryNode->SetDisplayName(sDisplayName); // // Add to connection node's list of queries // pConnectNode->AddQueryToList(pQueryData); if (pConnectNode->IsExpanded()) { VERIFY(pConnectNode->AddChildToListAndUI(pNewQueryNode, pComponentData)); pComponentData->SetDescriptionBarText(this); } } else { delete pObject; pObject = 0; delete pQueryData; pQueryData = 0; } } else { delete pObject; pObject = 0; } } } } void CADSIEditConnectionNode::OnFilter(CComponentDataObject* pComponentData) { CThemeContextActivator activator; CADSIFilterDialog filterDialog(m_pConnectData); if (filterDialog.DoModal() == IDOK) { CNodeList nodeList; nodeList.AddTail(this); OnRefresh(pComponentData, &nodeList); } } void CADSIEditConnectionNode::OnCreate(CComponentDataObject* pComponentData) { CThemeContextActivator activator; CCreatePageHolder* pHolder = new CCreatePageHolder(GetContainer(), this, pComponentData); ASSERT(pHolder != NULL); pHolder->SetSheetTitle(IDS_PROP_CONTAINER_TITLE, this); pHolder->DoModalWizard(); } BOOL CADSIEditConnectionNode::OnSetDeleteVerbState(DATA_OBJECT_TYPES type, BOOL* pbHideVerb, CNodeList* pNodeList) { *pbHideVerb = TRUE; // always hid the verb return FALSE; } BOOL CADSIEditConnectionNode::OnAddMenuItem(LPCONTEXTMENUITEM2 pContextMenuItem, long *pInsertionAllowed) { if (IsThreadLocked() || IsSheetLocked()) { pContextMenuItem->fFlags = MF_GRAYED; return TRUE; } if (GetConnectionData()->GetFilter()->InUse()) { pContextMenuItem->fFlags = MF_CHECKED; return TRUE; } return TRUE; } HRESULT CADSIEditConnectionNode::OnRename(CComponentDataObject* pComponentData, LPWSTR lpszNewName) { HRESULT hr = S_OK; BOOL bLocked = IsThreadLocked(); ASSERT(!bLocked); // cannot do refresh on locked node, the UI should prevent this if (bLocked) { return hr; } if (!lpszNewName) { return E_INVALIDARG; } CString szDisplayExtra; m_pConnectData->GetDomainServer(szDisplayExtra); szDisplayExtra = L" [" + szDisplayExtra + L"]"; m_pConnectData->SetName(lpszNewName); SetDisplayName(lpszNewName + szDisplayExtra); return hr; } void CADSIEditConnectionNode::OnRemove(CComponentDataObject* pComponentData) { CString sLoadString, sCaption; // NOTICE-2002/03/01-artm CString can throw out of memory exception, // but that needs to be handled at a higher level so don't worry about // it here. if (sLoadString.LoadString(IDS_MSG_REMOVE_CONNECTION)) { sCaption.Format((LPWSTR)(LPCWSTR)sLoadString, GetDisplayName()); } if (ADSIEditMessageBox(sCaption, MB_YESNO | MB_DEFBUTTON2) == IDYES) { if (IsSheetLocked()) { if (!CanCloseSheets()) return; pComponentData->GetPropertyPageHolderTable()->DeleteSheetsOfNode(this); } ASSERT(!IsSheetLocked()); // now remove from the UI DeleteHelper(pComponentData); pComponentData->SetDescriptionBarText(GetContainer()); pComponentData->UpdateResultPaneView(GetContainer()); delete this; // gone } } void CADSIEditConnectionNode::OnSettings(CComponentDataObject* pComponentData) { CWaitCursor cursor; CThemeContextActivator activator; CComponentDataObject* pComponentDataObject = ((CRootData*)(GetContainer()->GetRootContainer()))->GetComponentDataObject(); ASSERT(pComponentDataObject != NULL); CContainerNode* pContNode = dynamic_cast(GetContainer()); ASSERT(pContNode != NULL); CADSIEditConnectDialog ConnectDialog(pContNode, this, pComponentDataObject, m_pConnectData); if (ConnectDialog.DoModal() == IDOK) { cursor.Restore(); if (HasQueries()) { if (AfxMessageBox(IDS_MSG_EXISTING_QUERIES, MB_YESNO) == IDYES) { RemoveAllQueriesFromList(); } } CNodeList nodeList; nodeList.AddTail(this); OnRefresh(pComponentData, &nodeList); } } BOOL CADSIEditConnectionNode::OnSetRefreshVerbState(DATA_OBJECT_TYPES type, BOOL* pbHide, CNodeList* pNodeList) { ASSERT(pNodeList->GetCount() == 1); *pbHide = FALSE; return !IsThreadLocked(); } HRESULT CADSIEditConnectionNode::CreateFromStream(IStream* pStm, CADSIEditConnectionNode** ppConnectionNode) { WCHAR szBuffer[MAX_CONNECT_NAME_LENGTH + 1]; ULONG nLen; // WCHAR counting NULL ULONG cbRead; VERIFY(SUCCEEDED(pStm->Read((void*)&nLen,sizeof(UINT), &cbRead))); ASSERT(cbRead == sizeof(UINT)); VERIFY(SUCCEEDED(pStm->Read((void*)szBuffer,sizeof(WCHAR)*nLen, &cbRead))); ASSERT(cbRead == sizeof(WCHAR)*nLen); CConnectionData* pConnect = CConnectionData::Load(pStm); *ppConnectionNode = new CADSIEditConnectionNode(pConnect); ASSERT(*ppConnectionNode != NULL); CString szDisplayExtra, szDisplay; pConnect->GetDomainServer(szDisplayExtra); szDisplay = CString(szBuffer) + L" [" + szDisplayExtra + L"]"; (*ppConnectionNode)->SetDisplayName(szDisplay); (*ppConnectionNode)->SetConnectionNode(*ppConnectionNode); (*ppConnectionNode)->LoadQueryListFromStream(pStm); return S_OK; } HRESULT CADSIEditConnectionNode::SaveToStream(IStream* pStm) { // for each connection name, write # of chars+NULL, and then the name ULONG cbWrite; CString szName; m_pConnectData->GetName(szName); SaveStringToStream(pStm, szName); m_pConnectData->Save(pStm); SaveQueryListToStream(pStm); return S_OK; } void CADSIEditConnectionNode::LoadQueryListFromStream(IStream* pStm) { ULONG cbRead; int iCount; VERIFY(SUCCEEDED(pStm->Read((void*)&iCount,sizeof(int), &cbRead))); ASSERT(cbRead == sizeof(int)); for (int idx = 0; idx < iCount; idx++) { CADSIEditQueryData* pQueryData = new CADSIEditQueryData(); CString sName, sQueryString, sPath; // FUTURE-2002/03/01-artm Function LoadStringFromStream() should return // success/error code and this function should call it. // Who knows what kind of stream we've been given and how it could // fail???? LoadStringFromStream(pStm, sName); LoadStringFromStream(pStm, sQueryString); LoadStringFromStream(pStm, sPath); pQueryData->SetName(sName); pQueryData->SetFilter(sQueryString); CString sRootPath; BuildQueryPath(sPath, sRootPath); pQueryData->SetRootPath(sRootPath); ADS_SCOPEENUM scope; VERIFY(SUCCEEDED(pStm->Read((void*)&scope, sizeof(ADS_SCOPEENUM), &cbRead))); ASSERT(cbRead == sizeof(ADS_SCOPEENUM)); pQueryData->SetScope(scope); AddQueryToList(pQueryData); } } void CADSIEditConnectionNode::BuildQueryPath(const CString& sPath, CString& sRootPath) { CConnectionData* pConnectData = GetConnectionData(); CString sServer, sLDAP, sPort, sTemp; pConnectData->GetDomainServer(sServer); pConnectData->GetLDAP(sLDAP); pConnectData->GetPort(sPort); if (sServer != _T("")) { sTemp = sLDAP + sServer; if (sPort != _T("")) { sTemp = sTemp + _T(":") + sPort + _T("/"); } else { sTemp = sTemp + _T("/"); } sRootPath = sTemp + sPath; } else { sRootPath = sLDAP + sPath; } } void CADSIEditConnectionNode::SaveQueryListToStream(IStream* pStm) { ULONG cbWrite; int iCount = m_queryList.GetCount(); VERIFY(SUCCEEDED(pStm->Write((void*)&iCount, sizeof(int),&cbWrite))); ASSERT(cbWrite == sizeof(int)); POSITION pos = m_queryList.GetHeadPosition(); while (pos != NULL) { CADSIEditQueryData* pQueryData = m_queryList.GetNext(pos); ASSERT(pQueryData != NULL); ADS_SCOPEENUM scope; CString sName, sQueryString, sRootPath; pQueryData->GetName(sName); pQueryData->GetFilter(sQueryString); pQueryData->GetDisplayPath(sRootPath); scope = pQueryData->GetScope(); // save the query info to stream SaveStringToStream(pStm, sName); SaveStringToStream(pStm, sQueryString); SaveStringToStream(pStm, sRootPath); // Save the scope VERIFY(SUCCEEDED(pStm->Write((void*)&scope, sizeof(ADS_SCOPEENUM),&cbWrite))); ASSERT(cbWrite == sizeof(ADS_SCOPEENUM)); } }