Source code of Windows XP (NT5)
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.

544 lines
16 KiB

  1. #include "local.h"
  2. #include "../security.h"
  3. #include "../favorite.h"
  4. #include "resource.h"
  5. #include "chcommon.h"
  6. #include "cafolder.h"
  7. #include <mluisupp.h>
  8. #define DM_HSFOLDER 0
  9. STDAPI AddToFavorites(HWND hwnd, LPCITEMIDLIST pidlCur, LPCTSTR pszTitle,
  10. BOOL fDisplayUI, IOleCommandTarget *pCommandTarget, IHTMLDocument2 *pDoc);
  11. #define MAX_ITEM_OPEN 10
  12. //////////////////////////////////////////////////////////////////////////////
  13. //
  14. // CCacheItem Object
  15. //
  16. //////////////////////////////////////////////////////////////////////////////
  17. CCacheItem::CCacheItem()
  18. {
  19. _dwDelCookie = DEL_COOKIE_WARN;
  20. }
  21. CCacheItem::~CCacheItem()
  22. {
  23. if (_pCFolder)
  24. _pCFolder->Release(); // release the pointer to the sf
  25. }
  26. HRESULT CCacheItem::Initialize(CCacheFolder *pCFolder, HWND hwnd, UINT cidl, LPCITEMIDLIST *ppidl)
  27. {
  28. HRESULT hres = CBaseItem::Initialize(hwnd, cidl, ppidl);
  29. if (SUCCEEDED(hres))
  30. {
  31. _pCFolder = pCFolder;
  32. _pCFolder->AddRef(); // we're going to hold onto this pointer, so
  33. }
  34. return hres;
  35. }
  36. HRESULT CCacheItem_CreateInstance(CCacheFolder *pCFolder, HWND hwnd,
  37. UINT cidl, LPCITEMIDLIST *ppidl, REFIID riid, void **ppv)
  38. {
  39. HRESULT hr;
  40. *ppv = NULL; // null the out param
  41. CCacheItem *pHCItem = new CCacheItem;
  42. if (pHCItem)
  43. {
  44. hr = pHCItem->Initialize(pCFolder, hwnd, cidl, ppidl);
  45. if (SUCCEEDED(hr))
  46. hr = pHCItem->QueryInterface(riid, ppv);
  47. pHCItem->Release();
  48. }
  49. else
  50. hr = E_OUTOFMEMORY;
  51. return hr;
  52. }
  53. //////////////////////////////////
  54. //
  55. // IUnknown Methods...
  56. //
  57. HRESULT CCacheItem::QueryInterface(REFIID iid, void **ppv)
  58. {
  59. HRESULT hres = CBaseItem::QueryInterface(iid, ppv);
  60. if (FAILED(hres) && iid == IID_ICache)
  61. {
  62. *ppv = (LPVOID)this; // for our friends
  63. AddRef();
  64. hres = S_OK;
  65. }
  66. return hres;
  67. }
  68. //////////////////////////////////
  69. //
  70. // IQueryInfo Methods
  71. //
  72. HRESULT CCacheItem::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
  73. {
  74. return _pCFolder->_GetInfoTip(_ppidl[0], dwFlags, ppwszTip);
  75. }
  76. //////////////////////////////////
  77. //
  78. // IContextMenu Methods
  79. //
  80. HRESULT CCacheItem::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,UINT idCmdLast, UINT uFlags)
  81. {
  82. USHORT cItems;
  83. TraceMsg(DM_HSFOLDER, "hci - cm - QueryContextMenu() called.");
  84. if ((uFlags & CMF_VERBSONLY) || (uFlags & CMF_DVFILE))
  85. {
  86. cItems = MergePopupMenu(&hmenu, POPUP_CONTEXT_URL_VERBSONLY, 0, indexMenu,
  87. idCmdFirst, idCmdLast);
  88. }
  89. else // (uFlags & CMF_NORMAL)
  90. {
  91. UINT idResource = POPUP_CACHECONTEXT_URL;
  92. cItems = MergePopupMenu(&hmenu, idResource, 0, indexMenu, idCmdFirst, idCmdLast);
  93. if (IsInetcplRestricted(L"History"))
  94. {
  95. DeleteMenu(hmenu, RSVIDM_DELCACHE + idCmdFirst, MF_BYCOMMAND);
  96. _SHPrettyMenu(hmenu);
  97. }
  98. }
  99. if (hmenu)
  100. SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
  101. return ResultFromShort(cItems); // number of menu items
  102. }
  103. static BOOL CachevuWarningDlg(LPCEIPIDL pcei, UINT uIDWarning, HWND hwnd)
  104. {
  105. TCHAR szFormat[MAX_PATH], szBuff[MAX_PATH], szTitle[MAX_PATH];
  106. _GetCacheItemTitle(pcei, szTitle, ARRAYSIZE(szTitle));
  107. MLLoadString(uIDWarning, szFormat, ARRAYSIZE(szFormat));
  108. wnsprintf(szBuff, ARRAYSIZE(szFormat), szFormat);
  109. return DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_HISTCACHE_WARNING),
  110. hwnd, HistoryConfirmDeleteDlgProc, (LPARAM)szBuff) == IDYES;
  111. }
  112. STDMETHODIMP CCacheItem::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  113. {
  114. UINT i;
  115. int idCmd = _GetCmdID(pici->lpVerb);
  116. HRESULT hres = S_OK;
  117. DWORD dwAction;
  118. BOOL fCancelCopyAndOpen = FALSE;
  119. BOOL fZonesUI = FALSE;
  120. BOOL fMustFlushNotify = FALSE;
  121. BOOL fBulkDelete;
  122. TraceMsg(DM_HSFOLDER, "hci - cm - InvokeCommand() called.");
  123. // ZONES SECURITY CHECK.
  124. //
  125. // We need to cycle through each action and Zone Check the URLs.
  126. // We pass NOUI when zone checking the URLs because we don't want info
  127. // displayed to the user. We will stop when we find the first questionable
  128. // URL. We will then
  129. for (i = 0; (i < _cItems) && !fZonesUI; i++)
  130. {
  131. if (_ppidl[i])
  132. {
  133. switch (idCmd)
  134. {
  135. case RSVIDM_OPEN:
  136. if ((i < MAX_ITEM_OPEN))
  137. {
  138. if (!_ZoneCheck(i, URLACTION_SHELL_VERB))
  139. {
  140. fZonesUI = TRUE;
  141. dwAction = URLACTION_SHELL_VERB;
  142. }
  143. }
  144. break;
  145. case RSVIDM_COPY:
  146. if (!_ZoneCheck(i, URLACTION_SHELL_MOVE_OR_COPY))
  147. {
  148. fZonesUI = TRUE;
  149. dwAction = URLACTION_SHELL_MOVE_OR_COPY;
  150. }
  151. break;
  152. }
  153. }
  154. }
  155. if (fZonesUI)
  156. {
  157. LPCTSTR pszUrl = _GetUrl(i-1); // Sub 1 because of for loop above.
  158. if (S_OK != ZoneCheckUrl(pszUrl, dwAction, PUAF_DEFAULT|PUAF_WARN_IF_DENIED, NULL))
  159. {
  160. // The user cannot do this or does not want to do this.
  161. fCancelCopyAndOpen = TRUE;
  162. }
  163. }
  164. i = _cItems;
  165. fBulkDelete = i > LOTS_OF_FILES;
  166. // fCancelCopyAndOpen happens if the user cannot or chose not to proceed.
  167. while (i && !fCancelCopyAndOpen)
  168. {
  169. i--;
  170. if (_ppidl[i])
  171. {
  172. switch (idCmd)
  173. {
  174. case RSVIDM_OPEN:
  175. if (i >= MAX_ITEM_OPEN)
  176. {
  177. hres = S_FALSE;
  178. goto Done;
  179. }
  180. if ((CEI_CACHEENTRYTYPE((LPCEIPIDL)_ppidl[i]) & COOKIE_CACHE_ENTRY))
  181. {
  182. ASSERT(PathFindExtension(CEI_LOCALFILENAME((LPCEIPIDL)_ppidl[i])) && \
  183. !StrCmpI(PathFindExtension(CEI_LOCALFILENAME((LPCEIPIDL)_ppidl[i])),TEXT(".txt")));
  184. hres = _LaunchApp(pici->hwnd, CEI_LOCALFILENAME((LPCEIPIDL)_ppidl[i]));
  185. }
  186. else
  187. {
  188. TCHAR szDecoded[MAX_URL_STRING];
  189. LPCTSTR pszUrl = _GetUrl(i);
  190. if (pszUrl)
  191. {
  192. ConditionallyDecodeUTF8(pszUrl, szDecoded, ARRAYSIZE(szDecoded));
  193. hres = _LaunchApp(pici->hwnd, szDecoded);
  194. }
  195. else
  196. {
  197. hres = E_FAIL;
  198. }
  199. }
  200. break;
  201. case RSVIDM_ADDTOFAVORITES:
  202. hres = _AddToFavorites(i);
  203. goto Done;
  204. case RSVIDM_OPEN_NEWWINDOW:
  205. {
  206. LPCTSTR pszUrl = _GetUrl(i);
  207. if (pszUrl)
  208. {
  209. TCHAR szDecoded[MAX_URL_STRING];
  210. ConditionallyDecodeUTF8(pszUrl, szDecoded, ARRAYSIZE(szDecoded));
  211. LPWSTR pwszTarget;
  212. if (SUCCEEDED((hres = SHStrDup(szDecoded, &pwszTarget)))) {
  213. hres = NavToUrlUsingIEW(pwszTarget, TRUE);
  214. CoTaskMemFree(pwszTarget);
  215. }
  216. }
  217. else
  218. hres = E_FAIL;
  219. goto Done;
  220. }
  221. case RSVIDM_COPY:
  222. OleSetClipboard((IDataObject *)this);
  223. goto Done;
  224. case RSVIDM_DELCACHE:
  225. // pop warning msg for cookie only once
  226. if ((CEI_CACHEENTRYTYPE((LPCEIPIDL)_ppidl[i]) & COOKIE_CACHE_ENTRY) &&
  227. (_dwDelCookie == DEL_COOKIE_WARN ))
  228. {
  229. if(CachevuWarningDlg((LPCEIPIDL)_ppidl[i], IDS_WARN_DELETE_CACHE, pici->hwnd))
  230. _dwDelCookie = DEL_COOKIE_YES;
  231. else
  232. _dwDelCookie = DEL_COOKIE_NO;
  233. }
  234. if ((CEI_CACHEENTRYTYPE((LPCEIPIDL)_ppidl[i]) & COOKIE_CACHE_ENTRY) &&
  235. (_dwDelCookie == DEL_COOKIE_NO ))
  236. continue;
  237. if (DeleteUrlCacheEntry(CPidlToSourceUrl((LPCEIPIDL)_ppidl[i])))
  238. {
  239. if (!fBulkDelete)
  240. {
  241. _GenerateEvent(SHCNE_DELETE, _pCFolder->_pidl, _ppidl[i], NULL);
  242. }
  243. fMustFlushNotify = TRUE;
  244. }
  245. else
  246. hres = E_FAIL;
  247. break;
  248. case RSVIDM_PROPERTIES:
  249. // NOTE: We'll probably want to split this into two cases
  250. // and call a function in each case
  251. //
  252. _CreatePropSheet(pici->hwnd, _ppidl[i], DLG_CACHEITEMPROP, _sPropDlgProc,
  253. CEI_SOURCEURLNAME((LPCEIPIDL)_ppidl[i]));
  254. goto Done;
  255. default:
  256. hres = E_FAIL;
  257. break;
  258. }
  259. ASSERT(SUCCEEDED(hres));
  260. if (FAILED(hres))
  261. TraceMsg(DM_HSFOLDER, "Cachevu failed the command at: %s", CPidlToSourceUrl((LPCEIPIDL)_ppidl[i]));
  262. }
  263. }
  264. Done:
  265. if (fMustFlushNotify)
  266. {
  267. if (fBulkDelete)
  268. {
  269. _GenerateEvent(SHCNE_UPDATEDIR, _pCFolder->_pidl, NULL, NULL);
  270. }
  271. SHChangeNotifyHandleEvents();
  272. }
  273. return hres;
  274. }
  275. //////////////////////////////////
  276. //
  277. // IDataObject Methods...
  278. //
  279. HRESULT CCacheItem::GetData(LPFORMATETC pFEIn, LPSTGMEDIUM pSTM)
  280. {
  281. HRESULT hres;
  282. #ifdef DEBUG
  283. TCHAR szName[64];
  284. if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName)))
  285. wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
  286. TraceMsg(DM_HSFOLDER, "hci - do - GetData(%s)", szName);
  287. #endif
  288. pSTM->hGlobal = NULL;
  289. pSTM->pUnkForRelease = NULL;
  290. if (pFEIn->cfFormat == CF_HDROP && (pFEIn->tymed & TYMED_HGLOBAL))
  291. hres = _CreateHDROP(pSTM);
  292. else if ((pFEIn->cfFormat == g_cfPreferredEffect) && (pFEIn->tymed & TYMED_HGLOBAL))
  293. hres = _CreatePrefDropEffect(pSTM);
  294. else
  295. hres = DATA_E_FORMATETC;
  296. return hres;
  297. }
  298. HRESULT CCacheItem::QueryGetData(LPFORMATETC pFEIn)
  299. {
  300. #ifdef DEBUG
  301. TCHAR szName[64];
  302. if (!GetClipboardFormatName(pFEIn->cfFormat, szName, sizeof(szName)))
  303. wnsprintf(szName, ARRAYSIZE(szName), TEXT("#%d"), pFEIn->cfFormat);
  304. TraceMsg(DM_HSFOLDER, "hci - do - QueryGetData(%s)", szName);
  305. #endif
  306. if (pFEIn->cfFormat == CF_HDROP ||
  307. pFEIn->cfFormat == g_cfPreferredEffect)
  308. {
  309. TraceMsg(DM_HSFOLDER, " format supported.");
  310. return NOERROR;
  311. }
  312. return S_FALSE;
  313. }
  314. HRESULT CCacheItem::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC *ppEnum)
  315. {
  316. FORMATETC Cachefmte[] = {
  317. {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  318. {g_cfPreferredEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  319. };
  320. return SHCreateStdEnumFmtEtc(ARRAYSIZE(Cachefmte), Cachefmte, ppEnum);
  321. }
  322. //////////////////////////////////
  323. //
  324. // IExtractIconA Methods...
  325. //
  326. HRESULT CCacheItem::GetIconLocation(UINT uFlags, LPSTR pszIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  327. {
  328. if (ucchMax < 2)
  329. return E_FAIL;
  330. *puFlags = GIL_NOTFILENAME;
  331. pszIconFile[0] = '*';
  332. pszIconFile[1] = '\0';
  333. // "*" as the file name means iIndex is already a system icon index.
  334. return _pCFolder->GetIconOf(_ppidl[0], uFlags, pniIcon);
  335. }
  336. //////////////////////////////////////////////////////////////////////////////
  337. //
  338. // Helper Routines
  339. //
  340. //////////////////////////////////////////////////////////////////////////////
  341. UNALIGNED const TCHAR* CCacheItem::_GetURLTitle(LPCITEMIDLIST pidl)
  342. {
  343. return ::_GetURLTitle( (LPCEIPIDL) pidl);
  344. }
  345. LPCTSTR CCacheItem::_GetUrl(int nIndex)
  346. {
  347. LPCTSTR pszUrl = NULL;
  348. pszUrl = CPidlToSourceUrl((LPCEIPIDL)_ppidl[nIndex]);
  349. return pszUrl;
  350. }
  351. LPCTSTR CCacheItem::_PidlToSourceUrl(LPCITEMIDLIST pidl)
  352. {
  353. return CPidlToSourceUrl((LPCEIPIDL) pidl);
  354. }
  355. // Return value:
  356. // TRUE - URL is Safe.
  357. // FALSE - URL is questionable and needs to be re-zone checked w/o PUAF_NOUI.
  358. BOOL CCacheItem::_ZoneCheck(int nIndex, DWORD dwUrlAction)
  359. {
  360. LPCTSTR pszUrl = _GetUrl(nIndex);
  361. if (S_OK != ZoneCheckUrl(pszUrl, dwUrlAction, PUAF_NOUI, NULL))
  362. return FALSE;
  363. return TRUE;
  364. }
  365. INT_PTR CALLBACK CCacheItem::_sPropDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  366. {
  367. LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE) GetWindowLongPtr(hDlg, DWLP_USER);
  368. LPCEIPIDL pcei = lpPropSheet ? (LPCEIPIDL)lpPropSheet->lParam : NULL;
  369. switch(message) {
  370. case WM_INITDIALOG: {
  371. SHFILEINFO sfi;
  372. TCHAR szBuf[80];
  373. SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  374. pcei = (LPCEIPIDL)((LPPROPSHEETPAGE)lParam)->lParam;
  375. // get the icon and file type strings
  376. SHGetFileInfo(CEI_LOCALFILENAME(pcei), 0, &sfi, SIZEOF(sfi), SHGFI_ICON | SHGFI_TYPENAME);
  377. SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_SETICON, (WPARAM)sfi.hIcon, 0);
  378. // set the info strings
  379. SetDlgItemText(hDlg, IDD_HSFURL, CPidlToSourceUrl((LPCEIPIDL)pcei));
  380. SetDlgItemText(hDlg, IDD_FILETYPE, sfi.szTypeName);
  381. SetDlgItemText(hDlg, IDD_FILESIZE, StrFormatByteSize(pcei->cei.dwSizeLow, szBuf, ARRAYSIZE(szBuf)));
  382. SetDlgItemText(hDlg, IDD_CACHE_NAME, PathFindFileName(CEI_LOCALFILENAME(pcei)));
  383. FileTimeToDateTimeStringInternal(&pcei->cei.ExpireTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  384. SetDlgItemText(hDlg, IDD_EXPIRES, szBuf);
  385. FileTimeToDateTimeStringInternal(&pcei->cei.LastModifiedTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  386. SetDlgItemText(hDlg, IDD_LAST_MODIFIED, szBuf);
  387. FileTimeToDateTimeStringInternal(&pcei->cei.LastAccessTime, szBuf, ARRAYSIZE(szBuf), FALSE);
  388. SetDlgItemText(hDlg, IDD_LAST_ACCESSED, szBuf);
  389. break;
  390. }
  391. case WM_DESTROY:
  392. {
  393. HICON hIcon = (HICON)SendDlgItemMessage(hDlg, IDD_ITEMICON, STM_GETICON, 0, 0);
  394. if (hIcon)
  395. DestroyIcon(hIcon);
  396. }
  397. break;
  398. case WM_COMMAND:
  399. case WM_HELP:
  400. case WM_CONTEXTMENU:
  401. // user can't change anything, so we don't care about any messages
  402. break;
  403. default:
  404. return FALSE;
  405. } // end of switch
  406. return TRUE;
  407. }
  408. // use CEI_LOCALFILENAME to get the file name for the HDROP, but map that
  409. // to the final file name (store in the file system) through the "FileNameMap"
  410. // data which uses _GetURLTitle() as the final name of the file.
  411. HRESULT CCacheItem::_CreateHDROP(STGMEDIUM *pmedium)
  412. {
  413. UINT i;
  414. UINT cbAlloc = sizeof(DROPFILES) + sizeof(CHAR); // header + null terminator
  415. for (i = 0; i < _cItems; i++)
  416. {
  417. char szAnsiUrl[MAX_URL_STRING];
  418. SHTCharToAnsi(CEI_LOCALFILENAME((LPCEIPIDL)_ppidl[i]), szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  419. cbAlloc += sizeof(CHAR) * (lstrlenA(szAnsiUrl) + 1);
  420. }
  421. pmedium->tymed = TYMED_HGLOBAL;
  422. pmedium->pUnkForRelease = NULL;
  423. pmedium->hGlobal = GlobalAlloc(GPTR, cbAlloc);
  424. if (pmedium->hGlobal)
  425. {
  426. LPDROPFILES pdf = (LPDROPFILES)pmedium->hGlobal;
  427. LPSTR pszFiles = (LPSTR)(pdf + 1);
  428. int cchFiles = (cbAlloc - sizeof(DROPFILES) - sizeof(CHAR));
  429. pdf->pFiles = sizeof(DROPFILES);
  430. pdf->fWide = FALSE;
  431. for (i = 0; i < _cItems; i++)
  432. {
  433. LPTSTR pszPath = CEI_LOCALFILENAME((LPCEIPIDL)_ppidl[i]);
  434. int cchPath = lstrlen(pszPath);
  435. SHTCharToAnsi(pszPath, pszFiles, cchFiles);
  436. pszFiles += cchPath + 1;
  437. cchFiles -= cchPath + 1;
  438. ASSERT((UINT)((LPBYTE)pszFiles - (LPBYTE)pdf) < cbAlloc);
  439. }
  440. ASSERT((LPSTR)pdf + cbAlloc - 1 == pszFiles);
  441. ASSERT(*pszFiles == 0); // zero init alloc
  442. return NOERROR;
  443. }
  444. return E_OUTOFMEMORY;
  445. }