/*++

   Copyright    (c)    1994-2000    Microsoft Corporation

   Module  Name :

        iisdirectory.cpp

   Abstract:

        IIS Directory node 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 "connects.h"
#include "iisobj.h"
#include "ftpsht.h"
#include "w3sht.h"
#include "wdir.h"
#include "docum.h"
#include "wfile.h"
#include "wsecure.h"
#include "httppage.h"
#include "errors.h"
#include "fltdlg.h"
#include <lm.h>

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif



#define new DEBUG_NEW


//
// CIISDirectory Implementation
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//
// Site Result View definition
//
/* static */ int 
CIISDirectory::_rgnLabels[COL_TOTAL] =
{
    IDS_RESULT_NAME,
    IDS_RESULT_PATH,
    IDS_RESULT_STATUS,
};
    

/* static */ int 
CIISDirectory::_rgnWidths[COL_TOTAL] =
{
    180,
    200,
	200,
};

#if 0
/* static */ CComBSTR CIISDirectory::_bstrName;
/* static */ CComBSTR CIISDirectory::_bstrPath;
/* static */ BOOL     CIISDirectory::_fStaticsLoaded = FALSE;
#endif

CIISDirectory::CIISDirectory(
    IN CIISMachine * pOwner,
    IN CIISService * pService,
    IN LPCTSTR szNodeName
    )
/*++

Routine Description:

    Constructor which does not resolve all display information at 
    construction time.

Arguments:

    CIISMachine * pOwner        : Owner machine
    CIISService * pService      : Service type
    LPCTSTR szNodeName          : Node name

Return Value:

    N/A

--*/
    : CIISMBNode(pOwner, szNodeName),
      m_pService(pService),
      m_bstrDisplayName(szNodeName),
      m_fResolved(FALSE),
      //
      // Default Data
      //
      m_fEnabledApplication(FALSE),
      m_dwWin32Error(ERROR_SUCCESS)   
{
    ASSERT_PTR(m_pService);
}



CIISDirectory::CIISDirectory(
    CIISMachine * pOwner,
    CIISService * pService,
    LPCTSTR szNodeName,
    BOOL fEnabledApplication,
    DWORD dwWin32Error,
    LPCTSTR strRedirPath
    )
/*++

Routine Description:

    Constructor that takes full information

Arguments:

    CIISMachine * pOwner        : Owner machine
    CIISService * pService      : Service type
    LPCTSTR szNodeName          : Node name

Return Value:

    N/A

--*/
    : CIISMBNode(pOwner, szNodeName),
      m_pService(pService),
      m_bstrDisplayName(szNodeName),
      m_fResolved(TRUE),
      //
      // Data
      //
      m_fEnabledApplication(fEnabledApplication),
      m_dwWin32Error(dwWin32Error)
{
    m_strRedirectPath = strRedirPath;
    ASSERT_PTR(m_pService);
}



/* virtual */
CIISDirectory::~CIISDirectory()
/*++

Routine Description:

    Destructor

Arguments:

    N/A

Return Value:

    N/A

--*/
{
}



