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.

1480 lines
38 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: reload.cpp ( based on WebCheck's downld.cxx )
  7. //
  8. // Contents: Implmentation of Office9 Thicket Save API
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "priv.h"
  12. //#include "headers.hxx"
  13. #include "reload.h"
  14. #include <exdisp.h>
  15. #include <exdispid.h>
  16. #include <htiface.h>
  17. #include <mshtmdid.h>
  18. #include <mshtmcid.h>
  19. #include <mshtmhst.h>
  20. #include <optary.h> // needed for IHtmlLoadOptions
  21. #include <wininet.h>
  22. #include <winineti.h>
  23. #include <shlguid.h>
  24. #include <shlobj.h>
  25. #include "intshcut.h" // IUniformResourceLocator
  26. #undef DEFINE_STRING_CONSTANTS
  27. #pragma warning( disable : 4207 )
  28. #include "htmlstr.h"
  29. #pragma warning( default : 4207 )
  30. // Disable perf warning for typecasts to the native bool type
  31. // Useful for NT64 where pointers cannot be cast to "BOOL"
  32. #pragma warning( disable : 4800 )
  33. //MtDefine(CUrlDownload, Utilities, "CUrlDownload")
  34. #define TF_THISMODULE TF_DOWNLD
  35. LRESULT UrlDownloadWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  36. CLIPFORMAT g_cfHTML=CF_NULL;
  37. // User-Agent strings
  38. const WCHAR c_szUserAgent95[] = L"Mozilla/4.0 (compatible; MSIE 4.01; MSIECrawler; Windows 95)";
  39. const WCHAR c_szUserAgentNT[] = L"Mozilla/4.0 (compatible; MSIE 4.01; MSIECrawler; Windows NT)";
  40. // Refresh header for http-equiv (client-pull)
  41. const WCHAR c_wszRefresh[] = L"Refresh";
  42. const int MAX_CLIENT_PULL_NUM = 4; // max # redirections
  43. const int MAX_CLIENT_PULL_TIMEOUT = 6; // max timeout we'll follow
  44. // Function also present in shdocvw\basesb.cpp and in mshtml
  45. BOOL DLParseRefreshContent(LPWSTR pwzContent, UINT * puiDelay, LPWSTR pwzUrlBuf, UINT cchUrlBuf);
  46. const WCHAR c_wszHeadVerb[] = L"HEAD";
  47. const WCHAR c_szUserAgentPrefix[] = L"User-Agent: ";
  48. const WCHAR c_szAcceptLanguagePrefix[] = L"Accept-Language: ";
  49. #define WM_URLDL_CLEAN (WM_USER + 0x1010)
  50. #define WM_URLDL_ONDLCOMPLETE (WM_USER + 0x1012)
  51. #define WM_URLDL_CLIENTPULL (WM_USER+0x1013)
  52. #define PROP_CODEPAGE 3
  53. const PROPSPEC c_rgPropRead[] = {
  54. { PRSPEC_PROPID, PID_INTSITE_SUBSCRIPTION},
  55. { PRSPEC_PROPID, PID_INTSITE_FLAGS},
  56. { PRSPEC_PROPID, PID_INTSITE_TRACKING},
  57. { PRSPEC_PROPID, PID_INTSITE_CODEPAGE},
  58. };
  59. //---------------------------------------------------------------
  60. // CUrlDownload class
  61. CUrlDownload::CUrlDownload( CThicketProgress* ptp, HRESULT *phr, UINT cpDL )
  62. {
  63. // Maintain global count of objects
  64. //DllAddRef();
  65. m_ptp = ptp;
  66. m_phr = phr;
  67. m_cpDL = cpDL;
  68. m_dwProgMax = 0;
  69. m_cRef = 1;
  70. m_pDocument = NULL;
  71. m_dwConnectionCookie = 0;
  72. m_pwszURL = NULL;
  73. m_pScript = NULL;
  74. m_fAdviseOn = FALSE;
  75. m_pCP = NULL;
  76. m_pDocument = NULL;
  77. m_pPersistMk = NULL;
  78. m_pOleCmdTarget = NULL;
  79. m_pwszClientPullURL = NULL;
  80. m_fWaitingForReadyState = FALSE;
  81. m_fFormSubmitted = FALSE;
  82. m_fBrowserValid = FALSE;
  83. m_hwndMe = NULL;
  84. // find the HTML clipboard format
  85. if (!g_cfHTML)
  86. {
  87. g_cfHTML = RegisterClipboardFormat(CFSTR_MIME_HTML);
  88. }
  89. // find out if we need to set the "RESYNCHRONIZE" flag
  90. INTERNET_CACHE_CONFIG_INFOA CacheConfigInfo;
  91. DWORD dwBufSize = sizeof(CacheConfigInfo);
  92. if (GetUrlCacheConfigInfoA(&CacheConfigInfo, &dwBufSize, CACHE_CONFIG_SYNC_MODE_FC))
  93. {
  94. if ((WININET_SYNC_MODE_ONCE_PER_SESSION == CacheConfigInfo.dwSyncMode) ||
  95. (WININET_SYNC_MODE_NEVER == CacheConfigInfo.dwSyncMode) ||
  96. (WININET_SYNC_MODE_AUTOMATIC == CacheConfigInfo.dwSyncMode))
  97. {
  98. m_fSetResync = FALSE;
  99. }
  100. else
  101. {
  102. m_fSetResync = TRUE;
  103. }
  104. }
  105. else
  106. ASSERT(FALSE);
  107. m_lBindFlags = DLCTL_SILENT | DLCTL_NO_SCRIPTS | DLCTL_NO_FRAMEDOWNLOAD |
  108. DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_DLACTIVEXCTLS;
  109. if (m_fSetResync)
  110. m_lBindFlags |= DLCTL_RESYNCHRONIZE;
  111. // register our window class if necessary
  112. WNDCLASS wc;
  113. wc.style = 0;
  114. wc.lpfnWndProc = UrlDownloadWndProc;
  115. wc.cbClsExtra = 0;
  116. wc.cbWndExtra = 0;
  117. wc.hInstance = g_hinst;
  118. wc.hIcon = NULL;
  119. wc.hCursor = NULL;
  120. wc.hbrBackground = (HBRUSH)NULL;
  121. wc.lpszMenuName = NULL;
  122. wc.lpszClassName = URLDL_WNDCLASS;
  123. SHRegisterClass(&wc);
  124. }
  125. CUrlDownload::~CUrlDownload()
  126. {
  127. // Maintain global count of objects
  128. //DllRelease();
  129. CleanUp();
  130. }
  131. void CUrlDownload::CleanUpBrowser()
  132. {
  133. SAFERELEASE(m_pScript);
  134. if (m_fAdviseOn)
  135. {
  136. UnAdviseMe();
  137. }
  138. SAFERELEASE(m_pCP);
  139. SAFERELEASE(m_pDocument);
  140. SAFERELEASE(m_pPersistMk);
  141. SAFERELEASE(m_pOleCmdTarget);
  142. SAFELOCALFREE(m_pwszClientPullURL);
  143. }
  144. void CUrlDownload::CleanUp()
  145. {
  146. CleanUpBrowser();
  147. SAFELOCALFREE(m_pwszURL);
  148. if (m_hwndMe)
  149. {
  150. SetWindowLongPtr(m_hwndMe, GWLP_USERDATA, 0);
  151. DestroyWindow(m_hwndMe);
  152. m_hwndMe = NULL;
  153. }
  154. }
  155. LRESULT UrlDownloadWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  156. {
  157. CUrlDownload *pThis = (CUrlDownload *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  158. // Validate pThis
  159. #ifdef DEBUG
  160. if (pThis && IsBadWritePtr(pThis, sizeof(*pThis)))
  161. {
  162. ASSERT(FALSE);
  163. }
  164. #endif
  165. switch (Msg)
  166. {
  167. case WM_CREATE :
  168. {
  169. LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
  170. if (!pcs || !(pcs->lpCreateParams))
  171. {
  172. return -1;
  173. }
  174. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) pcs->lpCreateParams);
  175. return 0;
  176. }
  177. case WM_URLDL_CLIENTPULL :
  178. case WM_URLDL_ONDLCOMPLETE :
  179. if (pThis)
  180. pThis->HandleMessage(hWnd, Msg, wParam, lParam);
  181. break;
  182. default:
  183. return DefWindowProc(hWnd, Msg, wParam, lParam);
  184. }
  185. return 0;
  186. }
  187. HRESULT CUrlDownload::CreateMyWindow()
  188. {
  189. // Create our callback window
  190. if (NULL == m_hwndMe)
  191. {
  192. // TraceMsg(TF_THISMODULE, "Creating MeWnd, this=0x%08x", (DWORD)this);
  193. m_hwndMe = CreateWindow(URLDL_WNDCLASS, TEXT("CUrlDownloadWnd"), WS_OVERLAPPED,
  194. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  195. NULL, NULL, g_hinst, (LPVOID)this);
  196. if (NULL == m_hwndMe)
  197. {
  198. return E_FAIL;
  199. }
  200. }
  201. return S_OK;
  202. }
  203. HRESULT CUrlDownload::BeginDownloadURL2(
  204. LPCWSTR pwszURL, // URL
  205. BDUMethod iMethod, // download method
  206. BDUOptions iOptions, // download options
  207. LPTSTR pszLocalFile, // Local file to download to instead of cache
  208. DWORD dwMaxSize // Max size in bytes; will abort if exceeded
  209. )
  210. {
  211. HRESULT hr = S_OK;
  212. // Param validation
  213. ASSERT(pwszURL);
  214. ASSERT(!(iOptions & BDU2_NEEDSTREAM));
  215. ASSERT(!pszLocalFile);
  216. if (pszLocalFile)
  217. {
  218. hr = E_INVALIDARG;
  219. }
  220. else
  221. {
  222. CreateMyWindow();
  223. // Clean up some old stuff
  224. SAFERELEASE(m_pScript);
  225. m_fBrowserValid = FALSE;
  226. m_iMethod = iMethod;
  227. m_iOptions = iOptions;
  228. m_dwMaxSize = dwMaxSize;
  229. SAFELOCALFREE(m_pwszClientPullURL);
  230. m_iNumClientPull = 0;
  231. // Save URL
  232. SAFELOCALFREE(m_pwszURL);
  233. m_pwszURL = StrDupW(pwszURL);
  234. // Determine how to download this URL
  235. hr = BeginDownloadWithBrowser(pwszURL);
  236. }
  237. if (FAILED(hr))
  238. {
  239. OnDownloadComplete(BDU2_ERROR_GENERAL);
  240. }
  241. return (hr);
  242. }
  243. //
  244. // Looks up the Url in the url history object and if its not CP_ACP
  245. // inserts an IHTMLLoadOptions object that contains the codepage
  246. // into the bind context
  247. //
  248. HRESULT InsertCodepageIntoBindCtx(UINT codepage, IBindCtx * pbc)
  249. {
  250. HRESULT hr = S_OK;
  251. if (pbc == NULL)
  252. {
  253. hr = E_INVALIDARG;
  254. }
  255. else
  256. {
  257. if (codepage != CP_ACP)
  258. {
  259. DWORD dwcp = codepage;
  260. //
  261. // We got a codepage that wasn't the ansi one create an
  262. // HTMLLoadOptions object and set the code page in it.
  263. //
  264. IHtmlLoadOptions *phlo = NULL;
  265. hr = CoCreateInstance(CLSID_HTMLLoadOptions, NULL,
  266. CLSCTX_INPROC_SERVER, IID_IHtmlLoadOptions, (void**)&phlo);
  267. if (SUCCEEDED(hr) && phlo)
  268. {
  269. hr = phlo->SetOption(HTMLLOADOPTION_CODEPAGE, &dwcp,
  270. sizeof(dwcp));
  271. if (SUCCEEDED(hr))
  272. {
  273. //
  274. // Insert the option into the bindctx
  275. //
  276. pbc->RegisterObjectParam(L"__HTMLLOADOPTIONS", phlo);
  277. }
  278. phlo->Release();
  279. }
  280. }
  281. }
  282. return hr; // no return - may return S_FALSE
  283. }
  284. HRESULT CUrlDownload::BeginDownloadWithBrowser(LPCWSTR pwszURL)
  285. {
  286. HRESULT hr;
  287. // Get browser and hook up sink
  288. // (no-op if we're already set up)
  289. hr = GetBrowser();
  290. if (SUCCEEDED(hr))
  291. {
  292. // browse to the required URL
  293. LPMONIKER pURLMoniker = NULL;
  294. IBindCtx *pbc = NULL;
  295. // create a URL moniker from the canonicalized path
  296. hr=CreateURLMoniker(NULL, pwszURL, &pURLMoniker);
  297. // create an empty bind context so that Urlmon will call Trident's
  298. // QueryService on the proper thread so that Trident can delegate
  299. // it to use properly.
  300. hr=CreateBindCtx(0, &pbc);
  301. if (SUCCEEDED(hr))
  302. {
  303. //
  304. // Looks up the Url in the url history object and if its not CP_ACP
  305. // inserts an IHTMLLoadOptions object that contains the codepage
  306. // into the bind context. This is done so that TRIDENT is seeded
  307. // with the correct codepage.
  308. //
  309. InsertCodepageIntoBindCtx(m_cpDL, pbc);
  310. hr = m_pPersistMk->Load(FALSE, pURLMoniker, pbc, 0);
  311. if (SUCCEEDED(hr)) m_fWaitingForReadyState = TRUE;
  312. }
  313. // clean up junk
  314. if (pURLMoniker)
  315. pURLMoniker->Release();
  316. if (pbc)
  317. pbc->Release();
  318. if (SUCCEEDED(hr))
  319. {
  320. m_fBrowserValid = TRUE;
  321. }
  322. else
  323. {
  324. CleanUpBrowser();
  325. }
  326. }
  327. return (hr);
  328. }
  329. HRESULT CUrlDownload::OnDownloadComplete(int iError)
  330. {
  331. PostMessage(m_hwndMe, WM_URLDL_ONDLCOMPLETE, (WPARAM)iError, 0);
  332. return S_OK;
  333. }
  334. BOOL CUrlDownload::HandleMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  335. {
  336. switch (uMsg)
  337. {
  338. case WM_URLDL_CLIENTPULL :
  339. {
  340. HRESULT hr = S_OK;
  341. // Ask our parent if we should do this
  342. if (m_pwszClientPullURL)
  343. {
  344. if (m_iNumClientPull >= MAX_CLIENT_PULL_NUM)
  345. hr = E_FAIL;
  346. }
  347. if (SUCCEEDED(hr))
  348. {
  349. // Download this new url. Don't give "downloadcomplete" for first one
  350. // Save member vars since they get reset in BDU2
  351. int iNumClientPull = m_iNumClientPull;
  352. LPWSTR pszNewURL = m_pwszClientPullURL;
  353. m_pwszClientPullURL = NULL;
  354. hr = BeginDownloadURL2(pszNewURL, m_iMethod, m_iOptions, NULL, m_dwMaxSize);
  355. SAFELOCALFREE(pszNewURL);
  356. if (SUCCEEDED(hr))
  357. {
  358. m_iNumClientPull = iNumClientPull + 1;
  359. }
  360. }
  361. }
  362. break;
  363. case WM_URLDL_ONDLCOMPLETE :
  364. ASSERT(m_phr);
  365. *m_phr = S_OK;
  366. return TRUE;
  367. default:
  368. break;
  369. }
  370. return TRUE;
  371. }
  372. HRESULT CUrlDownload::AbortDownload(int iErrorCode /* =-1 */)
  373. {
  374. HRESULT hr=S_FALSE;
  375. BOOL fAborted=FALSE;
  376. if (m_fBrowserValid)
  377. {
  378. ASSERT(m_pOleCmdTarget);
  379. if (m_pOleCmdTarget)
  380. {
  381. m_pOleCmdTarget->Exec(NULL, OLECMDID_STOP, 0, NULL, NULL);
  382. }
  383. SAFELOCALFREE(m_pwszClientPullURL);
  384. fAborted=TRUE;
  385. m_fBrowserValid = FALSE;
  386. }
  387. return hr; // no return - may return S_FALSE
  388. }
  389. // Loads browser, creates sink and hooks it up to DIID_DWebBrowserEvents
  390. HRESULT CUrlDownload::GetBrowser()
  391. {
  392. HRESULT hr = S_OK;
  393. if (m_fAdviseOn)
  394. return (hr);
  395. if (NULL == m_pDocument)
  396. {
  397. ASSERT(!m_pPersistMk);
  398. ASSERT(!m_pCP);
  399. hr = CoCreateInstance(CLSID_HTMLDocument, NULL,
  400. CLSCTX_INPROC, IID_IHTMLDocument2, (void **)&m_pDocument);
  401. if (SUCCEEDED(hr)) // setting design mode faults Trident && SUCCEEDED(hr = m_pDocument->put_designMode( (BSTR)c_bstr_ON )))
  402. {
  403. IOleObject *pOleObj;
  404. hr = m_pDocument->QueryInterface(IID_IOleObject, (void **)&pOleObj);
  405. if (SUCCEEDED(hr))
  406. {
  407. pOleObj->SetClientSite((IOleClientSite *)this);
  408. pOleObj->Release();
  409. }
  410. }
  411. if (SUCCEEDED(hr))
  412. {
  413. hr = m_pDocument->QueryInterface(IID_IPersistMoniker, (void**)&m_pPersistMk);
  414. }
  415. if (SUCCEEDED(hr))
  416. {
  417. hr = m_pDocument->QueryInterface(IID_IOleCommandTarget, (void**)&m_pOleCmdTarget);
  418. }
  419. ASSERT(SUCCEEDED(hr));
  420. }
  421. // At this point we have m_pDocument and m_pPersistMk
  422. // Find our connection point if necessary
  423. if (NULL == m_pCP && SUCCEEDED(hr))
  424. {
  425. IConnectionPointContainer *pCPCont=NULL;
  426. hr = m_pDocument->QueryInterface(IID_IConnectionPointContainer,
  427. (void **)&pCPCont);
  428. if (SUCCEEDED(hr))
  429. {
  430. hr = pCPCont->FindConnectionPoint(IID_IPropertyNotifySink, &m_pCP);
  431. pCPCont->Release();
  432. pCPCont = NULL;
  433. }
  434. }
  435. // And hook it up to us
  436. if (SUCCEEDED(hr))
  437. {
  438. // create sink
  439. IPropertyNotifySink *pSink = (IPropertyNotifySink *)this;
  440. hr = m_pCP->Advise(pSink, &m_dwConnectionCookie);
  441. if (SUCCEEDED(hr))
  442. {
  443. m_fAdviseOn = TRUE;
  444. }
  445. }
  446. return (hr);
  447. }
  448. void CUrlDownload::UnAdviseMe()
  449. {
  450. if (m_fAdviseOn)
  451. {
  452. m_pCP->Unadvise(m_dwConnectionCookie);
  453. m_fAdviseOn = FALSE;
  454. }
  455. }
  456. void CUrlDownload::DestroyBrowser()
  457. {
  458. CleanUpBrowser();
  459. }
  460. void CUrlDownload::DoneDownloading()
  461. {
  462. // Don't send any more messages to the parent
  463. AbortDownload();
  464. CleanUp();
  465. }
  466. HRESULT CUrlDownload::GetScript(IHTMLWindow2 **ppWin)
  467. {
  468. HRESULT hr = E_FAIL;
  469. IDispatch *pDisp=NULL;
  470. ASSERT(ppWin);
  471. *ppWin=NULL;
  472. if (!m_fBrowserValid)
  473. {
  474. return (E_FAIL);
  475. }
  476. *ppWin = NULL;
  477. if (m_pScript)
  478. {
  479. m_pScript->AddRef();
  480. *ppWin = m_pScript;
  481. return S_OK;
  482. }
  483. if (m_pDocument)
  484. {
  485. hr = m_pDocument->get_Script(&pDisp);
  486. if (!pDisp) hr=E_NOINTERFACE;
  487. }
  488. if (SUCCEEDED(hr))
  489. {
  490. hr = pDisp->QueryInterface(IID_IHTMLWindow2, (void **)ppWin);
  491. if (*ppWin == NULL) hr = E_NOINTERFACE;
  492. pDisp->Release();
  493. }
  494. // Save this so future GetScript() calls much faster
  495. ASSERT(!m_pScript);
  496. if (SUCCEEDED(hr))
  497. {
  498. m_pScript = *ppWin;
  499. m_pScript->AddRef();
  500. }
  501. return (hr);
  502. }
  503. // Returns pointer to '.' or pointer to null-terminator or query '?'
  504. LPWSTR // ptr to period or to null-term or '?'
  505. URLFindExtensionW(
  506. LPCWSTR pszURL,
  507. int *piLen) // length including period
  508. {
  509. LPCWSTR pszDot;
  510. ASSERT(pszURL);
  511. for (pszDot = NULL; *pszURL && *pszURL!=TEXT('?'); pszURL++)
  512. {
  513. switch (*pszURL) {
  514. case TEXT('.'):
  515. pszDot = pszURL; // remember the last dot
  516. break;
  517. case TEXT('/'):
  518. pszDot = NULL; // forget last dot, it was in a directory
  519. break;
  520. }
  521. }
  522. if (piLen)
  523. {
  524. if (pszDot)
  525. *piLen = (int) (pszURL-pszDot);
  526. else
  527. *piLen = 0;
  528. }
  529. // if we found the extension, return ptr to the dot, else
  530. // ptr to end of the string (NULL extension) (cast->non const)
  531. return pszDot ? (LPWSTR)pszDot : (LPWSTR)pszURL;
  532. }
  533. // Returns TRUE if this appears to be an HTML URL
  534. BOOL CUrlDownload::IsHTMLURL(LPCWSTR lpURL)
  535. {
  536. LPWSTR pwch;
  537. int iLen;
  538. pwch = URLFindExtensionW(lpURL, &iLen);
  539. if (*pwch && iLen)
  540. {
  541. // We found an extension. Check it out.
  542. if ((iLen<4 || iLen>5) ||
  543. (iLen == 5 &&
  544. (StrCmpNIW(pwch, L".html", 5))) ||
  545. (iLen == 4 &&
  546. (StrCmpNIW(pwch, L".htm", 4) &&
  547. StrCmpNIW(pwch, L".htt", 4) &&
  548. StrCmpNIW(pwch, L".asp", 4) &&
  549. StrCmpNIW(pwch, L".htx", 4)
  550. )))
  551. {
  552. // extension < 3 chars, or extension > 4 chars, or
  553. // extension not one of the above
  554. return FALSE;
  555. }
  556. }
  557. else
  558. return FALSE; // no extension. Can't assume it's HTML.
  559. return TRUE;
  560. }
  561. // Returns TRUE if this is a URL we should try to download (http:)
  562. BOOL CUrlDownload::IsValidURL(LPCWSTR lpURL)
  563. {
  564. // Check protocol
  565. // HKEY hk;
  566. #if 0
  567. BOOL fValidProtocol = FALSE;
  568. // Always accept http or https
  569. if (!StrCmpNIW(lpURL, L"http", 4))
  570. fValidProtocol = TRUE;
  571. if (!fValidProtocol &&
  572. (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("PROTOCOLS\\Handler"), 0, KEY_QUERY_VALUE, &hk)))
  573. {
  574. // Crack out protocol
  575. DWORD dwData=0, cbData = sizeof(DWORD);
  576. int i;
  577. char ch[16];
  578. // we know we are 7-bit
  579. for (i=0; i<ARRAYSIZE(ch) && lpURL[i] != L':' && lpURL[i]; i++)
  580. ch[i] = (char) (lpURL[i]);
  581. if (i<ARRAYSIZE(ch))
  582. {
  583. ch[i] = '\0';
  584. // We have protocol
  585. if (NO_ERROR == SHGetValue(hk, ch, TEXT("SupportsNoUI"), NULL, &dwData, &cbData))
  586. {
  587. if (dwData != 0)
  588. fValidProtocol = TRUE; // Passed test
  589. }
  590. }
  591. RegCloseKey(hk);
  592. }
  593. #endif
  594. // See if this protocol will give us something for the cache
  595. BOOL fUsesCache=FALSE;
  596. DWORD dwBufSize=0;
  597. CoInternetQueryInfo(lpURL, QUERY_USES_CACHE, 0,
  598. &fUsesCache, sizeof(fUsesCache), &dwBufSize, 0);
  599. if (!fUsesCache || (S_FALSE == ::IsValidURL(NULL, lpURL, 0)))
  600. return FALSE;
  601. return TRUE;
  602. }
  603. HRESULT CUrlDownload::GetRealURL(LPWSTR *ppwszURL)
  604. {
  605. *ppwszURL = NULL;
  606. if (!m_fBrowserValid)
  607. {
  608. if (m_pwszURL)
  609. *ppwszURL = StrDupW(m_pwszURL);
  610. }
  611. else
  612. {
  613. // Get the real URL from the browser in case we were redirected
  614. // We could optimize to do this only once
  615. ITargetContainer *pTarget=NULL;
  616. LPWSTR pwszThisUrl=NULL;
  617. if (m_pDocument)
  618. {
  619. m_pDocument->QueryInterface(IID_ITargetContainer, (void **)&pTarget);
  620. if (pTarget)
  621. {
  622. pTarget->GetFrameUrl(&pwszThisUrl);
  623. pTarget->Release();
  624. }
  625. }
  626. if (pwszThisUrl)
  627. {
  628. if (m_pwszURL) SAFELOCALFREE(m_pwszURL);
  629. m_pwszURL = StrDupW(pwszThisUrl);
  630. *ppwszURL = StrDupW(pwszThisUrl);
  631. CoTaskMemFree(pwszThisUrl);
  632. }
  633. else if (m_pwszURL)
  634. {
  635. *ppwszURL = StrDupW(m_pwszURL);
  636. }
  637. }
  638. return (*ppwszURL) ? S_OK : E_OUTOFMEMORY;
  639. }
  640. HRESULT CUrlDownload::GetDocument(IHTMLDocument2 **ppDoc)
  641. {
  642. HRESULT hr;
  643. if (!m_fBrowserValid)
  644. {
  645. *ppDoc = NULL;
  646. return (E_FAIL);
  647. }
  648. *ppDoc = m_pDocument;
  649. if (m_pDocument)
  650. {
  651. m_pDocument->AddRef();
  652. hr = S_OK;
  653. }
  654. else
  655. hr = E_NOINTERFACE;
  656. return (hr);
  657. }
  658. //
  659. // IUnknown of CUrlDownload
  660. //
  661. STDMETHODIMP CUrlDownload::QueryInterface(REFIID riid, void ** ppv)
  662. {
  663. if (!ppv)
  664. return E_POINTER;
  665. *ppv=NULL;
  666. // Validate requested interface
  667. if (IID_IOleClientSite == riid)
  668. *ppv=(IOleClientSite *)this;
  669. else if (IID_IPropertyNotifySink == riid)
  670. *ppv=(IPropertyNotifySink *)this;
  671. else if (IID_IOleCommandTarget == riid)
  672. *ppv=(IOleCommandTarget *)this;
  673. else if (IID_IDispatch == riid)
  674. *ppv=(IDispatch *)this;
  675. else if (IID_IServiceProvider == riid)
  676. *ppv = (IServiceProvider *)this;
  677. else if (IID_IAuthenticate == riid)
  678. *ppv = (IAuthenticate *)this;
  679. else if (IID_IInternetSecurityManager == riid)
  680. *ppv = (IInternetSecurityManager *)this;
  681. else if ((IID_IUnknown == riid) ||
  682. (IID_IHlinkFrame == riid))
  683. *ppv = (IHlinkFrame *)this;
  684. else
  685. {
  686. // DBGIID("CUrlDownload::QueryInterface() failing", riid);
  687. }
  688. // Addref through the interface
  689. if (NULL != *ppv)
  690. {
  691. ((LPUNKNOWN)*ppv)->AddRef();
  692. return S_OK;
  693. }
  694. return E_NOINTERFACE;
  695. }
  696. STDMETHODIMP_(ULONG) CUrlDownload::AddRef(void)
  697. {
  698. // TraceMsg(TF_THISMODULE, "CUrlDownload addref to %d", m_cRef+1);
  699. return ++m_cRef;
  700. }
  701. STDMETHODIMP_(ULONG) CUrlDownload::Release(void)
  702. {
  703. // TraceMsg(TF_THISMODULE, "CUrlDownload release - %d", m_cRef-1);
  704. if( 0L != --m_cRef )
  705. return m_cRef;
  706. delete this;
  707. return 0L;
  708. }
  709. STDMETHODIMP CUrlDownload::GetTypeInfoCount(UINT *pctinfo)
  710. {
  711. return E_NOTIMPL;
  712. }
  713. STDMETHODIMP CUrlDownload::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  714. {
  715. return E_NOTIMPL;
  716. }
  717. STDMETHODIMP CUrlDownload::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  718. {
  719. return E_NOTIMPL;
  720. }
  721. STDMETHODIMP CUrlDownload::Invoke(DISPID dispidMember,
  722. REFIID riid,
  723. LCID lcid,
  724. WORD wFlags,
  725. DISPPARAMS *pdispparams,
  726. VARIANT *pvarResult,
  727. EXCEPINFO *pexcepinfo,
  728. UINT *puArgErr)
  729. {
  730. if (!pvarResult)
  731. return E_INVALIDARG;
  732. ASSERT(V_VT(pvarResult)== VT_EMPTY);
  733. if (wFlags == DISPATCH_PROPERTYGET)
  734. {
  735. switch (dispidMember)
  736. {
  737. case DISPID_AMBIENT_DLCONTROL :
  738. //TraceMsg(TF_THISMODULE, "Returning DLCONTROL ambient property 0x%08x", m_lBindFlags);
  739. pvarResult->vt = VT_I4;
  740. pvarResult->lVal = m_lBindFlags;
  741. break;
  742. case DISPID_AMBIENT_USERAGENT:
  743. CHAR szUserAgent[MAX_PATH]; // URLMON says the max length of the UA string is MAX_PATH
  744. DWORD dwSize;
  745. dwSize = MAX_PATH;
  746. szUserAgent[0] = '\0';
  747. pvarResult->vt = VT_BSTR;
  748. if ( ObtainUserAgentString( 0, szUserAgent, &dwSize ) == S_OK )
  749. {
  750. UINT cch = lstrlenA( szUserAgent );
  751. // Allocates size + 1
  752. pvarResult->bstrVal = SysAllocStringLen( 0, cch );
  753. if( pvarResult->bstrVal )
  754. {
  755. if( !MultiByteToWideChar( CP_ACP, 0, szUserAgent, -1, pvarResult->bstrVal, cch + 1 ) )
  756. {
  757. SysFreeString( pvarResult->bstrVal );
  758. pvarResult->bstrVal = 0;
  759. }
  760. }
  761. }
  762. break;
  763. case DISPID_AMBIENT_USERMODE:
  764. pvarResult->vt = VT_BOOL;
  765. pvarResult->boolVal = VARIANT_FALSE; // put it in design mode
  766. break;
  767. default:
  768. return DISP_E_MEMBERNOTFOUND;
  769. }
  770. return S_OK;
  771. }
  772. return DISP_E_MEMBERNOTFOUND;
  773. }
  774. // IPropertyNotifySink
  775. STDMETHODIMP CUrlDownload::OnChanged(DISPID dispID)
  776. {
  777. if ((DISPID_READYSTATE == dispID) ||
  778. (DISPID_UNKNOWN == dispID))
  779. {
  780. // Find out if we're done
  781. if (m_fWaitingForReadyState)
  782. {
  783. VARIANT varState;
  784. DISPPARAMS dp;
  785. VariantInit(&varState);
  786. if (SUCCEEDED(m_pDocument->Invoke(DISPID_READYSTATE,
  787. IID_NULL,
  788. GetUserDefaultLCID(),
  789. DISPATCH_PROPERTYGET,
  790. &dp,
  791. &varState, NULL, NULL)) &&
  792. V_VT(&varState)==VT_I4 &&
  793. V_I4(&varState)== READYSTATE_COMPLETE)
  794. {
  795. m_fWaitingForReadyState = FALSE;
  796. // Successful download. See if a client-pull is waiting.
  797. if (m_pwszClientPullURL)
  798. PostMessage(m_hwndMe, WM_URLDL_CLIENTPULL, 0, 0);
  799. else
  800. OnDownloadComplete(BDU2_ERROR_NONE);
  801. }
  802. }
  803. }
  804. return S_OK;
  805. }
  806. STDMETHODIMP CUrlDownload::OnRequestEdit(DISPID dispID)
  807. {
  808. return S_OK;
  809. }
  810. // IOleCommandTarget
  811. STDMETHODIMP CUrlDownload::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  812. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  813. {
  814. return OLECMDERR_E_UNKNOWNGROUP;
  815. }
  816. STDMETHODIMP CUrlDownload::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  817. DWORD nCmdexecopt, VARIANTARG *pvarargIn,
  818. VARIANTARG *pvarargOut)
  819. {
  820. HRESULT hres = OLECMDERR_E_NOTSUPPORTED;
  821. if (pguidCmdGroup == NULL)
  822. {
  823. switch(nCmdID)
  824. {
  825. case OLECMDID_SETPROGRESSPOS:
  826. {
  827. hres = S_OK;
  828. VARIANT varBytes;
  829. if (m_pOleCmdTarget)
  830. {
  831. varBytes.vt=VT_EMPTY;
  832. m_pOleCmdTarget->Exec(&CGID_MSHTML, IDM_GETBYTESDOWNLOADED, 0, NULL, &varBytes);
  833. if (varBytes.vt == VT_I4)
  834. {
  835. DWORD dwBytes = (DWORD) varBytes.lVal;
  836. //TraceMsg(TF_THISMODULE, "%d bytes on page so far (mshtml)", dwBytes);
  837. ProgressBytes(dwBytes);
  838. // for this mutant version, we also want to keep mom and dad up to date.
  839. LONG lPos;
  840. // we use 0..50 so that the progress meter won't max out
  841. // when only the download phase is finished and we still have
  842. // packaging work to do.
  843. if (pvarargIn && m_dwProgMax)
  844. lPos = (pvarargIn->lVal * 25) / m_dwProgMax;
  845. else
  846. lPos = 0;
  847. if (m_ptp)
  848. m_ptp->SetPercent( lPos );
  849. hres = S_OK;
  850. }
  851. }
  852. }
  853. break;
  854. case OLECMDID_SETPROGRESSMAX:
  855. {
  856. if (pvarargIn && pvarargIn->vt == VT_I4)
  857. m_dwProgMax = pvarargIn->lVal;
  858. hres = S_OK;
  859. }
  860. break;
  861. //
  862. // The containee has found an http-equiv meta tag; handle it
  863. // appropriately (client pull)
  864. //
  865. case OLECMDID_HTTPEQUIV_DONE:
  866. hres = S_OK;
  867. break;
  868. case OLECMDID_HTTPEQUIV:
  869. {
  870. LPWSTR pwszEquivString = pvarargIn? pvarargIn->bstrVal : NULL;
  871. BOOL fHasHeader = (bool) pwszEquivString;
  872. if (pvarargIn && pvarargIn->vt != VT_BSTR)
  873. return OLECMDERR_E_NOTSUPPORTED;
  874. if (!fHasHeader || StrCmpNIW(c_wszRefresh, pwszEquivString, lstrlenW(c_wszRefresh)) == 0)
  875. {
  876. // Hit. Now do the right thing for this header
  877. // We pass both the header and a pointer to the first char after
  878. // ':', which is usually the delimiter handlers will look for.
  879. LPWSTR pwszColon = fHasHeader ? StrChrW(pwszEquivString, ':') : NULL;
  880. // Enforce the : at the end of the header
  881. if (fHasHeader && !pwszColon)
  882. {
  883. return OLECMDERR_E_NOTSUPPORTED;
  884. }
  885. hres = HandleRefresh(pwszEquivString, pwszColon ? pwszColon+1:NULL,
  886. (nCmdID == OLECMDID_HTTPEQUIV_DONE));
  887. }
  888. }
  889. // if we return OLECMDERR_E_NOTSUPPORTED, we don't handle
  890. // client pull
  891. break;
  892. }
  893. }
  894. return hres;
  895. }
  896. // The basic operation was lifted from shdocvw\basesb.cpp
  897. HRESULT CUrlDownload::HandleRefresh(LPWSTR pwszEquivString, LPWSTR pwszContent, BOOL fDone)
  898. {
  899. unsigned int uiTimeout = 0;
  900. WCHAR awch[INTERNET_MAX_URL_LENGTH];
  901. if (fDone)
  902. {
  903. return S_OK; // fDone means we don't process this
  904. }
  905. // NSCompat: we only honor the first successfully parsed Refresh
  906. if (m_pwszClientPullURL)
  907. return S_OK;
  908. if (!pwszContent ||
  909. !DLParseRefreshContent(pwszContent, &uiTimeout, awch, INTERNET_MAX_URL_LENGTH))
  910. {
  911. return OLECMDERR_E_NOTSUPPORTED; // cannot handle refresh w/o timeout
  912. }
  913. if (!awch[0])
  914. {
  915. return S_OK;
  916. }
  917. if (m_iNumClientPull >= MAX_CLIENT_PULL_NUM)
  918. {
  919. return S_OK;
  920. }
  921. //TraceMsg(TF_THISMODULE, "CUrlDownload client pull (refresh=%d) url=%ws", uiTimeout, awch);
  922. if (uiTimeout > MAX_CLIENT_PULL_TIMEOUT)
  923. {
  924. return S_OK;
  925. }
  926. m_pwszClientPullURL = StrDupW(awch);
  927. // If we can't copy the URL, don't set the timer or else we'll
  928. // keep reloading the same page.
  929. if (m_pwszClientPullURL == NULL)
  930. return OLECMDERR_E_NOTSUPPORTED;
  931. return S_OK;
  932. }
  933. HRESULT CUrlDownload::SetDLCTL(long lFlags)
  934. {
  935. // TraceMsg(TF_THISMODULE, "CUrlDownload: SetDLCTL %04x", lFlags);
  936. m_lBindFlags = lFlags | DLCTL_SILENT;
  937. if (m_fSetResync)
  938. m_lBindFlags |= DLCTL_RESYNCHRONIZE;
  939. return S_OK;
  940. }
  941. #define INET_E_AGENT_BIND_IN_PROGRESS 0x800C0FFF
  942. HRESULT CUrlDownload::ProgressBytes(DWORD dwBytes)
  943. {
  944. if (m_dwMaxSize > 0 && dwBytes > m_dwMaxSize)
  945. {
  946. //TraceMsg(TF_THISMODULE, "CUrlDownload MaxSize exceeded aborting. %d of %d bytes", dwBytes, m_dwMaxSize);
  947. AbortDownload(BDU2_ERROR_MAXSIZE);
  948. return E_ABORT;
  949. }
  950. return S_OK;
  951. }
  952. //---------------------------------------------------------------
  953. // IServiceProvider
  954. STDMETHODIMP CUrlDownload::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
  955. {
  956. if ((SID_SHlinkFrame == guidService && IID_IHlinkFrame == riid) ||
  957. (IID_IAuthenticate == guidService && IID_IAuthenticate == riid) ||
  958. (SID_SInternetSecurityManager == guidService && IID_IInternetSecurityManager == riid))
  959. {
  960. return QueryInterface(riid, ppvObject);
  961. }
  962. else
  963. {
  964. *ppvObject = NULL;
  965. return E_NOINTERFACE;
  966. }
  967. }
  968. //---------------------------------------------------------------
  969. // IAuthenticate
  970. STDMETHODIMP CUrlDownload::Authenticate(HWND *phwnd, LPWSTR *ppszUsername, LPWSTR *ppszPassword)
  971. {
  972. HRESULT hr;
  973. ASSERT(phwnd && ppszUsername && ppszPassword);
  974. *phwnd = (HWND)-1;
  975. *ppszUsername = NULL;
  976. *ppszPassword = NULL;
  977. hr = E_NOTIMPL;
  978. //TraceMsg(TF_THISMODULE, "CUrlDownload::Authenticate returning hr=%08x", hr);
  979. return (hr);
  980. }
  981. //---------------------------------------------------------------
  982. // IHlinkFrame
  983. STDMETHODIMP CUrlDownload::SetBrowseContext(IHlinkBrowseContext *pihlbc)
  984. {
  985. return E_NOTIMPL;
  986. }
  987. STDMETHODIMP CUrlDownload::GetBrowseContext(IHlinkBrowseContext **ppihlbc)
  988. {
  989. return E_NOTIMPL;
  990. }
  991. STDMETHODIMP CUrlDownload::Navigate(DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pibsc, IHlink *pihlNavigate)
  992. {
  993. // We should only get a call through IHlinkFrame->Navigate()
  994. // when the webcrawler has submitted a form for authentication.
  995. // Bail out if that's not the case.
  996. if (!m_fFormSubmitted)
  997. {
  998. return E_NOTIMPL;
  999. }
  1000. // Our timer has already been started. If this fails, OnDownloadComplete will get
  1001. // called when we time out.
  1002. // We don't support a wide variety of parameters.
  1003. ASSERT(grfHLNF == 0);
  1004. ASSERT(pbc);
  1005. ASSERT(pibsc);
  1006. ASSERT(pihlNavigate);
  1007. // Get the moniker from IHlink
  1008. HRESULT hr;
  1009. IMoniker *pmk = NULL;
  1010. hr = pihlNavigate->GetMonikerReference(HLINKGETREF_ABSOLUTE, &pmk, NULL);
  1011. if (SUCCEEDED(hr))
  1012. {
  1013. // Load the URL with the post data.
  1014. // REARCHITECT: What if we get redirected to something other than HTML? (beta 2)
  1015. hr = m_pPersistMk->Load(FALSE, pmk, pbc, 0);
  1016. SAFERELEASE(pmk);
  1017. if (SUCCEEDED(hr))
  1018. {
  1019. m_fBrowserValid = TRUE;
  1020. // Need to wait again.
  1021. m_fWaitingForReadyState = TRUE;
  1022. }
  1023. }
  1024. return (hr);
  1025. }
  1026. STDMETHODIMP CUrlDownload::OnNavigate(DWORD grfHLNF, IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, DWORD dwreserved)
  1027. {
  1028. return E_NOTIMPL;
  1029. }
  1030. STDMETHODIMP CUrlDownload::UpdateHlink(ULONG uHLID, IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
  1031. {
  1032. return E_NOTIMPL;
  1033. }
  1034. //---------------------------------------------------------------------
  1035. // IInternetSecurityManager interface
  1036. // Used to override security to allow form submits, for form auth sites
  1037. HRESULT CUrlDownload::SetSecuritySite(IInternetSecurityMgrSite *pSite)
  1038. {
  1039. return E_NOTIMPL;
  1040. }
  1041. HRESULT CUrlDownload::GetSecuritySite(IInternetSecurityMgrSite **ppSite)
  1042. {
  1043. return E_NOTIMPL;
  1044. }
  1045. HRESULT CUrlDownload::MapUrlToZone(LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags)
  1046. {
  1047. return INET_E_DEFAULT_ACTION;
  1048. }
  1049. HRESULT CUrlDownload::GetSecurityId(LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
  1050. {
  1051. return INET_E_DEFAULT_ACTION;
  1052. }
  1053. HRESULT CUrlDownload::ProcessUrlAction(LPCWSTR pwszUrl, DWORD dwAction, BYTE __RPC_FAR *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved)
  1054. {
  1055. if ((dwAction == URLACTION_HTML_SUBMIT_FORMS_TO) ||
  1056. (dwAction == URLACTION_HTML_SUBMIT_FORMS_FROM))
  1057. {
  1058. return S_OK;
  1059. }
  1060. return INET_E_DEFAULT_ACTION;
  1061. }
  1062. HRESULT CUrlDownload::QueryCustomPolicy(LPCWSTR pwszUrl, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved)
  1063. {
  1064. return INET_E_DEFAULT_ACTION;
  1065. }
  1066. HRESULT CUrlDownload::SetZoneMapping(DWORD dwZone, LPCWSTR lpszPattern, DWORD dwFlags)
  1067. {
  1068. return INET_E_DEFAULT_ACTION;
  1069. }
  1070. HRESULT CUrlDownload::GetZoneMappings(DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags)
  1071. {
  1072. return INET_E_DEFAULT_ACTION;
  1073. }
  1074. //
  1075. // IOleClientSite
  1076. //
  1077. STDMETHODIMP CUrlDownload:: SaveObject(void)
  1078. {
  1079. return E_NOTIMPL;
  1080. }
  1081. STDMETHODIMP CUrlDownload:: GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
  1082. {
  1083. return E_NOTIMPL;
  1084. }
  1085. STDMETHODIMP CUrlDownload:: GetContainer(IOleContainer **ppContainer)
  1086. {
  1087. return E_NOTIMPL;
  1088. }
  1089. STDMETHODIMP CUrlDownload:: ShowObject(void)
  1090. {
  1091. return E_NOTIMPL;
  1092. }
  1093. STDMETHODIMP CUrlDownload:: OnShowWindow(BOOL fShow)
  1094. {
  1095. return E_NOTIMPL;
  1096. }
  1097. STDMETHODIMP CUrlDownload:: RequestNewObjectLayout(void)
  1098. {
  1099. return E_NOTIMPL;
  1100. }
  1101. // ParseRefreshContent was lifted in its entirety from shdocvw\basesb.cpp
  1102. BOOL DLParseRefreshContent(LPWSTR pwzContent,
  1103. UINT * puiDelay, LPWSTR pwzUrlBuf, UINT cchUrlBuf)
  1104. {
  1105. // We are parsing the following string:
  1106. //
  1107. // [ws]* [0-9]+ [ws]* ; [ws]* url [ws]* = [ws]* { ' | " } [any]* { ' | " }
  1108. //
  1109. // Netscape insists that the string begins with a delay. If not, it
  1110. // ignores the entire directive. There can be more than one URL mentioned,
  1111. // and the last one wins. An empty URL is treated the same as not having
  1112. // a URL at all. An empty URL which follows a non-empty URL resets
  1113. // the previous URL.
  1114. enum { PRC_START, PRC_DIG, PRC_DIG_WS, PRC_SEMI, PRC_SEMI_URL,
  1115. PRC_SEMI_URL_EQL, PRC_SEMI_URL_EQL_ANY };
  1116. #define ISSPACE(ch) (((ch) == 32) || ((unsigned)((ch) - 9)) <= 13 - 9)
  1117. UINT uiState = PRC_START;
  1118. UINT uiDelay = 0;
  1119. LPWSTR pwz = pwzContent;
  1120. LPWSTR pwzUrl = NULL;
  1121. UINT cchUrl = 0;
  1122. WCHAR wch, wchDel = 0;
  1123. *pwzUrlBuf = 0;
  1124. do
  1125. {
  1126. wch = *pwz;
  1127. switch (uiState)
  1128. {
  1129. case PRC_START:
  1130. if (wch >= TEXT('0') && wch <= TEXT('9'))
  1131. {
  1132. uiState = PRC_DIG;
  1133. uiDelay = wch - TEXT('0');
  1134. }
  1135. else if (!ISSPACE(wch))
  1136. goto done;
  1137. break;
  1138. case PRC_DIG:
  1139. if (wch >= TEXT('0') && wch <= TEXT('9'))
  1140. uiDelay = uiDelay * 10 + wch - TEXT('0');
  1141. else if (ISSPACE(wch))
  1142. uiState = PRC_DIG_WS;
  1143. else if (wch == TEXT(';'))
  1144. uiState = PRC_SEMI;
  1145. else
  1146. goto done;
  1147. break;
  1148. case PRC_DIG_WS:
  1149. if (wch == TEXT(';'))
  1150. uiState = PRC_SEMI;
  1151. else if (!ISSPACE(wch))
  1152. goto done;
  1153. break;
  1154. case PRC_SEMI:
  1155. if ( (wch == TEXT('u') || wch == TEXT('U'))
  1156. && (pwz[1] == TEXT('r') || pwz[1] == TEXT('R'))
  1157. && (pwz[2] == TEXT('l') || pwz[2] == TEXT('L')))
  1158. {
  1159. uiState = PRC_SEMI_URL;
  1160. pwz += 2;
  1161. }
  1162. else if (!ISSPACE(wch) && wch != TEXT(';'))
  1163. goto done;
  1164. break;
  1165. case PRC_SEMI_URL:
  1166. if (wch == TEXT('='))
  1167. {
  1168. uiState = PRC_SEMI_URL_EQL;
  1169. *pwzUrlBuf = 0;
  1170. }
  1171. else if (wch == TEXT(';'))
  1172. uiState = PRC_SEMI;
  1173. else if (!ISSPACE(wch))
  1174. goto done;
  1175. break;
  1176. case PRC_SEMI_URL_EQL:
  1177. if (wch == TEXT(';'))
  1178. uiState = PRC_SEMI;
  1179. else if (!ISSPACE(wch))
  1180. {
  1181. uiState = PRC_SEMI_URL_EQL_ANY;
  1182. pwzUrl = pwzUrlBuf;
  1183. cchUrl = cchUrlBuf;
  1184. if (wch == TEXT('\'')|| wch == TEXT('\"'))
  1185. wchDel = wch;
  1186. else
  1187. {
  1188. wchDel = 0;
  1189. *pwzUrl++ = wch;
  1190. cchUrl--;
  1191. }
  1192. }
  1193. break;
  1194. case PRC_SEMI_URL_EQL_ANY:
  1195. if ( !wch
  1196. || ( wchDel && wch == wchDel)
  1197. || (!wchDel && wch == L';'))
  1198. {
  1199. *pwzUrl = 0;
  1200. uiState = wch == TEXT(';') ? PRC_SEMI : PRC_DIG_WS;
  1201. }
  1202. else if (cchUrl > 1)
  1203. {
  1204. *pwzUrl++ = wch;
  1205. cchUrl--;
  1206. }
  1207. break;
  1208. }
  1209. ++pwz;
  1210. } while (wch);
  1211. done:
  1212. *puiDelay = uiDelay;
  1213. return(uiState >= PRC_DIG);
  1214. } // ParseRefreshContent