|
|
#include "local.h"
#include "../security.h"
#include "../favorite.h"
#include "resource.h"
#include "chcommon.h"
#include "hsfolder.h"
#include <mluisupp.h>
#define DM_HSFOLDER 0
STDAPI AddToFavorites(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle, BOOL fDisplayUI, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
#define MAX_ITEM_OPEN 10
static LPCTSTR _GetURLTitleForDisplay(LPBASEPIDL pcei, LPTSTR szBuf, DWORD cchBuf);
static BOOL _ValidateIDListArray(UINT cidl, LPCITEMIDLIST *ppidl) { UINT i;
for (i = 0; i < cidl; i++) { if (!_IsValid_IDPIDL(ppidl[i]) && !_IsValid_HEIPIDL(ppidl[i])) return FALSE; }
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
//
// CHistItem Object
//
//////////////////////////////////////////////////////////////////////////////
CHistItem::CHistItem() { }
CHistItem::~CHistItem() { if (_pHCFolder) _pHCFolder->Release(); // release the pointer to the sf
}
HRESULT CHistItem::Initialize(CHistFolder *pHCFolder, HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl) { HRESULT hres = CBaseItem::Initialize(hwnd, cidl, ppidl); if (SUCCEEDED(hres)) { _pHCFolder = pHCFolder; _pHCFolder->AddRef(); // we're going to hold onto this pointer, so
} return hres; }
HRESULT CHistItem_CreateInstance(CHistFolder *pHCFolder, HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl, REFIID riid, void **ppv) { HRESULT hr;
*ppv = NULL; // null the out param
if (!_ValidateIDListArray(cidl, ppidl)) return E_FAIL;
CHistItem *pHCItem = new CHistItem; if (pHCItem) { hr = pHCItem->Initialize(pHCFolder, hwnd, cidl, ppidl); if (SUCCEEDED(hr)) hr = pHCItem->QueryInterface(riid, ppv); pHCItem->Release(); } else hr = E_OUTOFMEMORY;
return hr; }
//////////////////////////////////
//
// IUnknown Methods...
//
HRESULT CHistItem::QueryInterface(REFIID iid, void **ppv) { HRESULT hres = CBaseItem::QueryInterface(iid, ppv);
if (FAILED(hres) && iid == IID_IHist) { *ppv = (LPVOID)this; // for our friends
AddRef(); hres = S_OK; } return hres; }
//////////////////////////////////
//
// IQueryInfo Methods
//
HRESULT CHistItem::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip) { return _pHCFolder->_GetInfoTip(_ppidl[0], dwFlags, ppwszTip); }
//////////////////////////////////
//
// IContextMenu Methods
//
HRESULT CHistItem::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,UINT idCmdLast, UINT uFlags) { USHORT cItems;
TraceMsg(DM_HSFOLDER, "hci - cm - QueryContextMenu() called."); if ((uFlags & CMF_VERBSONLY) || (uFlags & CMF_DVFILE)) { cItems = MergePopupMenu(&hmenu, POPUP_CONTEXT_URL_VERBSONLY, 0, indexMenu, idCmdFirst, idCmdLast); } else // (uFlags & CMF_NORMAL)
{ UINT idResource = POPUP_CACHECONTEXT_URL;
// always use the cachecontext menu unless:
if ( ((_pHCFolder->_uViewType == VIEWPIDL_ORDER_SITE) && (_pHCFolder->_uViewDepth == 0)) || (!IsLeaf(_pHCFolder->_foldertype)) ) idResource = POPUP_HISTORYCONTEXT_URL;
cItems = MergePopupMenu(&hmenu, idResource, 0, indexMenu, idCmdFirst, idCmdLast);
if (IsInetcplRestricted(L"History")) { DeleteMenu(hmenu, RSVIDM_DELCACHE + idCmdFirst, MF_BYCOMMAND); _SHPrettyMenu(hmenu); } } if (hmenu) SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
return ResultFromShort(cItems); // number of menu items
}
STDMETHODIMP CHistItem::InvokeCommand(LPCMINVOKECOMMANDINFO pici) { UINT i; int idCmd = _GetCmdID(pici->lpVerb); HRESULT hres = S_OK; DWORD dwAction; BOOL fCancelCopyAndOpen = FALSE; BOOL fZonesUI = FALSE; BOOL fMustFlushNotify = FALSE; BOOL fBulkDelete;
TraceMsg(DM_HSFOLDER, "hci - cm - InvokeCommand() called.");
if (idCmd == RSVIDM_DELCACHE) { TCHAR szBuff[INTERNET_MAX_URL_LENGTH+MAX_PATH]; TCHAR szFormat[MAX_PATH]; if (_cItems == 1) { TCHAR szTitle[MAX_URL_STRING];
if (_pHCFolder->_foldertype != FOLDER_TYPE_Hist) { _GetURLDispName((LPBASEPIDL)_ppidl[0], szTitle, ARRAYSIZE(szTitle)); } else { FILETIME ftStart, ftEnd; LPCUTSTR pszIntervalName = _GetURLTitle(_ppidl[0]);
if (SUCCEEDED(_ValueToIntervalW(pszIntervalName, &ftStart, &ftEnd))) { GetDisplayNameForTimeInterval(&ftStart, &ftEnd, szTitle, ARRAYSIZE(szTitle)); } }
MLLoadString(IDS_WARN_DELETE_HISTORYITEM, szFormat, ARRAYSIZE(szFormat)); wnsprintf(szBuff, ARRAYSIZE(szBuff), szFormat, szTitle); } else { MLLoadString(IDS_WARN_DELETE_MULTIHISTORY, szFormat, ARRAYSIZE(szFormat)); wnsprintf(szBuff, ARRAYSIZE(szBuff), szFormat, _cItems); } if (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_HISTCACHE_WARNING), pici->hwnd, HistoryConfirmDeleteDlgProc, (LPARAM)szBuff) != IDYES) { return S_FALSE; } return _pHCFolder->_DeleteItems(_ppidl, _cItems); }
// ZONES SECURITY CHECK.
//
// We need to cycle through each action and Zone Check the URLs.
// We pass NOUI when zone checking the URLs because we don't want info
// displayed to the user. We will stop when we find the first questionable
// URL. We will then
for (i = 0; (i < _cItems) && !fZonesUI; i++) { if (_ppidl[i]) { switch (idCmd) { case RSVIDM_OPEN: if ((i < MAX_ITEM_OPEN) && _pHCFolder->_IsLeaf()) { if (!_ZoneCheck(i, URLACTION_SHELL_VERB)) { fZonesUI = TRUE; dwAction = URLACTION_SHELL_VERB; } } break;
case RSVIDM_COPY: if (_pHCFolder->_IsLeaf()) { if (!_ZoneCheck(i, URLACTION_SHELL_MOVE_OR_COPY)) { fZonesUI = TRUE; dwAction = URLACTION_SHELL_MOVE_OR_COPY; } } break; } } }
if (fZonesUI) { LPCTSTR pszUrl = _GetUrl(i-1); // Sub 1 because of for loop above.
if (S_OK != ZoneCheckUrl(pszUrl, dwAction, PUAF_DEFAULT|PUAF_WARN_IF_DENIED, NULL)) { // The user cannot do this or does not want to do this.
fCancelCopyAndOpen = TRUE; } }
i = _cItems;
// NOTE (andrewgu): ie5.5 b#108361
// 1. on older versions of the shell, first deleting the items and then calling
// SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, _pHCFolder->_pidl, NULL) doesn't trigger a refresh;
// 2. but deleting an item and then calling calling
// SHChangeNotify(SHCNE_DELETE, SHCNF_IDLIST, ILCombine(_pHCFolder->_pidl, (LPITEMIDLIST)(_ppcei[i])), NULL) does;
// 3. so the fix is to not set fBulkDelete on older versions of the shell.
if (5 <= GetUIVersion()) fBulkDelete = i > LOTS_OF_FILES; else fBulkDelete = FALSE;
// fCancelCopyAndOpen happens if the user cannot or chose not to proceed.
while (i && !fCancelCopyAndOpen) { i--; if (_ppidl[i]) {
switch (idCmd) { case RSVIDM_OPEN: ASSERT(!_pHCFolder->_uViewType); if (i >= MAX_ITEM_OPEN) { hres = S_FALSE; goto Done; }
if (!IsLeaf(_pHCFolder->_foldertype)) { LPITEMIDLIST pidlOpen; hres = S_FALSE; pidlOpen = ILCombine(_pHCFolder->_pidl, _ppidl[i]); if (pidlOpen) { IShellBrowser *psb = FileCabinet_GetIShellBrowser(_hwndOwner); if (psb) { psb->AddRef(); psb->BrowseObject(pidlOpen, (i==_cItems-1) ? SBSP_DEFBROWSER:SBSP_NEWBROWSER); psb->Release(); hres = S_OK; } else { hres = _LaunchAppForPidl(pici->hwnd, pidlOpen); } ILFree(pidlOpen); } } else { TCHAR szDecoded[MAX_URL_STRING]; ConditionallyDecodeUTF8(_GetUrl(i), szDecoded, ARRAYSIZE(szDecoded));
hres = _LaunchApp(pici->hwnd, szDecoded); } break;
case RSVIDM_ADDTOFAVORITES: hres = _AddToFavorites(i); goto Done; case RSVIDM_OPEN_NEWWINDOW: { LPCTSTR pszUrl = _GetUrl(i); if (pszUrl) { TCHAR szDecoded[MAX_URL_STRING]; ConditionallyDecodeUTF8(_GetUrl(i), szDecoded, ARRAYSIZE(szDecoded)); LPWSTR pwszTarget; if (SUCCEEDED((hres = SHStrDup(szDecoded, &pwszTarget)))) { hres = NavToUrlUsingIEW(pwszTarget, TRUE); CoTaskMemFree(pwszTarget); } } else { hres = E_FAIL; } goto Done; } case RSVIDM_COPY: if (!_pHCFolder->_IsLeaf()) { hres = E_FAIL; } else { OleSetClipboard((IDataObject *)this); } goto Done;
case RSVIDM_DELCACHE: ASSERT(!_pHCFolder->_uViewType); // if (IsHistory(_pHCFolder->_foldertype))
hres = E_FAIL; break;
case RSVIDM_PROPERTIES: // NOTE: We'll probably want to split this into two cases
// and call a function in each case
//
if (IsLeaf(_pHCFolder->_foldertype)) { // this was a bug in IE4, too:
// the pidl is re-created so that it has the most up-to-date information
// possible -- this way we can avoid assuming that the NSC has cached the
// most up-to-date pidl (which, in most cases, it hasn't)
LPHEIPIDL pidlTemp = _pHCFolder->_CreateHCacheFolderPidlFromUrl(FALSE, HPidlToSourceUrl( (LPBASEPIDL)_ppidl[i])); if (pidlTemp) { TCHAR szTitle[MAX_URL_STRING]; _GetURLTitleForDisplay((LPBASEPIDL)pidlTemp, szTitle, ARRAYSIZE(szTitle)); _CreatePropSheet(pici->hwnd, (LPCITEMIDLIST)pidlTemp, DLG_HISTITEMPROP, _sPropDlgProc, szTitle); LocalFree(pidlTemp); pidlTemp = NULL; } } else { hres = E_FAIL; } goto Done;
default: hres = E_FAIL; break; } ASSERT(SUCCEEDED(hres)); if (FAILED(hres)) TraceMsg(DM_HSFOLDER, "Cachevu failed the command at: %s", HPidlToSourceUrl((LPBASEPIDL)_ppidl[i])); } } Done: if (fMustFlushNotify) { if (fBulkDelete) { ASSERT(!_pHCFolder->_uViewType); _GenerateEvent(SHCNE_UPDATEDIR, _pHCFolder->_pidl, NULL, NULL); }
SHChangeNotifyHandleEvents(); } return hres; }
//////////////////////////////////
//
// IDataObject Methods...
//
HRESULT CHistItem::GetData(LPFORMATETC pFEIn, LPSTGMEDIUM pSTM) { HRESULT hres;
#ifdef DEBUG
TCHAR szName[64]; if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName))) wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
TraceMsg(DM_HSFOLDER, "hci - do - GetData(%s)", szName); #endif
pSTM->hGlobal = NULL; pSTM->pUnkForRelease = NULL;
if ((pFEIn->cfFormat == g_cfFileDescW) && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreateFileDescriptorW(pSTM);
else if ((pFEIn->cfFormat == g_cfFileDescA) && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreateFileDescriptorA(pSTM);
else if ((pFEIn->cfFormat == g_cfFileContents) && (pFEIn->tymed & TYMED_ISTREAM)) hres = _CreateFileContents(pSTM, pFEIn->lindex);
else if (pFEIn->cfFormat == CF_UNICODETEXT && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreateUnicodeTEXT(pSTM);
else if (pFEIn->cfFormat == CF_TEXT && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreateHTEXT(pSTM);
else if (pFEIn->cfFormat == g_cfURL && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreateURL(pSTM);
else if ((pFEIn->cfFormat == g_cfPreferredEffect) && (pFEIn->tymed & TYMED_HGLOBAL)) hres = _CreatePrefDropEffect(pSTM);
else hres = DATA_E_FORMATETC; return hres; }
HRESULT CHistItem::QueryGetData(LPFORMATETC pFEIn) { #ifdef DEBUG
TCHAR szName[64]; if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName))) wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
TraceMsg(DM_HSFOLDER, "hci - do - QueryGetData(%s)", szName); #endif
if (pFEIn->cfFormat == g_cfFileDescW || pFEIn->cfFormat == g_cfFileDescA || pFEIn->cfFormat == g_cfFileContents || pFEIn->cfFormat == g_cfURL || pFEIn->cfFormat == CF_UNICODETEXT || pFEIn->cfFormat == CF_TEXT || pFEIn->cfFormat == g_cfPreferredEffect) { TraceMsg(DM_HSFOLDER, " format supported."); return NOERROR; } return S_FALSE; }
HRESULT CHistItem::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC *ppEnum) { FORMATETC Histfmte[] = { {g_cfFileDescW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {g_cfFileDescA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {g_cfFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM }, {g_cfURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, {g_cfPreferredEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }, }; return SHCreateStdEnumFmtEtc(ARRAYSIZE(Histfmte), Histfmte, ppEnum); }
//////////////////////////////////
//
// IExtractIconA Methods...
//
HRESULT CHistItem::GetIconLocation(UINT uFlags, LPSTR pszIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags) { int cbIcon;
if (_pHCFolder->_uViewType) { switch (_pHCFolder->_uViewType) { case VIEWPIDL_SEARCH: case VIEWPIDL_ORDER_FREQ: case VIEWPIDL_ORDER_TODAY: cbIcon = IDI_HISTURL; break; case VIEWPIDL_ORDER_SITE: switch(_pHCFolder->_uViewDepth) { case 0: cbIcon = (uFlags & GIL_OPENICON) ? IDI_HISTOPEN:IDI_HISTFOLDER; break; case 1: cbIcon = IDI_HISTURL; break; } break; default: return E_FAIL; } } else { switch (_pHCFolder->_foldertype) { case FOLDER_TYPE_Hist: cbIcon = IDI_HISTWEEK; break; case FOLDER_TYPE_HistInterval: cbIcon = (uFlags & GIL_OPENICON) ? IDI_HISTOPEN:IDI_HISTFOLDER; break; case FOLDER_TYPE_HistDomain: cbIcon = IDI_HISTURL; break; default: return E_FAIL; } } *puFlags = 0; *pniIcon = -cbIcon; StrCpyNA(pszIconFile, "shdocvw.dll", ucchMax); return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
// Helper Routines
//
//////////////////////////////////////////////////////////////////////////////
UNALIGNED const TCHAR* _GetURLTitle(LPBASEPIDL pcei) { if (pcei->usSign == HEIPIDL_SIGN) { LPHEIPIDL phei = (LPHEIPIDL) pcei;
if (phei->usTitle == 0) { const TCHAR* psz = _StripHistoryUrlToUrl(HPidlToSourceUrl((LPBASEPIDL)pcei));
return psz ? _FindURLFileName(psz) : TEXT(""); } else { return (LPTSTR)(((BYTE*)phei)+phei->usTitle); } } else if (VALID_IDSIGN(pcei->usSign)) { return ((LPHIDPIDL)pcei)->szID; } else { return TEXT(""); } }
static LPCTSTR _GetURLTitleForDisplay(LPBASEPIDL pcei, LPTSTR szBuf, DWORD cchBuf) { TCHAR szTitle[MAX_URL_STRING]; if (!_URLTitleIsURL(pcei) || FAILED(PrepareURLForDisplayUTF8(_GetURLTitleAlign(pcei, szTitle, ARRAYSIZE(szTitle)), szBuf, &cchBuf, TRUE))) { ualstrcpyn(szBuf, _GetURLTitle(pcei), cchBuf); } return szBuf; }
UNALIGNED const TCHAR* CHistItem::_GetURLTitle(LPCITEMIDLIST pidl) { return ::_GetURLTitle( (LPBASEPIDL)pidl); }
LPCTSTR CHistItem::_GetUrl(int nIndex) { return _StripHistoryUrlToUrl(HPidlToSourceUrl((LPBASEPIDL)_ppidl[nIndex])); }
LPCTSTR CHistItem::_PidlToSourceUrl(LPCITEMIDLIST pidl) { return HPidlToSourceUrl((LPBASEPIDL) pidl); }
// Return value:
// TRUE - URL is Safe.
// FALSE - URL is questionable and needs to be re-zone checked w/o PUAF_NOUI.
BOOL CHistItem::_ZoneCheck(int nIndex, DWORD dwUrlAction) { LPCTSTR pszUrl = _GetUrl(nIndex);
// Yes, then consider anything that is not
// a FILE URL safe.
int nScheme = GetUrlScheme(pszUrl); if (URL_SCHEME_FILE != nScheme) return TRUE; // It's safe because it's not a file URL.
if (S_OK != ZoneCheckUrl(pszUrl, dwUrlAction, PUAF_NOUI, NULL)) return FALSE;
return TRUE; }
//////////////////////////////////////////////////////////////////////////////
//
// Helper Routines
//
//////////////////////////////////////////////////////////////////////////////
INT_PTR CALLBACK CHistItem::_sPropDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE) GetWindowLongPtr(hDlg, DWLP_USER); LPHEIPIDL phei = lpPropSheet ? (LPHEIPIDL)lpPropSheet->lParam : NULL;
switch(message) {
case WM_INITDIALOG: { SHFILEINFO sfi; TCHAR szBuf[80]; TCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
SetWindowLongPtr(hDlg, DWLP_USER, lParam); phei = (LPHEIPIDL)((LPPROPSHEETPAGE)lParam)->lParam;
SHGetFileInfo(TEXT(".url"), 0, &sfi, SIZEOF(sfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)sfi.hIcon, 0);
_GetURLTitleForDisplay((LPBASEPIDL)phei, szDisplayUrl, ARRAYSIZE(szDisplayUrl)); SetDlgItemText(hDlg, IDD_TITLE, szDisplayUrl); SetDlgItemText(hDlg, IDD_FILETYPE, sfi.szTypeName); ConditionallyDecodeUTF8(_GetUrlForPidl((LPCITEMIDLIST)phei), szDisplayUrl, ARRAYSIZE(szDisplayUrl)); SetDlgItemText(hDlg, IDD_INTERNET_ADDRESS, szDisplayUrl);
FileTimeToDateTimeStringInternal(&phei->ftLastVisited, szBuf, ARRAYSIZE(szBuf), FALSE); SetDlgItemText(hDlg, IDD_LAST_VISITED, szBuf);
// It looks like the hitcount is double what it is supposed to be
// (ie - navigate to a site and hitcount += 2)
// For now, we'll just half the hitcount before we display it:
// Above statement is no longer true -- hitcount is correct. Removed the halving of hitcount.
wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%d"), (phei->dwNumHits)) ; SetDlgItemText(hDlg, IDD_NUMHITS, szBuf);
break; } case WM_DESTROY: { HICON hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_GETICON, 0, 0); if (hIcon) DestroyIcon(hIcon); } break;
case WM_COMMAND: case WM_HELP: case WM_CONTEXTMENU: // user can't change anything, so we don't care about any messages
break;
default: return FALSE; } // end of switch
return TRUE; }
HRESULT CHistItem::_CreateFileDescriptorW(LPSTGMEDIUM pSTM) { pSTM->tymed = TYMED_HGLOBAL; pSTM->pUnkForRelease = NULL; FILEGROUPDESCRIPTORW *pfgd = (FILEGROUPDESCRIPTORW*)GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORW) + (_cItems-1) * sizeof(FILEDESCRIPTORW)); if (pfgd == NULL) { TraceMsg(DM_HSFOLDER, "hci - Couldn't alloc file descriptor"); return E_OUTOFMEMORY; } pfgd->cItems = _cItems; // set the number of items
for (UINT i = 0; i < _cItems; i++) { FILEDESCRIPTORW *pfd = &(pfgd->fgd[i]); _GetURLTitleForDisplay((LPBASEPIDL)_ppidl[i], pfd->cFileName, ARRAYSIZE(pfd->cFileName)); MakeLegalFilenameW(pfd->cFileName);
UINT cchFilename = lstrlenW(pfd->cFileName); SHTCharToUnicode(L".URL", pfd->cFileName+cchFilename, ARRAYSIZE(pfd->cFileName)-cchFilename); }
pSTM->hGlobal = pfgd; return S_OK; }
|