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.

705 lines
17 KiB

  1. /*
  2. * X P A T C H . C P P
  3. *
  4. * XML push model parsing for PROPPATCH requests
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. #include "_xml.h"
  9. // class CNFPatch -------------------------------------------------------------
  10. //
  11. SCODE
  12. CNFPatch::ScCompleteAttribute (void)
  13. {
  14. SCODE sc = S_OK;
  15. // Recording mode is only allowed when we are inside a property. There
  16. // no support implemented for recording mode for multivalued properties.
  17. //
  18. Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
  19. // If we are value echoing, this is the point at which we much
  20. // complete outputting the attribute (i.e. add the quotation mark
  21. // after the value)
  22. //
  23. if (m_vestate == VE_INPROGRESS)
  24. {
  25. sc = m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 );
  26. if (FAILED(sc))
  27. goto ret;
  28. // Complete the current lextype
  29. //
  30. if (m_state == ST_LEXTYPE)
  31. m_state = ST_INPROP;
  32. }
  33. // Normal processing -- values not being echoed
  34. //
  35. else if (m_state == ST_LEXTYPE)
  36. {
  37. // Complete the current lextype
  38. //
  39. // Note that m_ppctx is non-NULL if and only if
  40. // ST_SET and the property to set is not a reserved
  41. // property.
  42. // (That means m_ppctx is NULL on ST_REMOVE, or if the impl
  43. // didn't add a pctx, say because it's a reserved prop
  44. // and they know the set of this prop will fail anyway....)
  45. //
  46. if ((m_sType == ST_SET) && m_ppctx.get())
  47. {
  48. m_sbValue.Append (sizeof(WCHAR), L"");
  49. sc = m_ppctx->ScSetType (m_sbValue.PContents());
  50. if (FAILED (sc))
  51. goto ret;
  52. m_sbValue.Reset();
  53. }
  54. m_state = ST_INPROP;
  55. }
  56. // Flags processing
  57. //
  58. else if (m_state == ST_FLAGS)
  59. {
  60. // Complete the current set of flags
  61. //
  62. // Note that m_ppctx is non-NULL if and only if
  63. // ST_SET and the property to set is not a reserved
  64. // property.
  65. //
  66. // That means m_ppctx is NULL on ST_REMOVE, or if the impl
  67. // didn't add a pctx, say because it's a reserved prop
  68. // and they know the set of this prop will fail anyway....
  69. //
  70. if ((m_sType == ST_SET) && m_ppctx.get())
  71. {
  72. m_sbValue.Append (sizeof(WCHAR), L"");
  73. sc = m_ppctx->ScSetFlags (wcstol (m_sbValue.PContents(), NULL, 0));
  74. if (FAILED (sc))
  75. goto ret;
  76. m_sbValue.Reset();
  77. }
  78. m_state = ST_INPROP;
  79. }
  80. else if (m_state == ST_SEARCHREQUEST)
  81. {
  82. sc = m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 );
  83. if (FAILED(sc))
  84. goto ret;
  85. }
  86. ret:
  87. return sc;
  88. }
  89. SCODE
  90. CNFPatch::ScCompleteCreateNode (
  91. /* [in] */ DWORD dwType)
  92. {
  93. // Recording mode is only allowed when we are inside a property. There
  94. // no support implemented for recording mode for multivalued properties.
  95. //
  96. Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
  97. if (ST_SEARCHREQUEST == m_state || VE_INPROGRESS == m_vestate)
  98. m_xo.CompleteCreateNode (dwType);
  99. return S_OK;
  100. }
  101. SCODE
  102. CNFPatch::ScCompleteChildren (
  103. /* [in] */ BOOL fEmptyNode,
  104. /* [in] */ DWORD dwType,
  105. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  106. /* [in] */ ULONG ulLen)
  107. {
  108. SCODE sc = S_OK;
  109. static const WCHAR wch = 0;
  110. // Recording mode is only allowed when we are inside a property. There
  111. // no support implemented for recording mode for multivalued properties.
  112. //
  113. Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
  114. switch (m_state)
  115. {
  116. case ST_UPDATE:
  117. Assert (dwType == XML_ELEMENT);
  118. m_state = ST_NODOC;
  119. break;
  120. case ST_SET:
  121. case ST_DELETE:
  122. Assert (dwType == XML_ELEMENT);
  123. m_state = ST_UPDATE;
  124. break;
  125. case ST_PROPS:
  126. Assert (dwType == XML_ELEMENT);
  127. m_state = m_sType;
  128. break;
  129. case ST_SEARCHREQUEST:
  130. // Do searchreqeust processing
  131. //
  132. Assert (dwType == XML_ELEMENT);
  133. sc = m_xo.ScCompleteChildren (fEmptyNode,
  134. dwType,
  135. pwcText,
  136. ulLen);
  137. if (FAILED (sc))
  138. goto ret;
  139. // 26/NOV/99: MAXB
  140. // REVIEW: if there are attributes will count really go to zero?
  141. //
  142. if (0 != m_xo.LDepth())
  143. break;
  144. // else fall through
  145. case ST_INPROP:
  146. // Complete the current property
  147. //
  148. // Note that m_ppctx is non-NULL if and only if
  149. // ST_SET and the property to set is not a reserved
  150. // property.
  151. //
  152. if (m_vestate != VE_NOECHO)
  153. {
  154. Assert (dwType == XML_ELEMENT);
  155. sc = m_xo.ScCompleteChildren (fEmptyNode,
  156. dwType,
  157. pwcText,
  158. ulLen);
  159. if (FAILED (sc))
  160. goto ret;
  161. if (0 != m_xo.LDepth())
  162. break;
  163. m_vestate = VE_NOECHO;
  164. }
  165. Assert (dwType == XML_ELEMENT);
  166. if ((m_sType == ST_SET) && m_ppctx.get())
  167. {
  168. m_sbValue.Append (sizeof(wch), &wch);
  169. sc = m_ppctx->ScSetValue (!fEmptyNode
  170. ? m_sbValue.PContents()
  171. : NULL,
  172. m_cmvValues);
  173. if (FAILED (sc))
  174. goto ret;
  175. sc = m_ppctx->ScComplete (fEmptyNode);
  176. if (FAILED (sc))
  177. goto ret;
  178. m_cmvValues = 0;
  179. m_sbValue.Reset();
  180. m_ppctx.clear();
  181. }
  182. m_state = ST_PROPS;
  183. break;
  184. // When dealing with multivalued properties, we need this extra
  185. // state such that each value gets added to the context via a single
  186. // call to ScSetValue() with multiple values layed end-to-end.
  187. //
  188. case ST_INMVPROP:
  189. Assert (dwType == XML_ELEMENT);
  190. if ((m_sType == ST_SET) && m_ppctx.get())
  191. {
  192. // Terminate the current value.
  193. //
  194. m_sbValue.Append (sizeof(wch), &wch);
  195. }
  196. m_state = ST_INPROP;
  197. break;
  198. // We are finishing a <DAV:resourcetype> tag, reset state to ST_PROPS
  199. //
  200. case ST_RESOURCETYPE:
  201. m_state = ST_PROPS;
  202. break;
  203. // We are inside a <DAV:resourcetype> tag, reset state to ST_RESOURCETYPE
  204. //
  205. case ST_STRUCTUREDDOCUMENT:
  206. m_state = ST_RESOURCETYPE;
  207. break;
  208. }
  209. ret:
  210. return sc;
  211. }
  212. SCODE
  213. CNFPatch::ScHandleNode (
  214. /* [in] */ DWORD dwType,
  215. /* [in] */ DWORD dwSubType,
  216. /* [in] */ BOOL fTerminal,
  217. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  218. /* [in] */ ULONG ulLen,
  219. /* [in] */ ULONG ulNamespaceLen,
  220. /* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
  221. /* [in] */ const ULONG ulNsPrefixLen)
  222. {
  223. CStackBuffer<WCHAR> wsz;
  224. LPCWSTR pwszTag;
  225. SCODE sc = S_FALSE;
  226. UINT cch;
  227. // Recording mode is only allowed when we are inside a property. There
  228. // no support implemented for recording mode for multivalued properties.
  229. //
  230. Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
  231. // Forward to searchreqeust node handling
  232. //
  233. if (ST_SEARCHREQUEST == m_state)
  234. {
  235. sc = m_xo.ScHandleNode (dwType,
  236. dwSubType,
  237. fTerminal,
  238. pwcText,
  239. ulLen,
  240. ulNamespaceLen,
  241. pwcNamespace,
  242. ulNsPrefixLen);
  243. goto ret;
  244. }
  245. // If we are performing value echoing, do it now
  246. // NOTE: that unlike ST_SEARCHREQUEST we *also*
  247. // do other processing.
  248. //
  249. if (m_vestate == VE_INPROGRESS)
  250. {
  251. sc = m_xo.ScHandleNode (dwType,
  252. dwSubType,
  253. fTerminal,
  254. pwcText,
  255. ulLen,
  256. ulNamespaceLen,
  257. pwcNamespace,
  258. ulNsPrefixLen);
  259. if (FAILED(sc))
  260. goto ret;
  261. }
  262. // Normal handling performed whether we are echoing
  263. // values or not
  264. //
  265. switch (dwType)
  266. {
  267. case XML_ELEMENT:
  268. // Handle any state changes based on element
  269. // names
  270. //
  271. sc = ScHandleElementNode (dwType,
  272. dwSubType,
  273. fTerminal,
  274. pwcText,
  275. ulLen,
  276. ulNamespaceLen,
  277. pwcNamespace,
  278. ulNsPrefixLen);
  279. if (FAILED (sc))
  280. goto ret;
  281. break;
  282. case XML_ATTRIBUTE:
  283. if ((m_state == ST_INPROP) && (XML_NS != dwSubType))
  284. {
  285. cch = ulNamespaceLen + ulLen;
  286. pwszTag = wsz.resize(CbSizeWsz(cch));
  287. if (NULL == pwszTag)
  288. {
  289. sc = E_OUTOFMEMORY;
  290. goto ret;
  291. }
  292. wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
  293. wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
  294. *(wsz.get() + cch) = 0;
  295. // If this is a lextype attribute, make the
  296. // appropriate transition
  297. //
  298. if (!_wcsnicmp (pwszTag, gc_wszLexType, cch) ||
  299. !wcsncmp (pwszTag, gc_wszDataTypes, cch) ||
  300. !wcsncmp (pwszTag, gc_wszLexTypeOfficial, cch))
  301. {
  302. m_state = ST_LEXTYPE;
  303. sc = S_OK;
  304. }
  305. else if (!wcsncmp (pwszTag, gc_wszFlags, cch))
  306. {
  307. m_state = ST_FLAGS;
  308. sc = S_OK;
  309. }
  310. }
  311. break;
  312. case XML_PCDATA:
  313. case XML_WHITESPACE:
  314. if (m_vestate != VE_INPROGRESS)
  315. {
  316. switch (m_state)
  317. {
  318. case ST_INPROP:
  319. // If we are in the transition from outside, value to
  320. // inside value -- and visa versa -- we do not want to
  321. // add anything to the current buffer.
  322. // Note that m_ppcxt may be NULL if we've encountered a
  323. // reserved property in the request.
  324. //
  325. if ((XML_WHITESPACE == dwType) &&
  326. (!m_ppctx.get() || m_ppctx->FMultiValued()))
  327. break;
  328. // !!! FALL THROUGH !!! */
  329. case ST_INMVPROP:
  330. // Note that m_ppctx is non-NULL if and only if
  331. // ST_SET and the property to set is not a reserved
  332. // property. If these are not set, then ignore the
  333. // value.
  334. //
  335. if ((m_sType != ST_SET) || !m_ppctx.get())
  336. break;
  337. /* !!! FALL THROUGH !!! */
  338. case ST_LEXTYPE:
  339. case ST_FLAGS:
  340. Assert (fTerminal);
  341. // Build up the value for later use...
  342. //
  343. m_sbValue.Append (ulLen * sizeof(WCHAR), pwcText);
  344. sc = S_OK;
  345. }
  346. }
  347. }
  348. ret:
  349. return sc;
  350. }
  351. SCODE
  352. CNFPatch::ScHandleElementNode (
  353. /* [in] */ DWORD dwType,
  354. /* [in] */ DWORD dwSubType,
  355. /* [in] */ BOOL fTerminal,
  356. /* [in] */ const WCHAR __RPC_FAR *pwcText,
  357. /* [in] */ ULONG ulLen,
  358. /* [in] */ ULONG ulNamespaceLen,
  359. /* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
  360. /* [in] */ const ULONG ulNsPrefixLen)
  361. {
  362. CStackBuffer<WCHAR> wsz;
  363. LPCWSTR pwszTag;
  364. SCODE sc = S_FALSE;
  365. UINT cch;
  366. // Recording mode is only allowed when we are inside a property. There
  367. // no support implemented for recording mode for multivalued properties.
  368. //
  369. Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
  370. // Construct the full name of the node
  371. //
  372. cch = ulNamespaceLen + ulLen;
  373. pwszTag = wsz.resize(CbSizeWsz(cch));
  374. if (NULL == pwszTag)
  375. {
  376. sc = E_OUTOFMEMORY;
  377. goto ret;
  378. }
  379. wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
  380. wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
  381. *(wsz.get() + cch) = 0;
  382. switch (m_state)
  383. {
  384. case ST_NODOC:
  385. // If this is the topmost node in a propfind request,
  386. // transition to the next state. Since there is no parent
  387. // node to provide scoping, FIsTag() cannot be used here!
  388. //
  389. if (!wcscmp (pwszTag, gc_wszPropertyUpdate))
  390. {
  391. m_state = ST_UPDATE;
  392. sc = S_OK;
  393. }
  394. break;
  395. case ST_UPDATE:
  396. // Look for our well know node types
  397. //
  398. if (FIsTag (pwszTag, gc_wszSet))
  399. {
  400. m_state = m_sType = ST_SET;
  401. sc = S_OK;
  402. }
  403. else if (FIsTag (pwszTag, gc_wszRemove))
  404. {
  405. m_state = m_sType = ST_DELETE;
  406. sc = S_OK;
  407. }
  408. break;
  409. case ST_SET:
  410. case ST_DELETE:
  411. // Look for our well know node types
  412. //
  413. if (FIsTag (pwszTag, gc_wszProp))
  414. {
  415. m_state = ST_PROPS;
  416. sc = S_OK;
  417. }
  418. break;
  419. case ST_PROPS:
  420. // Process the property as requested...
  421. //
  422. if (dwType == XML_ELEMENT)
  423. {
  424. m_state = ST_INPROP;
  425. if (m_sType == ST_SET)
  426. {
  427. // Get a property context from the patch context
  428. // that we can fill out and complete...
  429. //
  430. Assert (0 == m_cmvValues);
  431. Assert (NULL == m_ppctx.get());
  432. // If it's resourcetype request, change the state
  433. // and don't set props
  434. //
  435. if (FIsTag (pwszTag, gc_wszResoucetype))
  436. {
  437. m_state = ST_RESOURCETYPE;
  438. sc = S_OK;
  439. }
  440. else
  441. {
  442. sc = m_cpc.ScSetProp (NULL, pwszTag, m_ppctx);
  443. if (FAILED (sc))
  444. goto ret;
  445. // Special handling for search requests, recording
  446. // begins immediately
  447. //
  448. if (FIsTag (pwszTag, gc_wszSearchRequest))
  449. {
  450. CEmitNmspc cen(m_xo);
  451. // Make the state transition and start recording
  452. //
  453. m_state = ST_SEARCHREQUEST;
  454. sc = m_xo.ScHandleNode (dwType,
  455. dwSubType,
  456. fTerminal,
  457. pwcText,
  458. ulLen,
  459. ulNamespaceLen,
  460. pwcNamespace,
  461. ulNsPrefixLen);
  462. // Spit out the namespaces.
  463. //
  464. // Note that this will spit out any namespaces
  465. // decl'd in the DAV:owner node itself. So we
  466. // do not really want to emit these out to the
  467. // owners comments until ScCompleteAttribute()
  468. // is called.
  469. //
  470. Assert (!m_xo.FAddNamespaceDecl());
  471. m_cache.ForEach(cen);
  472. sc = S_OK;
  473. }
  474. // Special handling for case when we are PROPPATCH-ing
  475. // XML valued properties. In this case we don't begin
  476. // recording yet because we don't want the property
  477. // node just the XML value inside
  478. //
  479. else if (FValueIsXML (pwszTag))
  480. m_vestate = VE_NEEDNS;
  481. }
  482. }
  483. else
  484. {
  485. // Queue the property for deletion with
  486. // the patch context
  487. //
  488. Assert (m_sType == ST_DELETE);
  489. sc = m_cpc.ScDeleteProp (NULL, pwszTag);
  490. if (FAILED (sc))
  491. goto ret;
  492. }
  493. }
  494. break;
  495. case ST_INPROP:
  496. // Normal case -- value echoing is off. The work here is to
  497. // deal with multivalued properties. In this case we need an extra
  498. // state such that each value gets added to the context via a single
  499. // call to ScSetValue() with multiple values layed end-to-end.
  500. //
  501. // NOTE: support for handling multivalued properties has not been
  502. // added for echoing mode. If you add an XML valued multivalued
  503. // property you need to do some work in the echo mode cases below
  504. //
  505. if (m_vestate == VE_NOECHO)
  506. {
  507. // m_ppctx is NULL when we have attempted to set a reserved
  508. // (read only) property. when this happens, we need to continue
  509. // parsing the request, but we don't actually set the properties.
  510. // thus, we need to set the correct state as if this was a valid
  511. // request.
  512. //
  513. if (NULL == m_ppctx.get())
  514. {
  515. m_state = ST_INMVPROP;
  516. sc = S_OK;
  517. }
  518. else if (m_ppctx->FMultiValued() && FIsTag (pwszTag, gc_wszXml_V))
  519. {
  520. m_state = ST_INMVPROP;
  521. m_cmvValues += 1;
  522. sc = S_OK;
  523. }
  524. }
  525. // We are echoing values or about to start echoing values
  526. //
  527. else
  528. {
  529. // If this is the first element seen that is part of an XML-valued
  530. // property that we are PROPPATCH-ing, then we need to spit out
  531. // the cached namespaces they are available to the EXOLEDB side
  532. //
  533. if (m_vestate == VE_NEEDNS)
  534. {
  535. CEmitNmspc cen(m_xo);
  536. // Make the state transition and start recording
  537. //
  538. m_vestate = VE_INPROGRESS;
  539. sc = m_xo.ScHandleNode (dwType,
  540. dwSubType,
  541. fTerminal,
  542. pwcText,
  543. ulLen,
  544. ulNamespaceLen,
  545. pwcNamespace,
  546. ulNsPrefixLen);
  547. // Spit out the namespaces.
  548. //
  549. // Note that this will spit out any namespaces
  550. // decl'd in the DAV:owner node itself. So we
  551. // do not really want to emit these out to the
  552. // owners comments until ScCompleteAttribute()
  553. // is called.
  554. //
  555. Assert (!m_xo.FAddNamespaceDecl());
  556. m_cache.ForEach(cen);
  557. }
  558. // Indicate that additional namespace declarations
  559. // should be echoed as we see them
  560. //
  561. m_xo.CompleteAttribute();
  562. sc = S_OK;
  563. }
  564. break;
  565. // We see a <DAV:resourcetype> tag. It should be in a MKCOL body.
  566. //
  567. case ST_RESOURCETYPE:
  568. // If resourcetype is not structured doc, just ignore
  569. //
  570. if (FIsTag (pwszTag, gc_wszStructureddocument))
  571. {
  572. m_cpc.SetCreateStructureddocument();
  573. m_state = ST_STRUCTUREDDOCUMENT;
  574. sc = S_OK;
  575. }
  576. break;
  577. }
  578. ret:
  579. return sc;
  580. }
  581. // Tags that have XML values that need to be shipped across epoxy
  582. //
  583. const WCHAR * gc_rgwszXMLValueTags[] =
  584. {
  585. L"http://schemas.microsoft.com/exchange/security/admindescriptor",
  586. L"http://schemas.microsoft.com/exchange/security/descriptor",
  587. L"http://schemas.microsoft.com/exchange/security/creator",
  588. L"http://schemas.microsoft.com/exchange/security/lastmodifier",
  589. L"http://schemas.microsoft.com/exchange/security/sender",
  590. L"http://schemas.microsoft.com/exchange/security/sentrepresenting",
  591. L"http://schemas.microsoft.com/exchange/security/originalsender",
  592. L"http://schemas.microsoft.com/exchange/security/originalsentrepresenting",
  593. L"http://schemas.microsoft.com/exchange/security/readreceiptfrom",
  594. L"http://schemas.microsoft.com/exchange/security/reportfrom",
  595. L"http://schemas.microsoft.com/exchange/security/originator",
  596. L"http://schemas.microsoft.com/exchange/security/reportdestination",
  597. L"http://schemas.microsoft.com/exchange/security/originalauthor",
  598. L"http://schemas.microsoft.com/exchange/security/receivedby",
  599. L"http://schemas.microsoft.com/exchange/security/receivedrepresenting",
  600. };
  601. //This function tests to see if a property has an XML value that must be
  602. //shipped from DAVEX to EXOLEDB
  603. //
  604. BOOL
  605. CNFPatch::FValueIsXML( const WCHAR *pwcTag )
  606. {
  607. BOOL f = FALSE;
  608. ULONG iwsz;
  609. for (iwsz = 0; iwsz < sizeof(gc_rgwszXMLValueTags)/sizeof(WCHAR *); iwsz ++)
  610. {
  611. if (wcscmp (pwcTag, gc_rgwszXMLValueTags[iwsz]) == 0)
  612. {
  613. f = TRUE;
  614. break;
  615. }
  616. }
  617. return f;
  618. }