/*++ Copyright (c) 1994-2001 Microsoft Corporation Module Name : iismbnode.cpp Abstract: CIISMBNode Object Author: Ronald Meijer (ronaldm) Sergei Antonov (sergeia) Project: Internet Services Manager Revision History: 10/28/2000 sergeia Split from iisobj.cpp --*/ #include "stdafx.h" #include "common.h" #include "inetprop.h" #include "InetMgrApp.h" #include "supdlgs.h" #include "iisobj.h" #include "ftpsht.h" #include "w3sht.h" #include "fltdlg.h" #include "aclpage.h" #include "impexp.h" #include "util.h" #include "tracker.h" #include #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW extern INT g_iDebugOutputLevel; extern CPropertySheetTracker g_OpenPropertySheetTracker; // // CIISMBNode implementation // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* static */ LPOLESTR CIISMBNode::_cszSeparator = _T("/"); /* static */ CComBSTR CIISMBNode::_bstrRedirectPathBuf; CIISMBNode::CIISMBNode( IN CIISMachine * pOwner, IN LPCTSTR szNode ) /*++ Routine Description: Constructor Arguments: CIISMachine * pOwner : Owner machine object LPCTSTR szNode : Node name Return Value: N/A --*/ : m_bstrNode(szNode), m_bstrURL(NULL), m_pOwner(pOwner) { ASSERT_READ_PTR(szNode); ASSERT_READ_PTR(pOwner); if (this != m_pOwner) { m_pOwner->AddRef(); } m_pMachineObject = m_pOwner; if (g_iDebugOutputLevel & DEBUG_FLAG_CIISMBNODE) { TRACEEOL("AddRef to m_pOwner: node " << szNode << " count " << m_pOwner->UseCount()) } } CIISMBNode::~CIISMBNode() { if (this != m_pOwner) { m_pOwner->Release(); } if (g_iDebugOutputLevel & DEBUG_FLAG_CIISMBNODE) { TRACEEOL("Released m_pOwner: node " << m_bstrNode << " count " << m_pOwner->UseCount()) } } CIISMBNode::CreateTag() { CIISMachine * pMachine = GetOwner(); if (pMachine) { CComBSTR bstrPath; BuildMetaPath(bstrPath); m_strTag = pMachine->QueryDisplayName(); m_strTag += bstrPath; } } void CIISMBNode::SetErrorOverrides( IN OUT CError & err, IN BOOL fShort ) const /*++ Routine Description: Set error message overrides Arguments: CError err : Error message object BOOL fShort : TRUE to use only single-line errors Return Value: None --*/ { // // Substitute friendly message for some ID codes. // // CODEWORK: Add global overrides as well. // err.AddOverride(EPT_S_NOT_REGISTERED, fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA); err.AddOverride(RPC_S_SERVER_UNAVAILABLE, fShort ? IDS_ERR_RPC_NA_SHORT : IDS_ERR_RPC_NA); err.AddOverride(RPC_S_UNKNOWN_IF, IDS_ERR_INTERFACE); err.AddOverride(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE); err.AddOverride(REGDB_E_CLASSNOTREG, IDS_ERR_NO_INTERFACE); err.AddOverride(ERROR_DUP_NAME, fShort ? IDS_ERR_BINDING_SHORT : IDS_ERR_BINDING_LONG); if (!fShort) { err.AddOverride(ERROR_ACCESS_DENIED, IDS_ERR_ACCESS_DENIED); } } BOOL CIISMBNode::IsAdministrator() const { CIISMBNode * that = (CIISMBNode *)this; return that->GetOwner()->HasAdministratorAccess(); } void CIISMBNode::DisplayError(CError& err, HWND hWnd) const /*++ Routine Description: Display error message box. Substituting some friendly messages for some specific error codes Arguments: CError & err : Error object contains code to be displayed --*/ { if (err == E_POINTER) { err.Reset(); } if (err.Failed()) { SetErrorOverrides(err); err.MessageBox(hWnd); } } CIISMBNode * CIISMBNode::GetParentNode() const /*++ Routine Description: Helper function to return the parent node in the scope tree Arguments: None Return Value: Parent CIISMBNode or NULL. --*/ { LONG_PTR cookie = NULL; HSCOPEITEM hParent; CIISMBNode * pNode = NULL; HRESULT hr = S_OK; SCOPEDATAITEM si; ::ZeroMemory(&si, sizeof(SCOPEDATAITEM)); CIISObject * ThisConst = (CIISObject *)this; IConsoleNameSpace2 * pConsoleNameSpace = (IConsoleNameSpace2 *)ThisConst->GetConsoleNameSpace(); if (m_hResultItem != 0) { si.mask = SDI_PARAM; si.ID = m_hScopeItem; hr = pConsoleNameSpace->GetItem(&si); if (SUCCEEDED(hr)) { cookie = si.lParam; } } else { // Get our Item si.mask = SDI_PARAM; si.ID = m_hScopeItem; // if we can get our item, then try to get our parents // we need to do this because MMC will AV if we don't exist first... if (SUCCEEDED(pConsoleNameSpace->GetItem(&si))) { hr = pConsoleNameSpace->GetParentItem( m_hScopeItem, &hParent, &cookie ); } } if (SUCCEEDED(hr)) { pNode = (CIISMBNode *)cookie; ASSERT_PTR(pNode); } return pNode; } /* virtual */ HRESULT CIISMBNode::BuildMetaPath( OUT CComBSTR & bstrPath ) const /*++ Routine Description: Recursively build up the metabase path from the current node and its parents Arguments: CComBSTR & bstrPath : Returns metabase path Return Value: HRESULT --*/ { HRESULT hr = S_OK; CIISMBNode * pNode = GetParentNode(); if (pNode) { hr = pNode->BuildMetaPath(bstrPath); if (SUCCEEDED(hr)) { bstrPath.Append(_cszSeparator); bstrPath.Append(QueryNodeName()); } return hr; } // // No parent node // // ASSERT_MSG("No parent node"); return E_UNEXPECTED; } HRESULT CIISMBNode::FillCustomData(CLIPFORMAT cf, LPSTREAM pStream) { HRESULT hr = DV_E_CLIPFORMAT; ULONG uWritten; if (cf == m_CCF_MachineName) { hr = pStream->Write( QueryMachineName(), (ocslen((OLECHAR*)QueryMachineName()) + 1) * sizeof(OLECHAR), &uWritten ); ASSERT(SUCCEEDED(hr)); return hr; } // // Generate complete metabase path for this node // CString strField; CString strMetaPath; CComBSTR bstr; if (FAILED(hr = BuildMetaPath(bstr))) { ASSERT(FALSE); return hr; } strMetaPath = bstr; if (cf == m_CCF_MetaPath) { // // Whole metabase path requested // //BUG:670171 // Path from BuildMetaPath() is returning something like // /LM/W3SVC/1/ROOT // // however, it should be returned as LM/W3SVC/1/ROOT to be // backwards compatible with how iis5 used to work... if (_T("/") == strMetaPath.Left(1)) { strField = strMetaPath.Right(strMetaPath.GetLength() - 1); } else { strField = strMetaPath; } } else { // // A portion of the metabase is requested. Return the requested // portion // LPCTSTR lpMetaPath = (LPCTSTR)strMetaPath; LPCTSTR lpEndPath = lpMetaPath + strMetaPath.GetLength() + 1; LPCTSTR lpLM = NULL; LPCTSTR lpSvc = NULL; LPCTSTR lpInstance = NULL; LPCTSTR lpParent = NULL; LPCTSTR lpNode = NULL; // // Break up the metabase path in portions // if (lpLM = _tcschr(lpMetaPath, _T('/'))) { ++lpLM; if (lpSvc = _tcschr(lpLM, _T('/'))) { ++lpSvc; if (lpInstance = _tcschr(lpSvc, _T('/'))) { ++lpInstance; if (lpParent = _tcschr(lpInstance, _T('/'))) { ++lpParent; lpNode = _tcsrchr(lpParent, _T('/')); if (lpNode) { ++lpNode; } } } } } int n1, n2; if (cf == m_CCF_Service) { // // Requested the service string // if (lpSvc) { n1 = DIFF(lpSvc - lpMetaPath); n2 = lpInstance ? DIFF(lpInstance - lpSvc) : DIFF(lpEndPath - lpSvc); strField = strMetaPath.Mid(n1, n2 - 1); } } else if (cf == m_CCF_Instance) { // // Requested the instance number // if (lpInstance) { n1 = DIFF(lpInstance - lpMetaPath); n2 = lpParent ? DIFF(lpParent - lpInstance) : DIFF(lpEndPath - lpInstance); strField = strMetaPath.Mid(n1, n2 - 1); } } else if (cf == m_CCF_ParentPath) { // // Requestd the parent path // if (lpParent) { n1 = DIFF(lpParent - lpMetaPath); n2 = lpNode ? DIFF(lpNode - lpParent) : DIFF(lpEndPath - lpParent); strField = strMetaPath.Mid(n1, n2 - 1); } } else if (cf == m_CCF_Node) { // // Requested the node name // if (lpNode) { n1 = DIFF(lpNode - lpMetaPath); n2 = DIFF(lpEndPath - lpNode); strField = strMetaPath.Mid(n1, n2 - 1); } } else { ASSERT(FALSE); DV_E_CLIPFORMAT; } } TRACEEOLID("Requested metabase path data: " << strField); int len = strField.GetLength() + 1; hr = pStream->Write(strField, (ocslen(strField) + 1) * sizeof(OLECHAR), &uWritten); ASSERT(SUCCEEDED(hr)); return hr; } HRESULT CIISMBNode::BuildURL( OUT CComBSTR & bstrURL ) const /*++ Routine Description: Recursively build up the URL from the current node and its parents. Arguments: CComBSTR & bstrURL : Returns URL Return Value: HRESULT --*/ { HRESULT hr = S_OK; // // Prepend parent portion // CIISMBNode * pNode = GetParentNode(); if (pNode) { hr = pNode->BuildURL(bstrURL); // // And our portion // if (SUCCEEDED(hr)) { bstrURL.Append(_cszSeparator); bstrURL.Append(QueryNodeName()); } return hr; } // // No parent node // ASSERT_MSG("No parent node"); return E_UNEXPECTED; } BOOL CIISMBNode::OnLostInterface( IN OUT CError & err ) /*++ Routine Description: Deal with lost interface. Ask the user to reconnect. Arguments: CError & err : Error object Return Value: TRUE if the interface was successfully recreated. FALSE otherwise. If it tried and failed the error will --*/ { AFX_MANAGE_STATE(::AfxGetStaticModuleState()); CString str; str.Format(IDS_RECONNECT_WARNING, QueryMachineName()); if (YesNoMessageBox(str)) { // // Attempt to recreate the interface // err = CreateInterface(TRUE); return err.Succeeded(); } return FALSE; } HRESULT CIISMBNode::DeleteNode(IResultData * pResult) { CError err; // check if they have the property sheet open on it. if (IsMyPropertySheetOpen()) { ::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET); return S_OK; } // this could be an orphaned property sheet // check if an orphaned property sheet is open on this item. CIISObject * pAlreadyOpenProp = NULL; if (TRUE == g_OpenPropertySheetTracker.FindAlreadyOpenPropertySheet(this,&pAlreadyOpenProp)) { // Bring it to the foreground, and bail HWND hHwnd = 0; if (pAlreadyOpenProp) { if (hHwnd = pAlreadyOpenProp->IsMyPropertySheetOpen()) { if (hHwnd && (hHwnd != (HWND) 1)) { // Perhapse we should cancel the already // opened property sheet...just a thought if (!SetForegroundWindow(hHwnd)) { // wasn't able to bring this property sheet to // the foreground, the propertysheet must not // exist anymore. let's just clean the hwnd // so that the user will be able to open propertysheet pAlreadyOpenProp->SetMyPropertySheetOpen(0); } else { ::AfxMessageBox(IDS_CLOSE_PROPERTY_SHEET); return S_OK; } } } } } CComBSTR path; err = BuildMetaPath(path); if (err.Succeeded()) { err = CheckForMetabaseAccess(METADATA_PERMISSION_WRITE,this,TRUE,path); if (!IsLostInterface(err)) { // reset error if an other error other than No interface err.Reset(); } } if (err.Succeeded()) { if (!NoYesMessageBox(IDS_CONFIRM_DELETE)) return err; do { CMetaInterface * pInterface = QueryInterface(); ASSERT(pInterface != NULL); CMetaKey mk(pInterface, METADATA_MASTER_ROOT_HANDLE, METADATA_PERMISSION_WRITE); if (!mk.Succeeded()) break; err = mk.DeleteKey(path); if (err.Failed()) break; // don't hold the Metabasekey open // (RemoveScopeItem may do a lot of things,and lock the metabase for other read requests) mk.Close(); m_fFlaggedForDeletion = TRUE; err = RemoveScopeItem(); } while (FALSE); } if (err.Failed()) { DisplayError(err); } return err; } HRESULT CIISMBNode::EnumerateVDirs( HSCOPEITEM hParent, CIISService * pService, BOOL bDisplayError) /*++ Routine Description: Enumerate scope child items. Arguments: HSCOPEITEM hParent : Parent console handle CIISService * pService : Service type --*/ { ASSERT_PTR(pService); CError err; CString strVRoot; CIISDirectory * pDir; if (pService->QueryMajorVersion() < 6) { CMetaEnumerator * pme = NULL; err = CreateEnumerator(pme); while (err.Succeeded()) { err = pme->Next(strVRoot); if (err.Succeeded()) { CChildNodeProps child(pme, strVRoot, WITH_INHERITANCE, FALSE); err = child.LoadData(); DWORD dwWin32Error = err.Win32Error(); if (err.Failed()) { // // Filter out the non-fatal errors // switch(err.Win32Error()) { case ERROR_ACCESS_DENIED: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: err.Reset(); break; default: TRACEEOLID("Fatal error occurred " << err); } } if (err.Succeeded()) { // // Skip non-virtual directories (that is, those with // inherited vrpaths) // if (!child.IsPathInherited()) { // // Construct with full information. // pDir = new CIISDirectory( m_pOwner, pService, strVRoot, child.IsEnabledApplication(), child.QueryWin32Error(), child.GetRedirectedPath() ); if (!pDir) { err = ERROR_NOT_ENOUGH_MEMORY; break; } pDir->AddRef(); err = pDir->AddToScopePane(hParent); } } } } SAFE_DELETE(pme); if (err.Win32Error() == ERROR_NO_MORE_ITEMS) { err.Reset(); } } else { do { CComBSTR bstrPath; err = BuildMetaPath(bstrPath); BREAK_ON_ERR_FAILURE(err); err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrPath); if (!IsLostInterface(err)) { // reset error if an other error other than No interface err.Reset(); } BREAK_ON_ERR_FAILURE(err); CMetaKey mk(QueryInterface(), bstrPath, METADATA_PERMISSION_READ); err = mk.QueryResult(); BREAK_ON_ERR_FAILURE(err); CStringListEx list; err = mk.GetChildPaths(list); BREAK_ON_ERR_FAILURE(err); CString key_type; BOOL bPossbileVDir = FALSE; POSITION pos = list.GetHeadPosition(); while (err.Succeeded() && pos != NULL) { strVRoot = list.GetNext(pos); err = mk.QueryValue(MD_KEY_TYPE, key_type, NULL, strVRoot); bPossbileVDir = FALSE; if (err.Succeeded()) { if (key_type.CompareNoCase(_T(IIS_CLASS_WEB_VDIR)) == 0 || key_type.CompareNoCase(_T(IIS_CLASS_FTP_VDIR)) == 0) { bPossbileVDir = TRUE; } } else { if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND) { // there is no KeyType // for backward compatibility reasons -- this could be a VDir! bPossbileVDir = TRUE; } } if (bPossbileVDir) { CChildNodeProps child(&mk, strVRoot, WITH_INHERITANCE, FALSE); err = child.LoadData(); DWORD dwWin32Error = err.Win32Error(); if (err.Failed()) { // // Filter out the non-fatal errors // switch(err.Win32Error()) { case ERROR_ACCESS_DENIED: case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: err.Reset(); break; default: TRACEEOLID("Fatal error occurred " << err); } } if (err.Succeeded()) { // // Skip non-virtual directories (that is, those with // inherited vrpaths) // if (!child.IsPathInherited()) { pDir = new CIISDirectory( m_pOwner, pService, strVRoot, child.IsEnabledApplication(), child.QueryWin32Error(), child.GetRedirectedPath() ); if (!pDir) { err = ERROR_NOT_ENOUGH_MEMORY; break; } pDir->AddRef(); err = pDir->AddToScopePane(hParent); } } } if (err == (HRESULT)MD_ERROR_DATA_NOT_FOUND) { err.Reset(); } } } while (FALSE); } if (err.Failed() && bDisplayError) { DisplayError(err); } return err; } BOOL CIISMBNode::GetPhysicalPath( LPCTSTR metaPath, CString & alias, CString & physicalPath ) /*++ Routine Description: Build a physical path for the current node. Starting with the current node, walk up the tree appending node names until a virtual directory with a real physical path is found Arguments: CString & physicalPath : Returns file path Return Value: Pointer to path --*/ { if (CMetabasePath::IsMasterInstance(metaPath)) return FALSE; BOOL fInherit = FALSE; CMetaInterface * pInterface = QueryInterface(); CError err; ASSERT(pInterface != NULL); if (pInterface) { CMetaKey mk(pInterface); err = mk.QueryValue( MD_VR_PATH, physicalPath, &fInherit, metaPath ); if (err.Succeeded()) { physicalPath.TrimRight(); physicalPath.TrimLeft(); } } if (err.Failed()) { CString lastNode; CMetabasePath::GetLastNodeName(metaPath, lastNode); PathAppend(lastNode.GetBuffer(MAX_PATH), alias); lastNode.ReleaseBuffer(); CString buf(metaPath); if (NULL == CMetabasePath::ConvertToParentPath(buf)) { return FALSE; } else { if (GetPhysicalPath(buf, lastNode, physicalPath)) { return TRUE; } } } if (!alias.IsEmpty()) { // Check if physicalPath is \\.\ (device type) // PathAppend will hose on this and get rid of the \\.\ part // example: before \\.\c:\temp, after \\c:\temp // obviously this is bad if there are Device path's in there if (IsDevicePath(physicalPath)) { CString csTemp; csTemp = physicalPath; physicalPath = AppendToDevicePath(csTemp, alias); } else { PathAppend(physicalPath.GetBuffer(MAX_PATH), alias); physicalPath.ReleaseBuffer(); } } return TRUE; } HRESULT CIISMBNode::CleanResult(IResultData * lpResultData) { CError err; POSITION pos = m_ResultViewList.GetHeadPosition(); while (pos != NULL) { POSITION pos_current = pos; ResultViewEntry e = m_ResultViewList.GetNext(pos); if (e._ResultData == (DWORD_PTR)lpResultData) { if (!e._ResultItems->IsEmpty()) { // We should do this MMC cleaning before we delete our data err = lpResultData->DeleteAllRsltItems(); POSITION p = e._ResultItems->GetHeadPosition(); while (p != NULL) { CIISFileName * pNode = e._ResultItems->GetNext(p); // err = lpResultData->DeleteItem(pNode->m_hResultItem, 0); if (err.Failed()) { ASSERT(FALSE); break; } pNode->Release(); } e._ResultItems->RemoveAll(); } delete e._ResultItems; // pos was updated above in GetNext m_ResultViewList.RemoveAt(pos_current); } } return err; } HRESULT CIISMBNode::EnumerateResultPane_( BOOL fExpand, IHeaderCtrl * lpHeader, IResultData * lpResultData, CIISService * pService ) { CError err; CIISMachine * pMachine = (CIISMachine *) GetMachineObject(); WIN32_FIND_DATA w32data; HANDLE hFind = INVALID_HANDLE_VALUE; CString dir; CComBSTR root; CString physPath, alias, csPathMunged; if (m_fFlaggedForDeletion) { return S_OK; } if (!HasFileSystemFiles()) { goto EnumerateResultPane__Exit; } if (!fExpand) { err = CleanResult(lpResultData); goto EnumerateResultPane__Exit; } BuildMetaPath(root); err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,root); if (!IsLostInterface(err)) { // reset error if an other error other than No interface err.Reset(); } if (err.Failed()) { goto EnumerateResultPane__Exit; } GetPhysicalPath(CString(root), alias, physPath); // ------------------------------------------------------------- // Before we do anything we need to see if it's a "special" path // // Everything after this function must validate against csPathMunged... // this is because IsSpecialPath could have munged it... // ------------------------------------------------------------- csPathMunged = physPath; #ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS GetSpecialPathRealPath(0,physPath,csPathMunged); #endif // Prepare for target machine metabase lookup BOOL fCheckMetabase = FALSE; if (PathIsUNC(csPathMunged)) { fCheckMetabase = TRUE; CMetaKey mk(QueryInterface(), root, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE); CError errMB(mk.QueryResult()); if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND) { // // Metabase path not found, not a problem. // fCheckMetabase = FALSE; errMB.Reset(); } } if (IsDevicePath(csPathMunged)) { // check if the device path // points to an actual dir/file // if it does then enumerate it. if (IsSpecialPath(csPathMunged,TRUE,TRUE)) { // Remunge this one more time! CString csBefore; csBefore = csPathMunged; GetSpecialPathRealPath(1,csBefore,csPathMunged); } else { return err; } } // WARNING:physPath could be empty! csPathMunged.TrimLeft(); csPathMunged.TrimRight(); if (csPathMunged.IsEmpty()){goto EnumerateResultPane__Exit;} if (pService->IsLocal() || PathIsUNC(csPathMunged)) { dir = csPathMunged; } else { ::MakeUNCPath(dir, pService->QueryMachineName(), csPathMunged); } dir.TrimLeft(); dir.TrimRight(); if (dir.IsEmpty()){goto EnumerateResultPane__Exit;} if (PathIsUNC(dir)) { CString server, user, password; CString MyTestDir; MyTestDir = dir; MyTestDir += _T("\\*"); // we are trying to get the servername portion // PathFindNextComponent should return something like "servername\mydir\myfile.txt" // trim off everything after the 1st slash server = PathFindNextComponent(dir); int n = server.Find(_T('\\')); if (n != -1) { server = server.Left(n); } user = QueryInterface()->QueryAuthInfo()->QueryUserName(); password = QueryInterface()->QueryAuthInfo()->QueryPassword(); // we need to compare the servername that we want to get to // with the servername of the local computer. // this way we know if we need to net use to the machine! TCHAR szLocalMachineName[MAX_PATH + 1]; DWORD dwSize = MAX_PATH; if (0 == ::GetComputerName(szLocalMachineName, &dwSize)) { err.GetLastWinError(); goto EnumerateResultPane__Exit; } // // As it turned out in some cases we cannot get access to file system // even if we are connected to metabase. We will add connection in this // case also. // if (!pService->IsLocal() || server.CompareNoCase(szLocalMachineName) != 0 ) { BOOL bEmptyPassword = FALSE; // non-local resource, get connection credentials if (fCheckMetabase) { CMetaKey mk(QueryInterface(), root, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE); err = mk.QueryResult(); if (err.Succeeded()) { err = mk.QueryValue(MD_VR_USERNAME, user); if (err.Succeeded()) { err = mk.QueryValue(MD_VR_PASSWORD, password); bEmptyPassword = (err.Failed() ? TRUE : err.Succeeded() && password.IsEmpty()); } // these credentials could be empty. try defaults err.Reset(); } } // Add net use for this resource NETRESOURCE nr; nr.dwType = RESOURCETYPE_DISK; nr.lpLocalName = NULL; nr.lpRemoteName = (LPTSTR)(LPCTSTR)dir; nr.lpProvider = NULL; CString dir_ipc; dir_ipc = _T("\\\\"); dir_ipc += server; dir_ipc += _T("\\ipc$"); // Ensure we have a connection to this network file // if it already exists, it won't create another one // these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected. // Empty strings below mean no password, which is wrong. NULLs mean // default user and default password -- this could work better for local case. LPCTSTR p1 = password, p2 = user; // In case when password is really was set empty, passing NULL will fail. if (password.IsEmpty() && !bEmptyPassword){p1 = NULL;} if (user.IsEmpty()){p2 = NULL;} // Check if we have access // to the resource without netuse BOOL bNeedToNetUse = FALSE; hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // if we failed then we probably need to // net use to this resource! bNeedToNetUse = TRUE; } // -------------------- // Ensure we have a connection to this network file // if it already exists, it won't create another one // these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected. // -------------------- if (pMachine && bNeedToNetUse) { // try to setup a "net use \\computername\$ipc" connection // that everyone can use // set the share name to // \\machine\IPC$ nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir_ipc; //ERROR_LOGON_FAILURE DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (NO_ERROR == dwRet) { bNeedToNetUse = FALSE; } else { if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet) { pMachine->m_MachineWNetConnections.Disconnect(dir_ipc); dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); } } } // Check if we have access after the 1st net use. // We are connecting to a remote machine... // Check if we have access // to the resource without netuse hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // if we failed then we probably need to // net use to this resource! bNeedToNetUse = TRUE; } if (bNeedToNetUse) { if (pMachine) { nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir; DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (NO_ERROR != dwRet) { if (ERROR_ALREADY_ASSIGNED != dwRet) { if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet) { // Errored with already assigned // check if we have accesss... hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // stil don't have access // kill the current connection and the ipc$ resource pMachine->m_MachineWNetConnections.Disconnect(dir); pMachine->m_MachineWNetConnections.Disconnect(dir_ipc); // try to reconnect with the new path... nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir; dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet) { // Clean all connections to this machine and try again. pMachine->m_MachineWNetConnections.Clear(); dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); } } } else { err = dwRet; goto EnumerateResultPane__Exit; } } } } } } } if (PathIsUNCServerShare(dir)) { if (FALSE == DoesUNCShareExist(dir)) { err = ERROR_BAD_NETPATH; goto EnumerateResultPane__Exit; } } dir += _T("\\*"); hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(dir, &w32data); // Bug:756402, revert previous change. we need to display if hidden or system. const DWORD attr_skip = FILE_ATTRIBUTE_DIRECTORY; // | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; if (hFind == INVALID_HANDLE_VALUE) { err.GetLastWinError(); goto EnumerateResultPane__Exit; } ResultItemsList * pResList = AddResultItems(lpResultData); do { LPCTSTR name = w32data.cFileName; if ((w32data.dwFileAttributes & attr_skip) == 0) { CIISFileName * pNode = new CIISFileName( GetOwner(), pService, w32data.dwFileAttributes, name, NULL); if (!pNode) { err = ERROR_NOT_ENOUGH_MEMORY; break; } RESULTDATAITEM ri; ::ZeroMemory(&ri, sizeof(ri)); ri.mask = RDI_STR | RDI_IMAGE | RDI_PARAM; ri.str = MMC_CALLBACK; ri.nImage = pNode->QueryImage(); ri.lParam = (LPARAM)pNode; pNode->AddRef(); err = lpResultData->InsertItem(&ri); if (err.Succeeded()) { pNode->SetScopeItem(m_hScopeItem); pNode->SetResultItem(ri.itemID); pResList->AddTail(pNode); } else { pNode->Release(); } // commenting out this refreshdata // this is waaay too much of a performance hit // and slows down everything drastically. //pNode->RefreshData(); } } while (err.Succeeded() && FindNextFile(hFind, &w32data)); FindClose(hFind); EnumerateResultPane__Exit: return err; } ResultItemsList * CIISMBNode::AddResultItems(IResultData * pResultData) { ResultViewEntry e; e._ResultData = (DWORD_PTR)pResultData; e._ResultItems = new ResultItemsList; m_ResultViewList.AddTail(e); POSITION pos = m_ResultViewList.GetTailPosition(); return m_ResultViewList.GetAt(pos)._ResultItems; } HRESULT CIISMBNode::EnumerateWebDirs(HSCOPEITEM hParent, CIISService * pService) /*++ Routine Description: Enumerate scope file system child items. Arguments: HSCOPEITEM hParent : Parent console handle CIISService * pService : Service type Return Value: HRESULT --*/ { ASSERT_PTR(pService); CError err; CIISMachine * pMachine = (CIISMachine *) GetMachineObject(); WIN32_FIND_DATA w32data; HANDLE hFind = INVALID_HANDLE_VALUE; CString dir; CComBSTR root; BuildMetaPath(root); CString physPath, alias, csPathMunged; GetPhysicalPath(CString(root), alias, physPath); // ------------------------------------------------------------- // Before we do anything we need to see if it's a "special" path // // Everything after this function must validate against csPathMunged... // this is because IsSpecialPath could have munged it... // ------------------------------------------------------------- csPathMunged = physPath; #ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS GetSpecialPathRealPath(0,physPath,csPathMunged); #endif // Prepare for target machine metabase lookup BOOL fCheckMetabase = TRUE; CMetaKey mk(QueryInterface(), root, METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE); CError errMB(mk.QueryResult()); if (errMB.Win32Error() == ERROR_PATH_NOT_FOUND) { // // Metabase path not found, not a problem. // fCheckMetabase = FALSE; errMB.Reset(); } if (IsDevicePath(csPathMunged)) { // check if the device path // points to an actual dir/file // if it does then enumerate it. if (IsSpecialPath(csPathMunged,TRUE,TRUE)) { // Remunge this one more time! CString csBefore; csBefore = csPathMunged; GetSpecialPathRealPath(1,csBefore,csPathMunged); } else { goto EnumerateWebDirs_Exit; } } // WARNING:physPath could be empty! csPathMunged.TrimLeft(); csPathMunged.TrimRight(); if (csPathMunged.IsEmpty()){goto EnumerateWebDirs_Exit;} if (pService->IsLocal() || PathIsUNC(csPathMunged)) { dir = csPathMunged; } else { ::MakeUNCPath(dir, pService->QueryMachineName(), csPathMunged); } dir.TrimLeft(); dir.TrimRight(); if (dir.IsEmpty()){goto EnumerateWebDirs_Exit;} // ------------------------------ // Check if we need to "net use" // to the file resource on a remote machine // so we can enum it... // ------------------------------ if (PathIsUNC(dir)) { CString server, user, password; CString MyTestDir; MyTestDir = dir; MyTestDir += _T("\\*"); // we are trying to get the servername portion // PathFindNextComponent should return something like "servername\mydir\myfile.txt" // trim off everything after the 1st slash server = PathFindNextComponent(dir); int n = server.Find(_T('\\')); if (n != -1) {server = server.Left(n);} user = QueryInterface()->QueryAuthInfo()->QueryUserName(); password = QueryInterface()->QueryAuthInfo()->QueryPassword(); // we need to compare the servername that we want to get to // with the servername of the local computer. // this way we know if we need to net use to the machine! TCHAR szLocalMachineName[MAX_PATH + 1]; DWORD dwSize = MAX_PATH; if (0 == ::GetComputerName(szLocalMachineName, &dwSize)) { err.GetLastWinError(); goto EnumerateWebDirs_Exit; } // Check to see if the localmachine is different that the // machine we want to connect to to enum it's files upon... if (!pService->IsLocal() || server.CompareNoCase(szLocalMachineName) != 0 ) { // We are connecting to a path which is different from the computer name! BOOL bEmptyPassword = FALSE; // non-local resource, get connection credentials if (fCheckMetabase && PathIsUNC(csPathMunged)) { err = mk.QueryValue(MD_VR_USERNAME, user); if (err.Succeeded()) { err = mk.QueryValue(MD_VR_PASSWORD, password); bEmptyPassword = (err.Failed() ? TRUE : err.Succeeded() && password.IsEmpty()); } // these credentials could be empty. try defaults err.Reset(); } // Add use for this resource NETRESOURCE nr; nr.dwType = RESOURCETYPE_DISK; nr.lpLocalName = NULL; nr.lpRemoteName = (LPTSTR)(LPCTSTR)dir; nr.lpProvider = NULL; CString dir_ipc; dir_ipc = _T("\\\\"); dir_ipc += server; dir_ipc += _T("\\ipc$"); // Empty strings below mean no password, which is wrong. NULLs mean // default user and default password -- this could work better for local case. LPCTSTR p1 = password, p2 = user; // In case when password is really was set empty, passing NULL will fail. if (password.IsEmpty() && !bEmptyPassword){p1 = NULL;} if (user.IsEmpty()){p2 = NULL;} // Check if we have access // to the resource without netuse BOOL bNeedToNetUse = FALSE; hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // if we failed then we probably need to // net use to this resource! bNeedToNetUse = TRUE; } // -------------------- // Ensure we have a connection to this network file // if it already exists, it won't create another one // these Connections will be cleaned up in ~CIISMachine or when the machine is disconnected. // -------------------- if (pMachine && bNeedToNetUse) { // try to setup a "net use \\computername\$ipc" connection // that everyone can use // set the share name to // \\machine\IPC$ nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir_ipc; DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (NO_ERROR == dwRet) { bNeedToNetUse = FALSE; } else { if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet) { pMachine->m_MachineWNetConnections.Disconnect(dir_ipc); dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); } } } // Check if we have access after the 1st net use. // We are connecting to a remote machine... // Check if we have access // to the resource without netuse hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // if we failed then we probably need to // net use to this resource! bNeedToNetUse = TRUE; } if (bNeedToNetUse) { if (pMachine) { nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir; DWORD dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (NO_ERROR != dwRet) { if (ERROR_ALREADY_ASSIGNED != dwRet) { if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet || ERROR_ACCESS_DENIED == dwRet) { // Errored with already assigned // check if we have accesss... hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(MyTestDir, &w32data); if (hFind != INVALID_HANDLE_VALUE) { // successfull access FindClose(hFind); } else { // stil don't have access // kill the current connection and the ipc$ resource pMachine->m_MachineWNetConnections.Disconnect(dir); pMachine->m_MachineWNetConnections.Disconnect(dir_ipc); // try to reconnect with the new path... nr.lpRemoteName = (LPTSTR)(LPCTSTR) dir; dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwRet) { // Clean all connections to this machine and try again. pMachine->m_MachineWNetConnections.Clear(); dwRet = pMachine->m_MachineWNetConnections.Connect(&nr,p1,p2,0); } else { if (NO_ERROR != dwRet) { // Final failure, what now? } } } } else { err = dwRet; goto EnumerateWebDirs_Exit; } } } } } } } // ----------------------------------- // Enum thru the Physical file path... // ----------------------------------- dir += _T("\\*"); hFind = INVALID_HANDLE_VALUE; hFind = ::FindFirstFile(dir, &w32data); // Bug:756402, revert previous change. we need to display if hidden or system. // const DWORD attr_skip = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; if (hFind == INVALID_HANDLE_VALUE) { err.GetLastWinError(); goto EnumerateWebDirs_Exit; } do { LPCTSTR name = w32data.cFileName; if ( (w32data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 // Bug:756402, revert previous change. we need to display if hidden or system. // && (w32data.dwFileAttributes & attr_skip) == 0 && lstrcmp(name, _T(".")) != 0 && lstrcmp(name, _T("..")) != 0 ) { CIISFileName * pNode = new CIISFileName(m_pOwner, pService, w32data.dwFileAttributes, name, NULL); if (!pNode) { err = ERROR_NOT_ENOUGH_MEMORY; goto EnumerateWebDirs_Exit; } if (fCheckMetabase) { errMB = mk.DoesPathExist(w32data.cFileName); if (errMB.Succeeded()) { // // Match up with metabase properties. If the item // is found in the metabase with a non-inherited vrpath, // than a virtual root with this name exists, and this // file/directory should not be shown. // CString vrpath; BOOL f = FALSE; DWORD attr = 0; errMB = mk.QueryValue(MD_VR_PATH, vrpath, NULL, w32data.cFileName, &attr); if (errMB.Succeeded() && (attr & METADATA_ISINHERITED) == 0) { TRACEEOLID("file/directory exists as vroot -- tossing" << w32data.cFileName); pNode->Release(); continue; } } } pNode->AddRef(); err = pNode->AddToScopePane(hParent); } } while (err.Succeeded() && FindNextFile(hFind, &w32data)); FindClose(hFind); EnumerateWebDirs_Exit: if (err.Failed()) { DisplayError(err); } return err; } HRESULT CIISMBNode::CreateEnumerator(CMetaEnumerator *& pEnum) /*++ Routine Description: Create enumerator object for the current path. Requires interface to already be initialized Arguments: CMetaEnumerator *& pEnum : Returns enumerator Return Value: HRESULT --*/ { ASSERT(pEnum == NULL); ASSERT(m_hScopeItem != NULL); CComBSTR bstrPath; CError err(BuildMetaPath(bstrPath)); if (err.Succeeded()) { TRACEEOLID("Build metabase path: " << bstrPath); BOOL fContinue = TRUE; while(fContinue) { fContinue = FALSE; pEnum = new CMetaEnumerator(QueryInterface(), bstrPath); err = pEnum ? pEnum->QueryResult() : ERROR_NOT_ENOUGH_MEMORY; if (IsLostInterface(err)) { SAFE_DELETE(pEnum); fContinue = OnLostInterface(err); } } } return err; } /* virtual */ HRESULT CIISMBNode::Refresh(BOOL fReEnumerate) /*++ Routine Description: Refresh current node, and optionally re-enumerate child objects Arguments: BOOL fReEnumerate : If true, kill child objects, and re-enumerate --*/ { CError err; // // Set MFC state for wait cursor // AFX_MANAGE_STATE(::AfxGetStaticModuleState()); CWaitCursor wait; err = RefreshData(); if (err.Succeeded()) { if (fReEnumerate) { // // Kill child objects // TRACEEOLID("Killing child objects"); ASSERT(m_hScopeItem != NULL); if (m_hScopeItem != NULL) { err = RemoveChildren(m_hScopeItem); if (err.Succeeded()) { err = EnumerateScopePane(m_hScopeItem); } } } err = RefreshDisplay(); } return err; } /* virtual */ HRESULT CIISMBNode::GetResultViewType( OUT LPOLESTR * lplpViewType, OUT long * lpViewOptions ) /*++ Routine Description: If we have an URL built up, display our result view as that URL, and destroy it. This is done when 'browsing' a metabase node. The derived class will build the URL, and reselect the node. Arguments: BSTR * lplpViewType : Return view type here long * lpViewOptions : View options Return Value: S_FALSE to use default view type, S_OK indicates the view type is returned in *ppViewType --*/ { if (m_bstrURL.Length()) { *lpViewOptions = MMC_VIEW_OPTIONS_NONE; *lplpViewType = (LPOLESTR)::CoTaskMemAlloc( (m_bstrURL.Length() + 1) * sizeof(WCHAR) ); if (*lplpViewType) { lstrcpy(*lplpViewType, m_bstrURL); // // Destroy URL so we get a normal result view next time // m_bstrURL.Empty(); m_fSkipEnumResult = TRUE; return S_OK; } return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } // // No URL waiting -- use standard result view // return CIISObject::GetResultViewType(lplpViewType, lpViewOptions); } HRESULT ShellExecuteDirectory( LPCTSTR lpszCommand, LPCTSTR lpszOwner, LPCTSTR lpszDirectory, HWND hWnd ) /*++ Routine Description: Shell Open or explore on a given directory path Arguments: LPCTSTR lpszCommand : "open" or "explore" LPCTSTR lpszOwner : Owner server LPCTSTR lpszDirectory : Directory path Return Value: Error return code. --*/ { CString strDir; if (::IsServerLocal(lpszOwner) || ::IsUNCName(lpszDirectory)) { // // Local directory, or already a unc path // strDir = lpszDirectory; } else { ::MakeUNCPath(strDir, lpszOwner, lpszDirectory); } TRACEEOLID("Attempting to " << lpszCommand << " Path: " << strDir); CError err; { // // AFX_MANAGE_STATE required for wait cursor // AFX_MANAGE_STATE(::AfxGetStaticModuleState() ); CWaitCursor wait; if (::ShellExecute(NULL, lpszCommand, strDir, NULL,_T(""), SW_SHOW) <= (HINSTANCE)32) { err.GetLastWinError(); if (err.Win32Error() == ERROR_NO_ASSOCIATION) { // Open shell OpenAs dialog SHELLEXECUTEINFO ei = {0}; ei.cbSize = sizeof(ei); ei.fMask = SEE_MASK_NOQUERYCLASSSTORE; RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("Unknown"), 0, MAXIMUM_ALLOWED, &ei.hkeyClass); if (ei.hkeyClass != NULL) { ei.fMask |= SEE_MASK_NOQUERYCLASSSTORE; } ei.lpFile = strDir; ei.nShow = SW_SHOW; ei.lpVerb = _T("openas"); ei.hwnd = hWnd; err = ShellExecuteEx(&ei); if (ei.hkeyClass != NULL) { RegCloseKey(ei.hkeyClass); } } } } return err; } HRESULT CIISMBNode::CreatePropertyPages( LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, IUnknown * pUnk, DATA_OBJECT_TYPES type ) { CError err = CIISObject::CreatePropertyPages(lpProvider, handle, pUnk, type); if (err == S_FALSE) { return S_FALSE; } // Set this objects Tag to compare with something already opened CreateTag(); CIISObject * pAlreadyOpenProp = NULL; if (TRUE == g_OpenPropertySheetTracker.FindAlreadyOpenPropertySheet(this,&pAlreadyOpenProp)) { // Bring it to the foreground, and bail HWND hHwnd = 0; if (pAlreadyOpenProp) { if (hHwnd = pAlreadyOpenProp->IsMyPropertySheetOpen()) { if (hHwnd && (hHwnd != (HWND) 1)) { // Perhapse we should cancel the already // opened property sheet...just a thought if (!SetForegroundWindow(hHwnd)) { // wasn't able to bring this property sheet to // the foreground, the propertysheet must not // exist anymore. let's just clean the hwnd // so that the user will be able to open propertysheet pAlreadyOpenProp->SetMyPropertySheetOpen(0); } else { return ERROR_ALREADY_EXISTS; } } } } } // Check if we are still connected if (!GetOwner()->IsLocal()) { // Problem here could be that lpszOwner is not a computername but rather // an IP Address!!!! LPCTSTR lpszServer = PURE_COMPUTER_NAME(GetOwner()->QueryServerName()); if (LooksLikeIPAddress(lpszServer)) { // // Get by ip address // CString strTemp; CIPAddress ia(lpszServer); if (NOERROR != MyGetHostName((DWORD)ia, strTemp)) { // network is down!!! err = ERROR_NO_NETWORK; return err; } } do { // WARNING:QueryInterface() Can return NULL // and if the CMetakey is created with a NULL // pointer, it will AV. if (!GetOwner()->QueryInterface()) { return RPC_S_SERVER_UNAVAILABLE; } CMetaKey mk(GetOwner()->QueryInterface()); err = mk.QueryResult(); BREAK_ON_ERR_FAILURE(err); CComBSTR path; err = BuildMetaPath(path); BREAK_ON_ERR_FAILURE(err); CString buf = path; while (FAILED(mk.DoesPathExist(buf))) { // Goto parent if (NULL == CMetabasePath::ConvertToParentPath(buf)) { break; } } err = mk.Open( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, buf ); BREAK_ON_ERR_FAILURE(err); // // Write some nonsense // DWORD dwDummy = 0x1234; err = mk.SetValue(MD_ISM_ACCESS_CHECK, dwDummy); BREAK_ON_ERR_FAILURE(err); // // And delete it again // err = mk.DeleteValue(MD_ISM_ACCESS_CHECK); } while (FALSE); } return err; } HRESULT CIISMBNode::Command( IN long lCommandID, IN CSnapInObjectRootBase * pObj, IN DATA_OBJECT_TYPES type ) /*++ Routine Description: Handle command from context menu. Arguments: long lCommandID : Command ID CSnapInObjectRootBase * pObj : Base object DATA_OBJECT_TYPES type : Data object type Return Value: HRESULT --*/ { AFX_MANAGE_STATE(::AfxGetStaticModuleState()); HRESULT hr = S_OK; CError err = ERROR_NOT_ENOUGH_MEMORY; CComBSTR bstrMetaPath; BOOL bNeedMetabase = FALSE; BOOL bHaveMetabase = FALSE; switch (lCommandID) { case IDM_BROWSE: case IDM_OPEN: case IDM_PERMISSION: case IDM_EXPLORE: case IDM_NEW_FTP_SITE_FROM_FILE: case IDM_NEW_FTP_VDIR_FROM_FILE: case IDM_NEW_WEB_SITE_FROM_FILE: case IDM_NEW_WEB_VDIR_FROM_FILE: case IDM_NEW_APP_POOL_FROM_FILE: case IDM_TASK_EXPORT_CONFIG_WIZARD: bNeedMetabase = TRUE; break; default: bNeedMetabase = FALSE; } if (bNeedMetabase) { // WARNING:bstrMetaPath will be used by switch statement below VERIFY(SUCCEEDED(BuildMetaPath(bstrMetaPath))); err = CheckForMetabaseAccess(METADATA_PERMISSION_READ,this,TRUE,bstrMetaPath); if (!IsLostInterface(err)) { // reset error if an other error other than No interface err.Reset(); } if (err.Succeeded()) { bHaveMetabase = TRUE; } } switch (lCommandID) { case IDM_BROWSE: { if (bHaveMetabase) { // // Build URL for this node, and force a re-select so as to change // the result view // BuildURL(m_bstrURL); if (m_bstrURL.Length()) { // // After selection, the browsed URL will come up in the result view // SelectScopeItem(); } } } break; // // CODEWORK: Build path, and, using the explorer URL, put this stuff // in the result view. // case IDM_OPEN: { if (bHaveMetabase) { CString phys_path, alias; if (GetPhysicalPath(bstrMetaPath, alias, phys_path)) { hr = ShellExecuteDirectory(_T("open"), QueryMachineName(), phys_path, GetMainWindow(GetConsole())->m_hWnd); } } } break; case IDM_PERMISSION: { if (bHaveMetabase) { CString phys_path, alias, csPathMunged; if (GetPhysicalPath(bstrMetaPath, alias, phys_path)) { // ------------------------------------------------------------- // Before we do anything we need to see if it's a "special" path // // Everything after this function must validate against csPathMunged... // this is because IsSpecialPath could have munged it... // ------------------------------------------------------------- csPathMunged = phys_path; #ifdef SUPPORT_SLASH_SLASH_QUESTIONMARK_SLASH_TYPE_PATHS GetSpecialPathRealPath(0,phys_path,csPathMunged); #endif if (!IsDevicePath(csPathMunged)) { INT_PTR iReturn = PopupPermissionDialog( GetMainWindow(GetConsole())->m_hWnd, QueryMachineName(), csPathMunged); } } } } break; case IDM_EXPLORE: { if (bHaveMetabase) { CString phys_path, alias; if (GetPhysicalPath(bstrMetaPath, alias, phys_path)) { TCHAR url[MAX_PATH]; DWORD len = MAX_PATH; hr = UrlCreateFromPath(phys_path, url, &len, NULL); m_bstrURL = url; SelectScopeItem(); } } } break; case IDM_NEW_FTP_SITE_FROM_FILE: { if (bHaveMetabase) { CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_FTP_SERVER_W))) { // check if we need to just refresh this node or the node above us... CIISMBNode * pNode = GetParentNode(); if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cServiceCollectorNode)) { pNode->Refresh(TRUE); } else { BOOL bExpand = !IsLeafNode();Refresh(bExpand); } } } } break; case IDM_NEW_FTP_VDIR_FROM_FILE: { if (bHaveMetabase) { CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_FTP_VDIR_W))) { // check if we need to just refresh this node or the node above us... CIISMBNode * pNode = GetParentNode(); if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cInstanceNode)) { pNode->Refresh(TRUE); } else { BOOL bExpand = !IsLeafNode();Refresh(bExpand); } } } } break; case IDM_NEW_WEB_SITE_FROM_FILE: { if (bHaveMetabase) { CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_WEB_SERVER_W))) { // check if we need to just refresh this node or the node above us... CIISMBNode * pNode = GetParentNode(); if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cServiceCollectorNode)) { pNode->Refresh(TRUE); } else { BOOL bExpand = !IsLeafNode();Refresh(bExpand); } } } } break; case IDM_NEW_WEB_VDIR_FROM_FILE: { if (bHaveMetabase) { CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,IIS_CLASS_WEB_VDIR_W))) { // check if we need to just refresh this node or the node above us... CIISMBNode * pNode = GetParentNode(); if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cInstanceNode)) { pNode->Refresh(TRUE); } else { BOOL bExpand = !IsLeafNode();Refresh(bExpand); } } } } break; case IDM_NEW_APP_POOL_FROM_FILE: { if (bHaveMetabase) { CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); if (ERROR_SUCCESS == (hr = DoNodeImportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath,L"IIsApplicationPool"))) { // check if we need to just refresh this node or the node above us... CIISMBNode * pNode = GetParentNode(); if (IsEqualGUID(* (GUID *)pNode->GetNodeType(),cAppPoolsNode)) { pNode->Refresh(TRUE); } else { BOOL bExpand = !IsLeafNode();Refresh(bExpand); } } } } break; case IDM_TASK_EXPORT_CONFIG_WIZARD: { if (bHaveMetabase) { CString strNewPath, strRemainder; CComBSTR bstrServerName(QueryInterface()->QueryAuthInfo()->QueryServerName()); CComBSTR bstrUserName(QueryInterface()->QueryAuthInfo()->QueryUserName()); CComBSTR bstrUserPass(QueryInterface()->QueryAuthInfo()->QueryPassword()); // Is this the root?? LPCTSTR lpPath = CMetabasePath::GetRootPath(bstrMetaPath, strNewPath, &strRemainder); if (lpPath && (0 == _tcsicmp(lpPath,bstrMetaPath))) { CString strNewMetaPath; // // Get the instance properties // CMetabasePath::GetInstancePath(bstrMetaPath,strNewMetaPath); CComBSTR bstrNewMetaPath((LPCTSTR) strNewMetaPath); // if empty or if this is an app pool... if (IsEqualGUID(* (GUID *) GetNodeType(),cAppPoolNode)) { hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath); } else { if (strNewMetaPath.IsEmpty()) { hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath); } else { hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrNewMetaPath); } } } else { hr = DoNodeExportConfig(bstrServerName,bstrUserName,bstrUserPass,bstrMetaPath); } } } break; // // Pass on to base class // default: { hr = CIISObject::Command(lCommandID, pObj, type); } } // end switch return hr; } #if 0 HRESULT CIISMBNode::OnPropertyChange(BOOL fScope, IResultData * pResult) { CError err; err = Refresh(fScope); if (err.Succeeded()) { if ( fScope && HasFileSystemFiles() && !m_ResultItems.IsEmpty() ) { err = CleanResult(pResult); if (err.Succeeded()) { err = EnumerateResultPane(fScope, NULL, pResult); } } else if (!fScope) { pResult->UpdateItem(m_hResultItem); } } return err; } #endif HRESULT CIISMBNode::OnViewChange(BOOL fScope, IResultData * pResult, IHeaderCtrl * pHeader, DWORD hint) { CError err; BOOL bReenumResult = 0 != (hint & PROP_CHANGE_REENUM_FILES); BOOL bReenumScope = 0 != (hint & PROP_CHANGE_REENUM_VDIR) || 0 != (hint & PROP_CHANGE_REENUM_FILES); if (QueryScopeItem() || QueryResultItem()) { BOOL bExpand = fScope && !IsLeafNode() && bReenumScope // && IsExpanded() ; BOOL bHasResult = HasResultItems(pResult); if (bHasResult && bReenumResult) { // Remove files that could be in result pane err = CleanResult(pResult); } // after error this node could be not expanded, we should expand it anyway err = Refresh(bExpand); if (err.Succeeded()) { if (fScope && HasFileSystemFiles() && bReenumResult && bHasResult) { err = EnumerateResultPane(TRUE, pHeader, pResult); } else if (!fScope && (bReenumResult || 0 != (hint & PROP_CHANGE_DISPLAY_ONLY))) { pResult->UpdateItem(m_hResultItem); } } } return err; } HRESULT CIISMBNode::RemoveResultNode(CIISMBNode * pNode, IResultData * pResult) { CError err; ASSERT(HasFileSystemFiles()); err = pResult->DeleteItem(pNode->m_hResultItem, 0); if (err.Succeeded()) { POSITION pos = m_ResultViewList.GetHeadPosition(); while (pos != NULL) { ResultViewEntry e = m_ResultViewList.GetNext(pos); if (e._ResultData == (DWORD_PTR)pResult) { BOOL found = FALSE; POSITION p = e._ResultItems->GetHeadPosition(); POSITION pcur; while (p != NULL) { pcur = p; if (e._ResultItems->GetNext(p) == pNode) { found = TRUE; break; } } if (found) { e._ResultItems->RemoveAt(pcur); pNode->Release(); } } } } return err; } // See FtpAddNew.cpp for the method CIISMBNode::AddFTPSite // See WebAddNew.cpp for the method CIISMBNode::AddWebSite // See add_app_pool.cpp for the method CIISMBNode::AddAppPool