/* virtual */
HRESULT
CIISDirectory::RefreshData()
/*++

Routine Description:

    Refresh relevant configuration data required for display.

Arguments:

    None

Return Value:

    HRESULT

--*/
{
    CError err;

    CWaitCursor wait;
    CComBSTR bstrPath;
    CMetaKey * pKey = NULL;

    do
    {
        ASSERT_PTR(_lpConsoleNameSpace);
        err = BuildMetaPath(bstrPath);
		BREAK_ON_ERR_FAILURE(err)

        BOOL fContinue = TRUE;
        while (fContinue)
        {
            fContinue = FALSE;
            pKey = new CMetaKey(QueryInterface(), bstrPath);

            if (!pKey)
            {
                TRACEEOLID("RefreshData: OOM");
                err = ERROR_NOT_ENOUGH_MEMORY;
                break;
            }

            err = pKey->QueryResult();

            if (IsLostInterface(err))
            {
                SAFE_DELETE(pKey);

                fContinue = OnLostInterface(err);
            }
        }
		BREAK_ON_ERR_FAILURE(err)

        CChildNodeProps child(pKey, NULL /*bstrPath*/, WITH_INHERITANCE, FALSE);
        err = child.LoadData();
        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())
        {
            m_dwWin32Error = child.QueryWin32Error();
            m_fEnabledApplication = child.IsEnabledApplication();
        }
        else
        {
            m_dwWin32Error = err.Win32Error();
        }
		if (!child.IsRedirected())
		{
			CString dir;
			CString alias;
			if (GetPhysicalPath(bstrPath, alias, dir))
			{
                m_bstrPath = dir;
				if (PathIsUNCServerShare(dir))
				{
					CString server, share;
					int idx = dir.ReverseFind(_T('\\'));
					ASSERT(idx != -1);
					server = dir.Left(idx);
					share = dir.Mid(++idx);
					LPBYTE pbuf = NULL;
					NET_API_STATUS rc = NetShareGetInfo((LPTSTR)(LPCTSTR)server, (LPTSTR)(LPCTSTR)share, 0, &pbuf);
					if (NERR_Success == rc)
					{
						NetApiBufferFree(pbuf);
					}
					else
					{
						m_dwWin32Error = ERROR_BAD_NETPATH;
						break;
					}
				}
				else if (!PathIsDirectory(dir))
				{
					m_dwWin32Error = ERROR_PATH_NOT_FOUND;
					break;
				}
			}
		}
    }
    while(FALSE);

    SAFE_DELETE(pKey);

    if (m_dwWin32Error == ERROR_SUCCESS)
    {
        m_dwWin32Error = err.Win32Error();
    }

    return err;
}



/* virtual */
HRESULT 
CIISDirectory::EnumerateScopePane(HSCOPEITEM hParent)
/*++

Routine Description:

    Enumerate scope child items.

Arguments:

    HSCOPEITEM hParent                      : Parent console handle

Return Value:

    HRESULT

--*/
{
    CError err = EnumerateVDirs(hParent, m_pService);
    if (err.Succeeded() && IsWebDir() && m_strRedirectPath.IsEmpty())
    {
        if (m_dwWin32Error == ERROR_SUCCESS)
        {
            err = EnumerateWebDirs(hParent, m_pService);
        }
    }
    if (err.Failed())
    {
        m_dwWin32Error = err.Win32Error();
        RefreshDisplay();
    }
    return err;
}



/* virtual */
int      
CIISDirectory::QueryImage() const
/*++

Routine Description:

    Return bitmap index for the site

Arguments:

    None

Return Value:

    Bitmap index

--*/
{
    ASSERT_PTR(m_pService);
	if (!m_fResolved)
	{
        if (m_hScopeItem == NULL)
        {
            return iError;
        }
        AFX_MANAGE_STATE(::AfxGetStaticModuleState());
		CIISDirectory * that = (CIISDirectory *)this;
        CError err = that->RefreshData();
        that->m_fResolved = err.Succeeded();
	}
    if (m_dwWin32Error || !m_pService)
    {
        return iError;
    }

    return IsEnabledApplication()
        ? iApplication : m_pService->QueryVDirImage();
}
    
    
void 
CIISDirectory::InitializeChildHeaders(LPHEADERCTRL lpHeader)
{
    CIISDirectory::InitializeHeaders(lpHeader);
}

/* static */
void
CIISDirectory::InitializeHeaders(LPHEADERCTRL lpHeader)
{
    CIISObject::BuildResultView(lpHeader, COL_TOTAL, _rgnLabels, _rgnWidths);
//    if (!_fStaticsLoaded)
//    {
//        _fStaticsLoaded =
//            _bstrName.LoadString(IDS_RESULT_NAME)  &&
//            _bstrPath.LoadString(IDS_RESULT_PATH);
//    }
}

