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.

1957 lines
56 KiB

  1. // --------------------------------------------------------------------------------
  2. // Mhtmlurl.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "mhtmlurl.h"
  8. #include "icoint.h"
  9. #include "dllmain.h"
  10. #include "booktree.h"
  11. #include "shlwapi.h"
  12. #include "shlwapip.h"
  13. #include <demand.h>
  14. #include "icdebug.h"
  15. #include "stmlock.h"
  16. #include "strconst.h"
  17. #include "mimeapi.h"
  18. // --------------------------------------------------------------------------------
  19. // TraceProtocol
  20. // --------------------------------------------------------------------------------
  21. #define TraceProtocol(_pszFunction) \
  22. DOUTL(APP_DOUTL, "%08x > 0x%08X CActiveUrlRequest::%s (RootUrl = '%s', BodyUrl = '%s')", GetCurrentThreadId(), this, _pszFunction, m_pszRootUrl ? m_pszRootUrl : "", m_pszBodyUrl ? m_pszBodyUrl : "")
  23. // --------------------------------------------------------------------------------
  24. // AcitveUrlRequest_CreateInstance
  25. // --------------------------------------------------------------------------------
  26. HRESULT IMimeHtmlProtocol_CreateInstance(IUnknown *pUnkOuter, IUnknown** ppUnknown)
  27. {
  28. // Invalid Arg
  29. Assert(ppUnknown);
  30. // Initialize
  31. *ppUnknown = NULL;
  32. // Set the mimeole compat mode
  33. MimeOleSetCompatMode(MIMEOLE_COMPAT_OE5);
  34. // Create me
  35. CActiveUrlRequest *pNew = new CActiveUrlRequest(pUnkOuter);
  36. if (NULL == pNew)
  37. return TrapError(E_OUTOFMEMORY);
  38. // Return the Innter
  39. *ppUnknown = pNew->GetInner();
  40. // Done
  41. return S_OK;
  42. }
  43. // --------------------------------------------------------------------------------
  44. // CActiveUrlRequest::CActiveUrlRequest
  45. // --------------------------------------------------------------------------------
  46. CActiveUrlRequest::CActiveUrlRequest(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter)
  47. {
  48. DllAddRef();
  49. m_pProtSink = NULL;
  50. m_pBindInfo = NULL;
  51. m_pszRootUrl = NULL;
  52. m_pszBodyUrl = NULL;
  53. m_pUnkKeepAlive = NULL;
  54. m_pNext = NULL;
  55. m_pPrev = NULL;
  56. m_dwState = 0;
  57. m_pStream = NULL;
  58. m_hNeedFile = INVALID_HANDLE_VALUE;
  59. m_dwBSCF = 0;
  60. InitializeCriticalSection(&m_cs);
  61. TraceProtocol("CActiveUrlRequest");
  62. }
  63. // --------------------------------------------------------------------------------
  64. // CActiveUrlRequest::~CActiveUrlRequest
  65. // --------------------------------------------------------------------------------
  66. CActiveUrlRequest::~CActiveUrlRequest(void)
  67. {
  68. // Tracing
  69. TraceProtocol("~CActiveUrlRequest");
  70. // These should have been release in IOInetProtocl::Terminate
  71. Assert(NULL == m_pProtSink && NULL == m_pBindInfo && NULL == m_pUnkKeepAlive);
  72. // Release the protcol object just in case
  73. SafeRelease(m_pProtSink);
  74. SafeRelease(m_pBindInfo);
  75. SafeMemFree(m_pszRootUrl);
  76. SafeMemFree(m_pszBodyUrl);
  77. SafeRelease(m_pUnkKeepAlive);
  78. SafeRelease(m_pStream);
  79. // Close file...
  80. if (INVALID_HANDLE_VALUE != m_hNeedFile)
  81. CloseHandle(m_hNeedFile);
  82. // Kill the CS
  83. DeleteCriticalSection(&m_cs);
  84. // Release the Dll
  85. DllRelease();
  86. }
  87. // --------------------------------------------------------------------------------
  88. // CActiveUrlRequest::PrivateQueryInterface
  89. // --------------------------------------------------------------------------------
  90. HRESULT CActiveUrlRequest::PrivateQueryInterface(REFIID riid, LPVOID *ppv)
  91. {
  92. // Locals
  93. HRESULT hr=S_OK;
  94. // check params
  95. if (ppv == NULL)
  96. return TrapError(E_INVALIDARG);
  97. // Init
  98. *ppv = NULL;
  99. // Find IID
  100. if (IID_IOInetProtocol == riid)
  101. *ppv = (IOInetProtocol *)this;
  102. else if (IID_IOInetProtocolInfo == riid)
  103. *ppv = (IOInetProtocolInfo *)this;
  104. else if (IID_IOInetProtocolRoot == riid)
  105. *ppv = (IOInetProtocolRoot *)this;
  106. else if (IID_IServiceProvider == riid)
  107. *ppv = (IServiceProvider *)this;
  108. else
  109. {
  110. hr = TrapError(E_NOINTERFACE);
  111. goto exit;
  112. }
  113. // AddRef It
  114. ((IUnknown *)*ppv)->AddRef();
  115. exit:
  116. // Done
  117. return hr;
  118. }
  119. // --------------------------------------------------------------------------------
  120. // CActiveUrlRequest::_HrInitializeNeedFile
  121. // --------------------------------------------------------------------------------
  122. HRESULT CActiveUrlRequest::_HrInitializeNeedFile(LPMESSAGETREE pTree, HBODY hBody)
  123. {
  124. // Locals
  125. HRESULT hr=S_OK;
  126. CHAR szFilePath[MAX_PATH + MAX_PATH];
  127. ULONG cch;
  128. LPSTR pszFilePath=NULL;
  129. LPWSTR pwszFile=NULL;
  130. // Invalid Args
  131. Assert(INVALID_HANDLE_VALUE == m_hNeedFile);
  132. // Don't need a file ?
  133. if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
  134. goto exit;
  135. // Set sizeof szFilePath
  136. cch = ARRAYSIZE(szFilePath);
  137. // If cid:
  138. if (!m_pszBodyUrl || StrCmpNIA(m_pszBodyUrl, "cid:", 4) == 0 || FAILED(PathCreateFromUrlA(m_pszBodyUrl, szFilePath, &cch, 0)))
  139. {
  140. // Create temp file (m_pszFileName could be null)
  141. CHECKHR(hr = CreateTempFile(NULL, NULL, &pszFilePath, &m_hNeedFile));
  142. }
  143. else
  144. {
  145. // Create temp file
  146. CHECKHR(hr = CreateTempFile(szFilePath, NULL, &pszFilePath, &m_hNeedFile));
  147. }
  148. // Convert To Unicode
  149. CHECKALLOC(pwszFile = PszToUnicode(CP_ACP, pszFilePath));
  150. // Enter global Critical Section
  151. DeleteTempFileOnShutdownEx(pszFilePath, NULL);
  152. // Don't Free this
  153. pszFilePath = NULL;
  154. // Report the File...
  155. SideAssert(SUCCEEDED(m_pProtSink->ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE, pwszFile)));
  156. exit:
  157. // Cleanup
  158. SafeMemFree(pwszFile);
  159. SafeMemFree(pszFilePath);
  160. // Done
  161. return hr;
  162. }
  163. // --------------------------------------------------------------------------------
  164. // CActiveUrlRequest::OnFullyAvailable
  165. // --------------------------------------------------------------------------------
  166. void CActiveUrlRequest::OnFullyAvailable(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody)
  167. {
  168. // Locals
  169. HRESULT hr=S_OK;
  170. ULONG cb;
  171. // Invalid Arg
  172. Assert(pszCntType && pStream);
  173. // Thread Safety
  174. EnterCriticalSection(&m_cs);
  175. // Validate the state
  176. Assert(m_pProtSink && pStream && NULL == m_pStream);
  177. // Tracing
  178. TraceProtocol("OnFullyAvailable");
  179. // Feed the content-type to trident
  180. m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType);
  181. // GetNeedFile
  182. CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody));
  183. // Create Stream Lock wrapper
  184. m_pStream = pStream;
  185. m_pStream->AddRef();
  186. // Rewind that bad boy
  187. CHECKHR(hr = HrRewindStream(m_pStream));
  188. // Were complete
  189. FLAGSET(m_dwState, REQSTATE_DOWNLOADED);
  190. // Initialize bind status callback falgs
  191. m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
  192. // Go into report data loop
  193. CHECKHR(hr = _HrReportData());
  194. // First Report Data
  195. if (m_pProtSink)
  196. m_pProtSink->ReportResult(S_OK, 0, NULL);
  197. // We have reported the result
  198. FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
  199. exit:
  200. // Failure
  201. if (FAILED(hr))
  202. _ReportResult(hr);
  203. // Thread Safety
  204. LeaveCriticalSection(&m_cs);
  205. }
  206. // --------------------------------------------------------------------------------
  207. // CActiveUrlRequest::OnStartBinding
  208. // --------------------------------------------------------------------------------
  209. void CActiveUrlRequest::OnStartBinding(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody)
  210. {
  211. // Locals
  212. HRESULT hr=S_OK;
  213. // Thread Safety
  214. EnterCriticalSection(&m_cs);
  215. // Validate the state
  216. Assert(m_pProtSink && pStream && NULL == m_pStream);
  217. // Tracing
  218. TraceProtocol("OnBinding(pszCntType, pStream)");
  219. // Feed the content-type to trident
  220. m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType ? pszCntType : L"application/octet-stream");
  221. // GetNeedFile
  222. CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody));
  223. // Create Stream Lock wrapper
  224. m_pStream = pStream;
  225. m_pStream->AddRef();
  226. // Rewind that bad boy
  227. CHECKHR(hr = HrRewindStream(m_pStream));
  228. // Initialize bind status callback falgs
  229. m_dwBSCF = BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION;
  230. // Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available)
  231. if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
  232. {
  233. // Report me some data
  234. CHECKHR(hr = _HrReportData());
  235. }
  236. exit:
  237. // Failure
  238. if (FAILED(hr))
  239. _ReportResult(hr);
  240. // Thread Safety
  241. LeaveCriticalSection(&m_cs);
  242. }
  243. // --------------------------------------------------------------------------------
  244. // CActiveUrlRequest::OnBindingDataAvailable
  245. // --------------------------------------------------------------------------------
  246. void CActiveUrlRequest::OnBindingDataAvailable(void)
  247. {
  248. // Locals
  249. HRESULT hr=S_OK;
  250. // Thread Safety
  251. EnterCriticalSection(&m_cs);
  252. // Validate the state
  253. Assert(m_pProtSink && m_pStream);
  254. // Tracing
  255. TraceProtocol("OnBindingDataAvailable");
  256. // Initialize bind status callback falgs
  257. FLAGSET(m_dwBSCF, BSCF_INTERMEDIATEDATANOTIFICATION);
  258. // Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available)
  259. if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
  260. {
  261. // Report some data
  262. CHECKHR(hr = _HrReportData());
  263. }
  264. exit:
  265. // Failure
  266. if (FAILED(hr))
  267. _ReportResult(hr);
  268. // Thread Safety
  269. LeaveCriticalSection(&m_cs);
  270. }
  271. // --------------------------------------------------------------------------------
  272. // CActiveUrlRequest::OnBindingComplete
  273. // --------------------------------------------------------------------------------
  274. void CActiveUrlRequest::OnBindingComplete(HRESULT hrResult)
  275. {
  276. // Locals
  277. HRESULT hr=S_OK;
  278. // Thread Safety
  279. EnterCriticalSection(&m_cs);
  280. // Were complete
  281. FLAGSET(m_dwState, INETPROT_DOWNLOADED);
  282. // Tracing
  283. TraceProtocol("OnBindingComplete");
  284. // No Sink ?
  285. if (NULL == m_pProtSink)
  286. return;
  287. // Failure
  288. if (FAILED(hrResult))
  289. {
  290. _ReportResult(hrResult);
  291. goto exit;
  292. }
  293. // Initialize bind status callback falgs
  294. m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION;
  295. // Report last amount of data
  296. CHECKHR(hr = _HrReportData());
  297. // Tell sink to use the default protocol
  298. m_pProtSink->ReportResult(S_OK, 0, NULL);
  299. // We have reported the result
  300. FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
  301. exit:
  302. // Failure
  303. if (FAILED(hr))
  304. _ReportResult(hr);
  305. // Thread Safety
  306. LeaveCriticalSection(&m_cs);
  307. }
  308. // --------------------------------------------------------------------------------
  309. // CActiveUrlRequest::_ReportResult
  310. // --------------------------------------------------------------------------------
  311. void CActiveUrlRequest::_ReportResult(HRESULT hrResult)
  312. {
  313. // Locals
  314. LPWSTR pwszRedirUrl=NULL;
  315. // We should have a sink
  316. Assert(m_pProtSink);
  317. // No Sink ?
  318. if (m_pProtSink && !ISFLAGSET(m_dwState, REQSTATE_RESULTREPORTED))
  319. {
  320. // If Failure
  321. if (FAILED(hrResult))
  322. {
  323. // If we have a body Url
  324. if (m_pszBodyUrl)
  325. pwszRedirUrl = PszToUnicode(CP_ACP, m_pszBodyUrl);
  326. // Report Result,
  327. if (pwszRedirUrl)
  328. {
  329. TraceProtocol("_ReportResult(BINDSTATUS_REDIRECTING)");
  330. m_pProtSink->ReportResult(INET_E_REDIRECTING, 0, pwszRedirUrl);
  331. }
  332. else
  333. {
  334. TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)");
  335. m_pProtSink->ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER, 0, NULL);
  336. }
  337. }
  338. // Otherwise, report the result
  339. else
  340. {
  341. TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)");
  342. m_pProtSink->ReportResult(S_OK, 0, NULL);
  343. }
  344. // Cleanup
  345. SafeMemFree(pwszRedirUrl);
  346. // We have reported the result
  347. FLAGSET(m_dwState, REQSTATE_RESULTREPORTED);
  348. }
  349. }
  350. // --------------------------------------------------------------------------------
  351. // CActiveUrlRequest::_HrReportData
  352. // --------------------------------------------------------------------------------
  353. HRESULT CActiveUrlRequest::_HrReportData(void)
  354. {
  355. // Locals
  356. HRESULT hr=S_OK;
  357. // We better have a data source
  358. Assert(m_pStream);
  359. // Tracing
  360. TraceProtocol("_HrReportData");
  361. // BINDF_NEEDFILE
  362. if (ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE))
  363. {
  364. // Dump to File
  365. CHECKHR(hr = _HrStreamToNeedFile());
  366. }
  367. else
  368. {
  369. // Report Data
  370. SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0)));
  371. }
  372. exit:
  373. // Done
  374. return hr;
  375. }
  376. // --------------------------------------------------------------------------------
  377. // CActiveUrlRequest::_HrStreamToNeedFile
  378. // --------------------------------------------------------------------------------
  379. HRESULT CActiveUrlRequest::_HrStreamToNeedFile(void)
  380. {
  381. // Locals
  382. HRESULT hr=S_OK;
  383. ULONG cbTotal=0;
  384. // We better have a needfile
  385. Assert(INVALID_HANDLE_VALUE != m_hNeedFile && ISFLAGSET(m_dwState, REQSTATE_DOWNLOADED));
  386. // Write the stream to a file
  387. hr = WriteStreamToFileHandle(m_pStream, m_hNeedFile, &cbTotal);
  388. if (FAILED(hr) && E_PENDING != hr)
  389. {
  390. TrapError(hr);
  391. goto exit;
  392. }
  393. // Close the 77file
  394. CloseHandle(m_hNeedFile);
  395. m_hNeedFile = INVALID_HANDLE_VALUE;
  396. // Rewind the stream incase urlmon trys to read from me as well
  397. HrRewindStream(m_pStream);
  398. // All the data is there
  399. SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0)));
  400. exit:
  401. // Done
  402. return hr;
  403. }
  404. // --------------------------------------------------------------------------------
  405. // CActiveUrlRequest::Start
  406. // --------------------------------------------------------------------------------
  407. STDMETHODIMP CActiveUrlRequest::Start(LPCWSTR pwszUrl, IOInetProtocolSink *pProtSink,
  408. IOInetBindInfo *pBindInfo, DWORD grfSTI, HANDLE_PTR dwReserved)
  409. {
  410. // Locals
  411. HRESULT hr=S_OK;
  412. LPSTR pszUrl=NULL;
  413. LPMESSAGETREE pTree=NULL;
  414. DWORD dwBindF;
  415. BINDINFO rBindInfo;
  416. // Invalid Args
  417. if (NULL == pwszUrl || NULL == pProtSink || NULL == pBindInfo)
  418. return TrapError(E_INVALIDARG);
  419. // Thread Safety
  420. EnterCriticalSection(&m_cs);
  421. // Check State
  422. Assert(g_pUrlCache && m_pProtSink == NULL && m_pBindInfo == NULL);
  423. // BINDF_NEEDFILE
  424. ZeroMemory(&rBindInfo, sizeof(BINDINFO));
  425. rBindInfo.cbSize = sizeof(BINDINFO);
  426. if (SUCCEEDED(pBindInfo->GetBindInfo(&dwBindF, &rBindInfo)) && ISFLAGSET(dwBindF, BINDF_NEEDFILE))
  427. {
  428. // Set Flag
  429. FLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE);
  430. }
  431. // Assume the Sink
  432. m_pProtSink = pProtSink;
  433. m_pProtSink->AddRef();
  434. // Assume the BindInfo
  435. m_pBindInfo = pBindInfo;
  436. m_pBindInfo->AddRef();
  437. // Dup the Url
  438. CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl));
  439. // Unescape inplace
  440. CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
  441. // Split the Url
  442. CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &m_pszRootUrl, &m_pszBodyUrl));
  443. // for security purposes, disallow navigate using the mhtml protocl in IE except with correct ext
  444. // wait to do this check until after we have a protocol sink to report the error and we've parsed
  445. // out the root url
  446. if (StrCmpNI(m_pszRootUrl, TEXT("mid:"), 4) && GetModuleHandle(TEXT("IEXPLORE.EXE")))
  447. {
  448. LPTSTR pszExt = PathFindExtension(m_pszRootUrl);
  449. if (!pszExt || (StrCmpI(pszExt, TEXT(".mht")) && StrCmpI(pszExt, TEXT(".mhtml"))))
  450. {
  451. hr = INET_E_SECURITY_PROBLEM;
  452. goto exit;
  453. }
  454. }
  455. // Tracing
  456. TraceProtocol("Start");
  457. // Try to resolve the root url
  458. CHECKHR(hr = g_pUrlCache->ActiveObjectFromUrl(m_pszRootUrl, TRUE, IID_CMessageTree, (LPVOID *)&pTree, &m_pUnkKeepAlive));
  459. // Ask the BindTree to Resolve this Url
  460. CHECKHR(hr = pTree->HrActiveUrlRequest(this));
  461. exit:
  462. // Cleanup
  463. SafeMemFree(pszUrl);
  464. SafeRelease(pTree);
  465. // Failure
  466. //if (FAILED(hr))
  467. // _ReportResult(E_FAIL);
  468. // Thread Safety
  469. LeaveCriticalSection(&m_cs);
  470. // Done
  471. return hr;
  472. }
  473. // --------------------------------------------------------------------------------
  474. // CActiveUrlRequest::Terminate
  475. // --------------------------------------------------------------------------------
  476. STDMETHODIMP CActiveUrlRequest::Terminate(DWORD dwOptions)
  477. {
  478. // Thread Safety
  479. EnterCriticalSection(&m_cs);
  480. // Tracing
  481. TraceProtocol("Terminate");
  482. // Release Objects
  483. SafeRelease(m_pProtSink);
  484. SafeRelease(m_pBindInfo);
  485. SafeRelease(m_pUnkKeepAlive);
  486. // Thread Safety
  487. LeaveCriticalSection(&m_cs);
  488. // Done
  489. return S_OK;
  490. }
  491. // --------------------------------------------------------------------------------
  492. // CActiveUrlRequest::Read (IOInetProtocol)
  493. // --------------------------------------------------------------------------------
  494. STDMETHODIMP CActiveUrlRequest::Read(LPVOID pv,ULONG cb, ULONG *pcbRead)
  495. {
  496. // Locals
  497. HRESULT hr=S_OK;
  498. ULONG cbRead;
  499. // Init
  500. if (pcbRead)
  501. *pcbRead = 0;
  502. // No Stream Yet
  503. if (NULL == m_pStream)
  504. {
  505. Assert(FALSE);
  506. hr = TrapError(E_FAIL);
  507. goto exit;
  508. }
  509. // Read from the external offset
  510. CHECKHR(hr = m_pStream->Read(pv, cb, &cbRead));
  511. // Done
  512. if (0 == cbRead)
  513. {
  514. // S_FALSE = Were Done, E_PENDING = more data is coming
  515. hr = (ISFLAGSET(m_dwState, INETPROT_DOWNLOADED)) ? S_FALSE : E_PENDING;
  516. }
  517. // Otherwise, set to ok
  518. else
  519. hr = S_OK;
  520. // Return pcbRead
  521. if (pcbRead)
  522. *pcbRead = cbRead;
  523. exit:
  524. // Done
  525. return hr;
  526. }
  527. // --------------------------------------------------------------------------------
  528. // CActiveUrlRequest::Seek (IOInetProtocol)
  529. // --------------------------------------------------------------------------------
  530. STDMETHODIMP CActiveUrlRequest::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
  531. {
  532. // Locals
  533. HRESULT hr=S_OK;
  534. // Thread Safety
  535. EnterCriticalSection(&m_cs);
  536. // Tracing
  537. TraceProtocol("Seek");
  538. // No Stream Yet
  539. if (NULL == m_pStream)
  540. {
  541. Assert(FALSE);
  542. hr = TrapError(E_FAIL);
  543. goto exit;
  544. }
  545. // Call Utility Function
  546. CHECKHR(hr = m_pStream->Seek(dlibMove, dwOrigin, plibNew));
  547. exit:
  548. // Thread Safety
  549. LeaveCriticalSection(&m_cs);
  550. // Done
  551. return hr;
  552. }
  553. // --------------------------------------------------------------------------------
  554. // CActiveUrlRequest::QueryService
  555. // --------------------------------------------------------------------------------
  556. STDMETHODIMP CActiveUrlRequest::QueryService(REFGUID rsid, REFIID riid, void **ppvObject) /* IServiceProvider */
  557. {
  558. // Locals
  559. HRESULT hr=S_OK;
  560. IServiceProvider *pSP=NULL;
  561. // Thread Safety
  562. EnterCriticalSection(&m_cs);
  563. // Tracing
  564. TraceProtocol("QueryService");
  565. // No Protocol Sink Yet ?
  566. if (NULL == m_pProtSink)
  567. {
  568. hr = TrapError(E_UNEXPECTED);
  569. goto exit;
  570. }
  571. // QI the Sink for the IServiceProvider
  572. CHECKHR(hr = m_pProtSink->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP));
  573. // Query Service the Service Provider
  574. CHECKHR(hr = pSP->QueryService(rsid, riid, ppvObject));
  575. exit:
  576. // Cleanup
  577. SafeRelease(pSP);
  578. // Thread Safety
  579. LeaveCriticalSection(&m_cs);
  580. // Done
  581. return hr;
  582. }
  583. // --------------------------------------------------------------------------------
  584. // CActiveUrlRequest::_FillReturnString
  585. // --------------------------------------------------------------------------------
  586. HRESULT CActiveUrlRequest::_FillReturnString(LPCWSTR pszUrl, DWORD cchUrl, LPWSTR pszResult,
  587. DWORD cchResult, DWORD *pcchResult)
  588. {
  589. // Locals
  590. HRESULT hr=S_OK;
  591. // Want the Size
  592. if (pcchResult)
  593. *pcchResult = cchUrl;
  594. // No return value
  595. if (NULL == pszResult)
  596. goto exit;
  597. // Dest is big enought
  598. if (cchResult < cchUrl+1)
  599. {
  600. hr = TrapError(E_FAIL);
  601. goto exit;
  602. }
  603. // Copy to dest buffer
  604. CopyMemory((LPBYTE)pszResult, (LPBYTE)pszUrl, ((cchUrl + 1) * sizeof(WCHAR)));
  605. exit:
  606. // Done
  607. return hr;
  608. }
  609. // --------------------------------------------------------------------------------
  610. // CActiveUrlRequest::ParseUrl
  611. // --------------------------------------------------------------------------------
  612. STDMETHODIMP CActiveUrlRequest::ParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction,
  613. DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
  614. {
  615. // Locals
  616. HRESULT hr=S_OK;
  617. ULONG cchUrl;
  618. LPSTR pszUrl=NULL;
  619. LPSTR pszRootUrl=NULL;
  620. LPSTR pszBodyUrl=NULL;
  621. LPWSTR pwszBodyUrl=NULL;
  622. LPWSTR pszRootUrlW=NULL;
  623. LPWSTR pszSecurityUrlW=NULL;
  624. PROPVARIANT rVariant;
  625. // Invalid Arg
  626. if (NULL == pwzUrl)
  627. return TrapError(E_INVALIDARG);
  628. // Tracing
  629. DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::ParseUrl (pwzUrl = %ls)", GetCurrentThreadId(), this, pwzUrl);
  630. // Setup Variant
  631. ZeroMemory(&rVariant, sizeof(PROPVARIANT));
  632. // Only handle PARSE_CANONICALIZE
  633. if (PARSE_CANONICALIZE == ParseAction)
  634. {
  635. // Fill return value
  636. CHECKHR(hr = _FillReturnString(pwzUrl, lstrlenW(pwzUrl), pwzResult, cchResult, pcchResult));
  637. }
  638. // Strip MHTML: and return
  639. #ifndef WIN16
  640. else if (StrCmpNIW(pwzUrl, L"mhtml:", 6) == 0)
  641. #else
  642. else if (StrCmpNIW(pwzUrl, "mhtml:", 6) == 0)
  643. #endif // !WIN16
  644. {
  645. // If Getting Friendly
  646. if (PARSE_FRIENDLY == ParseAction)
  647. {
  648. // To ANSI
  649. CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl));
  650. // Split It
  651. CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl));
  652. // Convert To Unicode
  653. CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl));
  654. // Fill return value
  655. CHECKHR(hr = _FillReturnString(pwszBodyUrl, lstrlenW(pwszBodyUrl), pwzResult, cchResult, pcchResult));
  656. }
  657. // If the content-location is available, use it as the security URL
  658. else if (PARSE_SECURITY_URL == ParseAction)
  659. {
  660. BOOL fGotSecURL = FALSE;
  661. LPMESSAGETREE pTree=NULL;
  662. HBODY hBody;
  663. IInternetSecurityManager *pISM;
  664. DWORD dwZone=URLZONE_UNTRUSTED;
  665. // Base to ANSI
  666. CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl));
  667. // UnEscape the Url
  668. CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
  669. // Split It
  670. CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl));
  671. // RootUrl to UNICODE
  672. CHECKALLOC(pszRootUrlW = PszToUnicode(CP_ACP, pszRootUrl));
  673. // Check and see what ZONE the root url is running in
  674. if (CoInternetCreateSecurityManager(NULL, &pISM, 0)==S_OK)
  675. {
  676. pISM->MapUrlToZone(pszRootUrlW, &dwZone, 0);
  677. pISM->Release();
  678. }
  679. // default to the root-body part
  680. pszSecurityUrlW = pszRootUrlW;
  681. // if the root url is in the local-machine, then respect the Content-Location header
  682. // as the source of the url, otherwise defer to the root url
  683. if ((dwZone == URLZONE_LOCAL_MACHINE) &&
  684. SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL)))
  685. {
  686. if ( (pszBodyUrl != NULL && SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, &hBody))) ||
  687. SUCCEEDED(pTree->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBody)))
  688. {
  689. // Locals
  690. LPWSTR pwszSecURL = NULL;
  691. PSUACTION psua = (dwParseFlags == PSU_SECURITY_URL_ONLY)? PSU_SECURITY_URL_ONLY: PSU_DEFAULT;
  692. rVariant.vt = VT_LPWSTR;
  693. if (SUCCEEDED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant)) && rVariant.pwszVal && *rVariant.pwszVal)
  694. {
  695. pszSecurityUrlW = rVariant.pwszVal;
  696. }
  697. SafeMemFree(pwszSecURL);
  698. }
  699. }
  700. // Fill return value
  701. CHECKHR(hr = _FillReturnString(pszSecurityUrlW, lstrlenW(pszSecurityUrlW), pwzResult, cchResult, pcchResult));
  702. SafeRelease(pTree);
  703. }
  704. else if (PARSE_ENCODE == ParseAction)
  705. {
  706. hr = INET_E_DEFAULT_ACTION;
  707. }
  708. // Simply remove mhtml:
  709. else
  710. {
  711. // Fill return value
  712. CHECKHR(hr = _FillReturnString(pwzUrl + 6, lstrlenW(pwzUrl) - 6, pwzResult, cchResult, pcchResult));
  713. }
  714. }
  715. // INET_E_DEFAULT_ACTION
  716. else
  717. {
  718. hr = INET_E_DEFAULT_ACTION;
  719. goto exit;
  720. }
  721. exit:
  722. // Cleanup
  723. SafeMemFree(pszUrl);
  724. SafeMemFree(pszRootUrl);
  725. SafeMemFree(pszRootUrlW);
  726. SafeMemFree(pszBodyUrl);
  727. SafeMemFree(pwszBodyUrl);
  728. SafeMemFree(rVariant.pwszVal);
  729. // Done
  730. return hr;
  731. }
  732. // --------------------------------------------------------------------------------
  733. // CActiveUrlRequest::QueryInfo
  734. // --------------------------------------------------------------------------------
  735. STDMETHODIMP CActiveUrlRequest::QueryInfo(LPCWSTR pwzUrl, QUERYOPTION OueryOption,
  736. DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD *pcbBuf, DWORD dwReserved)
  737. {
  738. // QUERY_RECOMBINE
  739. if (QUERY_RECOMBINE == OueryOption)
  740. {
  741. // Sure
  742. if (cbBuffer < sizeof(DWORD))
  743. return S_FALSE;
  744. // True
  745. DWORD dw=TRUE;
  746. CopyMemory(pBuffer, &dw, sizeof(dw));
  747. *pcbBuf = sizeof(dw);
  748. // Done
  749. return S_OK;
  750. }
  751. // Failure
  752. return INET_E_QUERYOPTION_UNKNOWN;
  753. }
  754. // --------------------------------------------------------------------------------
  755. // CActiveUrlRequest::CombineUrl
  756. // --------------------------------------------------------------------------------
  757. STDMETHODIMP CActiveUrlRequest::CombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
  758. LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved)
  759. {
  760. // Locals
  761. HRESULT hr=S_OK;
  762. LPSTR pszBaseUrl=NULL;
  763. LPSTR pszRootUrl=NULL;
  764. LPSTR pszBodyUrl=NULL;
  765. LPSTR pszRelativeUrl=NULL;
  766. LPSTR pszNewUrl=NULL;
  767. LPSTR pszDocUrl=NULL;
  768. LPSTR pszPageUrl=NULL;
  769. LPWSTR pwszBodyUrl=NULL;
  770. LPWSTR pwszNewUrl=NULL;
  771. LPWSTR pwszSource=NULL;
  772. BOOL fCombine=FALSE;
  773. LPMESSAGETREE pTree=NULL;
  774. ULONG cchSource;
  775. ULONG cchPrefix=lstrlen(c_szMHTMLColon);
  776. HBODY hBody;
  777. // Invalid Arg
  778. if (NULL == pwzRelativeUrl)
  779. return TrapError(E_INVALIDARG);
  780. // Thread Safety
  781. EnterCriticalSection(&m_cs);
  782. // DebugTraceing
  783. #ifndef WIN16
  784. DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : L"" , pwzRelativeUrl ? pwzRelativeUrl : L"");
  785. #else
  786. DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : "" , pwzRelativeUrl ? pwzRelativeUrl : "");
  787. #endif // !WIN16
  788. // Raid-42722: MHTML: Bookmarks don't work
  789. if (L'#' == pwzRelativeUrl[0])
  790. {
  791. hr = E_FAIL;
  792. goto exit;
  793. }
  794. // Convert relative to ANSI
  795. CHECKALLOC(pszRelativeUrl = PszToANSI(CP_ACP, pwzRelativeUrl));
  796. // We should UnEscape only Url, but doesn't touch a query
  797. CHECKHR(hr = UrlUnescapeA(pszRelativeUrl, NULL, NULL, URL_UNESCAPE_INPLACE | URL_DONT_ESCAPE_EXTRA_INFO));
  798. // If the relative is already mhtml:, then retur that...
  799. if (StrCmpNI(pszRelativeUrl, c_szMHTMLColon, cchPrefix) == 0)
  800. {
  801. // Split It
  802. CHECKHR(hr = MimeOleParseMhtmlUrl(pszRelativeUrl, &pszRootUrl, &pszBodyUrl));
  803. // If no body url, then just return pszRelativeUrl
  804. if (NULL == pszBodyUrl)
  805. {
  806. // Set pwszSource
  807. pwszSource = (LPWSTR)(pwzRelativeUrl + cchPrefix);
  808. // Get Length
  809. cchSource = lstrlenW(pwzRelativeUrl) - cchPrefix;
  810. // Done
  811. goto set_return;
  812. }
  813. }
  814. // Otherwise, build a new url
  815. else
  816. {
  817. // Base to ANSI
  818. CHECKALLOC(pszBaseUrl = PszToANSI(CP_ACP, pwzBaseUrl));
  819. // UnEscape the Url
  820. CHECKHR(hr = UrlUnescapeA(pszBaseUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
  821. // Split It
  822. CHECKHR(hr = MimeOleParseMhtmlUrl(pszBaseUrl, &pszRootUrl, &pszPageUrl));
  823. // Set pszBodyUrl
  824. pszBodyUrl = pszRelativeUrl;
  825. // Don't need pszRelativeUrl anymore
  826. pszRelativeUrl = NULL;
  827. }
  828. // Better have a root and a body url
  829. Assert(pszRootUrl && pszBodyUrl);
  830. // Try to resolve the root url
  831. if (SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL)))
  832. {
  833. // If pszBodyUrl is in the WebBook or the bind is not finished...then do the url combine
  834. if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, NULL)) || pTree->IsState(TREESTATE_BINDDONE) == S_FALSE)
  835. {
  836. // Combine the Urls
  837. fCombine = TRUE;
  838. }
  839. // fCombine = TRUE;
  840. }
  841. // Should we combine
  842. if (fCombine)
  843. {
  844. // Allocate Some Memory
  845. DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2);
  846. CHECKALLOC(pszNewUrl = PszAllocA(cchSize));
  847. // Format the string
  848. wnsprintfA(pszNewUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl);
  849. // Convert to unicode
  850. CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl));
  851. // Get length
  852. cchSource = lstrlenW(pwszNewUrl);
  853. // Set Source
  854. pwszSource = pwszNewUrl;
  855. }
  856. // No Combine
  857. else
  858. {
  859. // If we have a WebBook
  860. if (pTree)
  861. {
  862. // If we don't have a page Url, then just call GetTextBody(html)
  863. if (NULL == pszPageUrl)
  864. MimeOleComputeContentBase(pTree, NULL, &pszDocUrl, NULL);
  865. // Otherwise, try to resolve the page url
  866. else if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszPageUrl, 0, &hBody)))
  867. pszDocUrl = MimeOleContentBaseFromBody(pTree, hBody);
  868. // If we have Url
  869. if (pszDocUrl)
  870. {
  871. // Unescape It
  872. CHECKHR(hr = UrlUnescapeA(pszDocUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
  873. }
  874. // Otheriwse, if the WebBook was loaded by a moniker, then use pszRootUrl
  875. else if (pTree->IsState(TREESTATE_LOADEDBYMONIKER) == S_OK)
  876. {
  877. // pszRootUrl is the pszDocUrl
  878. CHECKALLOC(pszDocUrl = PszDupA(pszRootUrl));
  879. }
  880. }
  881. // If there is a pszDocUrl
  882. if (pszDocUrl)
  883. {
  884. // Lets Combine with this url
  885. CHECKHR(hr = MimeOleCombineURL(pszDocUrl, lstrlen(pszDocUrl), pszBodyUrl, lstrlen(pszBodyUrl), FALSE, &pszNewUrl));
  886. // Convert to unicode
  887. CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl));
  888. // Get length
  889. cchSource = lstrlenW(pwszNewUrl);
  890. // Set Source
  891. pwszSource = pwszNewUrl;
  892. }
  893. else
  894. {
  895. // Need a wide body Url
  896. CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl));
  897. // Get length
  898. cchSource = lstrlenW(pwszBodyUrl);
  899. // Set Source
  900. pwszSource = pwszBodyUrl;
  901. }
  902. }
  903. set_return:
  904. // Set Dest Size
  905. if (pcchResult)
  906. *pcchResult = cchSource;
  907. // No return value
  908. if (NULL == pwzResult)
  909. goto exit;
  910. // Dest is big enought
  911. if (cchResult <= cchSource)
  912. {
  913. hr = TrapError(E_FAIL);
  914. goto exit;
  915. }
  916. // Copy to dest buffer
  917. CopyMemory((LPBYTE)pwzResult, (LPBYTE)pwszSource, ((cchSource + 1) * sizeof(WCHAR)));
  918. exit:
  919. // Cleanup
  920. SafeMemFree(pszRootUrl);
  921. SafeMemFree(pszRelativeUrl);
  922. SafeMemFree(pszBodyUrl);
  923. SafeMemFree(pszNewUrl);
  924. SafeMemFree(pwszNewUrl);
  925. SafeMemFree(pszBaseUrl);
  926. SafeMemFree(pszDocUrl);
  927. SafeMemFree(pwszBodyUrl);
  928. SafeMemFree(pszPageUrl);
  929. SafeRelease(pTree);
  930. // Thread Safety
  931. LeaveCriticalSection(&m_cs);
  932. // Done
  933. return hr;
  934. }
  935. // --------------------------------------------------------------------------------
  936. // CActiveUrl::CActiveUrl
  937. // --------------------------------------------------------------------------------
  938. CActiveUrl::CActiveUrl(void)
  939. {
  940. m_cRef = 1;
  941. m_pUnkAlive = NULL;
  942. m_pUnkInner = NULL;
  943. m_pWebBook = NULL;
  944. m_pNext = NULL;
  945. m_pPrev = NULL;
  946. m_dwFlags = 0;
  947. InitializeCriticalSection(&m_cs);
  948. }
  949. // --------------------------------------------------------------------------------
  950. // CActiveUrl::~CActiveUrl
  951. // --------------------------------------------------------------------------------
  952. CActiveUrl::~CActiveUrl(void)
  953. {
  954. SafeRelease(m_pUnkAlive);
  955. DeleteCriticalSection(&m_cs);
  956. }
  957. // --------------------------------------------------------------------------------
  958. // CActiveUrl::QueryInterface
  959. // --------------------------------------------------------------------------------
  960. STDMETHODIMP CActiveUrl::QueryInterface(REFIID riid, LPVOID *ppv)
  961. {
  962. // Locals
  963. HRESULT hr=S_OK;
  964. // check params
  965. if (ppv == NULL)
  966. return TrapError(E_INVALIDARG);
  967. // Find IID
  968. if (IID_IUnknown == riid)
  969. *ppv = (IUnknown *)this;
  970. else
  971. {
  972. *ppv = NULL;
  973. hr = TrapError(E_NOINTERFACE);
  974. goto exit;
  975. }
  976. // AddRef It
  977. ((IUnknown *)*ppv)->AddRef();
  978. exit:
  979. // Done
  980. return hr;
  981. }
  982. // --------------------------------------------------------------------------------
  983. // CActiveUrl::AddRef
  984. // --------------------------------------------------------------------------------
  985. STDMETHODIMP_(ULONG) CActiveUrl::AddRef(void)
  986. {
  987. return (ULONG)InterlockedIncrement(&m_cRef);
  988. }
  989. // --------------------------------------------------------------------------------
  990. // CActiveUrl::Release
  991. // --------------------------------------------------------------------------------
  992. STDMETHODIMP_(ULONG) CActiveUrl::Release(void)
  993. {
  994. LONG cRef = InterlockedDecrement(&m_cRef);
  995. if (0 == cRef)
  996. delete this;
  997. return (ULONG)cRef;
  998. }
  999. // --------------------------------------------------------------------------------
  1000. // CActiveUrl::Init
  1001. // --------------------------------------------------------------------------------
  1002. HRESULT CActiveUrl::Init(BINDF bindf, LPMESSAGETREE pTree)
  1003. {
  1004. // Locals
  1005. HRESULT hr=S_OK;
  1006. // Thread Safety
  1007. EnterCriticalSection(&m_cs);
  1008. // Better not have data
  1009. Assert(NULL == m_pWebBook && NULL == m_pUnkInner);
  1010. // No Message Object Passed in ?
  1011. if (NULL == pTree)
  1012. {
  1013. // Allocate the Message Object
  1014. CHECKALLOC(pTree = new CMessageTree);
  1015. // Set pMessage
  1016. m_pUnkAlive = pTree->GetInner();
  1017. // Init
  1018. CHECKHR(hr = pTree->InitNew());
  1019. }
  1020. // Set BINDF_PRAGMA_NO_CACHE
  1021. if (ISFLAGSET(bindf, BINDF_RESYNCHRONIZE))
  1022. {
  1023. // Set State
  1024. pTree->SetState(TREESTATE_RESYNCHRONIZE);
  1025. }
  1026. // Set pMessage
  1027. m_pWebBook = pTree;
  1028. // Get the Message Object's Inner Unknown
  1029. m_pUnkInner = pTree->GetInner();
  1030. // Register pActiveUrl as a handle in the message object
  1031. m_pWebBook->SetActiveUrl(this);
  1032. exit:
  1033. // Thread Safety
  1034. LeaveCriticalSection(&m_cs);
  1035. // Done
  1036. return hr;
  1037. }
  1038. // --------------------------------------------------------------------------------
  1039. // CActiveUrl::DontKeepAlive
  1040. // --------------------------------------------------------------------------------
  1041. void CActiveUrl::DontKeepAlive(void)
  1042. {
  1043. // Thread Safety
  1044. EnterCriticalSection(&m_cs);
  1045. // Set pMessage
  1046. if (m_pUnkAlive)
  1047. {
  1048. // Somebody should still have a refcount on this dude
  1049. SideAssert(m_pUnkAlive->Release() > 0);
  1050. // Null It
  1051. m_pUnkAlive = NULL;
  1052. }
  1053. // Thread Safety
  1054. LeaveCriticalSection(&m_cs);
  1055. }
  1056. // --------------------------------------------------------------------------------
  1057. // CActiveUrl::IsActive
  1058. // --------------------------------------------------------------------------------
  1059. HRESULT CActiveUrl::IsActive(void)
  1060. {
  1061. EnterCriticalSection(&m_cs);
  1062. HRESULT hr = m_pWebBook ? S_OK : S_FALSE;
  1063. LeaveCriticalSection(&m_cs);
  1064. return hr;
  1065. }
  1066. // --------------------------------------------------------------------------------
  1067. // CActiveUrl::RevokeWebBook
  1068. // --------------------------------------------------------------------------------
  1069. void CActiveUrl::RevokeWebBook(LPMESSAGETREE pTree)
  1070. {
  1071. // Thread Safety
  1072. EnterCriticalSection(&m_cs);
  1073. // Invalid Arg
  1074. Assert(NULL == pTree || m_pWebBook == pTree);
  1075. // Revoke This from the message
  1076. if (m_pWebBook)
  1077. m_pWebBook->SetActiveUrl(NULL);
  1078. // Null m_pWebBook
  1079. m_pWebBook = NULL;
  1080. m_pUnkInner = NULL;
  1081. // Check Ref Count
  1082. Assert(1 == m_cRef);
  1083. // Thread Safety
  1084. LeaveCriticalSection(&m_cs);
  1085. }
  1086. // --------------------------------------------------------------------------------
  1087. // CActiveUrl::CompareRootUrl
  1088. // --------------------------------------------------------------------------------
  1089. HRESULT CActiveUrl::CompareRootUrl(LPCSTR pszUrl)
  1090. {
  1091. // Thread Safety
  1092. EnterCriticalSection(&m_cs);
  1093. // Compare Root Url
  1094. HRESULT hr = m_pWebBook ? m_pWebBook->CompareRootUrl(pszUrl) : S_FALSE;
  1095. // Thread Safety
  1096. LeaveCriticalSection(&m_cs);
  1097. // Done
  1098. return hr;
  1099. }
  1100. // --------------------------------------------------------------------------------
  1101. // CActiveUrl::BindToObject
  1102. // --------------------------------------------------------------------------------
  1103. HRESULT CActiveUrl::BindToObject(REFIID riid, LPVOID *ppv)
  1104. {
  1105. // Thread Safety
  1106. EnterCriticalSection(&m_cs);
  1107. // Compare Root Url
  1108. HRESULT hr = m_pUnkInner ? m_pUnkInner->QueryInterface(riid, ppv) : TrapError(E_FAIL);
  1109. // Thread Safety
  1110. LeaveCriticalSection(&m_cs);
  1111. // Done
  1112. return hr;
  1113. }
  1114. // --------------------------------------------------------------------------------
  1115. // CActiveUrl::CreateWebPage
  1116. // --------------------------------------------------------------------------------
  1117. HRESULT CActiveUrl::CreateWebPage(IStream *pStmRoot, LPWEBPAGEOPTIONS pOptions,
  1118. DWORD dwReserved, IMoniker **ppMoniker)
  1119. {
  1120. // Locals
  1121. HRESULT hr=S_OK;
  1122. // Thread Safety
  1123. EnterCriticalSection(&m_cs);
  1124. // No Message
  1125. if (NULL == m_pWebBook)
  1126. {
  1127. hr = TrapError(E_FAIL);
  1128. goto exit;
  1129. }
  1130. // CreateWebPage
  1131. CHECKHR(hr = m_pWebBook->CreateWebPage(pStmRoot, pOptions, NULL, ppMoniker));
  1132. exit:
  1133. // Thread Safety
  1134. LeaveCriticalSection(&m_cs);
  1135. // Done
  1136. return hr;
  1137. }
  1138. // --------------------------------------------------------------------------------
  1139. // CMimeActiveUrlCache::CMimeActiveUrlCache
  1140. // --------------------------------------------------------------------------------
  1141. CMimeActiveUrlCache::CMimeActiveUrlCache(void)
  1142. {
  1143. m_cRef = 1;
  1144. m_cActive = 0;
  1145. m_pHead = NULL;
  1146. InitializeCriticalSection(&m_cs);
  1147. }
  1148. // --------------------------------------------------------------------------------
  1149. // CMimeActiveUrlCache::~CMimeActiveUrlCache
  1150. // --------------------------------------------------------------------------------
  1151. CMimeActiveUrlCache::~CMimeActiveUrlCache(void)
  1152. {
  1153. _FreeActiveUrlList(TRUE);
  1154. DeleteCriticalSection(&m_cs);
  1155. }
  1156. // --------------------------------------------------------------------------------
  1157. // CMimeActiveUrlCache::_FreeActiveUrlList
  1158. // --------------------------------------------------------------------------------
  1159. void CMimeActiveUrlCache::_FreeActiveUrlList(BOOL fAll)
  1160. {
  1161. // Locals
  1162. LPACTIVEURL pCurr;
  1163. LPACTIVEURL pNext;
  1164. // Init
  1165. pCurr = m_pHead;
  1166. // All
  1167. if (fAll)
  1168. {
  1169. // Loop and Free
  1170. while(pCurr)
  1171. {
  1172. // Set Next
  1173. pNext = pCurr->PGetNext();
  1174. // Revoke the handle
  1175. pCurr->RevokeWebBook(NULL);
  1176. // Free the Active Url
  1177. pCurr->Release();
  1178. // Goto Next
  1179. pCurr = pNext;
  1180. }
  1181. // No Active
  1182. m_cActive = 0;
  1183. m_pHead = NULL;
  1184. }
  1185. else
  1186. {
  1187. // Loop and Free
  1188. while(pCurr)
  1189. {
  1190. // Set Next
  1191. pNext = pCurr->PGetNext();
  1192. // Revoke the handle
  1193. if (pCurr->IsActive() == S_FALSE)
  1194. _RemoveUrl(pCurr);
  1195. // Goto Next
  1196. pCurr = pNext;
  1197. }
  1198. }
  1199. }
  1200. // --------------------------------------------------------------------------------
  1201. // CMimeActiveUrlCache::QueryInterface
  1202. // --------------------------------------------------------------------------------
  1203. STDMETHODIMP CMimeActiveUrlCache::QueryInterface(REFIID riid, LPVOID *ppv)
  1204. {
  1205. // Locals
  1206. HRESULT hr=S_OK;
  1207. // check params
  1208. if (ppv == NULL)
  1209. return TrapError(E_INVALIDARG);
  1210. // Find IID
  1211. if (IID_IUnknown == riid)
  1212. *ppv = (IUnknown *)this;
  1213. else
  1214. {
  1215. *ppv = NULL;
  1216. hr = TrapError(E_NOINTERFACE);
  1217. goto exit;
  1218. }
  1219. // AddRef It
  1220. ((IUnknown *)*ppv)->AddRef();
  1221. exit:
  1222. // Done
  1223. return hr;
  1224. }
  1225. // --------------------------------------------------------------------------------
  1226. // CMimeActiveUrlCache::AddRef
  1227. // --------------------------------------------------------------------------------
  1228. STDMETHODIMP_(ULONG) CMimeActiveUrlCache::AddRef(void)
  1229. {
  1230. return (ULONG)InterlockedIncrement(&m_cRef);
  1231. }
  1232. // --------------------------------------------------------------------------------
  1233. // CMimeActiveUrlCache::Release
  1234. // --------------------------------------------------------------------------------
  1235. STDMETHODIMP_(ULONG) CMimeActiveUrlCache::Release(void)
  1236. {
  1237. LONG cRef = InterlockedDecrement(&m_cRef);
  1238. if (0 == cRef)
  1239. delete this;
  1240. return (ULONG)cRef;
  1241. }
  1242. // --------------------------------------------------------------------------------
  1243. // CMimeActiveUrlCache::_RegisterUrl
  1244. // --------------------------------------------------------------------------------
  1245. HRESULT CMimeActiveUrlCache::_RegisterUrl(LPMESSAGETREE pTree, BINDF bindf,
  1246. LPACTIVEURL *ppActiveUrl)
  1247. {
  1248. // Locals
  1249. HRESULT hr=S_OK;
  1250. LPACTIVEURL pActiveUrl=NULL;
  1251. // Invalid Arg
  1252. Assert(ppActiveUrl);
  1253. // Init
  1254. *ppActiveUrl = NULL;
  1255. // Allocate an ActiveUrl
  1256. CHECKALLOC(pActiveUrl = new CActiveUrl);
  1257. // Init the Active Url
  1258. CHECKHR(hr = pActiveUrl->Init(bindf, pTree));
  1259. // Link Into Chain
  1260. if (NULL == m_pHead)
  1261. m_pHead = pActiveUrl;
  1262. else
  1263. {
  1264. pActiveUrl->SetNext(m_pHead);
  1265. m_pHead->SetPrev(pActiveUrl);
  1266. m_pHead = pActiveUrl;
  1267. }
  1268. // Increment Count
  1269. m_cActive++;
  1270. // Return It
  1271. *ppActiveUrl = pActiveUrl;
  1272. pActiveUrl = NULL;
  1273. exit:
  1274. // Release the Active Url
  1275. SafeRelease(pActiveUrl);
  1276. // Done
  1277. return hr;
  1278. }
  1279. // --------------------------------------------------------------------------------
  1280. // CMimeActiveUrlCache::_ResolveUrl
  1281. // --------------------------------------------------------------------------------
  1282. HRESULT CMimeActiveUrlCache::_ResolveUrl(LPCSTR pszUrl, LPACTIVEURL *ppActiveUrl)
  1283. {
  1284. // Locals
  1285. HRESULT hr=S_OK;
  1286. LPACTIVEURL pActiveUrl;
  1287. // Invalid Arg
  1288. Assert(pszUrl && ppActiveUrl);
  1289. // Init
  1290. *ppActiveUrl = NULL;
  1291. // Should not have mhtml:
  1292. Assert(StrCmpNI(pszUrl, "mhtml:", 6) != 0);
  1293. // Walk the Table
  1294. for (pActiveUrl=m_pHead; pActiveUrl!=NULL; pActiveUrl=pActiveUrl->PGetNext())
  1295. {
  1296. // Is this the Url
  1297. if (pActiveUrl->CompareRootUrl(pszUrl) == S_OK)
  1298. {
  1299. // Return the Active Url
  1300. *ppActiveUrl = pActiveUrl;
  1301. // Done
  1302. goto exit;
  1303. }
  1304. }
  1305. // Not Found
  1306. hr = TrapError(MIME_E_NOT_FOUND);
  1307. exit:
  1308. // Done
  1309. return hr;
  1310. }
  1311. // --------------------------------------------------------------------------------
  1312. // CMimeActiveUrlCache::_RemoveUrl
  1313. // --------------------------------------------------------------------------------
  1314. HRESULT CMimeActiveUrlCache::_RemoveUrl(LPACTIVEURL pActiveUrl)
  1315. {
  1316. EnterCriticalSection(&m_cs);
  1317. // Fixup Linked List
  1318. LPACTIVEURL pNext = pActiveUrl->PGetNext();
  1319. LPACTIVEURL pPrev = pActiveUrl->PGetPrev();
  1320. // Fixup
  1321. if (pPrev)
  1322. pPrev->SetNext(pNext);
  1323. if (pNext)
  1324. pNext->SetPrev(pPrev);
  1325. // Fixup m_pHead
  1326. if (m_pHead == pActiveUrl)
  1327. m_pHead = pNext;
  1328. // Revoke the handle
  1329. pActiveUrl->RevokeWebBook(NULL);
  1330. // Release the ActiveUrl
  1331. SideAssert(0 == pActiveUrl->Release());
  1332. // One less active
  1333. m_cActive--;
  1334. LeaveCriticalSection(&m_cs);
  1335. // Done
  1336. return S_OK;
  1337. }
  1338. // --------------------------------------------------------------------------------
  1339. // CMimeActiveUrlCache::RemoveUrl
  1340. // --------------------------------------------------------------------------------
  1341. HRESULT CMimeActiveUrlCache::RemoveUrl(LPACTIVEURL pActiveUrl)
  1342. {
  1343. return _RemoveUrl(pActiveUrl);
  1344. }
  1345. // --------------------------------------------------------------------------------
  1346. // CMimeActiveUrlCache::_HandlePragmaNoCache
  1347. // --------------------------------------------------------------------------------
  1348. void CMimeActiveUrlCache::_HandlePragmaNoCache(BINDF bindf, LPCSTR pszUrl)
  1349. {
  1350. // Locals
  1351. CActiveUrl *pActiveUrl;
  1352. // Invalid Arg
  1353. Assert(pszUrl);
  1354. // BINDF_PRAGMA_NO_CACHE - Reload the WebBook from original source (can't do if activeurl has a fake url)
  1355. if (ISFLAGSET((DWORD)bindf, BINDF_PRAGMA_NO_CACHE))
  1356. {
  1357. // Try to find the ActiveUrl associated with pszUrl
  1358. if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl)))
  1359. {
  1360. // If it is a fakeurl, then lets not unload it
  1361. if (FALSE == pActiveUrl->FIsFlagSet(ACTIVEURL_ISFAKEURL))
  1362. {
  1363. // Kill it from the cache so that its not found and reloaded
  1364. _RemoveUrl(pActiveUrl);
  1365. }
  1366. }
  1367. }
  1368. }
  1369. // --------------------------------------------------------------------------------
  1370. // CMimeActiveUrlCache::ActiveObjectFromMoniker - Called from Trident
  1371. // --------------------------------------------------------------------------------
  1372. HRESULT CMimeActiveUrlCache::ActiveObjectFromMoniker(
  1373. /* in */ BINDF bindf,
  1374. /* in */ IMoniker *pmkOriginal,
  1375. /* in */ IBindCtx *pBindCtx,
  1376. /* in */ REFIID riid,
  1377. /* out */ LPVOID *ppvObject,
  1378. /* out */ IMoniker **ppmkNew)
  1379. {
  1380. // Locals
  1381. HRESULT hr=S_OK;
  1382. LPWSTR pwszUrl=NULL;
  1383. LPSTR pszUrl=NULL;
  1384. LPSTR pszRootUrl=NULL;
  1385. IMoniker *pMoniker=NULL;
  1386. IPersistMoniker *pPersist=NULL;
  1387. LPACTIVEURL pActiveUrl=NULL;
  1388. BOOL fAsync=FALSE;
  1389. WEBPAGEOPTIONS Options={0};
  1390. // Invalid Arg
  1391. if (NULL == pmkOriginal || NULL == ppvObject || NULL == ppmkNew)
  1392. return TrapError(E_INVALIDARG);
  1393. // Init
  1394. *ppmkNew = NULL;
  1395. *ppvObject = NULL;
  1396. // Thread Safety
  1397. EnterCriticalSection(&m_cs);
  1398. // Get the Url from the Moniker
  1399. CHECKHR(hr = pmkOriginal->GetDisplayName(NULL, NULL, &pwszUrl));
  1400. // Convert to ANSI
  1401. CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl));
  1402. // Unescape inplace
  1403. CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE));
  1404. // Raid-2508: Comment tag ( <! comment> ) doesn't work in mhtml
  1405. if (StrCmpNI(pszUrl, c_szMHTMLColon, lstrlen(c_szMHTMLColon)) != 0)
  1406. {
  1407. // Fixup
  1408. ReplaceChars(pszUrl, '!', '_');
  1409. }
  1410. // Free pwszUrl
  1411. SafeMemFree(pwszUrl);
  1412. // This will fail if pszUrl is not an mhtml: url, if it succeeds it gives me the part Url
  1413. if (SUCCEEDED(MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, NULL)))
  1414. {
  1415. // _HandlePragmaNoCache
  1416. _HandlePragmaNoCache(bindf, pszRootUrl);
  1417. // See if pszUrl - mhtml: is an active Url
  1418. if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl)))
  1419. {
  1420. // Register an ActiveUrl
  1421. CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl));
  1422. // Convert pszRootUrl to a wide
  1423. CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl));
  1424. // Create an Actual Url Moniker
  1425. CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker));
  1426. // Get an IPersistMoniker
  1427. CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
  1428. // Load the message with pmkOriginal
  1429. hr = pPersist->Load(FALSE, pMoniker, NULL, 0);
  1430. if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
  1431. {
  1432. hr = TrapError(hr);
  1433. goto exit;
  1434. }
  1435. // Otheriwse, good
  1436. hr = S_OK;
  1437. }
  1438. // Return pmkOriginal
  1439. (*ppmkNew) = pmkOriginal;
  1440. (*ppmkNew)->AddRef();
  1441. // QI for the requested object iid
  1442. CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
  1443. }
  1444. // Otherwise Simply see if this Url is Active
  1445. else
  1446. {
  1447. // _HandlePragmaNoCache
  1448. _HandlePragmaNoCache(bindf, pszUrl);
  1449. // Try to resolve this url
  1450. if (FAILED(_ResolveUrl(pszUrl, &pActiveUrl)))
  1451. {
  1452. // Register an ActiveUrl
  1453. CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl));
  1454. // Get an IPersistMoniker
  1455. CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
  1456. // Load the message with pmkOriginal
  1457. hr = pPersist->Load(FALSE, pmkOriginal, pBindCtx, 0);
  1458. if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
  1459. {
  1460. hr = TrapError(hr);
  1461. goto exit;
  1462. }
  1463. // Otheriwse, good
  1464. hr = S_OK;
  1465. }
  1466. // Setup WebPage Options
  1467. Options.cbSize = sizeof(WEBPAGEOPTIONS);
  1468. Options.dwFlags = WPF_NOMETACHARSET | WPF_HTML | WPF_AUTOINLINE;
  1469. // Create the root moniker
  1470. CHECKHR(hr = pActiveUrl->CreateWebPage(NULL, &Options, 0, ppmkNew));
  1471. // QI for the requested object iid
  1472. CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
  1473. // Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl
  1474. pActiveUrl->DontKeepAlive();
  1475. }
  1476. exit:
  1477. // Cleanup
  1478. SafeRelease(pPersist);
  1479. SafeRelease(pMoniker);
  1480. SafeMemFree(pszRootUrl);
  1481. SafeMemFree(pszUrl);
  1482. SafeMemFree(pwszUrl);
  1483. // Thread Safety
  1484. LeaveCriticalSection(&m_cs);
  1485. // Failed, return hr, otherwise, return MK_S_ASYNCHRONOUS if going async
  1486. return hr;
  1487. }
  1488. // --------------------------------------------------------------------------------
  1489. // CMimeActiveUrlCache::ActiveObjectFromUrl - Called from CActiveUrlRequest::Start
  1490. // --------------------------------------------------------------------------------
  1491. HRESULT CMimeActiveUrlCache::ActiveObjectFromUrl(
  1492. /* in */ LPCSTR pszRootUrl,
  1493. /* in */ BOOL fCreate,
  1494. /* in */ REFIID riid,
  1495. /* out */ LPVOID *ppvObject,
  1496. /* out */ IUnknown **ppUnkKeepAlive)
  1497. {
  1498. // Locals
  1499. HRESULT hr=S_OK;
  1500. LPWSTR pwszUrl=NULL;
  1501. LPACTIVEURL pActiveUrl;
  1502. IMoniker *pMoniker=NULL;
  1503. IPersistMoniker *pPersist=NULL;
  1504. // Invalid Arg
  1505. if (NULL == pszRootUrl || NULL == ppvObject || (TRUE == fCreate && NULL == ppUnkKeepAlive))
  1506. return TrapError(E_INVALIDARG);
  1507. // Better not start with mhtml:
  1508. Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) != 0);
  1509. // Thread Safety
  1510. EnterCriticalSection(&m_cs);
  1511. // Try to resolve this url
  1512. if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl)))
  1513. {
  1514. // NoCreate ?
  1515. if (FALSE == fCreate)
  1516. {
  1517. hr = TrapError(MIME_E_NOT_FOUND);
  1518. goto exit;
  1519. }
  1520. // Register an ActiveUrl
  1521. CHECKHR(hr = _RegisterUrl(NULL, (BINDF)0, &pActiveUrl));
  1522. // Convert pszRootUrl to a wide
  1523. CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl));
  1524. // Create an Actual Url Moniker
  1525. CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker));
  1526. // Get an IPersistMoniker
  1527. CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist));
  1528. // Load the message with pmkOriginal
  1529. hr = pPersist->Load(FALSE, pMoniker, NULL, 0);
  1530. if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr)
  1531. {
  1532. hr = TrapError(hr);
  1533. goto exit;
  1534. }
  1535. // Return the IUnknown Keep Alive Object
  1536. CHECKHR(hr = pActiveUrl->BindToObject(IID_IUnknown, (LPVOID *)ppUnkKeepAlive));
  1537. // Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl
  1538. pActiveUrl->DontKeepAlive();
  1539. }
  1540. // Return an Interface
  1541. CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject));
  1542. exit:
  1543. // Cleanup
  1544. SafeMemFree(pwszUrl);
  1545. SafeRelease(pMoniker);
  1546. SafeRelease(pPersist);
  1547. // Thread Safety
  1548. LeaveCriticalSection(&m_cs);
  1549. // Done
  1550. return hr;
  1551. }
  1552. // --------------------------------------------------------------------------------
  1553. // CMimeActiveUrlCache::RegisterActiveObject
  1554. // --------------------------------------------------------------------------------
  1555. HRESULT CMimeActiveUrlCache::RegisterActiveObject(
  1556. /* in */ LPCSTR pszRootUrl,
  1557. /* in */ LPMESSAGETREE pTree)
  1558. {
  1559. // Locals
  1560. HRESULT hr=S_OK;
  1561. LPCSTR pszUrl;
  1562. LPACTIVEURL pActiveUrl;
  1563. // Invalid Arg
  1564. if (NULL == pszRootUrl || NULL == pTree)
  1565. return TrapError(E_INVALIDARG);
  1566. // Thread Safety
  1567. EnterCriticalSection(&m_cs);
  1568. // Better start with mhtml:
  1569. Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) == 0);
  1570. // Fixup pszUrl
  1571. pszUrl = (pszRootUrl + 6);
  1572. // Better not already be running
  1573. if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl)))
  1574. {
  1575. hr = TrapError(E_FAIL);
  1576. goto exit;
  1577. }
  1578. // Register an ActiveUrl
  1579. CHECKHR(hr = _RegisterUrl(pTree, (BINDF)0, &pActiveUrl));
  1580. exit:
  1581. // Thread Safety
  1582. LeaveCriticalSection(&m_cs);
  1583. // Done
  1584. return hr;
  1585. }