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

537 lines
15 KiB

  1. #include "local.h"
  2. #include "resource.h"
  3. #include <mluisupp.h>
  4. #ifdef _HSFOLDER
  5. #define LODWORD(_qw) (DWORD)(_qw)
  6. // Invoke Command verb strings
  7. const CHAR c_szOpen[] = "open";
  8. const CHAR c_szDelcache[] = "delete";
  9. const CHAR c_szProperties[] = "properties";
  10. const CHAR c_szCopy[] = "copy";
  11. void FileTimeToDateTimeStringInternal(FILETIME UNALIGNED *ulpft, LPTSTR pszText, int cchText, BOOL fUsePerceivedTime)
  12. {
  13. FILETIME ft;
  14. FILETIME aft;
  15. LPFILETIME lpft;
  16. aft = *ulpft;
  17. lpft = &aft;
  18. if (!fUsePerceivedTime && (FILETIMEtoInt64(*lpft) != FT_NTFS_UNKNOWNGMT))
  19. FileTimeToLocalFileTime(lpft, &ft);
  20. else
  21. ft = *lpft;
  22. if (FILETIMEtoInt64(ft) == FT_NTFS_UNKNOWNGMT ||
  23. FILETIMEtoInt64(ft) == FT_FAT_UNKNOWNLOCAL)
  24. {
  25. static TCHAR szNone[40] = {0};
  26. if (szNone[0] == 0)
  27. MLLoadString(IDS_HSFNONE, szNone, ARRAYSIZE(szNone));
  28. StrCpyN(pszText, szNone, cchText);
  29. }
  30. else
  31. {
  32. TCHAR szTempStr[MAX_PATH];
  33. LPTSTR pszTempStr = szTempStr;
  34. SYSTEMTIME st;
  35. FileTimeToSystemTime(&ft, &st);
  36. if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, szTempStr, ARRAYSIZE(szTempStr)) > 0)
  37. {
  38. int iLen = lstrlen(szTempStr);
  39. ASSERT(TEXT('\0') == szTempStr[iLen]); // Make sure multi-byte isn't biting us.
  40. pszTempStr = (LPTSTR)(pszTempStr + iLen);
  41. *pszTempStr++ = ' ';
  42. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszTempStr, ARRAYSIZE(szTempStr)-(iLen+1));
  43. StrCpyN(pszText, szTempStr, cchText);
  44. }
  45. }
  46. }
  47. HMENU LoadPopupMenu(UINT id, UINT uSubOffset)
  48. {
  49. HMENU hmParent, hmPopup;
  50. HINSTANCE hinst = MLLoadShellLangResources();
  51. hmParent = LoadMenu_PrivateNoMungeW(hinst, MAKEINTRESOURCEW(id));
  52. if (!hmParent)
  53. {
  54. long error = GetLastError();
  55. return NULL;
  56. }
  57. hmPopup = GetSubMenu(hmParent, uSubOffset);
  58. RemoveMenu(hmParent, uSubOffset, MF_BYPOSITION);
  59. DestroyMenu(hmParent);
  60. MLFreeLibrary(hinst);
  61. return hmPopup;
  62. }
  63. UINT MergePopupMenu(HMENU *phMenu, UINT idResource, UINT uSubOffset, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast)
  64. {
  65. HMENU hmMerge;
  66. if (*phMenu == NULL)
  67. {
  68. *phMenu = CreatePopupMenu();
  69. if (*phMenu == NULL)
  70. return 0;
  71. indexMenu = 0; // at the bottom
  72. }
  73. hmMerge = LoadPopupMenu(idResource, uSubOffset);
  74. if (!hmMerge)
  75. return 0;
  76. idCmdLast = Shell_MergeMenus(*phMenu, hmMerge, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  77. DestroyMenu(hmMerge);
  78. return idCmdLast;
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////
  81. //
  82. // Helper Fuctions for item.cpp and folder.cpp
  83. //
  84. ///////////////////////////////////////////////////////////////////////////////
  85. // copy and flatten the CACHE_ENTRY_INFO data
  86. void _CopyCEI(UNALIGNED INTERNET_CACHE_ENTRY_INFO *pdst, LPINTERNET_CACHE_ENTRY_INFO psrc, DWORD dwBuffSize)
  87. {
  88. // This assumes how urlcache does allocation
  89. memcpy(pdst, psrc, dwBuffSize);
  90. // convert pointers to offsets
  91. pdst->lpszSourceUrlName = (LPTSTR) PtrDifference(psrc->lpszSourceUrlName, psrc);
  92. pdst->lpszLocalFileName = (LPTSTR) PtrDifference(psrc->lpszLocalFileName, psrc);
  93. pdst->lpszFileExtension = (LPTSTR) PtrDifference(psrc->lpszFileExtension, psrc);
  94. pdst->lpHeaderInfo = psrc->lpHeaderInfo ? (TCHAR*) PtrDifference(psrc->lpHeaderInfo, psrc) : NULL;
  95. }
  96. INT g_fProfilesEnabled = -1;
  97. BOOL IsProfilesEnabled();
  98. BOOL _FilterUserName(LPINTERNET_CACHE_ENTRY_INFO pcei, LPCTSTR pszCachePrefix, LPTSTR pszUserName)
  99. {
  100. TCHAR szTemp[MAX_URL_STRING];
  101. LPCTSTR pszTemp = szTemp;
  102. // chrisfra 3/27/97, more constant crapola. this all needs to be fixed.
  103. TCHAR szPrefix[80];
  104. BOOL fRet = 0;
  105. if (g_fProfilesEnabled==-1)
  106. {
  107. g_fProfilesEnabled = IsProfilesEnabled();
  108. }
  109. if (g_fProfilesEnabled)
  110. {
  111. return TRUE;
  112. }
  113. StrCpyN(szTemp, pcei->lpszSourceUrlName, ARRAYSIZE(szTemp));
  114. StrCpyN(szPrefix, pszCachePrefix, ARRAYSIZE(szPrefix));
  115. StrCatBuff(szPrefix, pszUserName, ARRAYSIZE(szPrefix));
  116. // find the '@' character if it exists
  117. pszTemp = StrChr(pszTemp, TEXT('@'));
  118. if ( (pszTemp) && (*pszTemp == TEXT('@')) )
  119. {
  120. fRet = (StrCmpNI(szTemp, szPrefix, lstrlen(szPrefix)) == 0);
  121. }
  122. else
  123. {
  124. fRet = (*pszUserName == TEXT('\0'));
  125. }
  126. return fRet;
  127. }
  128. BOOL _FilterPrefix(LPINTERNET_CACHE_ENTRY_INFO pcei, LPCTSTR pszCachePrefix)
  129. {
  130. #define MAX_PREFIX (80)
  131. TCHAR szTemp[MAX_URL_STRING];
  132. LPCTSTR pszStripped;
  133. BOOL fRet = 0;
  134. StrCpyN(szTemp, pcei->lpszSourceUrlName, ARRAYSIZE(szTemp));
  135. pszStripped = _StripContainerUrlUrl(szTemp);
  136. if (pszStripped && pszStripped-szTemp < MAX_PREFIX)
  137. {
  138. fRet = (StrCmpNI(szTemp, pszCachePrefix, ((int) (pszStripped-szTemp))/sizeof(TCHAR)) == 0);
  139. }
  140. return fRet;
  141. }
  142. LPCTSTR _StripContainerUrlUrl(LPCTSTR pszHistoryUrl)
  143. {
  144. // NOTE: for our purposes, we don't want a history URL if we can't detect our
  145. // prefix, so we return NULL.
  146. LPCTSTR pszTemp = pszHistoryUrl;
  147. LPCTSTR pszCPrefix;
  148. LPCTSTR pszReturn = NULL;
  149. // Check for "Visited: "
  150. pszCPrefix = c_szHistPrefix;
  151. while (*pszTemp == *pszCPrefix && *pszTemp != TEXT('\0'))
  152. {
  153. pszTemp = CharNext(pszTemp);
  154. pszCPrefix = CharNext(pszCPrefix);
  155. }
  156. if (*pszCPrefix == TEXT('\0'))
  157. {
  158. // Found "Visited: "
  159. pszReturn = pszTemp;
  160. }
  161. else if (pszTemp == (LPTSTR) pszHistoryUrl)
  162. {
  163. // Check for ":YYYYMMDDYYYYMMDD: "
  164. pszCPrefix = TEXT(":nnnnnnnnnnnnnnnn: ");
  165. while (*pszTemp != TEXT('\0'))
  166. {
  167. if (*pszCPrefix == TEXT('n'))
  168. {
  169. if (*pszTemp < TEXT('0') || *pszTemp > TEXT('9')) break;
  170. }
  171. else if (*pszCPrefix != *pszTemp) break;
  172. pszTemp = CharNext(pszTemp);
  173. pszCPrefix = CharNext(pszCPrefix);
  174. }
  175. }
  176. return (*pszCPrefix == TEXT('\0')) ? pszTemp : pszReturn;
  177. }
  178. LPCTSTR _StripHistoryUrlToUrl(LPCTSTR pszHistoryUrl)
  179. {
  180. LPCTSTR pszTemp = pszHistoryUrl;
  181. if (!pszHistoryUrl)
  182. return NULL;
  183. pszTemp = StrChr(pszHistoryUrl, TEXT('@'));
  184. if (pszTemp && *pszTemp)
  185. return CharNext(pszTemp);
  186. pszTemp = StrChr(pszHistoryUrl, TEXT(' '));
  187. if (pszTemp && *pszTemp)
  188. return CharNext(pszTemp);
  189. else
  190. return NULL; // error, the URL passed in wasn't a history url
  191. }
  192. // assumes this is a real URL and not a "history" url
  193. void _GetURLHostFromUrl_NoStrip(LPCTSTR lpszUrl, LPTSTR szHost, DWORD dwHostSize, LPCTSTR pszLocalHost)
  194. {
  195. DWORD cch = dwHostSize;
  196. if (S_OK != UrlGetPart(lpszUrl, szHost, &cch, URL_PART_HOSTNAME, 0)
  197. || !*szHost)
  198. {
  199. // default to the local host name.
  200. StrCpyN(szHost, pszLocalHost, dwHostSize);
  201. }
  202. }
  203. void _GetURLHost(LPINTERNET_CACHE_ENTRY_INFO pcei, LPTSTR szHost, DWORD dwHostSize, LPCTSTR pszLocalHost)
  204. {
  205. TCHAR szSourceUrl[MAX_URL_STRING];
  206. ASSERT(ARRAYSIZE(szSourceUrl) > lstrlen(pcei->lpszSourceUrlName))
  207. StrCpyN(szSourceUrl, pcei->lpszSourceUrlName, ARRAYSIZE(szSourceUrl));
  208. _GetURLHostFromUrl(szSourceUrl, szHost, dwHostSize, pszLocalHost);
  209. }
  210. LPHEIPIDL _IsValid_HEIPIDL(LPCITEMIDLIST pidl)
  211. {
  212. LPHEIPIDL phei = (LPHEIPIDL)pidl;
  213. if (phei && ((phei->cb > sizeof(HEIPIDL)) && (phei->usSign == (USHORT)HEIPIDL_SIGN)) &&
  214. (phei->usUrl == 0 || phei->usUrl < phei->cb) &&
  215. (phei->usTitle == 0 || (phei->usTitle + sizeof(WCHAR)) <= phei->cb))
  216. {
  217. return phei;
  218. }
  219. return NULL;
  220. }
  221. LPBASEPIDL _IsValid_IDPIDL(LPCITEMIDLIST pidl)
  222. {
  223. LPBASEPIDL pcei = (LPBASEPIDL)pidl;
  224. if (pcei && VALID_IDSIGN(pcei->usSign) && pcei->cb > 0)
  225. {
  226. return pcei;
  227. }
  228. return NULL;
  229. }
  230. LPCTSTR _FindURLFileName(LPCTSTR pszURL)
  231. {
  232. LPCTSTR psz, pszRet = pszURL; // need to set to pszURL in case no '/'
  233. LPCTSTR pszNextToLast = NULL;
  234. for (psz = pszURL; *psz; psz = CharNext(psz))
  235. {
  236. if ((*psz == TEXT('\\') || *psz == TEXT('/')))
  237. {
  238. pszNextToLast = pszRet;
  239. pszRet = CharNext(psz);
  240. }
  241. }
  242. return *pszRet ? pszRet : pszNextToLast;
  243. }
  244. int _LaunchApp(HWND hwnd, LPCTSTR pszPath)
  245. {
  246. SHELLEXECUTEINFO ei = { 0 };
  247. ei.cbSize = sizeof(SHELLEXECUTEINFO);
  248. ei.hwnd = hwnd;
  249. ei.lpFile = pszPath;
  250. ei.nShow = SW_SHOWNORMAL;
  251. return ShellExecuteEx(&ei);
  252. }
  253. int _LaunchAppForPidl(HWND hwnd, LPITEMIDLIST pidl)
  254. {
  255. SHELLEXECUTEINFO ei = { 0 };
  256. ei.cbSize = sizeof(SHELLEXECUTEINFO);
  257. ei.fMask = SEE_MASK_IDLIST;
  258. ei.hwnd = hwnd;
  259. ei.lpIDList = pidl;
  260. ei.nShow = SW_SHOWNORMAL;
  261. return ShellExecuteEx(&ei);
  262. }
  263. void _GenerateEvent(LONG lEventId, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlIn, LPCITEMIDLIST pidlNewIn)
  264. {
  265. LPITEMIDLIST pidl;
  266. if (pidlIn)
  267. {
  268. pidl = ILCombine(pidlFolder, pidlIn);
  269. }
  270. else
  271. {
  272. pidl = ILClone(pidlFolder);
  273. }
  274. if (pidl)
  275. {
  276. if (pidlNewIn)
  277. {
  278. LPITEMIDLIST pidlNew = ILCombine(pidlFolder, pidlNewIn);
  279. if (pidlNew)
  280. {
  281. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew);
  282. ILFree(pidlNew);
  283. }
  284. }
  285. else
  286. {
  287. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL);
  288. }
  289. ILFree(pidl);
  290. }
  291. }
  292. const struct {
  293. LPCSTR pszVerb;
  294. UINT idCmd;
  295. } rgcmds[] = {
  296. { c_szOpen, RSVIDM_OPEN },
  297. { c_szCopy, RSVIDM_COPY },
  298. { c_szDelcache, RSVIDM_DELCACHE },
  299. { c_szProperties, RSVIDM_PROPERTIES }
  300. };
  301. int _GetCmdID(LPCSTR pszCmd)
  302. {
  303. if (HIWORD(pszCmd))
  304. {
  305. int i;
  306. for (i = 0; i < ARRAYSIZE(rgcmds); i++)
  307. {
  308. if (StrCmpIA(rgcmds[i].pszVerb, pszCmd) == 0)
  309. {
  310. return rgcmds[i].idCmd;
  311. }
  312. }
  313. return -1; // unknown
  314. }
  315. return (int)LOWORD(pszCmd);
  316. }
  317. HRESULT _CreatePropSheet(HWND hwnd, LPCITEMIDLIST pidl, int iDlg, DLGPROC pfnDlgProc, LPCTSTR pszTitle)
  318. {
  319. PROPSHEETPAGE psp = { 0 };
  320. PROPSHEETHEADER psh = { 0 } ;
  321. // initialize propsheet page.
  322. psp.dwSize = sizeof(PROPSHEETPAGE);
  323. psp.dwFlags = 0;
  324. psp.hInstance = MLGetHinst();
  325. psp.DUMMYUNION_MEMBER(pszTemplate) = MAKEINTRESOURCE(iDlg);
  326. psp.DUMMYUNION2_MEMBER(pszIcon) = NULL;
  327. psp.pfnDlgProc = pfnDlgProc;
  328. psp.pszTitle = NULL;
  329. psp.lParam = (LPARAM)pidl; // send it the cache entry struct
  330. // initialize propsheet header.
  331. psh.dwSize = sizeof(PROPSHEETHEADER);
  332. psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_PROPTITLE;
  333. psh.hwndParent = hwnd;
  334. psh.pszCaption = pszTitle;
  335. psh.nPages = 1;
  336. psh.DUMMYUNION2_MEMBER(nStartPage) = 0;
  337. psh.DUMMYUNION3_MEMBER(ppsp) = (LPCPROPSHEETPAGE)&psp;
  338. // invoke the property sheet
  339. PropertySheet(&psh);
  340. return NOERROR;
  341. }
  342. INT_PTR CALLBACK HistoryConfirmDeleteDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  343. {
  344. switch(message) {
  345. case WM_INITDIALOG:
  346. SetDlgItemText(hDlg, IDD_TEXT4, (LPCTSTR)lParam);
  347. break;
  348. case WM_DESTROY:
  349. break;
  350. case WM_COMMAND:
  351. switch(LOWORD(wParam))
  352. {
  353. case IDYES:
  354. case IDNO:
  355. case IDCANCEL:
  356. EndDialog(hDlg, wParam);
  357. break;
  358. }
  359. break;
  360. default:
  361. return FALSE;
  362. }
  363. return TRUE;
  364. }
  365. // This function restores the Unicode characters from file system URLs
  366. //
  367. // If the URL isn't a file URL, it is copied directly to pszBuf. Otherwise, any
  368. // UTF8-escaped parts of the URL are converted into Unicode, and the result is
  369. // stored in pszBuf. This should be the same as the string we received in
  370. // History in the first place
  371. //
  372. // The return value is always pszBuf.
  373. // The input and output buffers may be the same.
  374. LPCTSTR ConditionallyDecodeUTF8(LPCTSTR pszUrl, LPTSTR pszBuf, DWORD cchBuf)
  375. {
  376. BOOL fDecoded = FALSE;
  377. if (PathIsFilePath(pszUrl))
  378. {
  379. TCHAR szDisplayUrl[MAX_URL_STRING];
  380. DWORD cchDisplayUrl = ARRAYSIZE(szDisplayUrl);
  381. DWORD cchBuf2 = cchBuf; // we may need the old cchBuf later
  382. // After PrepareUrlForDisplayUTF8, we have a fully unescaped URL. If we
  383. // ShellExec this, then Shell will unescape it again, so we need to re-escape
  384. // it to preserve any real %dd sequences that might be in the string.
  385. if (SUCCEEDED(PrepareURLForDisplayUTF8(pszUrl, szDisplayUrl, &cchDisplayUrl, TRUE)) &&
  386. SUCCEEDED(UrlCanonicalize(szDisplayUrl, pszBuf, &cchBuf2, URL_ESCAPE_UNSAFE | URL_ESCAPE_PERCENT)))
  387. {
  388. fDecoded = TRUE;
  389. }
  390. }
  391. if (!fDecoded && (pszUrl != pszBuf))
  392. {
  393. StrCpyN(pszBuf, pszUrl, cchBuf);
  394. }
  395. return pszBuf;
  396. }
  397. //
  398. // These routines make a string into a legal filename by replacing
  399. // all invalid characters with spaces.
  400. //
  401. // The list of invalid characters was obtained from the NT error
  402. // message you get when you try to rename a file to an invalid name.
  403. //
  404. #ifndef UNICODE
  405. #error The MakeLegalFilename code only works when it's part of a UNICODE build
  406. #endif
  407. //
  408. // This function takes a string and makes it into a
  409. // valid filename (by calling PathCleanupSpec).
  410. //
  411. // The PathCleanupSpec function wants to know what
  412. // directory the file will live in. But it's going
  413. // on the clipboard, so we don't know. We just
  414. // guess the desktop.
  415. //
  416. // It only uses this path to decide if the filesystem
  417. // supports long filenames or not, and to check for
  418. // MAX_PATH overflow.
  419. //
  420. void MakeLegalFilenameW(LPWSTR pszFilename)
  421. {
  422. WCHAR szDesktopPath[MAX_PATH];
  423. GetWindowsDirectoryW(szDesktopPath, ARRAYSIZE(szDesktopPath));
  424. PathCleanupSpec(szDesktopPath, pszFilename);
  425. }
  426. //
  427. // ANSI wrapper for above function
  428. //
  429. void MakeLegalFilenameA(LPSTR pszFilename, int cchFilename)
  430. {
  431. WCHAR szFilenameW[MAX_PATH];
  432. SHAnsiToUnicode(pszFilename, szFilenameW, ARRAYSIZE(szFilenameW));
  433. MakeLegalFilenameW(szFilenameW);
  434. SHUnicodeToAnsi(szFilenameW, pszFilename, cchFilename);
  435. }
  436. #endif // _HSFOLDER