/* virtual */
LPOLESTR 
CIISDirectory::GetResultPaneColInfo(int nCol)
/*++

Routine Description:

    Return result pane string for the given column number

Arguments:

    int nCol        : Column number

Return Value:

    String

--*/
{
    switch(nCol)
    {
    case COL_ALIAS:
        return QueryDisplayName();

    case COL_PATH:
       if (!m_strRedirectPath.IsEmpty())
       {
           AFX_MANAGE_STATE(::AfxGetStaticModuleState());
           CString buf;
           buf.Format(IDS_REDIRECT_FORMAT, m_strRedirectPath);
           return (LPOLESTR)(LPCTSTR)buf;
       }
       if (m_bstrPath.Length() == 0)
       {
          CComBSTR mp;
          BuildMetaPath(mp);
          CString name, pp;
          GetPhysicalPath(mp, name, pp);
          m_bstrPath = pp;
       }
       return m_bstrPath;

    case COL_STATUS:
       {
          AFX_MANAGE_STATE(::AfxGetStaticModuleState());

          CError err(m_dwWin32Error);

          if (err.Succeeded())
          {
              return OLESTR("");
          }
   
          _bstrResult = err;
          return _bstrResult;
       }
    }
    TRACEEOLID("CIISDirectory: Bad column number" << nCol);
    return OLESTR("");
}

/*virtual*/
HRESULT
CIISDirectory::AddMenuItems(
    LPCONTEXTMENUCALLBACK piCallback,
    long * pInsertionAllowed,
    DATA_OBJECT_TYPES type
    )
{
    ASSERT_READ_PTR(piCallback);
    //
    // Add base menu items
    //
    HRESULT hr = CIISObject::AddMenuItems(
        piCallback,
        pInsertionAllowed,
        type
        );
    if (SUCCEEDED(hr))
    {
       ASSERT(pInsertionAllowed != NULL);
       if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
       {
           AddMenuSeparator(piCallback);
           if (IsFtpDir())
           {
              AddMenuItemByCommand(piCallback, IDM_NEW_FTP_VDIR);
           }
           else if (IsWebDir())
           {
              AddMenuItemByCommand(piCallback, IDM_NEW_WEB_VDIR);
           }
       }
       if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
       {
           AddMenuSeparator(piCallback);
           AddMenuItemByCommand(piCallback, IDM_TASK_SECURITY_WIZARD);
       }
    }
    return hr;
}

HRESULT
CIISDirectory::InsertNewAlias(CString alias)
{
    CError err;
    // Now we should insert and select this new site
    CIISDirectory * pAlias = new CIISDirectory(m_pOwner, m_pService, alias);
    if (pAlias != NULL)
    {
        // If item is not expanded we will get error and no effect
        if (!IsExpanded())
        {
            SelectScopeItem();
            IConsoleNameSpace2 * pConsole 
                    = (IConsoleNameSpace2 *)GetConsoleNameSpace();
            pConsole->Expand(QueryScopeItem());
        }
        err = pAlias->AddToScopePaneSorted(QueryScopeItem(), FALSE);
        if (err.Succeeded())
        {
            VERIFY(SUCCEEDED(pAlias->SelectScopeItem()));
        }
    }
    else
    {
        err = ERROR_NOT_ENOUGH_MEMORY;
    }
    return err;
}

/* virtual */
HRESULT
CIISDirectory::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;
    CString alias;

    switch (lCommandID)
    {
    case IDM_NEW_FTP_VDIR:
        if (SUCCEEDED(hr = CIISMBNode::AddFTPVDir(pObj, type, alias)))
        {
            hr = InsertNewAlias(alias);
        }
        break;

    case IDM_NEW_WEB_VDIR:
        if (SUCCEEDED(hr = CIISMBNode::AddWebVDir(pObj, type, alias)))
        {
            hr = InsertNewAlias(alias);
        }
        break;
    //
    // Pass on to base class
    //
    default:
        hr = CIISMBNode::Command(lCommandID, pObj, type);
    }

    return hr;
}

/* virtual */
HRESULT
CIISDirectory::CreatePropertyPages(
    IN LPPROPERTYSHEETCALLBACK lpProvider,
    IN LONG_PTR handle, 
    IN IUnknown * pUnk,
    IN DATA_OBJECT_TYPES type
    )
