Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2515 lines
68 KiB

/*++
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 <lm.h>
#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