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.

617 lines
16 KiB

  1. #include "priv.h"
  2. #ifdef FEATURE_PICS
  3. #include "asyncrat.h"
  4. #include <ratings.h>
  5. #include "dochost.h"
  6. #include <mshtmdid.h>
  7. /* There is a PicsQuery structure in the following global array for each
  8. * outstanding query. It records the address of the PicsData structure in
  9. * the corresponding w3doc, the window handle corresponding to the Mwin,
  10. * and a serial number. This way, RatingObtainQueryCallback can tell if
  11. * the page the query corresponds to still exists, before posting a message;
  12. * and PicsDataMessageLoop can tell if the doc still exists when the message
  13. * finally gets delivered.
  14. *
  15. * The array is dynamically allocated and is protected by the main HTML
  16. * critical section.
  17. */
  18. HDSA g_haQueries = NULL;
  19. DWORD g_dwPicsSerial = 1L;
  20. const UINT c_cQueryAllocSize = 8; /* should be plenty by default */
  21. UINT g_crefQueries = 0;
  22. /* AddPicsQuery - add an outstanding PICS query to the list, given a window
  23. * handle to send a completion message to. Returns the serial number of the
  24. * query for later reference.
  25. */
  26. DWORD _AddPicsQuery(HWND hwnd)
  27. {
  28. ENTERCRITICAL;
  29. DWORD dwRet = 0;
  30. if (g_haQueries == NULL) {
  31. g_haQueries = DSA_Create(sizeof(PicsQuery), c_cQueryAllocSize);
  32. }
  33. if (g_haQueries != NULL) {
  34. PicsQuery q;
  35. q.dwSerial = ::g_dwPicsSerial++;
  36. q.hwnd = hwnd;
  37. q.lpvRatingDetails = NULL;
  38. if (DSA_InsertItem(g_haQueries, DA_LAST, &q) >= 0)
  39. dwRet = q.dwSerial;
  40. }
  41. LEAVECRITICAL;
  42. return dwRet;
  43. }
  44. /* RemovePicsQuery - remove an outstanding query based on its serial number.
  45. */
  46. void _RemovePicsQuery(DWORD dwSerial)
  47. {
  48. ENTERCRITICAL;
  49. if (g_haQueries != NULL) {
  50. UINT cQueries = DSA_GetItemCount(g_haQueries);
  51. PicsQuery *pq = NULL;
  52. for (UINT i=0; i<cQueries; i++) {
  53. pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  54. if (pq != NULL && pq->dwSerial == dwSerial)
  55. break;
  56. }
  57. if (pq != NULL) {
  58. if (pq->lpvRatingDetails != NULL)
  59. ::RatingFreeDetails(pq->lpvRatingDetails);
  60. DSA_DeleteItem(g_haQueries, i);
  61. }
  62. }
  63. LEAVECRITICAL;
  64. }
  65. /* GetPicsQuery - get a copy of an outstanding PICS query record, given its
  66. * serial number. Returns TRUE if found.
  67. */
  68. BOOL _GetPicsQuery(DWORD dwSerial, PicsQuery *pOut)
  69. {
  70. ENTERCRITICAL;
  71. PicsQuery *pq = NULL;
  72. if (g_haQueries != NULL) {
  73. UINT cQueries = DSA_GetItemCount(g_haQueries);
  74. for (UINT i=0; i<cQueries; i++) {
  75. pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  76. if (pq != NULL && pq->dwSerial == dwSerial)
  77. break;
  78. }
  79. if (pq != NULL) {
  80. *pOut = *pq;
  81. pq->lpvRatingDetails = NULL; /* caller's copy owns this now */
  82. }
  83. }
  84. LEAVECRITICAL;
  85. return pq != NULL;
  86. }
  87. /* _RefPicsQueries - add a reference to the async query array */
  88. void _RefPicsQueries(void)
  89. {
  90. ENTERCRITICAL;
  91. ++g_crefQueries;
  92. LEAVECRITICAL;
  93. }
  94. /* _ReleasePicsQueries - cleanup all memory associated with outstanding queries
  95. */
  96. void _ReleasePicsQueries(void)
  97. {
  98. ENTERCRITICAL;
  99. if (!--g_crefQueries) {
  100. if (g_haQueries != NULL) {
  101. UINT cQueries = DSA_GetItemCount(g_haQueries);
  102. for (UINT i=0; i<cQueries; i++) {
  103. PicsQuery *pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  104. if (pq != NULL && pq->lpvRatingDetails != NULL) {
  105. RatingFreeDetails(pq->lpvRatingDetails);
  106. }
  107. }
  108. DSA_Destroy(g_haQueries);
  109. g_haQueries = NULL;
  110. // leave g_dwPicsSerial as it is, just in case we start up again
  111. }
  112. }
  113. LEAVECRITICAL;
  114. }
  115. /* PostPicsMessage - formats up a custom window message to signal that a
  116. * query is complete. Format is WM_PICS_STATUS(hresult,dwSerial). Other
  117. * information (the rating details blob obtained from RatingCheckUserAccess)
  118. * is stored in the query record for safekeeping.
  119. *
  120. * Returns TRUE if a message was posted successfully to the right window.
  121. */
  122. BOOL _PostPicsMessage(DWORD dwSerial, HRESULT hr, LPVOID lpvRatingDetails)
  123. {
  124. BOOL fRet = FALSE;
  125. ENTERCRITICAL;
  126. if (g_haQueries != NULL) {
  127. PicsQuery *pq = NULL;
  128. UINT cQueries = DSA_GetItemCount(g_haQueries);
  129. for (UINT i=0; i<cQueries; i++) {
  130. pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  131. if (pq != NULL && pq->dwSerial == dwSerial)
  132. break;
  133. }
  134. if (pq != NULL) {
  135. pq->lpvRatingDetails = lpvRatingDetails;
  136. fRet = PostMessage(pq->hwnd, WM_PICS_ASYNCCOMPLETE, (WPARAM)hr,
  137. (LPARAM)dwSerial);
  138. if (!fRet) { /* oops, couldn't post message, don't keep copy of details */
  139. pq->lpvRatingDetails = NULL;
  140. }
  141. }
  142. }
  143. LEAVECRITICAL;
  144. return fRet;
  145. }
  146. /* Class CPicsRootDownload manages the download of the root document of a
  147. * site, to get ratings from it.
  148. */
  149. CPicsRootDownload::CPicsRootDownload(IOleCommandTarget *pctParent, BOOL fFrameIsOffline, BOOL fFrameIsSilent)
  150. {
  151. m_cRef = 1;
  152. m_pctParent = pctParent; m_pctParent->AddRef();
  153. m_pole = NULL;
  154. m_pctObject = NULL;
  155. m_pBinding = NULL;
  156. m_fFrameIsOffline = fFrameIsOffline ? TRUE : FALSE;
  157. m_fFrameIsSilent = fFrameIsSilent ? TRUE : FALSE;
  158. }
  159. CPicsRootDownload::~CPicsRootDownload()
  160. {
  161. ATOMICRELEASE(m_pctParent);
  162. CleanUp();
  163. ATOMICRELEASE(m_pBinding);
  164. ATOMICRELEASE(m_pBindCtx);
  165. }
  166. HRESULT CPicsRootDownload::StartDownload(IMoniker *pmk)
  167. {
  168. IUnknown *punk = NULL;
  169. HRESULT hr;
  170. hr = CreateBindCtx(0, &m_pBindCtx);
  171. if (FAILED(hr))
  172. goto LErrExit;
  173. /*
  174. hr = m_pBindCtx->RegisterObjectParam(BROWSER_OPTIONS_OBJECT_NAME,
  175. (IBrowseControl *)this);
  176. if (FAILED(hr))
  177. goto LErrExit;
  178. */
  179. //
  180. // Associate the client site as an object parameter to this
  181. // bind context so that Trident can pick it up while processing
  182. // IPersistMoniker::Load().
  183. //
  184. m_pBindCtx->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite,
  185. SAFECAST(this, IOleClientSite*));
  186. hr = RegisterBindStatusCallback(m_pBindCtx,
  187. (IBindStatusCallback *)this,
  188. 0,
  189. 0L);
  190. if (FAILED(hr))
  191. goto LErrExit;
  192. hr = pmk->BindToObject(m_pBindCtx, NULL, IID_IUnknown, (LPVOID*)&punk);
  193. if (SUCCEEDED(hr) || hr==E_PENDING)
  194. {
  195. hr = S_OK;
  196. //
  197. // If moniker happen to return the object synchronously, emulate
  198. // OnDataAvailable callback and OnStopBinding.
  199. //
  200. if (punk)
  201. {
  202. OnObjectAvailable(IID_IUnknown, punk);
  203. OnStopBinding(hr, NULL);
  204. punk->Release();
  205. }
  206. }
  207. else
  208. {
  209. /* OnStopBinding can be called by URLMON within the BindToObject
  210. * call in some cases. So, don't call it ourselves if it's
  211. * already been called (we can tell by looking whether our
  212. * bind context still exists).
  213. */
  214. if (m_pBindCtx != NULL) {
  215. OnStopBinding(hr, NULL);
  216. }
  217. }
  218. LErrExit:
  219. if (FAILED(hr) && (m_pBindCtx != NULL)) {
  220. m_pBindCtx->Release();
  221. m_pBindCtx = NULL;
  222. }
  223. return hr;
  224. }
  225. /* _NotifyEndOfDocument is used in all the error cases to make sure the caller
  226. * gets a notification of some sort. The case where this function does not
  227. * send a notification is if we have a valid OLE object -- in that case, we're
  228. * assuming that we have it because we know it supports PICS, therefore we're
  229. * expecting it to send such a notification to the parent itself.
  230. */
  231. void CPicsRootDownload::_NotifyEndOfDocument(void)
  232. {
  233. if (m_pole == NULL) {
  234. if (m_pctParent != NULL) {
  235. m_pctParent->Exec(&CGID_ShellDocView, SHDVID_NOMOREPICSLABELS, 0, NULL, NULL);
  236. }
  237. }
  238. }
  239. HRESULT CPicsRootDownload::_Abort()
  240. {
  241. if (m_pBinding)
  242. {
  243. return m_pBinding->Abort();
  244. }
  245. return S_FALSE;
  246. }
  247. void CPicsRootDownload::CleanUp()
  248. {
  249. _Abort();
  250. if (m_pctObject != NULL) {
  251. VARIANTARG v;
  252. v.vt = VT_UNKNOWN;
  253. v.punkVal = NULL;
  254. m_pctObject->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
  255. m_pctObject->Exec(NULL, OLECMDID_STOP, NULL, NULL, NULL);
  256. ATOMICRELEASE(m_pctObject);
  257. }
  258. LPOLECLIENTSITE pcs;
  259. if (m_pole && SUCCEEDED(m_pole->GetClientSite(&pcs)) && pcs)
  260. {
  261. if (pcs == SAFECAST(this, LPOLECLIENTSITE))
  262. {
  263. m_pole->SetClientSite(NULL);
  264. }
  265. pcs->Release();
  266. }
  267. ATOMICRELEASE(m_pole);
  268. }
  269. // IUnknown members
  270. STDMETHODIMP CPicsRootDownload::QueryInterface(REFIID riid, void **punk)
  271. {
  272. *punk = NULL;
  273. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IsPicsBrowser))
  274. *punk = (IUnknown *)(IBindStatusCallback *)this;
  275. else if (IsEqualIID(riid, IID_IBindStatusCallback))
  276. *punk = (IBindStatusCallback *)this;
  277. else if (IsEqualIID(riid, IID_IOleClientSite))
  278. *punk = (IOleClientSite *)this;
  279. else if (IsEqualIID(riid, IID_IServiceProvider))
  280. *punk = (IServiceProvider *)this;
  281. else if (IsEqualIID(riid, IID_IDispatch))
  282. *punk = (IDispatch *)this;
  283. if (*punk != NULL) {
  284. ((IUnknown *)(*punk))->AddRef();
  285. return S_OK;
  286. }
  287. return E_NOINTERFACE;
  288. }
  289. STDMETHODIMP_(ULONG) CPicsRootDownload::AddRef(void)
  290. {
  291. ++m_cRef;
  292. TraceMsg(TF_SHDREF, "CPicsRootDownload(%x)::AddRef called, new m_cRef=%d", this, m_cRef);
  293. return m_cRef;
  294. }
  295. STDMETHODIMP_(ULONG) CPicsRootDownload::Release(void)
  296. {
  297. UINT crefNew = --m_cRef;
  298. TraceMsg(TF_SHDREF, "CPicsRootDownload(%x)::Release called, new m_cRef=%d", this, m_cRef);
  299. if (!crefNew)
  300. delete this;
  301. return crefNew;
  302. }
  303. // IBindStatusCallback methods
  304. STDMETHODIMP CPicsRootDownload::OnStartBinding(DWORD dwReserved, IBinding* pbinding)
  305. {
  306. if (m_pBinding != NULL)
  307. m_pBinding->Release();
  308. m_pBinding = pbinding;
  309. if (m_pBinding != NULL)
  310. m_pBinding->AddRef();
  311. return S_OK;
  312. }
  313. STDMETHODIMP CPicsRootDownload::GetPriority(LONG* pnPriority)
  314. {
  315. return E_NOTIMPL;
  316. }
  317. STDMETHODIMP CPicsRootDownload::OnLowResource(DWORD dwReserved)
  318. {
  319. return E_NOTIMPL;
  320. }
  321. STDMETHODIMP CPicsRootDownload::OnProgress(ULONG ulProgress, ULONG ulProgressMax,
  322. ULONG ulStatusCode, LPCWSTR pwzStatusText)
  323. {
  324. /* If the root document's data type is not HTML, don't try to get any
  325. * ratings out of it, just abort.
  326. */
  327. if (ulStatusCode == BINDSTATUS_CLASSIDAVAILABLE) {
  328. BOOL fContinueDownload = FALSE;
  329. CLSID clsid;
  330. // CLSIDFromString is prototyped wrong, non const first param
  331. HRESULT hresT = CLSIDFromString((WCHAR *)pwzStatusText, &clsid);
  332. if (SUCCEEDED(hresT)) {
  333. LPWSTR pwzProgID = NULL;
  334. hresT = ProgIDFromCLSID(clsid, &pwzProgID);
  335. if (SUCCEEDED(hresT)) {
  336. if (StrCmp(pwzProgID, L"htmlfile") == 0)
  337. {
  338. fContinueDownload = TRUE;
  339. }
  340. OleFree(pwzProgID);
  341. }
  342. }
  343. if (!fContinueDownload) {
  344. _Abort();
  345. }
  346. }
  347. return S_OK;
  348. }
  349. STDMETHODIMP CPicsRootDownload::OnStopBinding(HRESULT hrResult, LPCWSTR szError)
  350. {
  351. /* Some of the cleanup we do in here (RevokeObjectParam is suspect?) could
  352. * remove our last reference, causing the Releases at the end to fault.
  353. * Guard against this with an AddRef/Release. Dochost does this too.
  354. *
  355. * WARNING - if URLMON is calling back through this object, shouldn't he
  356. * have a reference to us? If so, where is it?
  357. */
  358. AddRef();
  359. /* Notify the caller that we've got to the end of the document */
  360. _NotifyEndOfDocument();
  361. m_pBindCtx->RevokeObjectParam(WSZGUID_OPID_DocObjClientSite);
  362. ::RevokeBindStatusCallback(m_pBindCtx, (IBindStatusCallback *)this);
  363. ATOMICRELEASE(m_pBinding);
  364. ATOMICRELEASE(m_pBindCtx);
  365. /* Undo above AddRef(). */
  366. Release();
  367. return S_OK;
  368. }
  369. void SetBindfFlagsBasedOnAmbient(BOOL fAmbientOffline, DWORD *pgrfBindf);
  370. STDMETHODIMP CPicsRootDownload::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
  371. {
  372. if ( !pgrfBINDF || !pbindInfo || !pbindInfo->cbSize )
  373. return E_INVALIDARG;
  374. *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
  375. *pgrfBINDF |= BINDF_GETNEWESTVERSION;
  376. if(m_fFrameIsSilent)
  377. {
  378. *pgrfBINDF |= BINDF_NO_UI;
  379. }
  380. else
  381. {
  382. *pgrfBINDF &= ~BINDF_NO_UI;
  383. }
  384. SetBindfFlagsBasedOnAmbient(BOOLIFY(m_fFrameIsOffline), pgrfBINDF);
  385. // clear BINDINFO except cbSize
  386. DWORD cbSize = pbindInfo->cbSize;
  387. ZeroMemory( pbindInfo, cbSize );
  388. pbindInfo->cbSize = cbSize;
  389. pbindInfo->dwBindVerb = BINDVERB_GET;
  390. return S_OK;
  391. }
  392. STDMETHODIMP CPicsRootDownload::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  393. FORMATETC *pfmtetc,
  394. STGMEDIUM* pstgmed)
  395. {
  396. return E_NOTIMPL;
  397. }
  398. STDMETHODIMP CPicsRootDownload::OnObjectAvailable(REFIID riid, IUnknown* punk)
  399. {
  400. if (SUCCEEDED(punk->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&m_pctObject))) {
  401. VARIANTARG v;
  402. v.vt = VT_UNKNOWN;
  403. v.punkVal = (IOleCommandTarget *)m_pctParent;
  404. HRESULT hresT = m_pctObject->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
  405. if (hresT == S_OK) {
  406. hresT = punk->QueryInterface(IID_IOleObject, (LPVOID *)&m_pole);
  407. if (FAILED(hresT))
  408. m_pole = NULL;
  409. }
  410. }
  411. if (m_pole == NULL) {
  412. ATOMICRELEASE(m_pctObject);
  413. _Abort();
  414. }
  415. return S_OK;
  416. }
  417. // IOleClientSite
  418. STDMETHODIMP CPicsRootDownload::SaveObject(void)
  419. {
  420. return E_NOTIMPL;
  421. }
  422. STDMETHODIMP CPicsRootDownload::GetMoniker(DWORD, DWORD, IMoniker **)
  423. {
  424. return E_NOTIMPL;
  425. }
  426. STDMETHODIMP CPicsRootDownload::GetContainer(IOleContainer **)
  427. {
  428. return E_NOTIMPL;
  429. }
  430. STDMETHODIMP CPicsRootDownload::ShowObject(void)
  431. {
  432. return E_NOTIMPL;
  433. }
  434. STDMETHODIMP CPicsRootDownload::OnShowWindow(BOOL fShow)
  435. {
  436. return E_NOTIMPL;
  437. }
  438. STDMETHODIMP CPicsRootDownload::RequestNewObjectLayout(void)
  439. {
  440. return E_NOTIMPL;
  441. }
  442. // IServiceProvider (must be QI'able from IOleClientSite)
  443. STDMETHODIMP CPicsRootDownload::QueryService(REFGUID guidService,
  444. REFIID riid, void **ppvObj)
  445. {
  446. if (IsEqualGUID(guidService, SID_STopLevelBrowser)) {
  447. if (IsEqualIID(riid, IID_IsPicsBrowser))
  448. return QueryInterface(riid, ppvObj);
  449. return E_NOINTERFACE;
  450. }
  451. return E_FAIL;
  452. }
  453. // IDispatch
  454. HRESULT CPicsRootDownload::Invoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams,
  455. VARIANT FAR* pVarResult,EXCEPINFO FAR* pexcepinfo,UINT FAR* puArgErr)
  456. {
  457. if (!pVarResult)
  458. return E_INVALIDARG;
  459. if (wFlags == DISPATCH_PROPERTYGET)
  460. {
  461. switch (dispidMember)
  462. {
  463. case DISPID_AMBIENT_DLCONTROL :
  464. // We support IDispatch so that Trident can ask us to control the
  465. // download. By specifying all the following flags, and by NOT
  466. // specifying DLCTL_DLIMAGES, DLCTL_VIDEOS, or DLCTL_BGSOUNDS,
  467. // we ensure we only download the HTML doc itself, and not a lot
  468. // of associated things that aren't going to help us find a META
  469. // tag.
  470. pVarResult->vt = VT_I4;
  471. pVarResult->lVal = DLCTL_SILENT | DLCTL_NO_SCRIPTS |
  472. DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS |
  473. DLCTL_NO_DLACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD |
  474. DLCTL_NO_CLIENTPULL;
  475. break;
  476. default:
  477. return DISP_E_MEMBERNOTFOUND;
  478. }
  479. return S_OK;
  480. }
  481. return DISP_E_MEMBERNOTFOUND;
  482. }
  483. #endif /* FEATURE_PICS */