/*++

Routine Description:

    Create the property pages for the given object

Arguments:

    LPPROPERTYSHEETCALLBACK lpProvider  : Provider
    LONG_PTR handle                     : Handle.
    IUnknown * pUnk,
    DATA_OBJECT_TYPES type

Return Value:

    HRESULT
                                                
--*/
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());

    CComBSTR bstrPath;

    //
    // CODEWORK: What to do with m_err?  This might be 
    // a bad machine object in the first place.  Aborting
    // when the machine object has an error code isn't 
    // such a bad solution here.
    //

    /*
    if (m_err.Failed())
    {
        m_err.MessageBox();
        return m_err;
    }
    */

    CError err(BuildMetaPath(bstrPath));

    if (err.Succeeded())
    {
        err = ShowPropertiesDlg(
            lpProvider,
            QueryAuthInfo(), 
            bstrPath,
            GetMainWindow(),
            (LPARAM)this,
            handle
            );
    }

    err.MessageBoxOnFailure();

    return err;
}

///////////////////////////////////////////////////////////////////

CIISFileName::CIISFileName(
      CIISMachine * pOwner,
      CIISService * pService,
      const DWORD dwAttributes,
      LPCTSTR alias,
      LPCTSTR redirect
      )
   : CIISMBNode(pOwner, alias),
     m_dwAttribute(dwAttributes),
     m_pService(pService),
     m_bstrFileName(alias),
     m_RedirectString(redirect),
     m_fEnabledApplication(FALSE),
     m_dwWin32Error(0),
	 m_fResolved(FALSE)
{
}

/* virtual */
LPOLESTR 
CIISFileName::GetResultPaneColInfo(int nCol)
/*++

Routine Description:

    Return result pane string for the given column number

Arguments:

    int nCol        : Column number

Return Value:

    String

--*/
{
    switch(nCol)
    {
    case COL_ALIAS:
        return QueryDisplayName();

    case COL_PATH:
		return OLESTR("");

    case COL_STATUS:
        {
            AFX_MANAGE_STATE(::AfxGetStaticModuleState());

            CError err(m_dwWin32Error);

            if (err.Succeeded())
            {
                return OLESTR("");
            }
            _bstrResult = err;
            return _bstrResult;
        }
    }
    TRACEEOLID("CIISFileName: Bad column number" << nCol);
    return OLESTR("");
}

void 
CIISFileName::InitializeChildHeaders(LPHEADERCTRL lpHeader)
{
    CIISDirectory::InitializeHeaders(lpHeader);
}

/* virtual */
HRESULT 
CIISFileName::EnumerateScopePane(
    IN HSCOPEITEM hParent
    )
/*++

Routine Description:

    Enumerate scope child items.

Arguments:

    HSCOPEITEM hParent                      : Parent console handle

Return Value:

    HRESULT

--*/
{
    return EnumerateWebDirs(hParent, m_pService);
}

/* virtual */
int      
CIISFileName::QueryImage() const
{
    ASSERT_PTR(m_pService);
	if (!m_fResolved)
	{
        if (m_hScopeItem == NULL)
        {
            TRACEEOLID("BUGBUG: Prematurely asked for display information");
            return MMC_IMAGECALLBACK;
        }
        //
        // Required for the wait cursor
        //
        AFX_MANAGE_STATE(::AfxGetStaticModuleState());
		CIISFileName * that = (CIISFileName *)this;
        CError err = that->RefreshData();
        that->m_fResolved = err.Succeeded();
	}

    if (m_dwWin32Error || !m_pService)
    {
        return iError;
    }

    if (IsDir())
    {
       return IsEnabledApplication() ? iApplication : iFolder;
    }
    return iFile;
}

    
HRESULT
CIISFileName::DeleteNode(IResultData * pResult)
{
    CString path;
    CComBSTR root;
    BuildMetaPath(root);
    CString physPath, alias;
    GetPhysicalPath(CString(root), alias, physPath);
    physPath.TrimRight(_T("/"));

    if (m_pService->IsLocal() || PathIsUNC(physPath))
    {
        //
        // Local directory, or already a unc path
        //
        path = physPath;
    }
    else
    {
        ::MakeUNCPath(path, m_pService->QueryMachineName(), physPath);
    }
    LPTSTR p = path.GetBuffer(MAX_PATH);
    PathRemoveBlanks(p);
    PathRemoveBackslash(p);
    path += _T('\0');

    TRACEEOLID("Attempting to remove file/directory: " << path);

    CWnd * pWnd = AfxGetMainWnd();

    //
    // Attempt to delete using shell APIs
    //
    SHFILEOPSTRUCT sos;
    ZeroMemory(&sos, sizeof(sos));
    sos.hwnd = pWnd ? pWnd->m_hWnd : NULL;
    sos.wFunc = FO_DELETE;
    sos.pFrom = path;
    sos.fFlags = FOF_ALLOWUNDO;

    CError err;
    // Use assignment to avoid conversion and wrong constructor call
    err = ::SHFileOperation(&sos);

    if (err.Succeeded() && !sos.fAnyOperationsAborted)
    {
        CComBSTR p;
        CMetaInterface * pInterface = QueryInterface();
        ASSERT(pInterface != NULL);
        err = BuildMetaPath(p);
        if (err.Succeeded()) 
        {
            CMetaKey mk(pInterface, METADATA_MASTER_ROOT_HANDLE, METADATA_PERMISSION_WRITE);
            if (mk.Succeeded())
            {
                err = mk.DeleteKey(p);
            }
        }
		if (IsDir())
		{
			err = RemoveScopeItem();
		}
		else
		{
			CIISMBNode * pParent = GetParentNode();
			ASSERT(pParent != NULL);
			err = pParent->RemoveResultNode(this, pResult);
		}
    }

    if (err.Failed())
    {
        DisplayError(err);
    }
    path.ReleaseBuffer();
    return err;
}

