mirror of https://github.com/tongzx/nt5src
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.
1512 lines
44 KiB
1512 lines
44 KiB
/*****************************************************************************\
|
|
FILE: view.cpp
|
|
|
|
DESCRIPTION:
|
|
This is our ShellView which implements FTP specific behavior. We get
|
|
the default DefView implementation and then use IShellFolderViewCB to
|
|
override behavior specific to us.
|
|
\*****************************************************************************/
|
|
|
|
#include "priv.h"
|
|
#include "view.h"
|
|
#include "ftpobj.h"
|
|
#include "statusbr.h"
|
|
#include "dialogs.h"
|
|
#include <inetcpl.h>
|
|
#include <htmlhelp.h>
|
|
#include "newmenu.h"
|
|
|
|
|
|
extern ULONG g_cRef_CFtpView;
|
|
|
|
// {FBDB45F0-DBF8-11d2-BB9B-006097DF5BD4} Private to msieftp.dll, NEVER EVER use outside of this DLL
|
|
const GUID IID_CFtpViewPrivThis = { 0xfbdb45f0, 0xdbf8, 0x11d2, { 0xbb, 0x9b, 0x0, 0x60, 0x97, 0xdf, 0x5b, 0xd4 } };
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* COLINFO, c_rgci
|
|
*
|
|
* Column information for DVM_GETDETAILSOF.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
const struct COLINFO {
|
|
UINT cchCol;
|
|
UINT uiFmt;
|
|
} c_rgci[] = {
|
|
{ 30, LVCFMT_LEFT },
|
|
{ 10, LVCFMT_RIGHT },
|
|
{ 20, LVCFMT_LEFT },
|
|
{ 20, LVCFMT_LEFT },
|
|
};
|
|
|
|
|
|
BOOL CFtpView::IsForegroundThread(void)
|
|
{
|
|
return (GetCurrentThreadId() == m_nThreadID);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _MOTDDialogProc
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
INT_PTR CALLBACK CFtpView::_MOTDDialogProc(HWND hDlg, UINT wm, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lResult = FALSE;
|
|
|
|
switch (wm)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
CFtpView * pThis = (CFtpView *) lParam;
|
|
CFtpGlob * pfg = pThis->m_pff->GetSiteMotd();
|
|
|
|
if (EVAL(pfg))
|
|
{
|
|
// TODO: NT #250018. Format the message and make it look pretty.
|
|
// so it doesn't have the FTP status numbers. We may also
|
|
// want to filter only the message that comes thru with
|
|
// status numbers 230
|
|
EVAL(SetWindowText(GetDlgItem(hDlg, IDC_MOTDDLG_MESSAGE), pfg->GetHGlobAsTCHAR()));
|
|
pfg->Release();
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
if ((IDOK == GET_WM_COMMAND_ID(wParam, lParam)) ||
|
|
(IDCANCEL == GET_WM_COMMAND_ID(wParam, lParam)))
|
|
EndDialog(hDlg, TRUE);
|
|
break;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _ShowMotdPsf
|
|
*
|
|
* Show the motd for a particular psf.
|
|
*
|
|
*****************************************************************************/
|
|
void CFtpView::_ShowMotdPsf(HWND hwndOwner)
|
|
{
|
|
DialogBoxParam(HINST_THISDLL, MAKEINTRESOURCE(IDD_MOTDDLG), hwndOwner, _MOTDDialogProc, (LPARAM)this);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _ShowMotd
|
|
*
|
|
* When Explorer finally goes idle, this procedure will be called,
|
|
* and we will show the FTP site's (new) motd.
|
|
*
|
|
*****************************************************************************/
|
|
void CFtpView::_ShowMotd(void)
|
|
{
|
|
m_hgtiWelcome = 0;
|
|
|
|
if (EVAL(m_pff))
|
|
_ShowMotdPsf(m_hwndOwner);
|
|
else
|
|
{
|
|
// We got cancelled prematurely
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* _OnGetDetailsOf
|
|
*
|
|
* ici - column for which information is requested
|
|
* pdi -> DETAILSINFO
|
|
*
|
|
* If pdi->pidl is 0, then we are asking for information about
|
|
* what columns to display. If pdi->pidl is nonzero, then we
|
|
* are asking for particular information about the specified pidl.
|
|
*
|
|
* _UNDOCUMENTED_: This callback and the DETAILSINFO structure
|
|
* are not documented. Nor is the quirk about pdi->pidl as
|
|
* noted above.
|
|
*
|
|
*****************************************************************************/
|
|
#define MAX_SIZE_STR 30
|
|
|
|
HRESULT CFtpView::_OnGetDetailsOf(UINT ici, PDETAILSINFO pdi)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (ici < COL_MAX)
|
|
{
|
|
pdi->str.uType = STRRET_CSTR;
|
|
pdi->str.cStr[0] = '\0';
|
|
|
|
if (pdi->pidl)
|
|
{
|
|
switch (ici)
|
|
{
|
|
case COL_NAME:
|
|
{
|
|
WCHAR wzDisplayName[MAX_PATH];
|
|
hr = FtpItemID_GetDisplayName(pdi->pidl, wzDisplayName, ARRAYSIZE(wzDisplayName));
|
|
if (EVAL(SUCCEEDED(hr)))
|
|
StringToStrRetW(wzDisplayName, &pdi->str);
|
|
}
|
|
break;
|
|
|
|
case COL_SIZE:
|
|
// (Directories don't get a size. Shell rules.)
|
|
if (!FtpPidl_IsDirectory(pdi->pidl, TRUE))
|
|
{
|
|
LONGLONG llSize = (LONGLONG) FtpItemID_GetFileSize(pdi->pidl);
|
|
WCHAR wzSizeStr[MAX_SIZE_STR];
|
|
|
|
if (StrFormatByteSizeW(llSize, wzSizeStr, ARRAYSIZE(wzSizeStr)))
|
|
SHUnicodeToAnsi(wzSizeStr, pdi->str.cStr, ARRAYSIZE(pdi->str.cStr));
|
|
else
|
|
StrFormatByteSizeA(FtpItemID_GetFileSizeLo(pdi->pidl), pdi->str.cStr, ARRAYSIZE(pdi->str.cStr));
|
|
}
|
|
hr = S_OK;
|
|
break;
|
|
|
|
case COL_TYPE:
|
|
hr = FtpPidl_GetFileTypeStrRet(pdi->pidl, &pdi->str);
|
|
break;
|
|
|
|
case COL_MODIFIED:
|
|
{
|
|
TCHAR szDateTime[MAX_PATH];
|
|
|
|
// We need the time in UTC because that's what Misc_StringFromFileTime()
|
|
// wants.
|
|
FILETIME ftLastModifiedUTC = FtpPidl_GetFileTime(pdi->pidl);
|
|
DWORD dwFlags = FDTF_SHORTDATE | FDTF_SHORTTIME;
|
|
|
|
switch (pdi->fmt)
|
|
{
|
|
case LVCFMT_LEFT_TO_RIGHT :
|
|
dwFlags |= FDTF_LTRDATE;
|
|
break;
|
|
|
|
case LVCFMT_RIGHT_TO_LEFT :
|
|
dwFlags |= FDTF_RTLDATE;
|
|
break;
|
|
}
|
|
|
|
// Misc_StringFromFileTime() wants UTC
|
|
Misc_StringFromFileTime(szDateTime, ARRAYSIZE(szDateTime), &ftLastModifiedUTC, dwFlags);
|
|
hr = StringToStrRetW(szDateTime, &pdi->str);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
WCHAR wzColumnLable[MAX_PATH];
|
|
|
|
pdi->fmt = c_rgci[ici].uiFmt;
|
|
pdi->cxChar = c_rgci[ici].cchCol;
|
|
|
|
EVAL(LoadStringW(HINST_THISDLL, IDS_HEADER_NAME(ici), wzColumnLable, ARRAYSIZE(wzColumnLable)));
|
|
hr = StringToStrRetW(wzColumnLable, &pdi->str);
|
|
}
|
|
}
|
|
else
|
|
hr = E_NOTIMPL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnColumnClick
|
|
|
|
DESCRIPTION:
|
|
_UNDOCUMENTED_: This callback and its parameters are not documented.
|
|
_UNDOCUMENTED_: ShellFolderView_ReArrange is not documented.
|
|
|
|
PARAMETERS:
|
|
hwnd - view window
|
|
ici - column that was clicked
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnColumnClick(UINT ici)
|
|
{
|
|
ShellFolderView_ReArrange(m_hwndOwner, ici);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CFtpView::_OnAddPropertyPages(SFVM_PROPPAGE_DATA * pData)
|
|
{
|
|
return AddFTPPropertyPages(pData->pfn, pData->lParam, &m_hinstInetCpl, m_psfv);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnInitMenuPopup
|
|
|
|
DESCRIPTION:
|
|
We use IContextMenu::QueryContectMenu() to merge background items into
|
|
the File menu. This doesn't work on browser only because it's not supported
|
|
so we would like to see if this works.
|
|
|
|
PARAMETERS:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnInitMenuPopup(HMENU hmenu, UINT idCmdFirst, UINT nIndex)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnMergeMenu
|
|
|
|
DESCRIPTION:
|
|
_UNDOCUMENTED_: This callback and its parameters are not documented.
|
|
_UNDOCUMENTED_: Nothing about menu merging is documented.
|
|
|
|
PARAMETERS:
|
|
pqcm - QueryContextMenu info
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnMergeMenu(LPQCMINFO pqcm)
|
|
{
|
|
HRESULT hr;
|
|
HMENU hmenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(IDM_FTPMERGE));
|
|
|
|
if (SHELL_VERSION_W95NT4 != GetShellVersion())
|
|
{
|
|
// We prefer to add "New" and "Login As" via
|
|
// IContextMenu::QueryContextMenu() but it wasn't implemented
|
|
// in browser only. The IDM_FTPMERGE menu contains a second
|
|
// copy for the browser only case so we need to remove them
|
|
// if it's not browser only.
|
|
EVAL(DeleteMenu(hmenu, FCIDM_MENU_FILE, MF_BYCOMMAND));
|
|
}
|
|
|
|
if (SHELL_VERSION_IE4 < GetShellVersion())
|
|
{
|
|
// Remove "Help.FTP Help" because we will have that work done
|
|
// in "Help.Help Topics" on NT5 and after. We don't do this for
|
|
// earlier versions of shell32 because shell32 in NT5 is the
|
|
// first version to support "HtmlHelp" over WinHelp. This is
|
|
// needed because FTP's help is stored in IE's HTML Help files.
|
|
EVAL(DeleteMenu(hmenu, IDC_ITEM_FTPHELP, MF_BYCOMMAND));
|
|
}
|
|
|
|
if (hmenu)
|
|
{
|
|
MergeMenuHierarchy(pqcm->hmenu, hmenu, pqcm->idCmdFirst, pqcm->idCmdLast);
|
|
m_idMergedMenus = pqcm->idCmdFirst;
|
|
m_nMenuItemsAdded = GetMenuItemCount(hmenu);
|
|
DestroyMenu(hmenu);
|
|
|
|
// Remove duplicate items. (Browser Only)
|
|
_SHPrettyMenu(pqcm->hmenu);
|
|
|
|
int nItems = GetMenuItemCount(pqcm->hmenu);
|
|
if (nItems)
|
|
{
|
|
// Pretty the submenus because we added separators. NT #358197
|
|
for (int nIndex = 0; nIndex < nItems; nIndex++)
|
|
{
|
|
HMENU hSubMenu = GetSubMenu(pqcm->hmenu, nIndex);
|
|
_SHPrettyMenu(hSubMenu);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
// NT #267081, some other people (IE) will reformat the StatusBar during the
|
|
// asynch navigation. I take this event (MergeMenus) and reformat the
|
|
// status bar if necessary.
|
|
_InitStatusBar();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: UnMergeMenu
|
|
|
|
DESCRIPTION:
|
|
|
|
PARAMETERS:
|
|
\*****************************************************************************/
|
|
HRESULT UnMergeMenu(HMENU hMenu, UINT idOffset, HMENU hMenuTemplate)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
UINT nIndex;
|
|
UINT nEnd = GetMenuItemCount(hMenuTemplate);
|
|
|
|
for (nIndex = 0; nIndex < nEnd; nIndex++)
|
|
{
|
|
UINT idToDelete = GetMenuItemID(hMenuTemplate, nIndex);
|
|
|
|
if (-1 != idToDelete)
|
|
DeleteMenu(hMenu, (idToDelete + idOffset), MF_BYPOSITION);
|
|
else
|
|
{
|
|
// It may be a submenu, so we may need to recurse.
|
|
MENUITEMINFO mii;
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_SUBMENU;
|
|
mii.cch = 0; // just in case
|
|
|
|
if (GetMenuItemInfo(hMenuTemplate, nIndex, TRUE, &mii) && mii.hSubMenu)
|
|
{
|
|
// It is a sub menu, so delete those items also.
|
|
hr = UnMergeMenu(hMenu, idOffset, mii.hSubMenu);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFtpView::_OnUnMergeMenu(HMENU hMenu)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Did I merge anything?
|
|
if (m_idMergedMenus && m_nMenuItemsAdded)
|
|
{
|
|
HMENU hMenuFTP = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(IDM_FTPMERGE));
|
|
|
|
if (hMenuFTP)
|
|
{
|
|
hr = UnMergeMenu(hMenu, m_idMergedMenus, hMenuFTP);
|
|
DestroyMenu(hMenuFTP);
|
|
}
|
|
|
|
m_idMergedMenus = 0;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnInvokeLoginAs
|
|
|
|
DESCRIPTION:
|
|
|
|
PARAMETERS:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnInvokeLoginAs(HWND hwndOwner)
|
|
{
|
|
ASSERT(m_pff);
|
|
return LoginAsViaFolder(hwndOwner, m_pff, m_psfv);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnInvokeNewFolder
|
|
|
|
DESCRIPTION:
|
|
|
|
PARAMETERS:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnInvokeNewFolder(HWND hwndOwner)
|
|
{
|
|
POINT pt = {0,0};
|
|
|
|
return CreateNewFolder(hwndOwner, m_pff, NULL, m_psfv, FALSE, pt);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnInvokeCommand
|
|
|
|
DESCRIPTION:
|
|
_UNDOCUMENTED_: This callback and its parameters are not documented.
|
|
_UNDOCUMENTED_: ShellFolderView_ReArrange is not documented.
|
|
|
|
PARAMETERS:
|
|
idc - Command being invoked
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnInvokeCommand(UINT idc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (idc)
|
|
{
|
|
case IDM_SORTBYNAME:
|
|
case IDM_SORTBYSIZE:
|
|
case IDM_SORTBYTYPE:
|
|
case IDM_SORTBYDATE:
|
|
ShellFolderView_ReArrange(m_hwndOwner, CONVERT_IDMID_TO_COLNAME(idc));
|
|
break;
|
|
|
|
case IDC_ITEM_ABOUTSITE:
|
|
_ShowMotdPsf(m_hwndOwner);
|
|
break;
|
|
|
|
case IDC_ITEM_FTPHELP:
|
|
_OnInvokeFtpHelp(m_hwndOwner);
|
|
break;
|
|
|
|
case IDC_LOGIN_AS:
|
|
_OnInvokeLoginAs(m_hwndOwner);
|
|
break;
|
|
|
|
case IDC_ITEM_NEWFOLDER:
|
|
_OnInvokeNewFolder(m_hwndOwner);
|
|
break;
|
|
|
|
#ifdef ADD_ABOUTBOX
|
|
case IDC_ITEM_ABOUTFTP:
|
|
hr = DisplayAboutBox(m_hwndOwner);
|
|
break;
|
|
#endif // ADD_ABOUTBOX
|
|
|
|
default:
|
|
ASSERT(0);
|
|
hr = E_NOTIMPL;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnGetHelpText
|
|
|
|
DESCRIPTION:
|
|
The shell want's the Help Text but they want it in their format (Ansi
|
|
vs. Unicode).
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnGetHelpText(LPARAM lParam, WPARAM wParam)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
UINT uiID = IDS_ITEM_HELP(LOWORD(wParam));
|
|
TCHAR szHelpText[MAX_PATH];
|
|
LPWSTR pwzHelpTextOut = (LPWSTR) lParam; // Only one of these is correct and fUnicodeShell indicates which one.
|
|
LPSTR pszHelpTextOut = (LPSTR) lParam;
|
|
|
|
pwzHelpTextOut[0] = L'\0'; // Terminate string. (Ok if it's ANSI)
|
|
|
|
szHelpText[0] = TEXT('\0');
|
|
// This will fail for some items that the shell will provide for us.
|
|
// These include View.ArrangeIcon.AutoArrange.
|
|
// NOTE: This currently doesn't work for everything in the View.ArrangeIcon
|
|
// menu except AutoArrange because uiID is 30-33,
|
|
// not 40-43 (IDS_HEADER_HELP(COL_NAME) - IDS_HEADER_HELP(COL_MODIFIED)).
|
|
// This will require changing the resource IDs but that will mess up
|
|
// the localizers and require changing IDS_HEADER_NAME().
|
|
if (LoadString(HINST_THISDLL, uiID, szHelpText, ARRAYSIZE(szHelpText)))
|
|
{
|
|
HMODULE hMod = GetModuleHandle(TEXT("shell32.dll"));
|
|
|
|
if (hMod)
|
|
{
|
|
BOOL fUnicodeShell = (NULL != GetProcAddress(hMod, "WOWShellExecute"));
|
|
|
|
// NOTE: DVM_GETHELPTEXT will want a UNICODE string if we are running
|
|
// on NT and an Ansi string if we are running on Win95. Let's thunk it to what
|
|
// they want.
|
|
|
|
if (fUnicodeShell)
|
|
SHTCharToUnicode(szHelpText, pwzHelpTextOut, HIWORD(wParam));
|
|
else
|
|
SHTCharToAnsi(szHelpText, pszHelpTextOut, HIWORD(wParam));
|
|
|
|
hres = S_OK;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
#define SZ_HELPTOPIC_FILEA "iexplore.chm > iedefault"
|
|
#define SZ_HELPTOPIC_FTPSECTIONA "ftp_over.htm"
|
|
#define SZ_HELPTOPIC_FILEW L"iexplore.chm"
|
|
#define SZ_HELPTOPIC_FTPSECTIONW L"ftp_over.htm"
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnInvokeFtpHelp
|
|
|
|
DESCRIPTION:
|
|
The wants Help specific to FTP.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnInvokeFtpHelp(HWND hwnd)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
uCLSSPEC ucs;
|
|
QUERYCONTEXT qc = { 0 };
|
|
|
|
ucs.tyspec = TYSPEC_CLSID;
|
|
ucs.tagged_union.clsid = CLSID_IEHelp;
|
|
|
|
// ASSERT(m_hwndOwner && m_psfv); // Not available on browser only
|
|
IUnknown_EnableModless((IUnknown *)m_psfv, FALSE);
|
|
hr = FaultInIEFeature(m_hwndOwner, &ucs, &qc, FIEF_FLAG_FORCE_JITUI);
|
|
IUnknown_EnableModless((IUnknown *)m_psfv, TRUE);
|
|
|
|
HtmlHelpA(NULL, SZ_HELPTOPIC_FILEA, HH_HELP_FINDER, (DWORD_PTR) SZ_HELPTOPIC_FTPSECTIONA);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnGetHelpTopic
|
|
|
|
DESCRIPTION:
|
|
Remove "Help.FTP Help" because we will have that work done
|
|
in "Help.Help Topics" on NT5 and after. We don't do this for
|
|
earlier versions of shell32 because shell32 in NT5 is the
|
|
first version to support "HtmlHelp" over WinHelp. This is
|
|
needed because FTP's help is stored in IE's HTML Help files.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnGetHelpTopic(SFVM_HELPTOPIC_DATA * phtd)
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
// Remove "Help.FTP Help" because we will have that work done
|
|
// in "Help.Help Topics" on NT5 and after. We don't do this for
|
|
// earlier versions of shell32 because shell32 in NT5 is the
|
|
// first version to support "HtmlHelp" over WinHelp. This is
|
|
// needed because FTP's help is stored in IE's HTML Help files.
|
|
if (SHELL_VERSION_IE4 < GetShellVersion())
|
|
{
|
|
StrCpyNW(phtd->wszHelpFile, SZ_HELPTOPIC_FILEW, ARRAYSIZE(phtd->wszHelpFile));
|
|
StrCpyNW(phtd->wszHelpTopic, SZ_HELPTOPIC_FTPSECTIONW, ARRAYSIZE(phtd->wszHelpTopic));
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnGetZone
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnGetZone(DWORD * pdwZone, WPARAM wParam)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
DWORD dwZone = URLZONE_INTERNET; // Default
|
|
LPCITEMIDLIST pidl = m_pff->GetPrivatePidlReference();
|
|
|
|
if (pidl)
|
|
{
|
|
WCHAR wzUrl[MAX_URL_STRING];
|
|
|
|
// NT #277100: This may fail if TweakUI is installed because
|
|
// they abuse us.
|
|
hr = UrlCreateFromPidlW(pidl, SHGDN_FORPARSING, wzUrl, ARRAYSIZE(wzUrl), ICU_ESCAPE | ICU_USERNAME, FALSE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IInternetSecurityManager * pism;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IInternetSecurityManager, (void **) &pism)))
|
|
{
|
|
pism->MapUrlToZone(wzUrl, &dwZone, 0);
|
|
pism->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pdwZone)
|
|
{
|
|
*pdwZone = dwZone;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnGetPane
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnGetPane(DWORD dwPaneID, DWORD * pdwPane)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
DWORD dwPane = PANE_NONE; // Default unknown
|
|
|
|
switch (dwPaneID)
|
|
{
|
|
case PANE_NAVIGATION:
|
|
dwPane = STATUS_PANE_STATUS;
|
|
break;
|
|
case PANE_ZONE:
|
|
dwPane = STATUS_PANE_ZONE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pdwPane)
|
|
{
|
|
*pdwPane = dwPane;
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnRefresh
|
|
|
|
DESCRIPTION:
|
|
We need to purge the cache and force our selves to hit the server again.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnRefresh(BOOL fReload)
|
|
{
|
|
if (EVAL(m_pff) && fReload)
|
|
m_pff->InvalidateCache();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnBackGroundEnumDone
|
|
|
|
DESCRIPTION:
|
|
Our enum happens on the background. Sometimes we decide that we want
|
|
to do a redirect during the enumeration because the UserName/Password
|
|
didn't allow access to the server but the user provided a pair that does.
|
|
Since we can't access the ComDlgBrowser's IShellBrowser::BrowseObject()
|
|
on the background, we need to call it on the forground. In order to do
|
|
that, we need an event that happens on the forground. Well this is that
|
|
even baby.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnBackGroundEnumDone(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_pidlRedirect)
|
|
{
|
|
LPITEMIDLIST pidlRedirect = NULL;
|
|
|
|
ENTERCRITICAL;
|
|
if (m_pidlRedirect)
|
|
{
|
|
pidlRedirect = m_pidlRedirect;
|
|
m_pidlRedirect = NULL;
|
|
}
|
|
LEAVECRITICAL;
|
|
|
|
if (pidlRedirect)
|
|
{
|
|
IShellBrowser * psb;
|
|
hr = IUnknown_QueryService(_punkSite, SID_SCommDlgBrowser, IID_IShellBrowser, (LPVOID *) &psb);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psb->BrowseObject(pidlRedirect, 0);
|
|
|
|
AssertMsg(SUCCEEDED(hr), TEXT("CFtpView::_OnBackGroundEnumDone() defview needs to support QS(SID_ShellFolderViewCB) on all platforms that hit this point"));
|
|
psb->Release();
|
|
}
|
|
|
|
ILFree(pidlRedirect);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnGetNotify
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnGetNotify(LPITEMIDLIST * ppidl, LONG * lEvents)
|
|
{
|
|
if (EVAL(lEvents))
|
|
*lEvents = FTP_SHCNE_EVENTS;
|
|
|
|
if (EVAL(ppidl))
|
|
{
|
|
// Normally I would use pidlRoot to get ChangeNotify messages but since
|
|
// that doesn't work, it's necessary to broadcast ChangeNotify messages
|
|
// using pidlTarget and receive them using pidlTarget. This is the later
|
|
// case.
|
|
if (EVAL(m_pff))
|
|
*ppidl = (LPITEMIDLIST) m_pff->GetPublicTargetPidlReference();
|
|
else
|
|
*ppidl = NULL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnSize
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnSize(LONG x, LONG y)
|
|
{
|
|
RECT rcCurrent;
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(m_hwndOwner);
|
|
GetWindowRect(m_hwndOwner, &rcCurrent);
|
|
|
|
// Has the size really changed?
|
|
if ((m_rcPrev.bottom != rcCurrent.bottom) ||
|
|
(m_rcPrev.top != rcCurrent.top) ||
|
|
(m_rcPrev.left != rcCurrent.left) ||
|
|
(m_rcPrev.right != rcCurrent.right))
|
|
{
|
|
// yes, so update the StatusBar.
|
|
if (m_psb)
|
|
hr = m_psb->Resize(x, y);
|
|
m_rcPrev = rcCurrent;
|
|
}
|
|
else
|
|
{
|
|
// No, so ignore it because we may stomp on some other
|
|
// active view. (Because we get this message even after
|
|
// another view took over the brower).
|
|
|
|
// I don't care about resizing to zero.
|
|
// I don't think the user will ever need it and it casues
|
|
// bug #198695 where the addressband goes blank. This is because
|
|
// defview will call us thru each of the two places:
|
|
// 1) CFtpFolder::CreateViewObject() (Old URL)
|
|
// 2) CDefView::CreateViewWindow2()->CFtpView::_OnSize() (Old URL)
|
|
// 3) DV_UpdateStatusBar()->CFtpView::_OnUpdateStatusBar() (New URL)
|
|
// 4) ReleaseWindowLV()->WndSize()->CFtpView::_OnSize() (Old URL)
|
|
// #4 makes us update the URL and replace #3 which is valid.
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnThisIDList
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnThisIDList(LPITEMIDLIST * ppidl)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(ppidl))
|
|
{
|
|
*ppidl = ILClone(m_pff->GetPublicRootPidlReference());
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnUpdateStatusBar
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnUpdateStatusBar(void)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
LPCITEMIDLIST pidl = m_pff->GetPrivatePidlReference();
|
|
|
|
if (EVAL(pidl))
|
|
{
|
|
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
|
|
BOOL fAnnonymousLogin = TRUE;
|
|
|
|
hr = FtpPidl_GetUserName(pidl, szUserName, ARRAYSIZE(szUserName));
|
|
if (SUCCEEDED(hr) && szUserName[0])
|
|
fAnnonymousLogin = FALSE;
|
|
|
|
if (m_psb)
|
|
{
|
|
// Even if the above call fails, we set the user name to clear out
|
|
// any old invalid values.
|
|
m_psb->SetUserName(szUserName, fAnnonymousLogin);
|
|
}
|
|
|
|
EVAL(SUCCEEDED(_SetStatusBarZone(m_psb, m_pff->m_pfs)));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: SetRedirectPidl
|
|
|
|
DESCRIPTION:
|
|
See the comments in _OnBackGroundEnumDone().
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::SetRedirectPidl(LPCITEMIDLIST pidlRedirect)
|
|
{
|
|
ENTERCRITICAL;
|
|
Pidl_Set(&m_pidlRedirect, pidlRedirect);
|
|
LEAVECRITICAL;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: DummyHintCallback
|
|
|
|
DESCRIPTION:
|
|
Doesn't do anything; simply forces the connection to be established
|
|
and the motd to be obtained.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::DummyHintCallback(HWND hwnd, CFtpFolder * pff, HINTERNET hint, LPVOID pv1, LPVOID pv2)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _InitStatusBar
|
|
|
|
DESCRIPTION:
|
|
Obtains and initializes the status bar window.
|
|
It is not an error if the viewer does not provide a status bar.
|
|
\*****************************************************************************/
|
|
void CFtpView::_InitStatusBar(void)
|
|
{
|
|
if (m_psb)
|
|
m_psb->SetStatusMessage(IDS_EMPTY, 0);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnWindowCreated (from shell32.IShellView)
|
|
|
|
DESCRIPTION:
|
|
When the window is created, we get the motd. Very soon thereafter,
|
|
DefView is going to ask for the IEnumIDList, which will now be
|
|
in the cache. (GROSS! Screws up background enumeration!)
|
|
|
|
Do this only if we don't already have a motd.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnWindowCreated(void)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
// Previously, we cached the MOTD here, but we now do it else where. We
|
|
// could do it here also if we wanted to have a MOTD per site and per folder
|
|
// but almost no servers support this and user's pretty much never need it.
|
|
// Besides, there are ambiguious cases that we couldn't get right on other
|
|
// servers.
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnDefItemCount (from shell32.IShellView)
|
|
|
|
DESCRIPTION:
|
|
_UNDOCUMENTED_: This callback and its parameters are not documented.
|
|
|
|
Called to advise the browser of how many items we might have. This
|
|
allows preliminary UI to appear while we are busy enumerating
|
|
the contents.
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnDefItemCount(LPINT pi)
|
|
{
|
|
*pi = 20;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: _OnDidDragDrop
|
|
|
|
DESCRIPTION:
|
|
Called to advise the browser that somebody did a drag/drop operation
|
|
on objects in the folder. If the effect was DROPEFFECT_MOVE, then
|
|
we delete the source, if we aren't still doing the copy asynch on a
|
|
background thread.
|
|
|
|
RETURN VALUES:
|
|
S_OK: We take responsibility of deleting the files which we can
|
|
do here in the synch case, or in IAsynchOperation::EndOperation()
|
|
in the asynch case.
|
|
S_FALSE: We didn't do the delete but it's OK for the caller to do it.
|
|
so the caller needs to display UI and then delete via
|
|
IContextMenu->InvokeCommand(-delete-).
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::_OnDidDragDrop(DROPEFFECT de, IDataObject * pdo)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (DROPEFFECT_MOVE == de)
|
|
{
|
|
IAsyncOperation * pao;
|
|
|
|
hr = pdo->QueryInterface(IID_IAsyncOperation, (void **) &pao);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BOOL fInAsyncOp = TRUE;
|
|
|
|
hr = pao->InOperation(&fInAsyncOp);
|
|
hr = S_OK; // Don't have caller do the delete.
|
|
if (FALSE == fInAsyncOp)
|
|
{
|
|
#ifdef FEATURE_CUT_MOVE
|
|
CLSID clsid;
|
|
BOOL fDoDelete = TRUE;
|
|
CFtpObj * pfo = (CFtpObj *) pdo;
|
|
|
|
// Is the destination the recycle bin?
|
|
if (SUCCEEDED(DataObj_GetDropTarget(pdo, &clsid)) &&
|
|
IsEqualCLSID(clsid, CLSID_RecycleBin))
|
|
{
|
|
// Yes, so we need to first inform the user that drops to the
|
|
// Recycle bin are perminate deletes and the user can't undo
|
|
// the operation.
|
|
if (IDYES != SHMessageBox(m_hwndOwner, NULL, IDS_RECYCLE_IS_PERM_WARNING, IDS_FTPERR_TITLE, (MB_ICONQUESTION | MB_YESNO)))
|
|
fDoDelete = FALSE;
|
|
}
|
|
|
|
// We didn't do the operation aynch so we need to DELETE the
|
|
// files now to complete the MOVE operation (MOVE=Copy + Delete).
|
|
if (fDoDelete)
|
|
{
|
|
Misc_DeleteHfpl(m_pff, m_hwndOwner, pfo->GetHfpl()); // Will fail on permission denied.
|
|
}
|
|
|
|
#else // FEATURE_CUT_MOVE
|
|
hr = S_FALSE; // Have parent do the delete.
|
|
#endif //FEATURE_CUT_MOVE
|
|
}
|
|
|
|
pao->Release();
|
|
}
|
|
else
|
|
hr = S_OK; // Don't have caller delete. IAsyncOperation::EndOperation() will.
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IFtpWebView Interface ***
|
|
//===========================
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_MessageOfTheDay
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_MessageOfTheDay(BSTR * pbstr)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(pbstr))
|
|
{
|
|
*pbstr = NULL;
|
|
|
|
if (EVAL(m_pff))
|
|
{
|
|
TCHAR szDefault[MAX_PATH];
|
|
LPCTSTR pszMOTD = szDefault;
|
|
CFtpGlob * pfg = m_pff->GetSiteMotd();
|
|
|
|
szDefault[0] = 0;
|
|
if (pfg)
|
|
pszMOTD = pfg->GetHGlobAsTCHAR();
|
|
|
|
// if we were not able to get the message of the day
|
|
// from CFtpFolder or it was empty, display "None"
|
|
if ((pszMOTD == szDefault) || (!pszMOTD[0]))
|
|
{
|
|
pszMOTD = szDefault;
|
|
LoadString(HINST_THISDLL, IDS_NO_MESSAGEOFTHEDAY, szDefault, ARRAYSIZE(szDefault));
|
|
}
|
|
|
|
*pbstr = TCharSysAllocString(pszMOTD);
|
|
|
|
if (pfg)
|
|
pfg->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
ASSERT_POINTER_MATCHES_HRESULT(*pbstr, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_Server
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_Server(BSTR * pbstr)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(pbstr))
|
|
{
|
|
*pbstr = NULL;
|
|
|
|
if (EVAL(m_pff))
|
|
{
|
|
TCHAR szServer[INTERNET_MAX_HOST_NAME_LENGTH];
|
|
|
|
if (SUCCEEDED(FtpPidl_GetServer(m_pff->GetPrivatePidlReference(), szServer, ARRAYSIZE(szServer))))
|
|
{
|
|
*pbstr = TCharSysAllocString(szServer);
|
|
if (*pbstr)
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
// ASSERT_POINTER_MATCHES_HRESULT(*pbstr, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_Directory
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_Directory(BSTR * pbstr)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(pbstr))
|
|
{
|
|
*pbstr = NULL;
|
|
|
|
if (EVAL(m_pff))
|
|
{
|
|
TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH];
|
|
|
|
if (EVAL(SUCCEEDED(GetDisplayPathFromPidl(m_pff->GetPrivatePidlReference(), szUrlPath, ARRAYSIZE(szUrlPath), FALSE))))
|
|
{
|
|
*pbstr = TCharSysAllocString(szUrlPath);
|
|
if (*pbstr)
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
ASSERT_POINTER_MATCHES_HRESULT(*pbstr, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_UserName
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_UserName(BSTR * pbstr)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(pbstr))
|
|
{
|
|
*pbstr = NULL;
|
|
|
|
if (EVAL(m_pff))
|
|
{
|
|
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
|
|
|
|
if (EVAL(SUCCEEDED(FtpPidl_GetUserName(m_pff->GetPrivatePidlReference(), szUserName, ARRAYSIZE(szUserName)))))
|
|
{
|
|
*pbstr = TCharSysAllocString((0 != szUserName[0]) ? szUserName : SZ_ANONYMOUS);
|
|
if (*pbstr)
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
ASSERT_POINTER_MATCHES_HRESULT(*pbstr, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_PasswordLength
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_PasswordLength(long * plLength)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (EVAL(plLength))
|
|
{
|
|
TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
|
|
|
|
*plLength = 0;
|
|
if (SUCCEEDED(FtpPidl_GetPassword(m_pff->GetPrivatePidlReference(), szPassword, ARRAYSIZE(szPassword), FALSE)))
|
|
{
|
|
*plLength = lstrlen(szPassword);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
ASSERT_POINTER_MATCHES_HRESULT(*plLength, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_EmailAddress
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_EmailAddress(BSTR * pbstr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (EVAL(pbstr))
|
|
{
|
|
TCHAR szEmailName[MAX_PATH];
|
|
DWORD dwType = REG_SZ;
|
|
DWORD cbSize = sizeof(szEmailName);
|
|
|
|
if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_INTERNET_SETTINGS, SZ_REGKEY_EMAIL_NAME, &dwType, szEmailName, &cbSize))
|
|
*pbstr = TCharSysAllocString(szEmailName);
|
|
else
|
|
{
|
|
hr = S_FALSE;
|
|
*pbstr = NULL;
|
|
}
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::put_EmailAddress
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::put_EmailAddress(BSTR bstr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (EVAL(bstr))
|
|
{
|
|
TCHAR szEmailName[MAX_PATH];
|
|
|
|
SHUnicodeToTChar(bstr, szEmailName, ARRAYSIZE(szEmailName));
|
|
if (ERROR_SUCCESS != SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_INTERNET_SETTINGS, SZ_REGKEY_EMAIL_NAME, REG_SZ, szEmailName, sizeof(szEmailName)))
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::get_CurrentLoginAnonymous
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::get_CurrentLoginAnonymous(VARIANT_BOOL * pfAnonymousLogin)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (EVAL(pfAnonymousLogin))
|
|
{
|
|
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
|
|
|
|
if (EVAL(m_pff) &&
|
|
SUCCEEDED(FtpPidl_GetUserName(m_pff->GetPrivatePidlReference(), szUserName, ARRAYSIZE(szUserName))) &&
|
|
szUserName[0] && (0 != StrCmpI(szUserName, TEXT("anonymous"))))
|
|
{
|
|
*pfAnonymousLogin = VARIANT_FALSE;
|
|
}
|
|
else
|
|
*pfAnonymousLogin = VARIANT_TRUE;
|
|
}
|
|
else
|
|
hr = E_INVALIDARG;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::LoginAnonymously
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::LoginAnonymously(void)
|
|
{
|
|
return _LoginWithPassword(NULL, NULL);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::LoginWithPassword
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::LoginWithPassword(BSTR bUserName, BSTR bPassword)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
|
|
TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
|
|
|
|
SHUnicodeToTChar(bUserName, szUserName, ARRAYSIZE(szUserName));
|
|
SHUnicodeToTChar(bPassword, szPassword, ARRAYSIZE(szPassword));
|
|
return _LoginWithPassword(szUserName, szPassword);
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
FUNCTION: IFtpWebView::LoginWithoutPassword
|
|
|
|
DESCRIPTION:
|
|
\*****************************************************************************/
|
|
HRESULT CFtpView::LoginWithoutPassword(BSTR bUserName)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
|
|
TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
|
|
|
|
SHUnicodeToTChar(bUserName, szUserName, ARRAYSIZE(szUserName));
|
|
if (SUCCEEDED(FtpPidl_GetPassword(m_pff->GetPrivatePidlReference(), szPassword, ARRAYSIZE(szPassword), TRUE)))
|
|
hr = _LoginWithPassword(szUserName, szPassword);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
HRESULT CFtpView::_LoginWithPassword(LPCTSTR pszUserName, LPCTSTR pszPassword)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPITEMIDLIST pidlUser;
|
|
|
|
hr = PidlReplaceUserPassword(m_pff->GetPrivatePidlReference(), &pidlUser, m_pff->GetItemAllocatorDirect(), pszUserName, pszPassword);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlFull = m_pff->CreateFullPublicPidl(pidlUser);
|
|
if (pidlFull)
|
|
{
|
|
hr = IUnknown_PidlNavigate(m_psfv, pidlFull, TRUE);
|
|
ASSERT(SUCCEEDED(hr));
|
|
ILFree(pidlFull);
|
|
}
|
|
|
|
ILFree(pidlUser);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
hr = S_FALSE; // Automation interfaces don't like failure returns.
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//===========================
|
|
// *** IDispatch Interface ***
|
|
//===========================
|
|
|
|
STDMETHODIMP CFtpView::GetTypeInfoCount(UINT * pctinfo)
|
|
{
|
|
return CImpIDispatch::GetTypeInfoCount(pctinfo);
|
|
}
|
|
|
|
STDMETHODIMP CFtpView::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo * * pptinfo)
|
|
{
|
|
return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo);
|
|
}
|
|
|
|
STDMETHODIMP CFtpView::GetIDsOfNames(REFIID riid, OLECHAR * * rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
|
|
{
|
|
return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
}
|
|
|
|
STDMETHODIMP CFtpView::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
|
|
{
|
|
return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* CFtpView_Create
|
|
*
|
|
* Creates a brand new enumerator based on an ftp site.
|
|
*
|
|
*****************************************************************************/
|
|
HRESULT CFtpView_Create(CFtpFolder * pff, HWND hwndOwner, REFIID riid, LPVOID * ppv)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CFtpView * pfv = new CFtpView(pff, hwndOwner);
|
|
|
|
if (pfv)
|
|
{
|
|
hr = pfv->QueryInterface(riid, ppv);
|
|
pfv->Release();
|
|
}
|
|
|
|
ASSERT_POINTER_MATCHES_HRESULT(*ppv, hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************\
|
|
Constructor
|
|
\****************************************************/
|
|
CFtpView::CFtpView(CFtpFolder * pff, HWND hwndOwner) : CImpIDispatch(&LIBID_MSIEFTPLib)
|
|
{
|
|
DllAddRef();
|
|
|
|
// This needs to be allocated in Zero Inited Memory.
|
|
// Assert that all Member Variables are inited to Zero.
|
|
ASSERT(!m_hwndOwner);
|
|
ASSERT(!m_hwndStatusBar);
|
|
ASSERT(!m_pff);
|
|
ASSERT(!m_hgtiWelcome);
|
|
|
|
m_nThreadID = GetCurrentThreadId();
|
|
if (hwndOwner)
|
|
{
|
|
m_hwndOwner = hwndOwner;
|
|
m_hwndStatusBar = Misc_FindStatusBar(hwndOwner);
|
|
m_psb = CStatusBar_Create(m_hwndStatusBar);
|
|
_InitStatusBar();
|
|
}
|
|
|
|
m_rcPrev.top = m_rcPrev.bottom = m_rcPrev.right = m_rcPrev.left = -1;
|
|
IUnknown_Set(&m_pff, pff);
|
|
|
|
LEAK_ADDREF(LEAK_CFtpView);
|
|
g_cRef_CFtpView++; // Needed to determine when to purge cache.
|
|
}
|
|
|
|
|
|
/****************************************************\
|
|
Destructor
|
|
\****************************************************/
|
|
/*****************************************************************************
|
|
* We release the psf before triggering the timeout, which is a
|
|
* signal to the trigger not to do anything.
|
|
*
|
|
* _UNDOCUMENTED_: This callback and its parameters are not documented.
|
|
*
|
|
*****************************************************************************/
|
|
CFtpView::~CFtpView()
|
|
{
|
|
IUnknown_Set(&m_pff, NULL);
|
|
|
|
TriggerDelayedAction(&m_hgtiWelcome); // Kick out the old one
|
|
|
|
SetRedirectPidl(NULL);
|
|
if (m_psb)
|
|
delete m_psb;
|
|
|
|
if (m_hinstInetCpl)
|
|
FreeLibrary(m_hinstInetCpl);
|
|
|
|
DllRelease();
|
|
LEAK_DELREF(LEAK_CFtpView);
|
|
g_cRef_CFtpView--; // Needed to determine when to purge cache.
|
|
}
|
|
|
|
|
|
//===========================
|
|
// *** IUnknown Interface ***
|
|
//===========================
|
|
|
|
HRESULT CFtpView::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch))
|
|
{
|
|
*ppvObj = SAFECAST(this, IDispatch *);
|
|
}
|
|
else if (IsEqualIID(riid, IID_IFtpWebView))
|
|
{
|
|
*ppvObj = SAFECAST(this, IFtpWebView *);
|
|
}
|
|
else if (IsEqualIID(riid, IID_CFtpViewPrivThis))
|
|
{
|
|
*ppvObj = (void *)this;
|
|
}
|
|
else
|
|
return CBaseFolderViewCB::QueryInterface(riid, ppvObj);
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
CFtpView * GetCFtpViewFromDefViewSite(IUnknown * punkSite)
|
|
{
|
|
CFtpView * pfv = NULL;
|
|
IShellFolderViewCB * psfvcb = NULL;
|
|
|
|
// This fails on Browser Only
|
|
IUnknown_QueryService(punkSite, SID_ShellFolderViewCB, IID_IShellFolderViewCB, (LPVOID *) &psfvcb);
|
|
if (psfvcb)
|
|
{
|
|
psfvcb->QueryInterface(IID_CFtpViewPrivThis, (void **) &pfv);
|
|
psfvcb->Release();
|
|
}
|
|
|
|
return pfv;
|
|
}
|
|
|
|
|
|
CStatusBar * GetCStatusBarFromDefViewSite(IUnknown * punkSite)
|
|
{
|
|
CStatusBar * psb = NULL;
|
|
CFtpView * pfv = GetCFtpViewFromDefViewSite(punkSite);
|
|
|
|
if (pfv)
|
|
{
|
|
psb = pfv->GetStatusBar();
|
|
pfv->Release();
|
|
}
|
|
|
|
return psb;
|
|
}
|
|
|
|
|