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.

1586 lines
44 KiB

  1. //------------------------------------------------------------------------
  2. //
  3. // Tabular Data Control
  4. // Copyright (C) Microsoft Corporation, 1996, 1997
  5. //
  6. // File: TDCCtl.cpp
  7. //
  8. // Contents: Implementation of the CTDCCtl ActiveX control.
  9. //
  10. //------------------------------------------------------------------------
  11. #include "stdafx.h"
  12. #include <simpdata.h>
  13. #include "TDCIds.h"
  14. #include "TDC.h"
  15. #include <MLang.h>
  16. #include "Notify.h"
  17. #include "TDCParse.h"
  18. #include "TDCArr.h"
  19. #include "TDCCtl.h"
  20. #include "locale.h"
  21. //------------------------------------------------------------------------
  22. //
  23. // Function: EmptyBSTR()
  24. //
  25. // Synopsis: Indicates whether the given BSTR object represents an
  26. // empty string.
  27. //
  28. // Arguments: bstr String to test
  29. //
  30. // Returns: TRUE if 'bstr' represents an empty string
  31. // FALSE otherwise.
  32. //
  33. //------------------------------------------------------------------------
  34. inline boolean EmptyBSTR(BSTR bstr)
  35. {
  36. return bstr == NULL || bstr[0] == 0;
  37. }
  38. void
  39. ClearInterfaceFn(IUnknown ** ppUnk)
  40. {
  41. IUnknown * pUnk;
  42. pUnk = *ppUnk;
  43. *ppUnk = NULL;
  44. if (pUnk)
  45. pUnk->Release();
  46. }
  47. // For some reason the standard definition of VARIANT_TRUE (0xffff) generates
  48. // truncation warnings when assigned to a VARIANT_BOOL
  49. #define TDCVARIANT_TRUE -1
  50. //------------------------------------------------------------------------
  51. //
  52. // Method: CTDCCtl()
  53. //
  54. // Synopsis: Class constructor
  55. //
  56. // Arguments: None
  57. //
  58. //------------------------------------------------------------------------
  59. CTDCCtl::CTDCCtl()
  60. {
  61. m_cbstrFieldDelim = DEFAULT_FIELD_DELIM;
  62. m_cbstrRowDelim = DEFAULT_ROW_DELIM;
  63. m_cbstrQuoteChar = DEFAULT_QUOTE_CHAR;
  64. m_fUseHeader = FALSE;
  65. m_fSortAscending = TRUE;
  66. m_fAppendData = FALSE;
  67. m_pSTD = NULL;
  68. m_pArr = NULL;
  69. m_pUnify = NULL;
  70. m_pEventBroker = new CEventBroker(this);
  71. m_pDataSourceListener = NULL;
  72. // ;begin_internal
  73. m_pDATASRCListener = NULL;
  74. // ;end_internal
  75. m_pBSC = NULL;
  76. m_enumFilterCriterion = (OSPCOMP) 0;
  77. m_fDataURLChanged = FALSE;
  78. m_lTimer = 0;
  79. m_fCaseSensitive = TRUE;
  80. m_hrDownloadStatus = S_OK;
  81. m_fInReset = FALSE;
  82. // Create an MLANG object
  83. //
  84. m_nCodePage = 0; // use default from host
  85. {
  86. HRESULT hr;
  87. m_pML = NULL;
  88. hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,
  89. CLSCTX_INPROC_SERVER, IID_IMultiLanguage,
  90. (void**) &m_pML);
  91. // Don't set the default Charset here. Leave m_nCodepage set
  92. // to 0 to indicate default charset. Later we'll try to query
  93. // our host's default charset, and failing that we'll use CP_ACP.
  94. _ASSERTE(SUCCEEDED(hr) && m_pML != NULL);
  95. }
  96. m_lcidRead = 0x0000; // use default from host
  97. }
  98. //------------------------------------------------------------------------
  99. //
  100. // Method: ~CTDCCtl()
  101. //
  102. // Synopsis: Class destructor
  103. //
  104. //------------------------------------------------------------------------
  105. CTDCCtl::~CTDCCtl()
  106. {
  107. ULONG cRef = _ThreadModel::Decrement(&m_dwRef);
  108. ClearInterface(&m_pSTD);
  109. if (cRef ==0)
  110. {
  111. TimerOff();
  112. ReleaseTDCArr(FALSE);
  113. if (m_pEventBroker)
  114. {
  115. m_pEventBroker->Release();
  116. m_pEventBroker = NULL;
  117. }
  118. ClearInterface(&m_pDataSourceListener);
  119. // ;begin_internal
  120. ClearInterface(&m_pDATASRCListener);
  121. // ;end_internal
  122. ClearInterface(&m_pML);
  123. }
  124. }
  125. //------------------------------------------------------------------------
  126. //
  127. // These set/get methods implement the control's properties,
  128. // copying values to and from class members. They perform no
  129. // other processing apart from argument validation.
  130. //
  131. //------------------------------------------------------------------------
  132. STDMETHODIMP CTDCCtl::get_ReadyState(LONG *plReadyState)
  133. {
  134. HRESULT hr;
  135. if (m_pEventBroker == NULL)
  136. {
  137. // We must provide a ReadyState whether we want to or not, or our
  138. // host can never go COMPLETE.
  139. *plReadyState = READYSTATE_COMPLETE;
  140. hr = S_OK;
  141. }
  142. else
  143. hr = m_pEventBroker->GetReadyState(plReadyState);
  144. return hr;
  145. }
  146. STDMETHODIMP CTDCCtl::put_ReadyState(LONG lReadyState)
  147. {
  148. // We don't allow setting of Ready State, but take advantage of a little
  149. // kludge here to update our container's impression of our readystate
  150. FireOnChanged(DISPID_READYSTATE);
  151. return S_OK;
  152. }
  153. STDMETHODIMP CTDCCtl::get_FieldDelim(BSTR* pbstrFieldDelim)
  154. {
  155. *pbstrFieldDelim = m_cbstrFieldDelim.Copy();
  156. return S_OK;
  157. }
  158. STDMETHODIMP CTDCCtl::put_FieldDelim(BSTR bstrFieldDelim)
  159. {
  160. HRESULT hr = S_OK;
  161. if (bstrFieldDelim == NULL || bstrFieldDelim[0] == 0)
  162. {
  163. m_cbstrFieldDelim = DEFAULT_FIELD_DELIM;
  164. if (m_cbstrFieldDelim == NULL)
  165. hr = E_OUTOFMEMORY;
  166. }
  167. else
  168. m_cbstrFieldDelim = bstrFieldDelim;
  169. return S_OK;
  170. }
  171. STDMETHODIMP CTDCCtl::get_RowDelim(BSTR* pbstrRowDelim)
  172. {
  173. *pbstrRowDelim = m_cbstrRowDelim.Copy();
  174. return S_OK;
  175. }
  176. STDMETHODIMP CTDCCtl::put_RowDelim(BSTR bstrRowDelim)
  177. {
  178. HRESULT hr = S_OK;
  179. if (bstrRowDelim == NULL || bstrRowDelim[0] == 0)
  180. {
  181. m_cbstrRowDelim = DEFAULT_ROW_DELIM;
  182. if (m_cbstrRowDelim == NULL)
  183. hr = E_OUTOFMEMORY;
  184. }
  185. else
  186. m_cbstrRowDelim = bstrRowDelim;
  187. return hr;
  188. }
  189. STDMETHODIMP CTDCCtl::get_TextQualifier(BSTR* pbstrTextQualifier)
  190. {
  191. *pbstrTextQualifier = m_cbstrQuoteChar.Copy();
  192. return S_OK;
  193. }
  194. STDMETHODIMP CTDCCtl::put_TextQualifier(BSTR bstrTextQualifier)
  195. {
  196. m_cbstrQuoteChar = bstrTextQualifier;
  197. return S_OK;
  198. }
  199. STDMETHODIMP CTDCCtl::get_EscapeChar(BSTR* pbstrEscapeChar)
  200. {
  201. *pbstrEscapeChar = m_cbstrEscapeChar.Copy();
  202. return S_OK;
  203. }
  204. STDMETHODIMP CTDCCtl::put_EscapeChar(BSTR bstrEscapeChar)
  205. {
  206. m_cbstrEscapeChar = bstrEscapeChar;
  207. return S_OK;
  208. }
  209. STDMETHODIMP CTDCCtl::get_UseHeader(VARIANT_BOOL* pfUseHeader)
  210. {
  211. *pfUseHeader = (VARIANT_BOOL)m_fUseHeader;
  212. return S_OK;
  213. }
  214. STDMETHODIMP CTDCCtl::put_UseHeader(VARIANT_BOOL fUseHeader)
  215. {
  216. m_fUseHeader = fUseHeader;
  217. return S_OK;
  218. }
  219. STDMETHODIMP CTDCCtl::get_SortColumn(BSTR* pbstrSortColumn)
  220. {
  221. *pbstrSortColumn = m_cbstrSortColumn.Copy();
  222. return S_OK;
  223. }
  224. STDMETHODIMP CTDCCtl::put_SortColumn(BSTR bstrSortColumn)
  225. {
  226. m_cbstrSortColumn = bstrSortColumn;
  227. return S_OK;
  228. }
  229. STDMETHODIMP CTDCCtl::get_SortAscending(VARIANT_BOOL* pfSortAscending)
  230. {
  231. *pfSortAscending = m_fSortAscending ? TDCVARIANT_TRUE : VARIANT_FALSE;
  232. return S_OK;
  233. }
  234. STDMETHODIMP CTDCCtl::put_SortAscending(VARIANT_BOOL fSortAscending)
  235. {
  236. m_fSortAscending = fSortAscending ? TRUE : FALSE;
  237. return S_OK;
  238. }
  239. STDMETHODIMP CTDCCtl::get_FilterValue(BSTR* pbstrFilterValue)
  240. {
  241. *pbstrFilterValue = m_cbstrFilterValue.Copy();
  242. return S_OK;
  243. }
  244. STDMETHODIMP CTDCCtl::put_FilterValue(BSTR bstrFilterValue)
  245. {
  246. m_cbstrFilterValue = bstrFilterValue;
  247. return S_OK;
  248. }
  249. STDMETHODIMP CTDCCtl::get_FilterCriterion(BSTR* pbstrFilterCriterion)
  250. {
  251. HRESULT hr;
  252. WCHAR *pwchCriterion;
  253. switch (m_enumFilterCriterion)
  254. {
  255. case OSPCOMP_EQ: pwchCriterion = L"="; break;
  256. case OSPCOMP_LT: pwchCriterion = L"<"; break;
  257. case OSPCOMP_LE: pwchCriterion = L"<="; break;
  258. case OSPCOMP_GE: pwchCriterion = L">="; break;
  259. case OSPCOMP_GT: pwchCriterion = L">"; break;
  260. case OSPCOMP_NE: pwchCriterion = L"<>"; break;
  261. default: pwchCriterion = L"??"; break;
  262. }
  263. *pbstrFilterCriterion = SysAllocString(pwchCriterion);
  264. hr = (*pbstrFilterCriterion == NULL) ? E_OUTOFMEMORY : S_OK;
  265. return hr;
  266. }
  267. STDMETHODIMP CTDCCtl::put_FilterCriterion(BSTR bstrFilterCriterion)
  268. {
  269. m_enumFilterCriterion = (OSPCOMP) 0;
  270. if (bstrFilterCriterion != NULL)
  271. {
  272. switch (bstrFilterCriterion[0])
  273. {
  274. case L'<':
  275. if (bstrFilterCriterion[1] == 0)
  276. m_enumFilterCriterion = OSPCOMP_LT;
  277. else if (bstrFilterCriterion[2] == 0)
  278. {
  279. if (bstrFilterCriterion[1] == L'>')
  280. m_enumFilterCriterion = OSPCOMP_NE;
  281. else if (bstrFilterCriterion[1] == L'=')
  282. m_enumFilterCriterion = OSPCOMP_LE;
  283. }
  284. break;
  285. case L'>':
  286. if (bstrFilterCriterion[1] == 0)
  287. m_enumFilterCriterion = OSPCOMP_GT;
  288. else if (bstrFilterCriterion[1] == L'=' && bstrFilterCriterion[2] == 0)
  289. m_enumFilterCriterion = OSPCOMP_GE;
  290. break;
  291. case L'=':
  292. if (bstrFilterCriterion[1] == 0)
  293. m_enumFilterCriterion = OSPCOMP_EQ;
  294. break;
  295. }
  296. }
  297. // Return SUCCESS, even on an invalid value; otherwise the
  298. // frameworks using the control will panic and abandon all hope.
  299. //
  300. return S_OK;
  301. }
  302. STDMETHODIMP CTDCCtl::get_FilterColumn(BSTR* pbstrFilterColumn)
  303. {
  304. *pbstrFilterColumn = m_cbstrFilterColumn.Copy();
  305. return S_OK;
  306. }
  307. STDMETHODIMP CTDCCtl::put_FilterColumn(BSTR bstrFilterColumn)
  308. {
  309. m_cbstrFilterColumn = bstrFilterColumn;
  310. return S_OK;
  311. }
  312. STDMETHODIMP CTDCCtl::get_CharSet(BSTR* pbstrCharSet)
  313. {
  314. HRESULT hr = E_FAIL;
  315. *pbstrCharSet = NULL;
  316. if (m_pML != NULL)
  317. {
  318. MIMECPINFO info;
  319. hr = m_pML->GetCodePageInfo(m_nCodePage, &info);
  320. if (SUCCEEDED(hr))
  321. {
  322. *pbstrCharSet = SysAllocString(info.wszWebCharset);
  323. if (*pbstrCharSet == NULL)
  324. hr = E_OUTOFMEMORY;
  325. }
  326. }
  327. return S_OK;
  328. }
  329. STDMETHODIMP CTDCCtl::put_CharSet(BSTR bstrCharSet)
  330. {
  331. HRESULT hr = E_FAIL;
  332. if (m_pML != NULL)
  333. {
  334. MIMECSETINFO info;
  335. hr = m_pML->GetCharsetInfo(bstrCharSet, &info);
  336. if (SUCCEEDED(hr))
  337. {
  338. m_nCodePage = info.uiInternetEncoding;
  339. }
  340. }
  341. return S_OK;
  342. }
  343. STDMETHODIMP CTDCCtl::get_Language(BSTR* pbstrLanguage)
  344. {
  345. if (m_pArr)
  346. {
  347. return m_pArr->getLocale(pbstrLanguage);
  348. }
  349. *pbstrLanguage = m_cbstrLanguage.Copy();
  350. return S_OK;
  351. }
  352. STDMETHODIMP CTDCCtl::put_Language_(LPWCH pwchLanguage)
  353. {
  354. HRESULT hr = S_OK;
  355. LCID lcid;
  356. hr = m_pML->GetLcidFromRfc1766(&lcid, pwchLanguage);
  357. if (SUCCEEDED(hr))
  358. {
  359. m_cbstrLanguage = pwchLanguage;
  360. m_lcidRead = lcid;
  361. }
  362. return S_OK;
  363. }
  364. STDMETHODIMP CTDCCtl::put_Language(BSTR bstrLanguage)
  365. {
  366. return put_Language_(bstrLanguage);
  367. }
  368. STDMETHODIMP CTDCCtl::get_DataURL(BSTR* pbstrDataURL)
  369. {
  370. *pbstrDataURL = m_cbstrDataURL.Copy();
  371. return S_OK;
  372. }
  373. STDMETHODIMP CTDCCtl::put_DataURL(BSTR bstrDataURL)
  374. {
  375. HRESULT hr = S_OK;
  376. m_cbstrDataURL = bstrDataURL;
  377. m_fDataURLChanged = TRUE;
  378. return hr;
  379. }
  380. // ;begin_internal
  381. #ifdef NEVER
  382. STDMETHODIMP CTDCCtl::get_RefreshInterval(LONG* plTimer)
  383. {
  384. *plTimer = m_lTimer;
  385. return S_OK;
  386. }
  387. STDMETHODIMP CTDCCtl::put_RefreshInterval(LONG lTimer)
  388. {
  389. m_lTimer = lTimer;
  390. if (m_lTimer > 0)
  391. TimerOn(m_lTimer * 1000);
  392. else
  393. TimerOff();
  394. return S_OK;
  395. }
  396. #endif
  397. // ;end_internal
  398. STDMETHODIMP CTDCCtl::get_Filter(BSTR* pbstrFilterExpr)
  399. {
  400. *pbstrFilterExpr = m_cbstrFilterExpr.Copy();
  401. return S_OK;
  402. }
  403. STDMETHODIMP CTDCCtl::put_Filter(BSTR bstrFilterExpr)
  404. {
  405. m_cbstrFilterExpr = bstrFilterExpr;
  406. return S_OK;
  407. }
  408. STDMETHODIMP CTDCCtl::get_Sort(BSTR* pbstrSortExpr)
  409. {
  410. *pbstrSortExpr = m_cbstrSortExpr.Copy();
  411. return S_OK;
  412. }
  413. STDMETHODIMP CTDCCtl::put_Sort(BSTR bstrSortExpr)
  414. {
  415. m_cbstrSortExpr = bstrSortExpr;
  416. return S_OK;
  417. }
  418. STDMETHODIMP CTDCCtl::get_AppendData(VARIANT_BOOL* pfAppendData)
  419. {
  420. *pfAppendData = m_fAppendData ? TDCVARIANT_TRUE : VARIANT_FALSE;
  421. return S_OK;
  422. }
  423. STDMETHODIMP CTDCCtl::put_AppendData(VARIANT_BOOL fAppendData)
  424. {
  425. m_fAppendData = fAppendData ? TRUE : FALSE;
  426. return S_OK;
  427. }
  428. STDMETHODIMP CTDCCtl::get_CaseSensitive(VARIANT_BOOL* pfCaseSensitive)
  429. {
  430. *pfCaseSensitive = m_fCaseSensitive ? TDCVARIANT_TRUE : VARIANT_FALSE;
  431. return S_OK;
  432. }
  433. STDMETHODIMP CTDCCtl::put_CaseSensitive(VARIANT_BOOL fCaseSensitive)
  434. {
  435. m_fCaseSensitive = fCaseSensitive ? TRUE : FALSE;
  436. return S_OK;
  437. }
  438. STDMETHODIMP CTDCCtl::get_OSP(OLEDBSimpleProviderX ** ppISTD)
  439. {
  440. // Return an OSP if we have one, but don't create one on demand!
  441. // (Otherwise property bag load stuff will cause us to create an
  442. // OSP prematurely).
  443. *ppISTD = NULL;
  444. if (m_pSTD)
  445. {
  446. *ppISTD = (OLEDBSimpleProviderX *)m_pSTD;
  447. m_pSTD->AddRef();
  448. }
  449. return S_OK;
  450. }
  451. //------------------------------------------------------------------------
  452. //
  453. // Method: UpdateReadyState
  454. //
  455. // Synopsis: Vectors to the event brokers ReadyState, if there is one.
  456. // ;begin_internal
  457. // Note, we have to be able to set our readystate and fire change
  458. // events on it, whether or not creation of the broker succeeded,
  459. // or we prevent our host container from reaching
  460. // READYSTATE_COMPLETE, which is not acceptable. We therefore
  461. // have to duplicate some of the broker's work here. This makes
  462. // me wonder whether the broker architecture was a good idea.
  463. // ;end_internal
  464. //
  465. // Arguments: None.
  466. //
  467. // Returns: S_OK upon success.
  468. // Error codes as per Reset() upon error.
  469. //
  470. //------------------------------------------------------------------------
  471. void
  472. CTDCCtl::UpdateReadyState(LONG lReadyState)
  473. {
  474. if (m_pEventBroker)
  475. m_pEventBroker->UpdateReadyState(lReadyState);
  476. else
  477. {
  478. // We have no broker, but our host is still waiting for us to
  479. // go READYSTATE_COMPLETE. We fire the OnChange here noting that
  480. // get_ReadyState with no broker will return COMPLETE.
  481. FireOnChanged(DISPID_READYSTATE);
  482. FireOnReadyStateChanged();
  483. }
  484. }
  485. //------------------------------------------------------------------------
  486. //
  487. // Method: _OnTimer()
  488. //
  489. // Synopsis: Handles an internal timer event by refreshing the control.
  490. //
  491. // Arguments: None.
  492. //
  493. // Returns: S_OK upon success.
  494. // Error codes as per Reset() upon error.
  495. //
  496. //------------------------------------------------------------------------
  497. STDMETHODIMP CTDCCtl::_OnTimer()
  498. {
  499. HRESULT hr = S_OK;
  500. if (m_pArr != NULL && m_pArr->GetLoadState() == CTDCArr::LS_LOADED)
  501. {
  502. m_fDataURLChanged = TRUE;
  503. hr = Reset();
  504. }
  505. return hr;
  506. }
  507. //------------------------------------------------------------------------
  508. //
  509. // Method: msDataSourceObject()
  510. //
  511. // Synopsis: Yields an ISimpleTabularData interface for this control.
  512. // If this is the first call, a load operation is initiated
  513. // reading data from the control's specified DataURL property.
  514. // An STD object is created to point to the control's embedded
  515. // TDCArr object.
  516. //
  517. // Arguments: qualifier Ignored - must be an empty BSTR.
  518. // ppUnk Pointer to returned interface [OUT]
  519. //
  520. // Returns: S_OK upon success.
  521. // E_INVALIDARG if 'qualifier' isn't an empty BSTR.
  522. // E_OUTOFMEMORY if non enough memory could be allocated to
  523. // complete the construction of the interface.
  524. //
  525. //------------------------------------------------------------------------
  526. STDMETHODIMP
  527. CTDCCtl::msDataSourceObject(BSTR qualifier, IUnknown **ppUnk)
  528. {
  529. HRESULT hr = S_OK;
  530. *ppUnk = NULL; // NULL in case of failure
  531. if (!EmptyBSTR(qualifier))
  532. {
  533. hr = E_INVALIDARG;
  534. goto error;
  535. }
  536. // Was there a previous attempt to load this page that failed?
  537. // (Probably due to security or file not found or something).
  538. if (m_hrDownloadStatus)
  539. {
  540. hr = m_hrDownloadStatus;
  541. goto error;
  542. }
  543. if (m_pArr == NULL)
  544. {
  545. // We don't have a valid TDC to give back, probably have to try
  546. // downloading one.
  547. UpdateReadyState(READYSTATE_LOADED);
  548. hr = CreateTDCArr(FALSE);
  549. if (hr)
  550. goto error;
  551. }
  552. _ASSERTE(m_pArr != NULL);
  553. if (m_pSTD == NULL)
  554. {
  555. OutputDebugStringX(_T("Creating an STD COM object\n"));
  556. // fetch ISimpleTabularData interface pointer
  557. m_pArr->QueryInterface(IID_OLEDBSimpleProvider, (void**)&m_pSTD);
  558. _ASSERTE(m_pSTD != NULL);
  559. }
  560. // Return the STD if we have one, otherwise it stays NULL
  561. if (m_pSTD && m_pArr->GetLoadState() >= CTDCArr::LS_LOADING_HEADER_AVAILABLE)
  562. {
  563. *ppUnk = (OLEDBSimpleProviderX *) m_pSTD;
  564. m_pSTD->AddRef(); // We must AddRef the STD we return!
  565. }
  566. cleanup:
  567. return hr;
  568. error:
  569. UpdateReadyState(READYSTATE_COMPLETE);
  570. goto cleanup;
  571. }
  572. // Override IPersistPropertyBagImpl::Load
  573. STDMETHODIMP
  574. CTDCCtl::Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
  575. {
  576. HRESULT hr;
  577. IUnknown *pSTD;
  578. // Find out our Ambient Charset. We need to know this surprisingly
  579. // early in life.
  580. VARIANT varCodepage;
  581. // 0 means user didn't set one, so ask our container.
  582. VariantInit(&varCodepage);
  583. GetAmbientProperty(DISPID_AMBIENT_CODEPAGE, varCodepage);
  584. // Ultimate default is Latin-1
  585. m_nAmbientCodePage = (varCodepage.vt == VT_UI4)
  586. ? (ULONG)varCodepage.lVal
  587. : CP_1252;
  588. // ignore Unicode ambient codepage - we want to allow non-Unicode
  589. // data files from Unicode pages. If the data file is Unicode,
  590. // we'll find out anyway when we see the Unicode signature.
  591. if (m_nAmbientCodePage == UNICODE_CP ||
  592. m_nAmbientCodePage == UNICODE_REVERSE_CP)
  593. {
  594. m_nAmbientCodePage = CP_1252;
  595. }
  596. // Do normal load
  597. // IPersistPropertyBagImpl<CTDCCtl>
  598. hr = IPersistPropertyBagImpl<CTDCCtl>::Load(pPropBag, pErrorLog);
  599. // and then start download, if we can
  600. (void)msDataSourceObject(NULL, &pSTD);
  601. // If we actually got an STD, we should release it. This won't really
  602. // make it go away, since we still have the ref from the QI. This is
  603. // a bit of a kludge that we should clean up later.
  604. ClearInterface(&pSTD);
  605. return hr;
  606. }
  607. //------------------------------------------------------------------------
  608. //
  609. // Method: CreateTDCArr()
  610. //
  611. // Synopsis: Creates the control's embedded TDCArr object.
  612. // Initiates a data download from the DataURL property.
  613. //
  614. // Arguments: fAppend Flag indicating whether data should be
  615. // appended to an existing TDC object.
  616. //
  617. // Returns: S_OK upon success.
  618. // E_OUTOFMEMORY if non enough memory could be allocated to
  619. // complete the construction of the TDCArr object.
  620. //
  621. //------------------------------------------------------------------------
  622. STDMETHODIMP
  623. CTDCCtl::CreateTDCArr(boolean fAppend)
  624. {
  625. HRESULT hr = S_OK;
  626. if (m_pEventBroker == NULL)
  627. {
  628. hr = E_FAIL;
  629. goto Error;
  630. }
  631. // Iff we're appending is m_pArr allowed to be non-null here.
  632. _ASSERT ((m_pArr != NULL) == !!fAppend);
  633. if (m_pArr == NULL)
  634. {
  635. m_pArr = new CTDCArr();
  636. if (m_pArr == NULL)
  637. {
  638. hr = E_OUTOFMEMORY;
  639. goto Error;
  640. }
  641. hr = m_pArr->Init(m_pEventBroker, m_pML);
  642. if (FAILED(hr))
  643. goto Error;
  644. }
  645. hr = InitiateDataLoad(fAppend);
  646. if (hr)
  647. goto Error;
  648. // We decide something is not async if it finished loading during
  649. // the InitiateDataLoad call.
  650. m_pArr->SetIsAsync(!(m_pArr->GetLoadState()==CTDCArr::LS_LOADED));
  651. Cleanup:
  652. return hr;
  653. Error:
  654. if (!fAppend)
  655. {
  656. ClearInterface(&m_pArr);
  657. }
  658. goto Cleanup;
  659. }
  660. //------------------------------------------------------------------------
  661. //
  662. // Method: ReleaseTDCArr()
  663. //
  664. // Synopsis: Releases the control's embedded TDCArr object.
  665. // Releases the control's CTDCUnify and CTDCTokenise objects.
  666. // Releases the old event broker and re-creates it if replacing.
  667. //
  668. // Arguments: fReplacingTDCArr Flag indicating whether a new TDCArr object
  669. // will be created.
  670. //
  671. // Returns: S_OK upon success.
  672. // Error code upon failure.
  673. // E_OUTOFMEMORY if non enough memory could be allocated to
  674. // complete the construction of the new CEventBroker object.
  675. //
  676. //------------------------------------------------------------------------
  677. STDMETHODIMP
  678. CTDCCtl::ReleaseTDCArr(boolean fReplacingTDCArr)
  679. {
  680. HRESULT hr = S_OK;
  681. TerminateDataLoad(m_pBSC);
  682. // Release the reference to the current TDCArr object
  683. //
  684. if (m_pArr != NULL)
  685. {
  686. m_pArr->Release();
  687. m_pArr = NULL;
  688. // Since we've shut down the CTDCArr object, we should release
  689. // it's OLEDBSimplerProviderListener sink.
  690. if (m_pEventBroker)
  691. {
  692. m_pEventBroker->SetSTDEvents(NULL);
  693. }
  694. if (fReplacingTDCArr)
  695. {
  696. // Release our previous Event Broker.
  697. if (m_pEventBroker)
  698. {
  699. m_pEventBroker->Release();
  700. m_pEventBroker = NULL;
  701. }
  702. // Create a new event broker.
  703. m_pEventBroker = new CEventBroker(this);
  704. if (m_pEventBroker == NULL)
  705. {
  706. hr = E_OUTOFMEMORY;
  707. goto Cleanup;
  708. }
  709. // Set the DataSourceListener for the new event broker.
  710. m_pEventBroker->SetDataSourceListener(m_pDataSourceListener);
  711. // ;begin_internal
  712. m_pEventBroker->SetDATASRCListener(m_pDATASRCListener);
  713. // ;end_internal
  714. }
  715. }
  716. Cleanup:
  717. return hr;
  718. }
  719. const IID IID_IDATASRCListener = {0x3050f380,0x98b5,0x11cf,{0xbb,0x82,0x00,0xaa,0x00,0xbd,0xce,0x0b}};
  720. const IID IID_DataSourceListener = {0x7c0ffab2,0xcd84,0x11d0,{0x94,0x9a,0x00,0xa0,0xc9,0x11,0x10,0xed}};
  721. //------------------------------------------------------------------------
  722. //
  723. // Method: addDataSourceListener()
  724. //
  725. // Synopsis: Sets the COM object which should receive notification
  726. // events.
  727. //
  728. // Arguments: pEvent Pointer to COM object to receive notification
  729. // events, or NULL if no notifications to be sent.
  730. //
  731. // Returns: S_OK upon success.
  732. // Error code upon failure.
  733. //
  734. //------------------------------------------------------------------------
  735. STDMETHODIMP
  736. CTDCCtl::addDataSourceListener(IUnknown *pListener)
  737. {
  738. if (m_pEventBroker != NULL)
  739. {
  740. HRESULT hr = S_OK;
  741. IUnknown * pDatasrcListener;
  742. // Make sure this is the interface we expect
  743. hr = pListener->QueryInterface(IID_DataSourceListener,
  744. (void **)&pDatasrcListener);
  745. if (SUCCEEDED(hr))
  746. {
  747. m_pEventBroker->
  748. SetDataSourceListener((DataSourceListener *)pDatasrcListener);
  749. // Clear any previous
  750. ClearInterface (&m_pDataSourceListener);
  751. // and remember the new.
  752. m_pDataSourceListener = (DataSourceListener *)pDatasrcListener;
  753. }
  754. // ;begin_internal
  755. else
  756. {
  757. // The definition of this interface was changed from IDATASRCListener to
  758. // DataSourceListener. To make sure we don't cause crashes, we QI to
  759. // determine which one we were handed.
  760. hr = pListener->QueryInterface(IID_IDATASRCListener,
  761. (void **)&pDatasrcListener);
  762. if (SUCCEEDED(hr))
  763. {
  764. m_pEventBroker->
  765. SetDATASRCListener((DATASRCListener *) pDatasrcListener);
  766. // Clear any previous
  767. ClearInterface (&m_pDATASRCListener);
  768. // and remember the new.
  769. m_pDATASRCListener = (DATASRCListener *)pDatasrcListener;
  770. }
  771. }
  772. // ;end_internal
  773. return hr;
  774. }
  775. else
  776. return E_FAIL;
  777. }
  778. //------------------------------------------------------------------------
  779. //
  780. // Method: Reset()
  781. //
  782. // Synopsis: Reset the control's filter/sort criteria.
  783. //
  784. // Arguments: None.
  785. //
  786. // Returns: S_OK upon success.
  787. // Error code upon failure.
  788. //
  789. //------------------------------------------------------------------------
  790. STDMETHODIMP CTDCCtl::Reset()
  791. {
  792. HRESULT hr = S_OK;
  793. // The next query to msDataSourceObject should get a new STD
  794. ClearInterface(&m_pSTD);
  795. // Infinite recursive calls to Reset can occur if script code calls reset
  796. // from within the datasetchanged event. This isn't a good idea.
  797. if (m_fInReset)
  798. {
  799. hr = E_FAIL;
  800. goto Cleanup;
  801. }
  802. m_fInReset = TRUE;
  803. // Clear any previous error
  804. m_hrDownloadStatus = S_OK;
  805. if (m_fDataURLChanged)
  806. {
  807. if (!m_fAppendData)
  808. {
  809. // Release previous TDC array with "replacing" flag.
  810. hr = ReleaseTDCArr(TRUE);
  811. if (!SUCCEEDED(hr)) // possible memory failure
  812. goto Cleanup;
  813. }
  814. // Read the new data into a TDC arry, appending if specified.
  815. hr = CreateTDCArr((BOOL)m_fAppendData);
  816. }
  817. else if (m_pArr != NULL)
  818. {
  819. // Re-apply the sort and filter criteria
  820. hr = m_pArr->SetSortFilterCriteria(bstrConstructSortExpr(),
  821. bstrConstructFilterExpr(),
  822. m_fCaseSensitive ? 1 : 0);
  823. }
  824. m_fInReset = FALSE;
  825. Cleanup:
  826. return hr;
  827. }
  828. //------------------------------------------------------------------------
  829. //
  830. // Method: bstrConstructSortExpr()
  831. //
  832. // Synopsis: Constructs a sort expression from the Sort property or
  833. // (for backward compatibility) from the SortColumn/SortAscending
  834. // properties.
  835. //
  836. // This method only exists to isolate backward-compatibility
  837. // with the old-fashioned sort properties.
  838. //
  839. // Arguments: None.
  840. //
  841. // Returns: The constructed sort expression.
  842. //
  843. // NB! It is the caller's responsibility to free the string returned.
  844. //
  845. //------------------------------------------------------------------------
  846. BSTR
  847. CTDCCtl::bstrConstructSortExpr()
  848. {
  849. BSTR bstr = NULL;
  850. if (!EmptyBSTR(m_cbstrSortExpr))
  851. bstr = SysAllocString(m_cbstrSortExpr);
  852. else if (!EmptyBSTR(m_cbstrSortColumn))
  853. {
  854. // Use the old-fashioned sort properties
  855. // Construct a sort expression of the form:
  856. // <SortColumn> or
  857. // -<SortColumn>
  858. //
  859. if (m_fSortAscending)
  860. bstr = SysAllocString(m_cbstrSortColumn);
  861. else
  862. {
  863. bstr = SysAllocStringLen(NULL, SysStringLen(m_cbstrSortColumn) + 1);
  864. if (bstr != NULL)
  865. {
  866. bstr[0] = L'-';
  867. wch_cpy(&bstr[1], m_cbstrSortColumn);
  868. }
  869. }
  870. }
  871. return bstr;
  872. }
  873. //------------------------------------------------------------------------
  874. //
  875. // Method: bstrConstructFilterExpr()
  876. //
  877. // Synopsis: Constructs a filter expression from the Filter property or
  878. // (for backward compatibility) from the FilterColumn/FilterValue/
  879. // FilterCriterion properties.
  880. //
  881. // This method only exists to isolate backward-compatibility
  882. // with the old-fashioned filter properties.
  883. //
  884. // Arguments: None.
  885. //
  886. // Returns: The constructed filter expression
  887. //
  888. // NB! It is the caller's responsibility to free the string returned.
  889. //
  890. //------------------------------------------------------------------------
  891. BSTR
  892. CTDCCtl::bstrConstructFilterExpr()
  893. {
  894. BSTR bstr = NULL;
  895. if (!EmptyBSTR(m_cbstrFilterExpr))
  896. bstr = SysAllocString(m_cbstrFilterExpr);
  897. else if (!EmptyBSTR(m_cbstrFilterColumn))
  898. {
  899. // Use the old-fashioned filter properties
  900. // Construct a sort expression of the form:
  901. // <FilterColumn> <FilterCriterion> "<FilterValue>"
  902. //
  903. BSTR bstrFilterOp;
  904. HRESULT hr;
  905. hr = get_FilterCriterion(&bstrFilterOp);
  906. if (!SUCCEEDED(hr))
  907. goto Cleanup;
  908. bstr = SysAllocStringLen(NULL,
  909. SysStringLen(m_cbstrFilterColumn) +
  910. SysStringLen(bstrFilterOp) +
  911. 1 +
  912. SysStringLen(m_cbstrFilterValue) +
  913. 1);
  914. if (bstr != NULL)
  915. {
  916. DWORD pos = 0;
  917. wch_cpy(&bstr[pos], m_cbstrFilterColumn);
  918. pos = wch_len(bstr);
  919. wch_cpy(&bstr[pos], bstrFilterOp);
  920. pos = wch_len(bstr);
  921. bstr[pos++] = L'"';
  922. wch_cpy(&bstr[pos], m_cbstrFilterValue);
  923. pos = wch_len(bstr);
  924. bstr[pos++] = L'"';
  925. bstr[pos] = 0;
  926. }
  927. SysFreeString(bstrFilterOp);
  928. }
  929. Cleanup:
  930. return bstr;
  931. }
  932. //------------------------------------------------------------------------
  933. //
  934. // Method: TerminateDataLoad()
  935. //
  936. // Synopsis: Stop the current data load operation.
  937. //
  938. // Returns: S_OK upon success.
  939. //
  940. //------------------------------------------------------------------------
  941. STDMETHODIMP CTDCCtl::TerminateDataLoad(CMyBindStatusCallback<CTDCCtl> *pBSC)
  942. {
  943. HRESULT hr = S_OK;
  944. // if the termination isn't for the current download, ignore it (bug 104042)
  945. if (pBSC != m_pBSC)
  946. goto done;
  947. // Make sure if we call Reset() right away now, we don't re-download
  948. // the data.
  949. m_fDataURLChanged = FALSE;
  950. m_pBSC = NULL; // Block any outstanding OnData calls
  951. if (m_pEventBroker)
  952. m_pEventBroker->m_pBSC = NULL; // kill all
  953. if (m_pUnify != NULL)
  954. delete m_pUnify;
  955. m_pUnify = NULL;
  956. done:
  957. return hr;
  958. }
  959. //------------------------------------------------------------------------
  960. //
  961. // Method: InitiateDataLoad()
  962. //
  963. // Synopsis: Start loading data from the control's DataURL property.
  964. //
  965. // Arguments: fAppend Flag to indicate whether data should be
  966. // appended to an existing TDCArr object.
  967. //
  968. // Returns: S_OK upon success.
  969. // E_OUTOFMEMORY if not enough memory could be allocated to
  970. // complete the download.
  971. //
  972. //------------------------------------------------------------------------
  973. STDMETHODIMP CTDCCtl::InitiateDataLoad(boolean fAppend)
  974. {
  975. HRESULT hr = S_OK;
  976. WCHAR wchFieldDelim = (!m_cbstrFieldDelim) ? 0 : m_cbstrFieldDelim[0];
  977. WCHAR wchRowDelim = (!m_cbstrRowDelim) ? 0 : m_cbstrRowDelim[0];
  978. // Default quote char to double-quote, not NULL
  979. WCHAR wchQuoteChar = (!m_cbstrQuoteChar) ? 0 : m_cbstrQuoteChar[0];
  980. WCHAR wchEscapeChar = (!m_cbstrEscapeChar) ? 0 : m_cbstrEscapeChar[0];
  981. //
  982. // Default LCID
  983. //
  984. if (0==m_lcidRead)
  985. {
  986. hr = GetAmbientLocaleID(m_lcidRead);
  987. if (FAILED(hr))
  988. {
  989. // Ultimate default is US locale -- sort of Web global
  990. // language default.
  991. put_Language_(L"en-us");
  992. }
  993. }
  994. if (EmptyBSTR(m_cbstrDataURL))
  995. {
  996. hr = S_FALSE; // quiet failure
  997. goto Error;
  998. }
  999. OutputDebugStringX(_T("Initiating Data Download\n"));
  1000. // No data load should currently be in progress -
  1001. // This data load has been initiated on the construction of a new
  1002. // TDCArr object, or appending to an existing loaded TDCArr object.
  1003. // Any currently running data load would have been
  1004. // terminated by the call to ReleaseTDCArr().
  1005. //
  1006. _ASSERT(m_pUnify == NULL);
  1007. _ASSERT(m_pBSC == NULL);
  1008. m_hrDownloadStatus = S_OK;
  1009. // Create a pipeline of objects to process the URL data
  1010. //
  1011. // CMyBindStatusCallback -> CTDCUnify -> CTDCTokenise -> CTDCArr
  1012. //
  1013. CComObject<CMyBindStatusCallback<CTDCCtl> >::CreateInstance(&m_pBSC);
  1014. if (m_pBSC == NULL)
  1015. {
  1016. hr = E_FAIL;
  1017. goto Error;
  1018. }
  1019. hr = m_pArr->StartDataLoad(m_fUseHeader ? TRUE : FALSE,
  1020. bstrConstructSortExpr(),
  1021. bstrConstructFilterExpr(),
  1022. m_lcidRead,
  1023. m_pBSC,
  1024. fAppend,
  1025. m_fCaseSensitive ? 1 : 0);
  1026. if (!SUCCEEDED(hr))
  1027. goto Error;
  1028. m_pUnify = new CTDCUnify();
  1029. if (m_pUnify == NULL)
  1030. {
  1031. hr = E_OUTOFMEMORY;
  1032. goto Error;
  1033. }
  1034. m_pUnify->Create(m_nCodePage, m_nAmbientCodePage, m_pML);
  1035. // Init tokenizer
  1036. m_pUnify->InitTokenizer(m_pArr, wchFieldDelim, wchRowDelim,
  1037. wchQuoteChar, wchEscapeChar);
  1038. m_fSecurityChecked = FALSE;
  1039. // Start (and maybe perform) actual download.
  1040. // If we're within a Reset() call, always force a "reload" of the data
  1041. // from the server -- i.e. turn on BINDF_GETNEWESTVERSION to make sure
  1042. // sure the cache data isn't stale.
  1043. hr = m_pBSC->StartAsyncDownload(this, OnData, m_cbstrDataURL, m_spClientSite, TRUE,
  1044. m_fInReset == TRUE);
  1045. if (FAILED(hr))
  1046. goto Error;
  1047. // m_hrDownloadStatus remembers the first (if any) error that occured during
  1048. // the OnData callbacks. Unlike an error returning from StartAsyncDownload,
  1049. // this doesn't necessarily cause us to throw away the TDC array.
  1050. hr = m_hrDownloadStatus;
  1051. if (!SUCCEEDED(hr))
  1052. m_pBSC = NULL;
  1053. Cleanup:
  1054. return hr;
  1055. Error:
  1056. TerminateDataLoad(m_pBSC);
  1057. if (m_pEventBroker)
  1058. {
  1059. // Fire data set changed to indicate query failed,
  1060. m_pEventBroker->STDDataSetChanged();
  1061. // and go complete.
  1062. UpdateReadyState(READYSTATE_COMPLETE);
  1063. }
  1064. goto Cleanup;
  1065. }
  1066. //------------------------------------------------------------------------
  1067. //
  1068. // Method: SecurityCheckDataURL(pszURL)
  1069. //
  1070. // Synopsis: Check that the data URL is within the same security zone
  1071. // as the document that loaded the control.
  1072. //
  1073. // Arguments: URL to check
  1074. //
  1075. // Returns: S_OK upon success.
  1076. // E_INVALID if the security check failed or we failed to get
  1077. // an interface that we needed
  1078. //
  1079. //------------------------------------------------------------------------
  1080. // ;begin_internal
  1081. // Wendy Richards(v-wendri) 6/6/97
  1082. // Copied this here because I couldn't link without it. The version
  1083. // of URLMON.LIB I have does not have this symbol exported
  1084. // ;end_internal
  1085. EXTERN_C const IID IID_IInternetHostSecurityManager;
  1086. #define MAX_SEC_ID 256
  1087. STDMETHODIMP CTDCCtl::SecurityCheckDataURL(LPOLESTR pszURL)
  1088. {
  1089. CComQIPtr<IServiceProvider, &IID_IServiceProvider> pSP(m_spClientSite);
  1090. CComPtr<IInternetSecurityManager> pSM;
  1091. CComPtr<IInternetHostSecurityManager> pHSM;
  1092. CComPtr<IMoniker> pMoniker;
  1093. BYTE bSecIDHost[MAX_SEC_ID], bSecIDURL[MAX_SEC_ID];
  1094. DWORD cbSecIDHost = MAX_SEC_ID, cbSecIDURL = MAX_SEC_ID;
  1095. HRESULT hr = E_FAIL;
  1096. USES_CONVERSION;
  1097. // If we're running under the timer, it's quite possible our ClientSite will
  1098. // disappear out from under us. We'll obviously fail the security check,
  1099. // but things are shutting down anyway..
  1100. if (pSP==NULL)
  1101. goto Cleanup;
  1102. hr = CoInternetCreateSecurityManager(pSP, &pSM, 0L);
  1103. if (!SUCCEEDED(hr))
  1104. goto Cleanup;
  1105. hr = pSP->QueryService(IID_IInternetHostSecurityManager,
  1106. IID_IInternetHostSecurityManager,
  1107. (LPVOID *)&pHSM);
  1108. if (!SUCCEEDED(hr))
  1109. goto Cleanup;
  1110. hr = pHSM->GetSecurityId(bSecIDHost, &cbSecIDHost, 0L);
  1111. if (!SUCCEEDED(hr))
  1112. goto Cleanup;
  1113. hr = pSM->GetSecurityId(OLE2W(pszURL), bSecIDURL, &cbSecIDURL, 0L);
  1114. if (!SUCCEEDED(hr))
  1115. goto Cleanup;
  1116. if (cbSecIDHost != cbSecIDURL)
  1117. {
  1118. hr = E_FAIL;
  1119. goto Cleanup;
  1120. }
  1121. if (memcmp(bSecIDHost, bSecIDURL, cbSecIDHost) != 0)
  1122. {
  1123. hr = E_FAIL;
  1124. goto Cleanup;
  1125. }
  1126. Cleanup:
  1127. #ifdef ATLTRACE
  1128. LPOLESTR pszHostName = NULL;
  1129. TCHAR *pszFailPass = hr ? _T("Failed") : _T("Passed");
  1130. GetHostURL(m_spClientSite, &pszHostName);
  1131. ATLTRACE(_T("CTDCCtl: %s security check on %S referencing %S\n"), pszFailPass,
  1132. pszHostName, pszURL);
  1133. bSecIDHost[cbSecIDHost] = 0;
  1134. bSecIDURL[cbSecIDURL] = 0;
  1135. ATLTRACE(_T("CTDCCtl: Security ID Host %d bytes: %s\n"), cbSecIDHost, bSecIDHost);
  1136. ATLTRACE(_T("CTDCCtl: Security ID URL %d bytes: %s\n"), cbSecIDURL, bSecIDURL);
  1137. CoTaskMemFree(pszHostName);
  1138. #endif
  1139. return hr;
  1140. }
  1141. //------------------------------------------------------------------------
  1142. //
  1143. // Method: OnData()
  1144. //
  1145. // Synopsis: Accepts a chunk of data loaded from a URL and parses it.
  1146. //
  1147. // Arguments: pBSC The invoking data transfer object.
  1148. // pBytes Character buffer containing data.
  1149. // dwSize Count of the number of bytes in 'pBytes'.
  1150. //
  1151. // Returns: Nothing.
  1152. //
  1153. //------------------------------------------------------------------------
  1154. void CTDCCtl::OnData(CMyBindStatusCallback<CTDCCtl> *pBSC, BYTE *pBytes, DWORD dwSize)
  1155. {
  1156. HRESULT hr = S_OK;
  1157. CTDCUnify::ALLOWDOMAINLIST nAllowDomainList;
  1158. if (pBSC != m_pBSC)
  1159. {
  1160. OutputDebugStringX(_T("OnData called from invalid callback object\n"));
  1161. goto Cleanup;
  1162. }
  1163. // ignore callbacks from an aborted download
  1164. if (m_hrDownloadStatus == E_ABORT)
  1165. goto Cleanup;
  1166. // Process this chunk of data
  1167. //
  1168. hr = m_pUnify->ConvertByteBuffer(pBytes, dwSize);
  1169. if (hr == S_FALSE)
  1170. {
  1171. // not enough data has shown up yet, just keep going
  1172. hr = S_OK;
  1173. goto Cleanup;
  1174. }
  1175. if (hr)
  1176. goto Error;
  1177. if (!m_fSecurityChecked)
  1178. {
  1179. // this forces the code below to check the DataURL, unless the allow_domain
  1180. // list needs checking and it passes. In that case, we need only check
  1181. // the protocols, not the whole URL.
  1182. hr = E_FAIL;
  1183. if (!m_pUnify->ProcessedAllowDomainList())
  1184. {
  1185. // Note that we MUST check for the allow domain list at the
  1186. // front of every file, even if it's on the same host. This
  1187. // is to make sure if we always strip off the @!allow_domain line.
  1188. nAllowDomainList = m_pUnify->CheckForAllowDomainList();
  1189. switch (nAllowDomainList)
  1190. {
  1191. // Don't have enough chars to tell yet.
  1192. case CTDCUnify::ALLOW_DOMAINLIST_DONTKNOW:
  1193. if (pBytes != NULL && dwSize != 0)
  1194. {
  1195. // Return without errors or arborting.
  1196. // Presumably the next data packet will bring more info.
  1197. return;
  1198. }
  1199. _ASSERT(FAILED(hr));
  1200. break;
  1201. case CTDCUnify::ALLOW_DOMAINLIST_NO:
  1202. _ASSERT(FAILED(hr));
  1203. break;
  1204. case CTDCUnify::ALLOW_DOMAINLIST_YES:
  1205. // The file is decorated. Now check the domain list
  1206. // against our host domain name.
  1207. hr = SecurityMatchAllowDomainList();
  1208. #ifdef ATLTRACE
  1209. if (!hr) ATLTRACE(_T("CTDCCtl: @!allow_domain list matched."));
  1210. else ATLTRACE(_T("CTDCCtl: @!allow_domain list did not match"));
  1211. #endif
  1212. break;
  1213. }
  1214. }
  1215. // Unless we passed the previous security check, we still have to
  1216. // do the next one.
  1217. if (FAILED(hr))
  1218. {
  1219. if (FAILED(hr = SecurityCheckDataURL(m_pBSC->m_pszURL)))
  1220. goto Error;
  1221. }
  1222. else
  1223. {
  1224. hr = SecurityMatchProtocols(m_pBSC->m_pszURL);
  1225. if (FAILED(hr))
  1226. goto Error;
  1227. }
  1228. // Set m_fSecurityChecked only if it passes security. This is in case for some
  1229. // reason we get more callbacks before the StopTransfer takes affect.
  1230. m_fSecurityChecked = TRUE;
  1231. }
  1232. if (pBytes != NULL && dwSize != 0)
  1233. {
  1234. OutputDebugStringX(_T("OnData called with data buffer\n"));
  1235. // Normal case, we can process data!
  1236. hr = m_pUnify->AddWcharBuffer(FALSE);
  1237. if (hr == E_ABORT)
  1238. goto Error;
  1239. }
  1240. else if (pBytes == NULL || dwSize == 0)
  1241. {
  1242. OutputDebugStringX(_T("OnData called with empty (terminating) buffer\n"));
  1243. // No more data - trigger an EOF
  1244. //
  1245. hr = m_pUnify->AddWcharBuffer(TRUE); // last chance to parse any stragglers
  1246. if (hr == E_ABORT)
  1247. goto Error;
  1248. if (m_pArr!=NULL)
  1249. hr = m_pArr->EOF();
  1250. TerminateDataLoad(pBSC);
  1251. }
  1252. Cleanup:
  1253. // Void fn - can't return an error code ...
  1254. //
  1255. if (SUCCEEDED(m_hrDownloadStatus))
  1256. m_hrDownloadStatus = hr;
  1257. return;
  1258. Error:
  1259. // Security failure.
  1260. // Abort the current download
  1261. if (m_pBSC && m_pBSC->m_spBinding)
  1262. {
  1263. (void) m_pBSC->m_spBinding->Abort();
  1264. // also delete the downloaded file from the internet cache
  1265. m_pBSC->DeleteDataFile();
  1266. }
  1267. m_hrDownloadStatus = hr;
  1268. // Notify data set changed for the abort
  1269. if (m_pEventBroker != NULL)
  1270. {
  1271. hr = m_pEventBroker->STDDataSetChanged();
  1272. // and go complete.
  1273. UpdateReadyState(READYSTATE_COMPLETE);
  1274. }
  1275. goto Cleanup;
  1276. }
  1277. //
  1278. // Utility routine to get our
  1279. //
  1280. HRESULT
  1281. GetHostURL(IOleClientSite *pSite, LPOLESTR *ppszHostName)
  1282. {
  1283. HRESULT hr;
  1284. CComPtr<IMoniker> spMoniker;
  1285. CComPtr<IBindCtx> spBindCtx;
  1286. if (!pSite)
  1287. {
  1288. hr = E_FAIL;
  1289. goto Cleanup;
  1290. }
  1291. hr = pSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_CONTAINER,
  1292. &spMoniker);
  1293. if (FAILED(hr))
  1294. goto Cleanup;
  1295. hr = CreateBindCtx(0, &spBindCtx);
  1296. if (FAILED(hr))
  1297. goto Cleanup;
  1298. hr = spMoniker->GetDisplayName(spBindCtx, NULL, ppszHostName);
  1299. if (FAILED(hr))
  1300. goto Cleanup;
  1301. Cleanup:
  1302. return hr;
  1303. }
  1304. HRESULT
  1305. CTDCCtl::SecurityMatchProtocols(LPOLESTR pszURL)
  1306. {
  1307. HRESULT hr = E_FAIL;
  1308. LPOLESTR pszHostURL = NULL;
  1309. LPWCH pszPostHostProtocol;
  1310. LPWCH pszPostProtocol;
  1311. if (FAILED(GetHostURL(m_spClientSite, &pszHostURL)))
  1312. goto Cleanup;
  1313. pszPostHostProtocol = wch_chr(pszHostURL, _T(':'));
  1314. pszPostProtocol = wch_chr(pszURL, _T(':'));
  1315. if (!pszPostHostProtocol || !pszPostProtocol)
  1316. goto Cleanup;
  1317. else
  1318. {
  1319. int ccChars1 = pszPostHostProtocol - pszHostURL;
  1320. int ccChars2 = pszPostProtocol - pszURL;
  1321. if (ccChars1 != ccChars2)
  1322. goto Cleanup;
  1323. else if (wch_ncmp(pszHostURL, pszURL, ccChars1) != 0)
  1324. goto Cleanup;
  1325. }
  1326. hr = S_OK;
  1327. Cleanup:
  1328. if (pszHostURL)
  1329. CoTaskMemFree(pszHostURL);
  1330. return hr;
  1331. }
  1332. HRESULT
  1333. CTDCCtl::SecurityMatchAllowDomainList()
  1334. {
  1335. HRESULT hr;
  1336. WCHAR swzHostDomain[INTERNET_MAX_HOST_NAME_LENGTH];
  1337. DWORD cchHostDomain = INTERNET_MAX_HOST_NAME_LENGTH;
  1338. LPOLESTR pszHostName = NULL;
  1339. hr = GetHostURL(m_spClientSite, &pszHostName);
  1340. if (FAILED(hr))
  1341. goto Cleanup;
  1342. hr = CoInternetParseUrl(pszHostName, PARSE_DOMAIN, 0, swzHostDomain, cchHostDomain,
  1343. &cchHostDomain, 0);
  1344. if (FAILED(hr))
  1345. goto Cleanup;
  1346. hr = m_pUnify->MatchAllowDomainList(swzHostDomain);
  1347. Cleanup:
  1348. CoTaskMemFree(pszHostName);
  1349. return hr;
  1350. }