HRESULT
CIISFileName::RenameItem(LPOLESTR new_name)
{
   if (new_name == NULL || lstrlen(new_name) == 0)
   {
      return S_OK;
   }
   CString pathFrom, pathTo;
   CComBSTR root;
   BuildMetaPath(root);
   CString physPath, alias;
   GetPhysicalPath(CString(root), alias, physPath);
   physPath.TrimRight(_T("/"));

   if (m_pService->IsLocal() || PathIsUNC(physPath))
   {
       //
       // Local directory, or already a unc path
       //
       pathFrom = physPath;
   }
   else
   {
       ::MakeUNCPath(pathFrom, m_pService->QueryMachineName(), physPath);
   }
   LPTSTR p = pathFrom.GetBuffer(MAX_PATH);
   PathRemoveBlanks(p);
   PathRemoveBackslash(p);
   pathFrom.ReleaseBuffer();
   pathFrom += _T('\0');

   pathTo = pathFrom;
   p = pathTo.GetBuffer(MAX_PATH);
   PathRemoveFileSpec(p);
   PathAppend(p, new_name);
   pathTo.ReleaseBuffer();
   pathTo += _T('\0');

   CWnd * pWnd = AfxGetMainWnd();
   //
   // Attempt to delete using shell APIs
   //
   SHFILEOPSTRUCT sos;
   ZeroMemory(&sos, sizeof(sos));
   sos.hwnd = pWnd ? pWnd->m_hWnd : NULL;
   sos.wFunc = FO_RENAME;
   sos.pFrom = pathFrom;
   sos.pTo = pathTo;
   sos.fFlags = FOF_ALLOWUNDO;

   CError err;
   // Use assignment to avoid conversion and wrong constructor call
   err = ::SHFileOperation(&sos);

   if (err.Succeeded() && !sos.fAnyOperationsAborted)
   {
      CComQIPtr<IResultData, &IID_IResultData> lpResultData(_lpConsole);
      m_bstrFileName = new_name;
      err = lpResultData->UpdateItem(m_hResultItem);
	  m_bstrNode = new_name;
   }
   return err;
}

