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.

466 lines
15 KiB

  1. /*
  2. * url.cpp - IUniformResourceLocator implementation for InternetShortcut class.
  3. */
  4. /* Headers
  5. **********/
  6. #include "priv.h"
  7. #pragma hdrstop
  8. #define INC_OLE2
  9. #include "intshcut.h"
  10. /* Module Constants
  11. *******************/
  12. const TCHAR c_szURLPrefixesKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes");
  13. const TCHAR c_szDefaultURLPrefixKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix");
  14. // DPA array that holds the IURLSearchHook Pointers
  15. static HDPA g_hdpaHooks = NULL;
  16. // CURRENT_USER
  17. static const TCHAR c_szURLSearchHook[] = TSZIEPATH TEXT("\\URLSearchHooks");
  18. /***************************** Private Functions *****************************/
  19. int DPA_DestroyURLSearchHooksCallback(LPVOID p, LPVOID d)
  20. {
  21. IURLSearchHook * psuh = (IURLSearchHook *)p;
  22. ASSERT(psuh);
  23. ATOMICRELEASET(psuh, IURLSearchHook);
  24. return 1;
  25. }
  26. extern "C" {
  27. void DestroyHdpaHooks()
  28. {
  29. if (g_hdpaHooks)
  30. {
  31. ENTERCRITICAL;
  32. //---------------------------- Critical Section -------------------------
  33. HDPA hdpa = g_hdpaHooks;
  34. g_hdpaHooks = NULL;
  35. //-----------------------------------------------------------------------
  36. LEAVECRITICAL;
  37. if (hdpa)
  38. {
  39. DPA_DestroyCallback(hdpa, DPA_DestroyURLSearchHooksCallback, 0);
  40. hdpa = NULL;
  41. }
  42. }
  43. }
  44. }
  45. HRESULT InvokeURLSearchHook(IURLSearchHook * pusHook, LPCTSTR pcszQuery, LPTSTR pszResult, ISearchContext * pSC)
  46. {
  47. HRESULT hr = E_FAIL;
  48. ASSERT(pusHook);
  49. WCHAR szSearchURL[MAX_URL_STRING];
  50. SHTCharToUnicode(pcszQuery, szSearchURL, ARRAYSIZE(szSearchURL));
  51. // if we can get an IURLSearchHook2, we'll pass in the
  52. // search context, otherwise we'll just do without
  53. IURLSearchHook2 * pUSH2 = NULL;
  54. hr = pusHook->QueryInterface(IID_IURLSearchHook2, (void **)&pUSH2);
  55. if (SUCCEEDED(hr))
  56. {
  57. RIP(pUSH2 != NULL);
  58. hr = pUSH2->TranslateWithSearchContext(szSearchURL, ARRAYSIZE(szSearchURL), pSC);
  59. pUSH2->Release();
  60. }
  61. else
  62. {
  63. hr = pusHook->Translate(szSearchURL, ARRAYSIZE(szSearchURL));
  64. }
  65. // In case the URLSearchHook worked, convert result to TCHAR
  66. // This includes two cases: S_OK and S_FALSE
  67. if (SUCCEEDED(hr))
  68. {
  69. //WARNING: (dli) Assuming pszResult size = MAX_URL_STRING
  70. SHUnicodeToTChar(szSearchURL, pszResult, MAX_URL_STRING);
  71. }
  72. return hr;
  73. }
  74. /*
  75. * Returns:
  76. * S_OK Search handled completely, pszResult has the full URL to browse to.
  77. * 0x00000000 Stop running any further IURLSearchHooks and pass this URL back to
  78. * the browser for browsing.
  79. *
  80. * S_FALSE Query has been preprocessed, pszResult has the result of the preprocess,
  81. * 0x00000001 further search still needed. Go on executing the rest of the IURLSearchHooks
  82. * The preprocessing steps can be: 1. replaced certain characters
  83. * 2. added more hints
  84. *
  85. * E_ABORT Search handled completely, stop running any further IURLSearchHooks,
  86. * 0x80004004 but NO BROWSING NEEDED as a result, pszResult is a copy of pcszQuery.
  87. * FEATURE: This is not fully implemented, yet, making IURLQualify return this
  88. * involves too much change.
  89. *
  90. * E_FAIL This Hook was unsuccessful. Search not handled at all, pcszQueryURL has the
  91. * 0x80004005 query string. Please go on running other IURLSearchHooks.
  92. * return
  93. */
  94. HRESULT TryURLSearchHooks(LPCTSTR pcszQuery, LPTSTR pszResult, ISearchContext * pSC)
  95. {
  96. HRESULT hr = E_FAIL;
  97. TCHAR szNewQuery[MAX_URL_STRING];
  98. StrCpyN(szNewQuery, pcszQuery, ARRAYSIZE(szNewQuery));
  99. int ihdpa;
  100. for (ihdpa = 0; ihdpa < (g_hdpaHooks ? DPA_GetPtrCount(g_hdpaHooks) : 0); ihdpa++)
  101. {
  102. IURLSearchHook * pusHook;
  103. pusHook = (IURLSearchHook *) DPA_GetPtr(g_hdpaHooks, ihdpa);
  104. if (!pusHook)
  105. return E_FAIL;
  106. hr = InvokeURLSearchHook(pusHook, szNewQuery, pszResult, pSC);
  107. if ((hr == S_OK) || (hr == E_ABORT))
  108. break;
  109. else if (hr == S_FALSE)
  110. StrCpyN(szNewQuery, pszResult, ARRAYSIZE(szNewQuery));
  111. }
  112. return hr;
  113. }
  114. void InitURLSearchHooks()
  115. {
  116. HDPA hdpa = DPA_Create(4);
  117. // We need to look in LOCAL_MACHINE if this registry entry doesn't exist in CURRENT_USER.
  118. // The installer needs to install the values into LOCAL_MACHINE so they are accessable
  119. // to all users. Then anyone wanting to modify the value, will need to determine if they
  120. // want to add it to a specific user's CURRENT_USER or modify the LOCAL_MACHINE value to
  121. // apply the change to all users. (bryanst - #6722)
  122. HUSKEY hkeyHooks;
  123. if ((hdpa) && (SHRegOpenUSKey(c_szURLSearchHook, KEY_READ, NULL, &hkeyHooks, FALSE) == ERROR_SUCCESS))
  124. {
  125. TCHAR szCLSID[GUIDSTR_MAX];
  126. DWORD dwccCLSIDLen;
  127. LONG lEnumReturn;
  128. DWORD dwiValue = 0;
  129. do {
  130. dwccCLSIDLen = ARRAYSIZE(szCLSID);
  131. lEnumReturn = SHRegEnumUSValue(hkeyHooks, dwiValue, szCLSID, &dwccCLSIDLen,
  132. NULL, NULL, NULL, SHREGENUM_DEFAULT);
  133. if (lEnumReturn == ERROR_SUCCESS)
  134. {
  135. CLSID clsidHook;
  136. if (SUCCEEDED(SHCLSIDFromString(szCLSID, &clsidHook)))
  137. {
  138. IURLSearchHook * pusHook;
  139. HRESULT hr = CoCreateInstance(clsidHook, NULL, CLSCTX_INPROC_SERVER,
  140. IID_PPV_ARG(IURLSearchHook, &pusHook));
  141. if (SUCCEEDED(hr))
  142. DPA_AppendPtr(hdpa, pusHook);
  143. }
  144. }
  145. dwiValue++;
  146. } while (lEnumReturn == ERROR_SUCCESS);
  147. SHRegCloseUSKey(hkeyHooks);
  148. }
  149. ENTERCRITICAL;
  150. //---------------------------- Critical Section --------------------------
  151. if (!g_hdpaHooks)
  152. {
  153. g_hdpaHooks = hdpa;
  154. hdpa = NULL;
  155. }
  156. //------------------------------------------------------------------------
  157. LEAVECRITICAL;
  158. if (hdpa)
  159. {
  160. DPA_DestroyCallback(hdpa, DPA_DestroyURLSearchHooksCallback, 0);
  161. hdpa = NULL;
  162. }
  163. }
  164. HRESULT ApplyURLSearch(LPCTSTR pcszQuery, LPTSTR pszTranslatedUrl, ISearchContext * pSC)
  165. {
  166. if (!g_hdpaHooks)
  167. InitURLSearchHooks();
  168. return TryURLSearchHooks(pcszQuery, pszTranslatedUrl, pSC);
  169. }
  170. /*----------------------------------------------------------
  171. Purpose: This function qualifies a string as a URL. Strings
  172. such as "www.foo.com" would have the scheme guessed
  173. if the correct flags are given. Local paths are
  174. converted to "file:" URLs.
  175. pszTranslatedURL may point to the same buffer as
  176. pcszURL.
  177. If the given string is already a URL (not necessarily
  178. canonicalized, though), this function will not touch it,
  179. unless UQF_CANONICALIZE is set, in which case the string
  180. will be canonicalized.
  181. Returns: S_OK or S_FALSE means we filled in pszTranslatedURL.
  182. S_OK means we altered the URL to qualify it too.
  183. various failure codes too
  184. Cond: --
  185. */
  186. SHDOCAPI
  187. IURLQualifyWithContext(
  188. IN LPCWSTR pcszURL,
  189. IN DWORD dwFlags, // UQF_*
  190. IN DWORD cchTranslatedURL,
  191. OUT LPWSTR pszTranslatedURL,
  192. LPBOOL pbWasSearchURL,
  193. LPBOOL pbWasCorrected,
  194. ISearchContext * pSC)
  195. {
  196. HRESULT hres = S_FALSE;
  197. DWORD cchSize;
  198. SHSTR strOut;
  199. BOOL bWasCorrected = FALSE;
  200. ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
  201. ASSERT(IS_VALID_WRITE_BUFFER(pszTranslatedURL, TCHAR, MAX_URL_STRING));
  202. if (pbWasSearchURL)
  203. *pbWasSearchURL = FALSE;
  204. // Special cases: URLs of the form <drive>:<filename>
  205. // URLs of the form \<filename>
  206. // we'll assume that if the second character is a : or |, this is an url of
  207. // that form, and we will guess "file://" for the prefix.
  208. // we'll assume any url that begins with a single \ is a file: url
  209. // NOTE: We do this here because these are cases where the protocol is
  210. // left off, and is likely to be incorrectly guessed, such as a
  211. // relative path \data\ftp\docs, would wrongly be turned
  212. // into "ftp://\data\ftp\docs".
  213. // Note: PathIsURL returns TRUE for non-canonicalized URLs too
  214. if (PathIsURL(pcszURL))
  215. {
  216. LPCWSTR pcszTemp = pcszURL;
  217. cchSize = MAX_URL_STRING;
  218. if (IsFlagSet(dwFlags, UQF_AUTOCORRECT))
  219. {
  220. hres = UrlFixup(pcszURL, pszTranslatedURL, cchSize);
  221. if (hres == S_OK)
  222. {
  223. bWasCorrected = TRUE;
  224. pcszTemp = pszTranslatedURL;
  225. }
  226. }
  227. if (dwFlags & UQF_CANONICALIZE)
  228. hres = UrlCanonicalize(pcszTemp, pszTranslatedURL, &cchSize, 0);
  229. else if (pszTranslatedURL != pcszTemp)
  230. StrCpyN(pszTranslatedURL, pcszTemp, cchTranslatedURL);
  231. hres = S_OK;
  232. }
  233. else
  234. {
  235. // Look for file paths
  236. if (IsFlagClear(dwFlags, UQF_IGNORE_FILEPATHS) && ( pcszURL[1] == TEXT(':') || pcszURL[1] == TEXT('|') || pcszURL[0] == TEXT('\\')))
  237. {
  238. hres = strOut.SetSize(MAX_PATH);
  239. if(SUCCEEDED(hres))
  240. {
  241. // SHSTRs have a size granularity, so the size
  242. // will be equal to or greater than what was set.
  243. // this means we need to get it our self.
  244. DWORD cchOut = strOut.GetSize();
  245. TCHAR szCurrentDir[MAX_PATH];
  246. //
  247. // APPCOMPAT - IE30 compatibility - zekel 8-Jan-97
  248. // we need to GetCurrentDirectory() in order to
  249. // put a default drive letter on the path
  250. // if necessary.
  251. //
  252. if(GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir))
  253. PathCombine(strOut.GetInplaceStr(), szCurrentDir, pcszURL);
  254. else
  255. hres = strOut.SetStr(pcszURL);
  256. if(SUCCEEDED(hres))
  257. {
  258. hres = UrlCreateFromPath(strOut, strOut.GetInplaceStr(), &cchOut, 0);
  259. if (E_POINTER == hres && SUCCEEDED(hres = strOut.SetSize(cchOut)))
  260. {
  261. cchOut = strOut.GetSize();
  262. hres = UrlCreateFromPath(strOut, strOut.GetInplaceStr(), &cchOut, 0);
  263. }
  264. }
  265. }
  266. }
  267. else if (SUCCEEDED(hres = strOut.SetSize(MAX_URL_STRING)))
  268. {
  269. // all the Apply*() below rely on MAX_URL_STRING
  270. // No; begin processing general-case URLs. Try to guess the
  271. // protocol or resort to the default protocol.
  272. DWORD cchOut = strOut.GetSize();
  273. if (IsFlagSet(dwFlags, UQF_GUESS_PROTOCOL))
  274. hres = UrlApplyScheme(pcszURL, strOut.GetInplaceStr(), &cchOut, URL_APPLY_GUESSSCHEME);
  275. //
  276. // Try to auto-correct the protocol
  277. //
  278. if (hres == S_FALSE &&
  279. IsFlagSet(dwFlags, UQF_AUTOCORRECT))
  280. {
  281. hres = UrlFixup(pcszURL, strOut.GetInplaceStr(), strOut.GetSize());
  282. bWasCorrected = (hres == S_OK);
  283. }
  284. if (hres == S_FALSE &&
  285. IsFlagSet(dwFlags, UQF_USE_DEFAULT_PROTOCOL))
  286. {
  287. // run the search with or without the search context
  288. hres = ApplyURLSearch(pcszURL, strOut.GetInplaceStr(), pSC);
  289. if (SUCCEEDED(hres) && pbWasSearchURL) {
  290. *pbWasSearchURL = TRUE;
  291. }
  292. // If that fails, then tack on the default protocol
  293. if (FAILED(hres) || hres == S_FALSE)
  294. {
  295. cchOut = strOut.GetSize();
  296. hres = UrlApplyScheme(pcszURL, strOut.GetInplaceStr(), &cchOut, URL_APPLY_DEFAULT);
  297. }
  298. }
  299. // Did the above fail?
  300. if (S_FALSE == hres)
  301. {
  302. // Yes; return the real reason why the URL is bad
  303. hres = URL_E_INVALID_SYNTAX;
  304. }
  305. else if (dwFlags & UQF_CANONICALIZE)
  306. {
  307. // No; canonicalize
  308. cchSize = strOut.GetSize();
  309. hres = UrlCanonicalize(strOut, strOut.GetInplaceStr(), &cchSize, 0);
  310. }
  311. }
  312. if (SUCCEEDED(hres))
  313. {
  314. StrCpyN(pszTranslatedURL, strOut, cchTranslatedURL);
  315. }
  316. }
  317. if (pbWasCorrected)
  318. *pbWasCorrected = bWasCorrected;
  319. return hres;
  320. }
  321. SHDOCAPI
  322. IURLQualify(
  323. IN LPCWSTR pcszURL,
  324. IN DWORD dwFlags, // UQF_*
  325. OUT LPWSTR pszTranslatedURL,
  326. LPBOOL pbWasSearchURL,
  327. LPBOOL pbWasCorrected)
  328. {
  329. // this is exported
  330. return IURLQualifyWithContext(pcszURL, dwFlags, MAX_URL_STRING, pszTranslatedURL, pbWasSearchURL, pbWasCorrected, NULL);
  331. }
  332. /***************************** Exported Functions ****************************/
  333. STDAPI
  334. URLQualifyA(
  335. LPCSTR pszURL,
  336. DWORD dwFlags, // UQF_*
  337. LPSTR *ppszOut)
  338. {
  339. HRESULT hres;
  340. ASSERT(IS_VALID_STRING_PTRA(pszURL, -1));
  341. ASSERT(IS_VALID_WRITE_PTR(ppszOut, LPSTR));
  342. *ppszOut = NULL;
  343. WCHAR szTempTranslatedURL[MAX_URL_STRING];
  344. WCHAR szURL[MAX_URL_STRING];
  345. SHAnsiToUnicode(pszURL, szURL, ARRAYSIZE(szURL));
  346. hres = IURLQualifyWithContext(szURL, dwFlags, ARRAYSIZE(szTempTranslatedURL), szTempTranslatedURL, NULL, NULL, NULL);
  347. if (SUCCEEDED(hres))
  348. {
  349. CHAR szOut[MAX_URL_STRING];
  350. SHUnicodeToAnsi(szTempTranslatedURL, szOut, ARRAYSIZE(szOut));
  351. *ppszOut = StrDupA(szOut);
  352. if (!*ppszOut)
  353. hres = E_OUTOFMEMORY;
  354. }
  355. return hres;
  356. }
  357. STDAPI
  358. URLQualifyW(
  359. LPCWSTR pszURL,
  360. DWORD dwFlags, // UQF_*
  361. LPWSTR *ppszOut)
  362. {
  363. HRESULT hres;
  364. ASSERT(IS_VALID_STRING_PTRW(pszURL, -1));
  365. ASSERT(IS_VALID_WRITE_PTR(ppszOut, LPWSTR));
  366. WCHAR szTempTranslatedURL[MAX_URL_STRING];
  367. hres = IURLQualify(pszURL, dwFlags, szTempTranslatedURL, NULL, NULL);
  368. if (SUCCEEDED(hres))
  369. {
  370. *ppszOut = StrDup(szTempTranslatedURL);
  371. if (!*ppszOut)
  372. hres = E_OUTOFMEMORY;
  373. }
  374. return hres;
  375. }