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.

912 lines
12 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. pcprase.cpp
  5. Abstract:
  6. This module implements an object for parsing FROM values.
  7. It works by creating a function for each grammer rule.
  8. When called the function will "eat up" any characters that
  9. parse and return TRUE. If no characters parse, then none
  10. will be eaten up and the return will be FALSE.
  11. Author:
  12. Carl Kadie (CarlK) 11-Dec-1995
  13. Revision History:
  14. --*/
  15. //#include "tigris.hxx"
  16. #include "stdinc.h"
  17. BOOL
  18. CPCParse::fParenChar(
  19. void
  20. )
  21. /*++
  22. Routine Description:
  23. Parse a "("
  24. Arguments:
  25. None.
  26. Return Value:
  27. TRUE, if successful. FALSE, otherwise.
  28. --*/
  29. {
  30. if ((0<m_cch) && fParenCharTest(m_pch[0]))
  31. {
  32. m_pch++;
  33. m_cch--;
  34. return TRUE;
  35. }
  36. return FALSE;
  37. }
  38. BOOL
  39. CPCParse::fIsChar(
  40. char ch
  41. )
  42. /*++
  43. Routine Description:
  44. Look at next char to see if it matches ch.
  45. Arguments:
  46. ch - The character to look for.
  47. Return Value:
  48. TRUE, if successful. FALSE, otherwise.
  49. --*/
  50. {
  51. if ((0<m_cch) && (ch == m_pch[0]))
  52. {
  53. return TRUE;
  54. }
  55. return FALSE;
  56. }
  57. BOOL
  58. CPCParse::fParseSingleChar(
  59. char ch
  60. )
  61. /*++
  62. Routine Description:
  63. Parse a single character.
  64. Arguments:
  65. ch - The character to look for.
  66. Return Value:
  67. TRUE, if successful. FALSE, otherwise.
  68. --*/
  69. {
  70. if ((0<m_cch) && (ch == m_pch[0]))
  71. {
  72. m_pch++;
  73. m_cch--;
  74. return TRUE;
  75. }
  76. return FALSE;
  77. }
  78. BOOL
  79. CPCParse::fAtLeast1QuotedChar(
  80. void
  81. )
  82. /*++
  83. Routine Description:
  84. Parse one or more occurances of a "QuotedChar"
  85. Arguments:
  86. None.
  87. Return Value:
  88. TRUE, if successful. FALSE, otherwise.
  89. --*/
  90. {
  91. //
  92. // Is it even long enough?
  93. //
  94. DWORD dwN = 1;
  95. if (m_cch < dwN)
  96. return FALSE;
  97. //
  98. // Are their N occuraces?
  99. //
  100. DWORD dw;
  101. for (dw = 0; dw < dwN; dw++)
  102. {
  103. if (!fQuotedCharTest(m_pch[dw]))
  104. return FALSE;
  105. }
  106. vSkipStart(dw);
  107. //
  108. // Process any additional occuracies
  109. //
  110. while ((0<m_cch) && fQuotedCharTest(m_pch[0]))
  111. {
  112. m_pch++;
  113. m_cch--;
  114. }
  115. return TRUE;
  116. }
  117. BOOL
  118. CPCParse::fAtLeast1UnquotedChar(
  119. void
  120. )
  121. /*++
  122. Routine Description:
  123. Parse one or more occurances of a "UnquotedChar"
  124. Arguments:
  125. None.
  126. Return Value:
  127. TRUE, if successful. FALSE, otherwise.
  128. --*/
  129. {
  130. //
  131. // Is it even long enough?
  132. //
  133. DWORD dwN = 1;
  134. if (m_cch < dwN)
  135. return FALSE;
  136. //
  137. // Are their N occuraces?
  138. //
  139. DWORD dw;
  140. for (dw = 0; dw < dwN; dw++)
  141. {
  142. if (!fUnquotedCharTest(m_pch[dw]))
  143. return FALSE;
  144. }
  145. vSkipStart(dw);
  146. //
  147. // Process any additional occuracies
  148. //
  149. while ((0<m_cch) && fUnquotedCharTest(m_pch[0]))
  150. {
  151. m_pch++;
  152. m_cch--;
  153. }
  154. return TRUE;
  155. }
  156. BOOL
  157. CPCParse::fAtLeast1UnquotedDotChar(
  158. void
  159. )
  160. /*++
  161. Routine Description:
  162. Parse one or more occurances of a "UnquotedChar" - allows Dots to be present
  163. Arguments:
  164. None.
  165. Return Value:
  166. TRUE, if successful. FALSE, otherwise.
  167. --*/
  168. {
  169. //
  170. // Is it even long enough?
  171. //
  172. DWORD dwN = 1;
  173. if (m_cch < dwN)
  174. return FALSE;
  175. //
  176. // Are their N occuraces?
  177. //
  178. DWORD dw;
  179. for (dw = 0; dw < dwN; dw++)
  180. {
  181. if (!fUnquotedDotCharTest(m_pch[dw]))
  182. return FALSE;
  183. }
  184. vSkipStart(dw);
  185. //
  186. // Process any additional occuracies
  187. //
  188. while ((0<m_cch) && fUnquotedDotCharTest(m_pch[0]))
  189. {
  190. m_pch++;
  191. m_cch--;
  192. }
  193. return TRUE;
  194. }
  195. BOOL
  196. CPCParse::fAtLeast1Space(
  197. void
  198. )
  199. /*++
  200. Routine Description:
  201. Parse one or more occurances of a "Space"
  202. Arguments:
  203. None.
  204. Return Value:
  205. TRUE, if successful. FALSE, otherwise.
  206. --*/
  207. {
  208. //
  209. // Is it even long enough?
  210. //
  211. DWORD dwN = 1;
  212. if (m_cch < dwN)
  213. return FALSE;
  214. //
  215. // Are their N occuraces?
  216. //
  217. DWORD dw;
  218. for (dw = 0; dw < dwN; dw++)
  219. {
  220. if (!fSpaceTest(m_pch[dw]))
  221. return FALSE;
  222. }
  223. vSkipStart(dw);
  224. //
  225. // Process any additional occuracies
  226. // Process any additional occuracies
  227. //
  228. while ((0<m_cch) && fSpaceTest(m_pch[0]))
  229. {
  230. m_pch++;
  231. m_cch--;
  232. }
  233. return TRUE;
  234. }
  235. BOOL
  236. CPCParse::fAtLeast1QuotedCharOrSpace(
  237. void
  238. )
  239. /*++
  240. Routine Description:
  241. Parse one or more occurances of a "QuotedChar" or Space
  242. Arguments:
  243. None.
  244. Return Value:
  245. TRUE, if successful. FALSE, otherwise.
  246. --*/
  247. {
  248. //
  249. // Is it even long enough?
  250. //
  251. DWORD dwN = 1;
  252. if (m_cch < dwN)
  253. return FALSE;
  254. //
  255. // Are their N occuraces?
  256. //
  257. DWORD dw;
  258. for (dw = 0; dw < dwN; dw++)
  259. {
  260. if (!fQuotedCharOrSpaceTest(m_pch[dw]))
  261. return FALSE;
  262. }
  263. vSkipStart(dw);
  264. //
  265. // Process any additional occuracies
  266. // Process any additional occuracies
  267. //
  268. while ((0<m_cch) /*&& fParenCharTest(m_pch[0]*/ && *m_pch != '\"' )
  269. {
  270. m_pch++;
  271. m_cch--;
  272. }
  273. return TRUE;
  274. }
  275. BOOL
  276. CPCParse::fAtLeast1ParenChar(
  277. void
  278. )
  279. /*++
  280. Routine Description:
  281. Parse at least one "ParenChar"
  282. Arguments:
  283. None.
  284. Return Value:
  285. TRUE, if successful. FALSE, otherwise.
  286. --*/
  287. {
  288. //
  289. // Is it even long enough?
  290. //
  291. DWORD dwN = 1;
  292. if (m_cch < dwN)
  293. return FALSE;
  294. //
  295. // Are their N occuraces?
  296. //
  297. DWORD dw;
  298. for (dw = 0; dw < dwN; dw++)
  299. {
  300. if (!fParenCharTest(m_pch[dw]))
  301. return FALSE;
  302. }
  303. vSkipStart(dw);
  304. //
  305. // Process any additional occuracies
  306. // Process any additional occuracies
  307. //
  308. while ((0<m_cch) && fParenCharTest(m_pch[0]))
  309. {
  310. m_pch++;
  311. m_cch--;
  312. }
  313. return TRUE;
  314. }
  315. BOOL
  316. CPCParse::fAtLeast1CodeChar(
  317. void
  318. )
  319. /*++
  320. Routine Description:
  321. Parse at least one "CodeChar"
  322. Arguments:
  323. None.
  324. Return Value:
  325. TRUE, if successful. FALSE, otherwise.
  326. --*/
  327. {
  328. //
  329. // Is it even long enough?
  330. //
  331. DWORD dwN = 1;
  332. if (m_cch < dwN)
  333. return FALSE;
  334. //
  335. // Are their N occuraces?
  336. //
  337. DWORD dw;
  338. for (dw = 0; dw < dwN; dw++)
  339. {
  340. if (!fCodeCharTest(m_pch[dw]))
  341. return FALSE;
  342. }
  343. vSkipStart(dw);
  344. //
  345. // Process any additional occuracies
  346. // Process any additional occuracies
  347. //
  348. while ((0<m_cch) && fCodeCharTest(m_pch[0]))
  349. {
  350. m_pch++;
  351. m_cch--;
  352. }
  353. return TRUE;
  354. }
  355. BOOL
  356. CPCParse::fAtLeast1TagChar(
  357. void
  358. )
  359. /*++
  360. Routine Description:
  361. Parse at least one "TagChar"
  362. Arguments:
  363. None.
  364. Return Value:
  365. TRUE, if successful. FALSE, otherwise.
  366. --*/
  367. {
  368. //
  369. // Is it even long enough?
  370. //
  371. DWORD dwN = 1;
  372. if (m_cch < dwN)
  373. return FALSE;
  374. //
  375. // Are their N occuraces?
  376. //
  377. DWORD dw;
  378. for (dw = 0; dw < dwN; dw++)
  379. {
  380. if (!fTagCharTest(m_pch[dw]))
  381. return FALSE;
  382. }
  383. vSkipStart(dw);
  384. //
  385. // Process any additional occuracies
  386. // Process any additional occuracies
  387. //
  388. while ((0<m_cch) && fTagCharTest(m_pch[0]))
  389. {
  390. m_pch++;
  391. m_cch--;
  392. }
  393. return TRUE;
  394. }
  395. BOOL
  396. CPCParse::fQuotedWord(
  397. void
  398. )
  399. /*++
  400. Routine Description:
  401. quoted-word = quote 1*( quoted-char / space ) quote
  402. Arguments:
  403. None.
  404. Return Value:
  405. TRUE, if successful. FALSE, otherwise.
  406. --*/
  407. {
  408. CPCParse pcOld = *this;
  409. if (fParseSingleChar('\"') //!!!constize
  410. && fAtLeast1QuotedCharOrSpace()
  411. && fParseSingleChar('\"')
  412. )
  413. return TRUE;
  414. *this = pcOld;
  415. return FALSE;
  416. }
  417. BOOL
  418. CPCParse::fLocalPart(
  419. void
  420. )
  421. /*++
  422. Routine Description:
  423. local-part = unquoted-word *( "." unquoted-word )
  424. Arguments:
  425. None.
  426. Return Value:
  427. TRUE, if successful. FALSE, otherwise.
  428. --*/
  429. {
  430. if (!fUnquotedWord())
  431. return FALSE;
  432. CPCParse pcOld = *this;
  433. while(fParseSingleChar('.') && fUnquotedWord())
  434. pcOld = *this;
  435. *this = pcOld;
  436. return TRUE;
  437. }
  438. BOOL
  439. CPCParse::fStrictAddress(
  440. void
  441. )
  442. /*++
  443. Routine Description:
  444. address = local-part "@" domain
  445. !!!X LATER - do we want a flag that tells if just local-part is acceptable?
  446. Arguments:
  447. None.
  448. Return Value:
  449. TRUE, if successful. FALSE, otherwise.
  450. --*/
  451. {
  452. CPCParse pcOld = *this;
  453. if (!fLocalPart())
  454. return FALSE;
  455. if (!fParseSingleChar('@'))
  456. return FALSE;
  457. if (fDomain())
  458. return TRUE;
  459. *this = pcOld;
  460. return FALSE;
  461. }
  462. BOOL
  463. CPCParse::fAddress(
  464. void
  465. )
  466. /*++
  467. Routine Description:
  468. address = local-part "@" domain or JUST local-part
  469. !!!X LATER - do we want a flag that tells if just local-part is acceptable?
  470. Arguments:
  471. None.
  472. Return Value:
  473. TRUE, if successful. FALSE, otherwise.
  474. --*/
  475. {
  476. CPCParse pcOld = *this;
  477. if (!fLocalPart())
  478. return FALSE;
  479. if (!fParseSingleChar('@'))
  480. return TRUE;
  481. if (fDomain())
  482. return TRUE;
  483. *this = pcOld;
  484. return FALSE;
  485. }
  486. BOOL
  487. CPCParse::fPlainPhrase(
  488. void
  489. )
  490. /*++
  491. Routine Description:
  492. plain-phrase = plain-word *( space plain-word )
  493. Arguments:
  494. None.
  495. Return Value:
  496. TRUE, if successful. FALSE, otherwise.
  497. --*/
  498. {
  499. if (!fPlainWord())
  500. return FALSE;
  501. CPCParse pcOld = *this;
  502. while(fSpace() && fPlainWord())
  503. pcOld = *this;
  504. *this = pcOld;
  505. return TRUE;
  506. }
  507. BOOL
  508. CPCParse::fParenPhrase(
  509. void
  510. )
  511. /*++
  512. Routine Description:
  513. paren-phrase = 1*( paren-char / space / encoded-word )
  514. Arguments:
  515. None.
  516. Return Value:
  517. TRUE, if successful. FALSE, otherwise.
  518. --*/
  519. {
  520. if (!(
  521. fParenChar()
  522. || fSpace()
  523. || fEncodedWord()
  524. )) {
  525. //
  526. // special case () to fix rfc-non-compliance by TIN
  527. //
  528. return fIsChar(')');
  529. }
  530. CPCParse pcOld = *this;
  531. while(fParenChar()|| fSpace() || fEncodedWord())
  532. pcOld = *this;
  533. *this = pcOld;
  534. return TRUE;
  535. }
  536. BOOL
  537. CPCParse::fFromContent(
  538. void
  539. )
  540. /*++
  541. Routine Description:
  542. From-content = address [ space "(" paren-phrase ")" ]
  543. / [ plain-phrase space ] "<" address ">"
  544. Arguments:
  545. None.
  546. Return Value:
  547. TRUE, if successful. FALSE, otherwise.
  548. --*/
  549. {
  550. CPCParse pcOld = *this;
  551. BOOL fOK = FALSE; // Assume the worst
  552. // try style 1
  553. if (fStrictAddress())
  554. {
  555. // address is ok
  556. fOK = TRUE;
  557. // now check for optional [ space "(" paren-phrase ")" ]
  558. if (fSpace())
  559. {
  560. if (!(
  561. fParseSingleChar('(')
  562. && fParenPhrase()
  563. && fParseSingleChar(')')
  564. ))
  565. {
  566. fOK = FALSE;
  567. }
  568. else
  569. {
  570. fOK = TRUE ;
  571. }
  572. }
  573. }
  574. // If it didn't parse that way, try style 2
  575. if (!fOK)
  576. {
  577. *this = pcOld;
  578. if (fPlainPhrase() && !fSpace())
  579. {
  580. fOK = FALSE;
  581. } else if (!(fParseSingleChar('<')
  582. && fAddress()
  583. && fParseSingleChar('>')
  584. ))
  585. {
  586. fOK = FALSE;
  587. } else {
  588. fOK = TRUE ;
  589. }
  590. }
  591. // style 1 and 2 both failed
  592. if( !fOK )
  593. {
  594. *this = pcOld;
  595. if( fAddress() ) {
  596. fOK = TRUE;
  597. }
  598. }
  599. //
  600. // There should be no characters left
  601. //
  602. if (0 != m_cch)
  603. {
  604. *this = pcOld;
  605. return FALSE;
  606. }
  607. return TRUE;
  608. }
  609. BOOL
  610. CPCParse::fEncodedWord(
  611. void
  612. )
  613. /*++
  614. Routine Description:
  615. encoded-word = "=?" charset "?" encoding "?" codes "?="
  616. Arguments:
  617. None.
  618. Return Value:
  619. TRUE, if successful. FALSE, otherwise.
  620. --*/
  621. {
  622. CPCParse pcOld = *this;
  623. if (
  624. fParseSingleChar('=')
  625. && fParseSingleChar('?')
  626. && fCharset()
  627. && fParseSingleChar('?')
  628. && fEncoding()
  629. && fParseSingleChar('?')
  630. && fCodes()
  631. && fParseSingleChar('?')
  632. && fParseSingleChar('=')
  633. )
  634. return TRUE;
  635. *this = pcOld;
  636. return FALSE;
  637. }