/* virtual */
HRESULT
CIISFileName::RefreshData()
/*++

Routine Description:

    Refresh relevant configuration data required for display.

Arguments:

    None

Return Value:

    HRESULT

--*/
{
    CError err;

    CWaitCursor wait;
    CComBSTR bstrPath;
    CMetaKey * pKey = NULL;

    do
    {
        ASSERT_PTR(_lpConsoleNameSpace);
        err = BuildMetaPath(bstrPath);

        if (err.Failed())
        {
            break;
        }

        BOOL fContinue = TRUE;

        while (fContinue)
        {
            fContinue = FALSE;
            pKey = new CMetaKey(QueryInterface(), bstrPath);

            if (!pKey)
            {
                TRACEEOLID("RefreshData: OOM");
                err = ERROR_NOT_ENOUGH_MEMORY;
                break;
            }
			err = pKey->QueryResult();
            if (IsLostInterface(err))
            {
				SAFE_DELETE(pKey);
                fContinue = OnLostInterface(err);
            }
        }

        if (err.Succeeded())
        {
			CChildNodeProps child(pKey, NULL /*bstrPath*/, WITH_INHERITANCE, FALSE);
			err = child.LoadData();
			if (err.Succeeded())
			{
				m_dwWin32Error = child.QueryWin32Error();
				CString buf = child.m_strAppRoot;
				m_fEnabledApplication = (buf.CompareNoCase(bstrPath) == 0);
			}
			else
			{
				m_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);
            }
        }

    }
    while(FALSE);

    SAFE_DELETE(pKey);

    if (SUCCEEDED(m_dwWin32Error))
    {
        m_dwWin32Error = err.Win32Error();
    }

    ASSERT(err.Succeeded());
    return err;
}

/*virtual*/
HRESULT
CIISFileName::AddMenuItems(
    LPCONTEXTMENUCALLBACK piCallback,
    long * pInsertionAllowed,
    DATA_OBJECT_TYPES type
    )
{
    ASSERT_READ_PTR(piCallback);
    //
    // Add base menu items
    //
    HRESULT hr = CIISObject::AddMenuItems(
        piCallback,
        pInsertionAllowed,
        type
        );
    if (SUCCEEDED(hr))
    {
       if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0)
       {
           AddMenuSeparator(piCallback);
           if (lstrcmpi(m_pService->QueryServiceName(), SZ_MBN_FTP) == 0)
           {
              AddMenuItemByCommand(piCallback, IDM_NEW_FTP_VDIR);
           }
           else if (lstrcmpi(m_pService->QueryServiceName(), SZ_MBN_WEB) == 0)
           {
              AddMenuItemByCommand(piCallback, IDM_NEW_WEB_VDIR);
           }
       }
       ASSERT(pInsertionAllowed != NULL);
       if ((*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0)
       {
           AddMenuSeparator(piCallback);
           AddMenuItemByCommand(piCallback, IDM_TASK_SECURITY_WIZARD);
       }
    }
    return hr;
}


/* virtual */
HRESULT
CIISFileName::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;
    CString alias;

    switch (lCommandID)
    {
    case IDM_NEW_FTP_VDIR:
        if (SUCCEEDED(hr = CIISMBNode::AddFTPVDir(pObj, type, alias)))
        {
            hr = InsertNewAlias(alias);
        }
        break;

    case IDM_NEW_WEB_VDIR:
        if (SUCCEEDED(hr = CIISMBNode::AddWebVDir(pObj, type, alias)))
        {
            hr = InsertNewAlias(alias);
        }
        break;

	case IDM_BROWSE:
		if (m_hResultItem != 0)
		{
			BuildURL(m_bstrURL);
			if (m_bstrURL.Length())
			{
			   ShellExecute(GetMainWindow()->m_hWnd, _T("open"), m_bstrURL, NULL, NULL, SW_SHOWNORMAL);
			}
		}
		else
		{
			hr = CIISMBNode::Command(lCommandID, pObj, type);
		}
        break;

    //
    // Pass on to base class
    //
    default:
        hr = CIISMBNode::Command(lCommandID, pObj, type);
    }

    ASSERT(SUCCEEDED(hr));

    return hr;
}

HRESULT
CIISFileName::InsertNewAlias(CString alias)
{
    CError err;
    // Now we should insert and select this new site
    CIISDirectory * pAlias = new CIISDirectory(m_pOwner, m_pService, alias);
    if (pAlias != NULL)
    {
        // If item is not expanded we will get error and no effect
        if (!IsExpanded())
        {
            SelectScopeItem();
            IConsoleNameSpace2 * pConsole 
                    = (IConsoleNameSpace2 *)GetConsoleNameSpace();
            pConsole->Expand(QueryScopeItem());
        }
        err = pAlias->AddToScopePaneSorted(QueryScopeItem(), FALSE);
        if (err.Succeeded())
        {
            VERIFY(SUCCEEDED(pAlias->SelectScopeItem()));
        }
    }
    else
    {
        err = ERROR_NOT_ENOUGH_MEMORY;
    }
    return err;
}

