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.

1265 lines
35 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)
  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::DoneDownloading()
  457. {
  458. // Don't send any more messages to the parent
  459. AbortDownload();
  460. CleanUp();
  461. }
  462. // Returns TRUE if this appears to be an HTML URL
  463. HRESULT CUrlDownload::GetDocument(IHTMLDocument2 **ppDoc)
  464. {
  465. HRESULT hr;
  466. if (!m_fBrowserValid)
  467. {
  468. *ppDoc = NULL;
  469. return (E_FAIL);
  470. }
  471. *ppDoc = m_pDocument;
  472. if (m_pDocument)
  473. {
  474. m_pDocument->AddRef();
  475. hr = S_OK;
  476. }
  477. else
  478. hr = E_NOINTERFACE;
  479. return (hr);
  480. }
  481. //
  482. // IUnknown of CUrlDownload
  483. //
  484. STDMETHODIMP CUrlDownload::QueryInterface(REFIID riid, void ** ppv)
  485. {
  486. if (!ppv)
  487. return E_POINTER;
  488. *ppv=NULL;
  489. // Validate requested interface
  490. if (IID_IOleClientSite == riid)
  491. *ppv=(IOleClientSite *)this;
  492. else if (IID_IPropertyNotifySink == riid)
  493. *ppv=(IPropertyNotifySink *)this;
  494. else if (IID_IOleCommandTarget == riid)
  495. *ppv=(IOleCommandTarget *)this;
  496. else if (IID_IDispatch == riid)
  497. *ppv=(IDispatch *)this;
  498. else if (IID_IServiceProvider == riid)
  499. *ppv = (IServiceProvider *)this;
  500. else if (IID_IAuthenticate == riid)
  501. *ppv = (IAuthenticate *)this;
  502. else if (IID_IInternetSecurityManager == riid)
  503. *ppv = (IInternetSecurityManager *)this;
  504. else if ((IID_IUnknown == riid) ||
  505. (IID_IHlinkFrame == riid))
  506. *ppv = (IHlinkFrame *)this;
  507. else
  508. {
  509. // DBGIID("CUrlDownload::QueryInterface() failing", riid);
  510. }
  511. // Addref through the interface
  512. if (NULL != *ppv)
  513. {
  514. ((LPUNKNOWN)*ppv)->AddRef();
  515. return S_OK;
  516. }
  517. return E_NOINTERFACE;
  518. }
  519. STDMETHODIMP_(ULONG) CUrlDownload::AddRef(void)
  520. {
  521. // TraceMsg(TF_THISMODULE, "CUrlDownload addref to %d", m_cRef+1);
  522. return ++m_cRef;
  523. }
  524. STDMETHODIMP_(ULONG) CUrlDownload::Release(void)
  525. {
  526. // TraceMsg(TF_THISMODULE, "CUrlDownload release - %d", m_cRef-1);
  527. if( 0L != --m_cRef )
  528. return m_cRef;
  529. delete this;
  530. return 0L;
  531. }
  532. STDMETHODIMP CUrlDownload::GetTypeInfoCount(UINT *pctinfo)
  533. {
  534. return E_NOTIMPL;
  535. }
  536. STDMETHODIMP CUrlDownload::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  537. {
  538. return E_NOTIMPL;
  539. }
  540. STDMETHODIMP CUrlDownload::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  541. {
  542. return E_NOTIMPL;
  543. }
  544. STDMETHODIMP CUrlDownload::Invoke(DISPID dispidMember,
  545. REFIID riid,
  546. LCID lcid,
  547. WORD wFlags,
  548. DISPPARAMS *pdispparams,
  549. VARIANT *pvarResult,
  550. EXCEPINFO *pexcepinfo,
  551. UINT *puArgErr)
  552. {
  553. if (!pvarResult)
  554. return E_INVALIDARG;
  555. ASSERT(V_VT(pvarResult)== VT_EMPTY);
  556. if (wFlags == DISPATCH_PROPERTYGET)
  557. {
  558. switch (dispidMember)
  559. {
  560. case DISPID_AMBIENT_DLCONTROL :
  561. //TraceMsg(TF_THISMODULE, "Returning DLCONTROL ambient property 0x%08x", m_lBindFlags);
  562. pvarResult->vt = VT_I4;
  563. pvarResult->lVal = m_lBindFlags;
  564. break;
  565. case DISPID_AMBIENT_USERAGENT:
  566. CHAR szUserAgent[MAX_PATH]; // URLMON says the max length of the UA string is MAX_PATH
  567. DWORD dwSize;
  568. dwSize = MAX_PATH;
  569. szUserAgent[0] = '\0';
  570. pvarResult->vt = VT_BSTR;
  571. if ( ObtainUserAgentString( 0, szUserAgent, &dwSize ) == S_OK )
  572. {
  573. UINT cch = lstrlenA( szUserAgent );
  574. // Allocates size + 1
  575. pvarResult->bstrVal = SysAllocStringLen( 0, cch );
  576. if( pvarResult->bstrVal )
  577. {
  578. if( !MultiByteToWideChar( CP_ACP, 0, szUserAgent, -1, pvarResult->bstrVal, cch + 1 ) )
  579. {
  580. SysFreeString( pvarResult->bstrVal );
  581. pvarResult->bstrVal = 0;
  582. }
  583. }
  584. }
  585. break;
  586. case DISPID_AMBIENT_USERMODE:
  587. pvarResult->vt = VT_BOOL;
  588. pvarResult->boolVal = VARIANT_FALSE; // put it in design mode
  589. break;
  590. default:
  591. return DISP_E_MEMBERNOTFOUND;
  592. }
  593. return S_OK;
  594. }
  595. return DISP_E_MEMBERNOTFOUND;
  596. }
  597. // IPropertyNotifySink
  598. STDMETHODIMP CUrlDownload::OnChanged(DISPID dispID)
  599. {
  600. if ((DISPID_READYSTATE == dispID) ||
  601. (DISPID_UNKNOWN == dispID))
  602. {
  603. // Find out if we're done
  604. if (m_fWaitingForReadyState)
  605. {
  606. VARIANT varState;
  607. DISPPARAMS dp;
  608. VariantInit(&varState);
  609. if (SUCCEEDED(m_pDocument->Invoke(DISPID_READYSTATE,
  610. IID_NULL,
  611. GetUserDefaultLCID(),
  612. DISPATCH_PROPERTYGET,
  613. &dp,
  614. &varState, NULL, NULL)) &&
  615. V_VT(&varState)==VT_I4 &&
  616. V_I4(&varState)== READYSTATE_COMPLETE)
  617. {
  618. m_fWaitingForReadyState = FALSE;
  619. // Successful download. See if a client-pull is waiting.
  620. if (m_pwszClientPullURL)
  621. PostMessage(m_hwndMe, WM_URLDL_CLIENTPULL, 0, 0);
  622. else
  623. OnDownloadComplete(BDU2_ERROR_NONE);
  624. }
  625. }
  626. }
  627. return S_OK;
  628. }
  629. STDMETHODIMP CUrlDownload::OnRequestEdit(DISPID dispID)
  630. {
  631. return S_OK;
  632. }
  633. // IOleCommandTarget
  634. STDMETHODIMP CUrlDownload::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  635. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  636. {
  637. return OLECMDERR_E_UNKNOWNGROUP;
  638. }
  639. STDMETHODIMP CUrlDownload::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  640. DWORD nCmdexecopt, VARIANTARG *pvarargIn,
  641. VARIANTARG *pvarargOut)
  642. {
  643. HRESULT hres = OLECMDERR_E_NOTSUPPORTED;
  644. if (pguidCmdGroup == NULL)
  645. {
  646. switch(nCmdID)
  647. {
  648. case OLECMDID_SETPROGRESSPOS:
  649. {
  650. hres = S_OK;
  651. VARIANT varBytes;
  652. if (m_pOleCmdTarget)
  653. {
  654. varBytes.vt=VT_EMPTY;
  655. m_pOleCmdTarget->Exec(&CGID_MSHTML, IDM_GETBYTESDOWNLOADED, 0, NULL, &varBytes);
  656. if (varBytes.vt == VT_I4)
  657. {
  658. DWORD dwBytes = (DWORD) varBytes.lVal;
  659. //TraceMsg(TF_THISMODULE, "%d bytes on page so far (mshtml)", dwBytes);
  660. ProgressBytes(dwBytes);
  661. // for this mutant version, we also want to keep mom and dad up to date.
  662. LONG lPos;
  663. // we use 0..50 so that the progress meter won't max out
  664. // when only the download phase is finished and we still have
  665. // packaging work to do.
  666. if (pvarargIn && m_dwProgMax)
  667. lPos = (pvarargIn->lVal * 25) / m_dwProgMax;
  668. else
  669. lPos = 0;
  670. if (m_ptp)
  671. m_ptp->SetPercent( lPos );
  672. hres = S_OK;
  673. }
  674. }
  675. }
  676. break;
  677. case OLECMDID_SETPROGRESSMAX:
  678. {
  679. if (pvarargIn && pvarargIn->vt == VT_I4)
  680. m_dwProgMax = pvarargIn->lVal;
  681. hres = S_OK;
  682. }
  683. break;
  684. //
  685. // The containee has found an http-equiv meta tag; handle it
  686. // appropriately (client pull)
  687. //
  688. case OLECMDID_HTTPEQUIV_DONE:
  689. hres = S_OK;
  690. break;
  691. case OLECMDID_HTTPEQUIV:
  692. {
  693. LPWSTR pwszEquivString = pvarargIn? pvarargIn->bstrVal : NULL;
  694. BOOL fHasHeader = (bool) pwszEquivString;
  695. if (pvarargIn && pvarargIn->vt != VT_BSTR)
  696. return OLECMDERR_E_NOTSUPPORTED;
  697. if (!fHasHeader || StrCmpNIW(c_wszRefresh, pwszEquivString, lstrlenW(c_wszRefresh)) == 0)
  698. {
  699. // Hit. Now do the right thing for this header
  700. // We pass both the header and a pointer to the first char after
  701. // ':', which is usually the delimiter handlers will look for.
  702. LPWSTR pwszColon = fHasHeader ? StrChrW(pwszEquivString, ':') : NULL;
  703. // Enforce the : at the end of the header
  704. if (fHasHeader && !pwszColon)
  705. {
  706. return OLECMDERR_E_NOTSUPPORTED;
  707. }
  708. hres = HandleRefresh(pwszEquivString, pwszColon ? pwszColon+1:NULL,
  709. (nCmdID == OLECMDID_HTTPEQUIV_DONE));
  710. }
  711. }
  712. // if we return OLECMDERR_E_NOTSUPPORTED, we don't handle
  713. // client pull
  714. break;
  715. }
  716. }
  717. return hres;
  718. }
  719. // The basic operation was lifted from shdocvw\basesb.cpp
  720. HRESULT CUrlDownload::HandleRefresh(LPWSTR pwszEquivString, LPWSTR pwszContent, BOOL fDone)
  721. {
  722. unsigned int uiTimeout = 0;
  723. WCHAR awch[INTERNET_MAX_URL_LENGTH];
  724. if (fDone)
  725. {
  726. return S_OK; // fDone means we don't process this
  727. }
  728. // NSCompat: we only honor the first successfully parsed Refresh
  729. if (m_pwszClientPullURL)
  730. return S_OK;
  731. if (!pwszContent ||
  732. !DLParseRefreshContent(pwszContent, &uiTimeout, awch, INTERNET_MAX_URL_LENGTH))
  733. {
  734. return OLECMDERR_E_NOTSUPPORTED; // cannot handle refresh w/o timeout
  735. }
  736. if (!awch[0])
  737. {
  738. return S_OK;
  739. }
  740. if (m_iNumClientPull >= MAX_CLIENT_PULL_NUM)
  741. {
  742. return S_OK;
  743. }
  744. //TraceMsg(TF_THISMODULE, "CUrlDownload client pull (refresh=%d) url=%ws", uiTimeout, awch);
  745. if (uiTimeout > MAX_CLIENT_PULL_TIMEOUT)
  746. {
  747. return S_OK;
  748. }
  749. m_pwszClientPullURL = StrDupW(awch);
  750. // If we can't copy the URL, don't set the timer or else we'll
  751. // keep reloading the same page.
  752. if (m_pwszClientPullURL == NULL)
  753. return OLECMDERR_E_NOTSUPPORTED;
  754. return S_OK;
  755. }
  756. HRESULT CUrlDownload::SetDLCTL(long lFlags)
  757. {
  758. // TraceMsg(TF_THISMODULE, "CUrlDownload: SetDLCTL %04x", lFlags);
  759. m_lBindFlags = lFlags | DLCTL_SILENT;
  760. if (m_fSetResync)
  761. m_lBindFlags |= DLCTL_RESYNCHRONIZE;
  762. return S_OK;
  763. }
  764. #define INET_E_AGENT_BIND_IN_PROGRESS 0x800C0FFF
  765. HRESULT CUrlDownload::ProgressBytes(DWORD dwBytes)
  766. {
  767. if (m_dwMaxSize > 0 && dwBytes > m_dwMaxSize)
  768. {
  769. //TraceMsg(TF_THISMODULE, "CUrlDownload MaxSize exceeded aborting. %d of %d bytes", dwBytes, m_dwMaxSize);
  770. AbortDownload(BDU2_ERROR_MAXSIZE);
  771. return E_ABORT;
  772. }
  773. return S_OK;
  774. }
  775. //---------------------------------------------------------------
  776. // IServiceProvider
  777. STDMETHODIMP CUrlDownload::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
  778. {
  779. if ((SID_SHlinkFrame == guidService && IID_IHlinkFrame == riid) ||
  780. (IID_IAuthenticate == guidService && IID_IAuthenticate == riid) ||
  781. (SID_SInternetSecurityManager == guidService && IID_IInternetSecurityManager == riid))
  782. {
  783. return QueryInterface(riid, ppvObject);
  784. }
  785. else
  786. {
  787. *ppvObject = NULL;
  788. return E_NOINTERFACE;
  789. }
  790. }
  791. //---------------------------------------------------------------
  792. // IAuthenticate
  793. STDMETHODIMP CUrlDownload::Authenticate(HWND *phwnd, LPWSTR *ppszUsername, LPWSTR *ppszPassword)
  794. {
  795. HRESULT hr;
  796. ASSERT(phwnd && ppszUsername && ppszPassword);
  797. *phwnd = (HWND)-1;
  798. *ppszUsername = NULL;
  799. *ppszPassword = NULL;
  800. hr = E_NOTIMPL;
  801. //TraceMsg(TF_THISMODULE, "CUrlDownload::Authenticate returning hr=%08x", hr);
  802. return (hr);
  803. }
  804. //---------------------------------------------------------------
  805. // IHlinkFrame
  806. STDMETHODIMP CUrlDownload::SetBrowseContext(IHlinkBrowseContext *pihlbc)
  807. {
  808. return E_NOTIMPL;
  809. }
  810. STDMETHODIMP CUrlDownload::GetBrowseContext(IHlinkBrowseContext **ppihlbc)
  811. {
  812. return E_NOTIMPL;
  813. }
  814. STDMETHODIMP CUrlDownload::Navigate(DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pibsc, IHlink *pihlNavigate)
  815. {
  816. // We should only get a call through IHlinkFrame->Navigate()
  817. // when the webcrawler has submitted a form for authentication.
  818. // Bail out if that's not the case.
  819. if (!m_fFormSubmitted)
  820. {
  821. return E_NOTIMPL;
  822. }
  823. // Our timer has already been started. If this fails, OnDownloadComplete will get
  824. // called when we time out.
  825. // We don't support a wide variety of parameters.
  826. ASSERT(grfHLNF == 0);
  827. ASSERT(pbc);
  828. ASSERT(pibsc);
  829. ASSERT(pihlNavigate);
  830. // Get the moniker from IHlink
  831. HRESULT hr;
  832. IMoniker *pmk = NULL;
  833. hr = pihlNavigate->GetMonikerReference(HLINKGETREF_ABSOLUTE, &pmk, NULL);
  834. if (SUCCEEDED(hr))
  835. {
  836. // Load the URL with the post data.
  837. // REARCHITECT: What if we get redirected to something other than HTML? (beta 2)
  838. hr = m_pPersistMk->Load(FALSE, pmk, pbc, 0);
  839. SAFERELEASE(pmk);
  840. if (SUCCEEDED(hr))
  841. {
  842. m_fBrowserValid = TRUE;
  843. // Need to wait again.
  844. m_fWaitingForReadyState = TRUE;
  845. }
  846. }
  847. return (hr);
  848. }
  849. STDMETHODIMP CUrlDownload::OnNavigate(DWORD grfHLNF, IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, DWORD dwreserved)
  850. {
  851. return E_NOTIMPL;
  852. }
  853. STDMETHODIMP CUrlDownload::UpdateHlink(ULONG uHLID, IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
  854. {
  855. return E_NOTIMPL;
  856. }
  857. //---------------------------------------------------------------------
  858. // IInternetSecurityManager interface
  859. // Used to override security to allow form submits, for form auth sites
  860. HRESULT CUrlDownload::SetSecuritySite(IInternetSecurityMgrSite *pSite)
  861. {
  862. return E_NOTIMPL;
  863. }
  864. HRESULT CUrlDownload::GetSecuritySite(IInternetSecurityMgrSite **ppSite)
  865. {
  866. return E_NOTIMPL;
  867. }
  868. HRESULT CUrlDownload::MapUrlToZone(LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags)
  869. {
  870. return INET_E_DEFAULT_ACTION;
  871. }
  872. HRESULT CUrlDownload::GetSecurityId(LPCWSTR pwszUrl, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
  873. {
  874. return INET_E_DEFAULT_ACTION;
  875. }
  876. HRESULT CUrlDownload::ProcessUrlAction(LPCWSTR pwszUrl, DWORD dwAction, BYTE __RPC_FAR *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved)
  877. {
  878. if ((dwAction == URLACTION_HTML_SUBMIT_FORMS_TO) ||
  879. (dwAction == URLACTION_HTML_SUBMIT_FORMS_FROM))
  880. {
  881. return S_OK;
  882. }
  883. return INET_E_DEFAULT_ACTION;
  884. }
  885. HRESULT CUrlDownload::QueryCustomPolicy(LPCWSTR pwszUrl, REFGUID guidKey, BYTE **ppPolicy, DWORD *pcbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwReserved)
  886. {
  887. return INET_E_DEFAULT_ACTION;
  888. }
  889. HRESULT CUrlDownload::SetZoneMapping(DWORD dwZone, LPCWSTR lpszPattern, DWORD dwFlags)
  890. {
  891. return INET_E_DEFAULT_ACTION;
  892. }
  893. HRESULT CUrlDownload::GetZoneMappings(DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags)
  894. {
  895. return INET_E_DEFAULT_ACTION;
  896. }
  897. //
  898. // IOleClientSite
  899. //
  900. STDMETHODIMP CUrlDownload:: SaveObject(void)
  901. {
  902. return E_NOTIMPL;
  903. }
  904. STDMETHODIMP CUrlDownload:: GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)
  905. {
  906. return E_NOTIMPL;
  907. }
  908. STDMETHODIMP CUrlDownload:: GetContainer(IOleContainer **ppContainer)
  909. {
  910. return E_NOTIMPL;
  911. }
  912. STDMETHODIMP CUrlDownload:: ShowObject(void)
  913. {
  914. return E_NOTIMPL;
  915. }
  916. STDMETHODIMP CUrlDownload:: OnShowWindow(BOOL fShow)
  917. {
  918. return E_NOTIMPL;
  919. }
  920. STDMETHODIMP CUrlDownload:: RequestNewObjectLayout(void)
  921. {
  922. return E_NOTIMPL;
  923. }
  924. // ParseRefreshContent was lifted in its entirety from shdocvw\basesb.cpp
  925. BOOL DLParseRefreshContent(LPWSTR pwzContent,
  926. UINT * puiDelay, LPWSTR pwzUrlBuf, UINT cchUrlBuf)
  927. {
  928. // We are parsing the following string:
  929. //
  930. // [ws]* [0-9]+ [ws]* ; [ws]* url [ws]* = [ws]* { ' | " } [any]* { ' | " }
  931. //
  932. // Netscape insists that the string begins with a delay. If not, it
  933. // ignores the entire directive. There can be more than one URL mentioned,
  934. // and the last one wins. An empty URL is treated the same as not having
  935. // a URL at all. An empty URL which follows a non-empty URL resets
  936. // the previous URL.
  937. enum { PRC_START, PRC_DIG, PRC_DIG_WS, PRC_SEMI, PRC_SEMI_URL,
  938. PRC_SEMI_URL_EQL, PRC_SEMI_URL_EQL_ANY };
  939. #define ISSPACE(ch) (((ch) == 32) || ((unsigned)((ch) - 9)) <= 13 - 9)
  940. UINT uiState = PRC_START;
  941. UINT uiDelay = 0;
  942. LPWSTR pwz = pwzContent;
  943. LPWSTR pwzUrl = NULL;
  944. UINT cchUrl = 0;
  945. WCHAR wch, wchDel = 0;
  946. *pwzUrlBuf = 0;
  947. do
  948. {
  949. wch = *pwz;
  950. switch (uiState)
  951. {
  952. case PRC_START:
  953. if (wch >= TEXT('0') && wch <= TEXT('9'))
  954. {
  955. uiState = PRC_DIG;
  956. uiDelay = wch - TEXT('0');
  957. }
  958. else if (!ISSPACE(wch))
  959. goto done;
  960. break;
  961. case PRC_DIG:
  962. if (wch >= TEXT('0') && wch <= TEXT('9'))
  963. uiDelay = uiDelay * 10 + wch - TEXT('0');
  964. else if (ISSPACE(wch))
  965. uiState = PRC_DIG_WS;
  966. else if (wch == TEXT(';'))
  967. uiState = PRC_SEMI;
  968. else
  969. goto done;
  970. break;
  971. case PRC_DIG_WS:
  972. if (wch == TEXT(';'))
  973. uiState = PRC_SEMI;
  974. else if (!ISSPACE(wch))
  975. goto done;
  976. break;
  977. case PRC_SEMI:
  978. if ( (wch == TEXT('u') || wch == TEXT('U'))
  979. && (pwz[1] == TEXT('r') || pwz[1] == TEXT('R'))
  980. && (pwz[2] == TEXT('l') || pwz[2] == TEXT('L')))
  981. {
  982. uiState = PRC_SEMI_URL;
  983. pwz += 2;
  984. }
  985. else if (!ISSPACE(wch) && wch != TEXT(';'))
  986. goto done;
  987. break;
  988. case PRC_SEMI_URL:
  989. if (wch == TEXT('='))
  990. {
  991. uiState = PRC_SEMI_URL_EQL;
  992. *pwzUrlBuf = 0;
  993. }
  994. else if (wch == TEXT(';'))
  995. uiState = PRC_SEMI;
  996. else if (!ISSPACE(wch))
  997. goto done;
  998. break;
  999. case PRC_SEMI_URL_EQL:
  1000. if (wch == TEXT(';'))
  1001. uiState = PRC_SEMI;
  1002. else if (!ISSPACE(wch))
  1003. {
  1004. uiState = PRC_SEMI_URL_EQL_ANY;
  1005. pwzUrl = pwzUrlBuf;
  1006. cchUrl = cchUrlBuf;
  1007. if (wch == TEXT('\'')|| wch == TEXT('\"'))
  1008. wchDel = wch;
  1009. else
  1010. {
  1011. wchDel = 0;
  1012. *pwzUrl++ = wch;
  1013. cchUrl--;
  1014. }
  1015. }
  1016. break;
  1017. case PRC_SEMI_URL_EQL_ANY:
  1018. if ( !wch
  1019. || ( wchDel && wch == wchDel)
  1020. || (!wchDel && wch == L';'))
  1021. {
  1022. *pwzUrl = 0;
  1023. uiState = wch == TEXT(';') ? PRC_SEMI : PRC_DIG_WS;
  1024. }
  1025. else if (cchUrl > 1)
  1026. {
  1027. *pwzUrl++ = wch;
  1028. cchUrl--;
  1029. }
  1030. break;
  1031. }
  1032. ++pwz;
  1033. } while (wch);
  1034. done:
  1035. *puiDelay = uiDelay;
  1036. return(uiState >= PRC_DIG);
  1037. } // ParseRefreshContent