/* virtual */
HRESULT
CIISFileName::CreatePropertyPages(
    IN LPPROPERTYSHEETCALLBACK lpProvider,
    IN LONG_PTR handle, 
    IN IUnknown * pUnk,
    IN DATA_OBJECT_TYPES type
    )
/*++

Routine Description:

    Create the property pages for the given object

Arguments:

    LPPROPERTYSHEETCALLBACK lpProvider  : Provider
    LONG_PTR handle                     : Handle.
    IUnknown * pUnk,
    DATA_OBJECT_TYPES type

Return Value:

    HRESULT
                                                
--*/
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());

    CComBSTR bstrPath;
    CError err(BuildMetaPath(bstrPath));

    if (err.Succeeded())
    {
        if (IsDir())
        {
            err = ShowDirPropertiesDlg(
                lpProvider,
                QueryAuthInfo(), 
                bstrPath,
                GetMainWindow(),
                (LPARAM)this,
                handle
                );
        }
        else
        {
            err = ShowFilePropertiesDlg(
                lpProvider,
                QueryAuthInfo(), 
                bstrPath,
                GetMainWindow(),
                (LPARAM)this,
                handle
                );
        }
    }

    err.MessageBoxOnFailure();

    return err;
}

HRESULT
CIISFileName::ShowDirPropertiesDlg(
    LPPROPERTYSHEETCALLBACK lpProvider,
    CComAuthInfo * pAuthInfo,
    LPCTSTR lpszMDPath,
    CWnd * pMainWnd,
    LPARAM  lParam,
    LONG_PTR handle
    )
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());
    ASSERT_PTR(lpProvider);

    CError err;

    CW3Sheet * pSheet = new CW3Sheet(
        pAuthInfo,
        lpszMDPath,
        0, 
        pMainWnd,
        lParam,
        handle
        );

    if (pSheet)
    {
        pSheet->SetModeless();

        //
        // Add file pages
        //
        pSheet->SetSheetType(pSheet->SHEET_TYPE_DIR);
        err = AddMMCPage(lpProvider, new CW3DirPage(pSheet));
        err = AddMMCPage(lpProvider, new CW3DocumentsPage(pSheet));
        err = AddMMCPage(lpProvider, new CW3SecurityPage(pSheet, FALSE, FILE_ATTRIBUTE_DIRECTORY));
        err = AddMMCPage(lpProvider, new CW3HTTPPage(pSheet));
        err = AddMMCPage(lpProvider, new CW3ErrorsPage(pSheet));

    }
    else
    {
        err = ERROR_NOT_ENOUGH_MEMORY;
    }

    return err;
}

HRESULT
CIISFileName::ShowFilePropertiesDlg(
    LPPROPERTYSHEETCALLBACK lpProvider,
    CComAuthInfo * pAuthInfo,
    LPCTSTR lpszMDPath,
    CWnd * pMainWnd,
    LPARAM  lParam,
    LONG_PTR handle
    )
{
    AFX_MANAGE_STATE(::AfxGetStaticModuleState());
    ASSERT_PTR(lpProvider);

    CError err;

    CW3Sheet * pSheet = new CW3Sheet(
        pAuthInfo,
        lpszMDPath,
        0, 
        pMainWnd,
        lParam,
        handle
        );

    if (pSheet)
    {
        pSheet->SetModeless();
        //
        // Add file pages
        //
        pSheet->SetSheetType(pSheet->SHEET_TYPE_FILE);
        err = AddMMCPage(lpProvider, new CW3FilePage(pSheet));
        err = AddMMCPage(lpProvider, new CW3SecurityPage(pSheet, FALSE, 0));
        err = AddMMCPage(lpProvider, new CW3HTTPPage(pSheet));
        err = AddMMCPage(lpProvider, new CW3ErrorsPage(pSheet));

    }
    else
    {
        err = ERROR_NOT_ENOUGH_MEMORY;
    }

    return err;
}

HRESULT
CIISFileName::OnPropertyChange(BOOL fScope, IResultData * pResult)
{
	CError err;
	// We cannot change anything visible in file
	if (IsDir())
	{
		// We cannot change path, therefore we don't need to reenumerate
		err = Refresh(FALSE);
	}
	return err;
}