PageRenderTime 185ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/kdepimlibs-4.8.97/kcalcore/versit/vcc.y

#
Happy | 1226 lines | 1091 code | 135 blank | 0 comment | 0 complexity | d41246d8e05465bf77332e0440589ff7 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-2-Clause, GPL-2.0, LGPL-2.1
  1. %{
  2. /***************************************************************************
  3. (C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
  4. Business Machines Corporation and Siemens Rolm Communications Inc.
  5. For purposes of this license notice, the term Licensors shall mean,
  6. collectively, Apple Computer, Inc., AT&T Corp., International
  7. Business Machines Corporation and Siemens Rolm Communications Inc.
  8. The term Licensor shall mean any of the Licensors.
  9. Subject to acceptance of the following conditions, permission is hereby
  10. granted by Licensors without the need for written agreement and without
  11. license or royalty fees, to use, copy, modify and distribute this
  12. software for any purpose.
  13. The above copyright notice and the following four paragraphs must be
  14. reproduced in all copies of this software and any software including
  15. this software.
  16. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
  17. ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
  18. MODIFICATIONS.
  19. IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
  20. INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
  21. OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  22. DAMAGE.
  23. EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
  24. INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
  25. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  26. PURPOSE.
  27. The software is provided with RESTRICTED RIGHTS. Use, duplication, or
  28. disclosure by the government are subject to restrictions set forth in
  29. DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
  30. ***************************************************************************/
  31. /*
  32. * src: vcc.c
  33. * doc: Parser for vCard and vCalendar. Note that this code is
  34. * generated by a yacc parser generator. Generally it should not
  35. * be edited by hand. The real source is vcc.y. The #line directives
  36. * can be commented out here to make it easier to trace through
  37. * in a debugger. However, if a bug is found it should
  38. * be fixed in vcc.y and this file regenerated.
  39. */
  40. /* debugging utilities */
  41. #ifdef __DEBUG
  42. #define DBG_(x) printf x
  43. #else
  44. #define DBG_(x)
  45. #endif
  46. /**** External Functions ****/
  47. /* assign local name to parser variables and functions so that
  48. we can use more than one yacc based parser.
  49. */
  50. #define yyparse mime_parse
  51. #define yylex mime_lex
  52. #define yyerror mime_error
  53. #define yychar mime_char
  54. /* #define p_yyval p_mime_val */
  55. #undef yyval
  56. #define yyval mime_yyval
  57. /* #define p_yylval p_mime_lval */
  58. #undef yylval
  59. #define yylval mime_yylval
  60. #define yydebug mime_debug
  61. #define yynerrs mime_nerrs
  62. #define yyerrflag mime_errflag
  63. #define yyss mime_ss
  64. #define yyssp mime_ssp
  65. #define yyvs mime_vs
  66. #define yyvsp mime_vsp
  67. #define yylhs mime_lhs
  68. #define yylen mime_len
  69. #define yydefred mime_defred
  70. #define yydgoto mime_dgoto
  71. #define yysindex mime_sindex
  72. #define yyrindex mime_rindex
  73. #define yygindex mime_gindex
  74. #define yytable mime_table
  75. #define yycheck mime_check
  76. #define yyname mime_name
  77. #define yyrule mime_rule
  78. #undef YYPREFIX
  79. #define YYPREFIX "mime_"
  80. #ifndef _NO_LINE_FOLDING
  81. #define _SUPPORT_LINE_FOLDING 1
  82. #endif
  83. #include <string.h>
  84. #include <stdio.h>
  85. #include <stdlib.h>
  86. #include <ctype.h>
  87. #include "vcc.h"
  88. /* The following is a hack that I hope will get things compiling
  89. * on SunOS 4.1.x systems
  90. */
  91. #ifndef SEEK_SET
  92. #define SEEK_SET 0 /* Seek from beginning of file. */
  93. #define SEEK_CUR 1 /* Seek from current position. */
  94. #define SEEK_END 2 /* Seek from end of file. */
  95. #endif
  96. /**** Types, Constants ****/
  97. #define YYDEBUG 0 /* 1 to compile in some debugging code */
  98. #define MAXTOKEN 256 /* maximum token (line) length */
  99. #define YYSTACKSIZE 1000 /* ~unref ? */
  100. #define MAXLEVEL 10 /* max # of nested objects parseable */
  101. /* (includes outermost) */
  102. /**** Global Variables ****/
  103. int mime_lineNum, mime_numErrors; /* yyerror() can use these */
  104. static VObject* vObjList;
  105. static VObject *curProp;
  106. static VObject *curObj;
  107. static VObject* ObjStack[MAXLEVEL];
  108. static int ObjStackTop;
  109. /* A helpful utility for the rest of the app. */
  110. #ifdef __CPLUSPLUS__
  111. extern "C" {
  112. #endif
  113. /* static void Parse_Debug(const char *s);*/
  114. static void yyerror(const char *s);
  115. #ifdef __CPLUSPLUS__
  116. };
  117. #endif
  118. int yyparse();
  119. static int yylex();
  120. static VObject* popVObject();
  121. enum LexMode {
  122. L_NORMAL,
  123. L_VCARD,
  124. L_VCAL,
  125. L_VEVENT,
  126. L_VTODO,
  127. L_VALUES,
  128. L_BASE64,
  129. L_QUOTED_PRINTABLE
  130. };
  131. /**** Private Forward Declarations ****/
  132. static int pushVObject(const char *prop);
  133. static VObject* popVObject();
  134. char* lexDataFromBase64();
  135. static void lexPopMode(int top);
  136. static int lexWithinMode(enum LexMode mode);
  137. static void lexPushMode(enum LexMode mode);
  138. static void enterProps(const char *s);
  139. static void enterAttr(const char *s1, const char *s2);
  140. /* static void enterValues(const char *value); */
  141. static void appendValue(const char *value);
  142. static void mime_error_(const char *s);
  143. %}
  144. /***************************************************************************/
  145. /*** The grammar ****/
  146. /***************************************************************************/
  147. %union {
  148. char *str;
  149. VObject *vobj;
  150. }
  151. %token
  152. EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
  153. BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
  154. BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
  155. ID
  156. /*
  157. * NEWLINE is the token that would occur outside a vCard,
  158. * while LINESEP is the token that would occur inside a vCard.
  159. */
  160. %token <str>
  161. STRING ID
  162. %type <str> name value
  163. %type <vobj> vcard vcal vobject
  164. %start mime
  165. %%
  166. mime: vobjects
  167. ;
  168. vobjects: vobject
  169. { addList(&vObjList, $1); curObj = 0; }
  170. vobjects
  171. | vobject
  172. { addList(&vObjList, $1); curObj = 0; }
  173. ;
  174. vobject: vcard
  175. | vcal
  176. ;
  177. vcard:
  178. BEGIN_VCARD
  179. {
  180. lexPushMode(L_VCARD);
  181. if (!pushVObject(VCCardProp)) YYERROR;
  182. }
  183. items END_VCARD
  184. {
  185. lexPopMode(0);
  186. $$ = popVObject();
  187. }
  188. | BEGIN_VCARD
  189. {
  190. lexPushMode(L_VCARD);
  191. if (!pushVObject(VCCardProp)) YYERROR;
  192. }
  193. END_VCARD
  194. {
  195. lexPopMode(0);
  196. $$ = popVObject();
  197. }
  198. ;
  199. items: item items
  200. | item
  201. ;
  202. item: prop COLON
  203. {
  204. lexPushMode(L_VALUES);
  205. }
  206. values LINESEP
  207. {
  208. if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
  209. lexPopMode(0);
  210. lexPopMode(0);
  211. }
  212. | error
  213. ;
  214. prop: name
  215. {
  216. enterProps($1);
  217. }
  218. attr_params
  219. | name
  220. {
  221. enterProps($1);
  222. }
  223. ;
  224. attr_params: attr_param attr_params
  225. | attr_param
  226. ;
  227. attr_param: SEMICOLON attr
  228. ;
  229. attr: name
  230. {
  231. enterAttr($1,0);
  232. }
  233. | name EQ name
  234. {
  235. enterAttr($1,$3);
  236. }
  237. ;
  238. name: ID
  239. ;
  240. values: value SEMICOLON { appendValue($1); } values
  241. | value
  242. { appendValue($1); }
  243. ;
  244. value: STRING
  245. |
  246. { $$ = 0; }
  247. ;
  248. vcal:
  249. BEGIN_VCAL
  250. { if (!pushVObject(VCCalProp)) YYERROR; }
  251. calitems
  252. END_VCAL
  253. { $$ = popVObject(); }
  254. | BEGIN_VCAL
  255. { if (!pushVObject(VCCalProp)) YYERROR; }
  256. END_VCAL
  257. { $$ = popVObject(); }
  258. ;
  259. calitems: calitem calitems
  260. | calitem
  261. ;
  262. calitem:
  263. eventitem
  264. | todoitem
  265. | items
  266. ;
  267. eventitem:
  268. BEGIN_VEVENT
  269. {
  270. lexPushMode(L_VEVENT);
  271. if (!pushVObject(VCEventProp)) YYERROR;
  272. }
  273. items
  274. END_VEVENT
  275. {
  276. lexPopMode(0);
  277. popVObject();
  278. }
  279. | BEGIN_VEVENT
  280. {
  281. lexPushMode(L_VEVENT);
  282. if (!pushVObject(VCEventProp)) YYERROR;
  283. }
  284. END_VEVENT
  285. {
  286. lexPopMode(0);
  287. popVObject();
  288. }
  289. ;
  290. todoitem:
  291. BEGIN_VTODO
  292. {
  293. lexPushMode(L_VTODO);
  294. if (!pushVObject(VCTodoProp)) YYERROR;
  295. }
  296. items
  297. END_VTODO
  298. {
  299. lexPopMode(0);
  300. popVObject();
  301. }
  302. | BEGIN_VTODO
  303. {
  304. lexPushMode(L_VTODO);
  305. if (!pushVObject(VCTodoProp)) YYERROR;
  306. }
  307. END_VTODO
  308. {
  309. lexPopMode(0);
  310. popVObject();
  311. }
  312. ;
  313. %%
  314. /****************************************************************************/
  315. static int pushVObject(const char *prop)
  316. {
  317. VObject *newObj;
  318. if (ObjStackTop == MAXLEVEL)
  319. return FALSE;
  320. ObjStack[++ObjStackTop] = curObj;
  321. if (curObj) {
  322. newObj = addProp(curObj,prop);
  323. curObj = newObj;
  324. }
  325. else
  326. curObj = newVObject(prop);
  327. return TRUE;
  328. }
  329. /****************************************************************************/
  330. /* This pops the recently built vCard off the stack and returns it. */
  331. static VObject* popVObject()
  332. {
  333. VObject *oldObj;
  334. if (ObjStackTop < 0) {
  335. yyerror("pop on empty Object Stack\n");
  336. return 0;
  337. }
  338. oldObj = curObj;
  339. curObj = ObjStack[ObjStackTop--];
  340. return oldObj;
  341. }
  342. /* static void enterValues(const char *value) */
  343. /* { */
  344. /* if (fieldedProp && *fieldedProp) { */
  345. /* if (value) { */
  346. /* addPropValue(curProp,*fieldedProp,value); */
  347. /* } */
  348. /* else this field is empty, advance to next field */
  349. /* fieldedProp++; */
  350. /* } */
  351. /* else { */
  352. /* if (value) { */
  353. /* setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); */
  354. /* } */
  355. /* } */
  356. /* deleteStr(value); */
  357. /* } */
  358. static void appendValue(const char *value)
  359. {
  360. char *p1, *p2;
  361. wchar_t *p3;
  362. int i;
  363. if (fieldedProp && *fieldedProp) {
  364. if (value) {
  365. addPropValue(curProp, *fieldedProp, value);
  366. }
  367. /* else this field is empty, advance to next field */
  368. fieldedProp++;
  369. } else {
  370. if (value) {
  371. if (vObjectUStringZValue(curProp)) {
  372. p1 = fakeCString(vObjectUStringZValue(curProp));
  373. p2 = malloc(sizeof(char *) * (strlen(p1)+strlen(value)+1));
  374. strcpy(p2, p1);
  375. deleteStr(p1);
  376. i = strlen(p2);
  377. p2[i] = ',';
  378. p2[i+1] = '\0';
  379. p2 = strcat(p2, value);
  380. p3 = (wchar_t *) vObjectUStringZValue(curProp);
  381. free(p3);
  382. setVObjectUStringZValue_(curProp,fakeUnicode(p2,0));
  383. deleteStr(p2);
  384. } else {
  385. setVObjectUStringZValue_(curProp,fakeUnicode(value,0));
  386. }
  387. }
  388. }
  389. deleteStr(value);
  390. }
  391. static void enterProps(const char *s)
  392. {
  393. curProp = addGroup(curObj,s);
  394. deleteStr(s);
  395. }
  396. static void enterAttr(const char *s1, const char *s2)
  397. {
  398. const char *p1=0L, *p2=0L;
  399. p1 = lookupProp_(s1);
  400. if (s2) {
  401. VObject *a;
  402. p2 = lookupProp_(s2);
  403. a = addProp(curProp,p1);
  404. setVObjectStringZValue(a,p2);
  405. }
  406. else
  407. addProp(curProp,p1);
  408. if (strcasecmp(p1,VCBase64Prop) == 0 || (s2 && strcasecmp(p2,VCBase64Prop)==0))
  409. lexPushMode(L_BASE64);
  410. else if (strcasecmp(p1,VCQuotedPrintableProp) == 0
  411. || (s2 && strcasecmp(p2,VCQuotedPrintableProp)==0))
  412. lexPushMode(L_QUOTED_PRINTABLE);
  413. deleteStr(s1); deleteStr(s2);
  414. }
  415. #define MAX_LEX_LOOKAHEAD_0 32
  416. #define MAX_LEX_LOOKAHEAD 64
  417. #define MAX_LEX_MODE_STACK_SIZE 10
  418. #define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
  419. struct LexBuf {
  420. /* input */
  421. FILE *inputFile;
  422. char *inputString;
  423. unsigned long curPos;
  424. unsigned long inputLen;
  425. /* lookahead buffer */
  426. /* -- lookahead buffer is short instead of char so that EOF
  427. / can be represented correctly.
  428. */
  429. unsigned long len;
  430. short buf[MAX_LEX_LOOKAHEAD];
  431. unsigned long getPtr;
  432. /* context stack */
  433. unsigned long lexModeStackTop;
  434. enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
  435. /* token buffer */
  436. unsigned long maxToken;
  437. char *strs;
  438. unsigned long strsLen;
  439. } lexBuf;
  440. static void lexPushMode(enum LexMode mode)
  441. {
  442. if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
  443. yyerror("lexical context stack overflow");
  444. else {
  445. lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
  446. }
  447. }
  448. static void lexPopMode(int top)
  449. {
  450. /* special case of pop for ease of error recovery -- this
  451. version will never underflow */
  452. if (top)
  453. lexBuf.lexModeStackTop = 0;
  454. else
  455. if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
  456. }
  457. static int lexWithinMode(enum LexMode mode) {
  458. unsigned long i;
  459. for (i=0;i<lexBuf.lexModeStackTop;i++)
  460. if (mode == lexBuf.lexModeStack[i]) return 1;
  461. return 0;
  462. }
  463. static int lexGetc_()
  464. {
  465. /* get next char from input, no buffering. */
  466. if (lexBuf.curPos == lexBuf.inputLen)
  467. return EOF;
  468. else if (lexBuf.inputString)
  469. return *(lexBuf.inputString + lexBuf.curPos++);
  470. else {
  471. if (!feof(lexBuf.inputFile))
  472. return fgetc(lexBuf.inputFile);
  473. else
  474. return EOF;
  475. }
  476. }
  477. static int lexGeta()
  478. {
  479. ++lexBuf.len;
  480. return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
  481. }
  482. static int lexGeta_(int i)
  483. {
  484. ++lexBuf.len;
  485. return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
  486. }
  487. static void lexSkipLookahead() {
  488. if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
  489. /* don't skip EOF. */
  490. lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
  491. lexBuf.len--;
  492. }
  493. }
  494. static int lexLookahead() {
  495. int c = (lexBuf.len)?
  496. lexBuf.buf[lexBuf.getPtr]:
  497. lexGeta();
  498. /* do the \r\n -> \n or \r -> \n translation here */
  499. if (c == '\r') {
  500. int a = (lexBuf.len>1)?
  501. lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
  502. lexGeta_(1);
  503. if (a == '\n') {
  504. lexSkipLookahead();
  505. }
  506. lexBuf.buf[lexBuf.getPtr] = c = '\n';
  507. }
  508. else if (c == '\n') {
  509. int a;
  510. if (lexBuf.len > 1)
  511. a = lexBuf.buf[lexBuf.getPtr];
  512. else
  513. a = lexGeta_(1);
  514. if (a == '\r') {
  515. lexSkipLookahead();
  516. }
  517. lexBuf.buf[lexBuf.getPtr] = '\n';
  518. }
  519. return c;
  520. }
  521. static int lexGetc() {
  522. int c = lexLookahead();
  523. if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
  524. /* EOF will remain in lookahead buffer */
  525. lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
  526. lexBuf.len--;
  527. }
  528. return c;
  529. }
  530. static void lexSkipLookaheadWord() {
  531. if (lexBuf.strsLen <= lexBuf.len) {
  532. lexBuf.len -= lexBuf.strsLen;
  533. lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
  534. }
  535. }
  536. static void lexClearToken()
  537. {
  538. lexBuf.strsLen = 0;
  539. }
  540. static void lexAppendc(int c)
  541. {
  542. /* not sure if I am doing this right to fix purify report -- PGB */
  543. lexBuf.strs = (char *) realloc(lexBuf.strs, (size_t) lexBuf.strsLen + 1);
  544. lexBuf.strs[lexBuf.strsLen] = c;
  545. /* append up to zero termination */
  546. if (c == 0) return;
  547. lexBuf.strsLen++;
  548. if (lexBuf.strsLen > lexBuf.maxToken) {
  549. /* double the token string size */
  550. lexBuf.maxToken <<= 1;
  551. lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
  552. }
  553. }
  554. static char* lexStr() {
  555. return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
  556. }
  557. static void lexSkipWhite() {
  558. int c = lexLookahead();
  559. while (c == ' ' || c == '\t') {
  560. lexSkipLookahead();
  561. c = lexLookahead();
  562. }
  563. }
  564. static char* lexGetWord() {
  565. int c;
  566. lexSkipWhite();
  567. lexClearToken();
  568. c = lexLookahead();
  569. /* some "words" have a space in them, like "NEEDS ACTION".
  570. this may be an oversight of the spec, but it is true nevertheless.
  571. while (c != EOF && !strchr("\t\n ;:=",c)) { */
  572. while (c != EOF && !strchr("\n;:=",c)) {
  573. lexAppendc(c);
  574. lexSkipLookahead();
  575. c = lexLookahead();
  576. }
  577. lexAppendc(0);
  578. return lexStr();
  579. }
  580. void lexPushLookahead(char *s, int len) {
  581. int putptr;
  582. if (len == 0) len = strlen(s);
  583. putptr = (int)lexBuf.getPtr - len;
  584. /* this function assumes that length of word to push back
  585. / is not greater than MAX_LEX_LOOKAHEAD.
  586. */
  587. if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
  588. lexBuf.getPtr = putptr;
  589. while (*s) {
  590. lexBuf.buf[putptr] = *s++;
  591. putptr = (putptr + 1) % MAX_LEX_LOOKAHEAD;
  592. }
  593. lexBuf.len += len;
  594. }
  595. static void lexPushLookaheadc(int c) {
  596. int putptr;
  597. /* can't putback EOF, because it never leaves lookahead buffer */
  598. if (c == EOF) return;
  599. putptr = (int)lexBuf.getPtr - 1;
  600. if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
  601. lexBuf.getPtr = putptr;
  602. lexBuf.buf[putptr] = c;
  603. lexBuf.len += 1;
  604. }
  605. static char* lexLookaheadWord() {
  606. /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
  607. / and thing bigger than that will stop the lookahead and return 0;
  608. / leading white spaces are not recoverable.
  609. */
  610. int c;
  611. int len = 0;
  612. int curgetptr = 0;
  613. lexSkipWhite();
  614. lexClearToken();
  615. curgetptr = (int)lexBuf.getPtr; /* remember! */
  616. while (len < (MAX_LEX_LOOKAHEAD_0)) {
  617. c = lexGetc();
  618. len++;
  619. if (c == EOF || strchr("\t\n ;:=", c)) {
  620. lexAppendc(0);
  621. /* restore lookahead buf. */
  622. lexBuf.len += len;
  623. lexBuf.getPtr = curgetptr;
  624. return lexStr();
  625. }
  626. else
  627. lexAppendc(c);
  628. }
  629. lexBuf.len += len; /* char that has been moved to lookahead buffer */
  630. lexBuf.getPtr = curgetptr;
  631. return 0;
  632. }
  633. #ifdef _SUPPORT_LINE_FOLDING
  634. static void handleMoreRFC822LineBreak(int c) {
  635. /* support RFC 822 line break in cases like
  636. * ADR: foo;
  637. * morefoo;
  638. * more foo;
  639. */
  640. if (c == ';') {
  641. int a;
  642. lexSkipLookahead();
  643. /* skip white spaces */
  644. a = lexLookahead();
  645. while (a == ' ' || a == '\t') {
  646. lexSkipLookahead();
  647. a = lexLookahead();
  648. }
  649. if (a == '\n') {
  650. lexSkipLookahead();
  651. a = lexLookahead();
  652. if (a == ' ' || a == '\t') {
  653. /* continuation, throw away all the \n and spaces read so
  654. * far
  655. */
  656. lexSkipWhite();
  657. lexPushLookaheadc(';');
  658. }
  659. else {
  660. lexPushLookaheadc('\n');
  661. lexPushLookaheadc(';');
  662. }
  663. }
  664. else {
  665. lexPushLookaheadc(';');
  666. }
  667. }
  668. }
  669. static char* lexGet1Value() {
  670. int c;
  671. lexSkipWhite();
  672. c = lexLookahead();
  673. lexClearToken();
  674. while (c != EOF && c != ';') {
  675. if (c == '\n') {
  676. int a;
  677. lexSkipLookahead();
  678. a = lexLookahead();
  679. if (a == ' ' || a == '\t') {
  680. lexAppendc(' ');
  681. lexSkipLookahead();
  682. }
  683. else {
  684. lexPushLookaheadc('\n');
  685. break;
  686. }
  687. }
  688. else {
  689. lexAppendc(c);
  690. lexSkipLookahead();
  691. }
  692. c = lexLookahead();
  693. }
  694. lexAppendc(0);
  695. handleMoreRFC822LineBreak(c);
  696. return c==EOF?0:lexStr();
  697. }
  698. #endif
  699. char* lexGetStrUntil(char *termset) {
  700. int c = lexLookahead();
  701. lexClearToken();
  702. while (c != EOF && !strchr(termset,c)) {
  703. lexAppendc(c);
  704. lexSkipLookahead();
  705. c = lexLookahead();
  706. }
  707. lexAppendc(0);
  708. return c==EOF?0:lexStr();
  709. }
  710. static int match_begin_name(int end) {
  711. char *n = lexLookaheadWord();
  712. int token = ID;
  713. if (n) {
  714. if (!strcasecmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
  715. else if (!strcasecmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
  716. else if (!strcasecmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
  717. else if (!strcasecmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
  718. deleteStr(n);
  719. return token;
  720. }
  721. return 0;
  722. }
  723. void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
  724. {
  725. /* initialize lex mode stack */
  726. lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
  727. /* iniatialize lex buffer. */
  728. lexBuf.inputString = (char*) inputstring;
  729. lexBuf.inputLen = inputlen;
  730. lexBuf.curPos = 0;
  731. lexBuf.inputFile = inputfile;
  732. lexBuf.len = 0;
  733. lexBuf.getPtr = 0;
  734. lexBuf.maxToken = MAXTOKEN;
  735. lexBuf.strs = (char*)malloc(MAXTOKEN);
  736. lexBuf.strsLen = 0;
  737. }
  738. static void finiLex() {
  739. free(lexBuf.strs);
  740. }
  741. /****************************************************************************/
  742. /* This parses and converts the base64 format for binary encoding into
  743. * a decoded buffer (allocated with new). See RFC 1521.
  744. */
  745. static char * lexGetDataFromBase64()
  746. {
  747. unsigned long bytesLen = 0, bytesMax = 0;
  748. int quadIx = 0, pad = 0;
  749. unsigned long trip = 0;
  750. unsigned char b;
  751. int c;
  752. unsigned char *bytes = NULL;
  753. unsigned char *oldBytes = NULL;
  754. DBG_(("db: lexGetDataFromBase64\n"));
  755. while (1) {
  756. c = lexGetc();
  757. if (c == '\n') {
  758. ++mime_lineNum;
  759. if (lexLookahead() == '\n') {
  760. /* a '\n' character by itself means end of data */
  761. break;
  762. }
  763. else continue; /* ignore '\n' */
  764. }
  765. else {
  766. if ((c >= 'A') && (c <= 'Z'))
  767. b = (unsigned char)(c - 'A');
  768. else if ((c >= 'a') && (c <= 'z'))
  769. b = (unsigned char)(c - 'a') + 26;
  770. else if ((c >= '0') && (c <= '9'))
  771. b = (unsigned char)(c - '0') + 52;
  772. else if (c == '+')
  773. b = 62;
  774. else if (c == '/')
  775. b = 63;
  776. else if (c == '=') {
  777. b = 0;
  778. pad++;
  779. } else if ((c == ' ') || (c == '\t')) {
  780. continue;
  781. } else { /* error condition */
  782. if (bytes) free(bytes);
  783. else if (oldBytes) free(oldBytes);
  784. /* error recovery: skip until 2 adjacent newlines. */
  785. DBG_(("db: invalid character 0x%x '%c'\n", c,c));
  786. if (c != EOF) {
  787. c = lexGetc();
  788. while (c != EOF) {
  789. if (c == '\n' && lexLookahead() == '\n') {
  790. ++mime_lineNum;
  791. break;
  792. }
  793. c = lexGetc();
  794. }
  795. }
  796. return NULL;
  797. }
  798. trip = (trip << 6) | b;
  799. if (++quadIx == 4) {
  800. unsigned char outBytes[3];
  801. unsigned int numOut;
  802. int i;
  803. for (i = 0; i < 3; i++) {
  804. outBytes[2-i] = (unsigned char)(trip & 0xFF);
  805. trip >>= 8;
  806. }
  807. numOut = 3 - pad;
  808. if (bytesLen + numOut > bytesMax) {
  809. if (!bytes) {
  810. bytesMax = 1024;
  811. bytes = (unsigned char*)malloc((size_t)bytesMax);
  812. }
  813. else {
  814. bytesMax <<= 2;
  815. oldBytes = bytes;
  816. bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
  817. }
  818. if (bytes == 0) {
  819. mime_error("out of memory while processing BASE64 data\n");
  820. }
  821. }
  822. if (bytes) {
  823. memcpy(bytes + bytesLen, outBytes, numOut);
  824. bytesLen += numOut;
  825. }
  826. trip = 0;
  827. quadIx = 0;
  828. }
  829. }
  830. } /* while */
  831. DBG_(("db: bytesLen = %d\n", bytesLen));
  832. /* kludge: all this won't be necessary if we have tree form
  833. representation */
  834. if (bytes) {
  835. setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
  836. free(bytes);
  837. }
  838. else if (oldBytes) {
  839. setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
  840. free(oldBytes);
  841. }
  842. return 0;
  843. }
  844. static int match_begin_end_name(int end) {
  845. int token;
  846. lexSkipWhite();
  847. if (lexLookahead() != ':') return ID;
  848. lexSkipLookahead();
  849. lexSkipWhite();
  850. token = match_begin_name(end);
  851. if (token == ID) {
  852. lexPushLookaheadc(':');
  853. DBG_(("db: ID '%s'\n", yylval.str));
  854. return ID;
  855. }
  856. else if (token != 0) {
  857. lexSkipLookaheadWord();
  858. deleteStr(yylval.str);
  859. DBG_(("db: begin/end %d\n", token));
  860. return token;
  861. }
  862. return 0;
  863. }
  864. static char* lexGetQuotedPrintable()
  865. {
  866. char cur;
  867. lexClearToken();
  868. do {
  869. cur = lexGetc();
  870. switch (cur) {
  871. case '=': {
  872. int c = 0;
  873. int next[2];
  874. int i;
  875. for (i = 0; i < 2; i++) {
  876. next[i] = lexGetc();
  877. if (next[i] >= '0' && next[i] <= '9')
  878. c = c * 16 + next[i] - '0';
  879. else if (next[i] >= 'A' && next[i] <= 'F')
  880. c = c * 16 + next[i] - 'A' + 10;
  881. else
  882. break;
  883. }
  884. if (i == 0) {
  885. /* single '=' follow by LINESEP is continuation sign? */
  886. if (next[0] == '\n') {
  887. ++mime_lineNum;
  888. }
  889. else {
  890. lexPushLookaheadc('=');
  891. goto EndString;
  892. }
  893. }
  894. else if (i == 1) {
  895. lexPushLookaheadc(next[1]);
  896. lexPushLookaheadc(next[0]);
  897. lexAppendc('=');
  898. } else {
  899. lexAppendc(c);
  900. }
  901. break;
  902. } /* '=' */
  903. case '\n': {
  904. lexPushLookaheadc('\n');
  905. goto EndString;
  906. }
  907. case (char)EOF:
  908. break;
  909. default:
  910. lexAppendc(cur);
  911. break;
  912. } /* switch */
  913. } while (cur != (char)EOF);
  914. EndString:
  915. lexAppendc(0);
  916. return lexStr();
  917. } /* LexQuotedPrintable */
  918. static int yylex() {
  919. int lexmode = LEXMODE();
  920. if (lexmode == L_VALUES) {
  921. int c = lexGetc();
  922. if (c == ';') {
  923. DBG_(("db: SEMICOLON\n"));
  924. lexPushLookaheadc(c);
  925. handleMoreRFC822LineBreak(c);
  926. lexSkipLookahead();
  927. return SEMICOLON;
  928. }
  929. else if (strchr("\n",c)) {
  930. ++mime_lineNum;
  931. /* consume all line separator(s) adjacent to each other */
  932. c = lexLookahead();
  933. while (strchr("\n",c)) {
  934. lexSkipLookahead();
  935. c = lexLookahead();
  936. ++mime_lineNum;
  937. }
  938. DBG_(("db: LINESEP\n"));
  939. return LINESEP;
  940. }
  941. else {
  942. char *p = 0;
  943. lexPushLookaheadc(c);
  944. if (lexWithinMode(L_BASE64)) {
  945. /* get each char and convert to bin on the fly... */
  946. p = lexGetDataFromBase64();
  947. yylval.str = p;
  948. return STRING;
  949. }
  950. else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
  951. p = lexGetQuotedPrintable();
  952. }
  953. else {
  954. #ifdef _SUPPORT_LINE_FOLDING
  955. p = lexGet1Value();
  956. #else
  957. p = lexGetStrUntil(";\n");
  958. #endif
  959. }
  960. if (p) {
  961. DBG_(("db: STRING: '%s'\n", p));
  962. yylval.str = p;
  963. return STRING;
  964. }
  965. else return 0;
  966. }
  967. }
  968. else {
  969. /* normal mode */
  970. while (1) {
  971. int c = lexGetc();
  972. switch(c) {
  973. case ':': {
  974. DBG_(("db: COLON\n"));
  975. return COLON;
  976. }
  977. case ';':
  978. DBG_(("db: SEMICOLON\n"));
  979. return SEMICOLON;
  980. case '=':
  981. DBG_(("db: EQ\n"));
  982. return EQ;
  983. /* ignore tabs/newlines in this mode. We can't ignore
  984. * spaces, because values like NEEDS ACTION have a space. */
  985. case '\t': continue;
  986. case '\n': {
  987. ++mime_lineNum;
  988. continue;
  989. }
  990. case EOF: return 0;
  991. break;
  992. default: {
  993. lexPushLookaheadc(c);
  994. if (isalpha(c) || c == ' ') {
  995. char *t = lexGetWord();
  996. yylval.str = t;
  997. if (!strcasecmp(t, "begin")) {
  998. return match_begin_end_name(0);
  999. }
  1000. else if (!strcasecmp(t,"end")) {
  1001. return match_begin_end_name(1);
  1002. }
  1003. else {
  1004. DBG_(("db: ID '%s'\n", t));
  1005. return ID;
  1006. }
  1007. }
  1008. else {
  1009. /* unknown token */
  1010. return 0;
  1011. }
  1012. break;
  1013. }
  1014. }
  1015. }
  1016. }
  1017. return 0;
  1018. }
  1019. /***************************************************************************/
  1020. /*** Public Functions ****/
  1021. /***************************************************************************/
  1022. static VObject* Parse_MIMEHelper()
  1023. {
  1024. ObjStackTop = -1;
  1025. mime_numErrors = 0;
  1026. mime_lineNum = 1;
  1027. vObjList = 0;
  1028. curObj = 0;
  1029. if (yyparse() != 0)
  1030. return 0;
  1031. finiLex();
  1032. return vObjList;
  1033. }
  1034. /****************************************************************************/
  1035. VObject* Parse_MIME(const char *input, unsigned long len)
  1036. {
  1037. initLex(input, len, 0);
  1038. return Parse_MIMEHelper();
  1039. }
  1040. VObject* Parse_MIME_FromFile(FILE *file)
  1041. {
  1042. VObject *result;
  1043. long startPos;
  1044. initLex(0,(unsigned long)-1,file);
  1045. startPos = ftell(file);
  1046. if (startPos <0)
  1047. return NULL;
  1048. if (!(result = Parse_MIMEHelper())) {
  1049. fseek(file,startPos,SEEK_SET);
  1050. }
  1051. return result;
  1052. }
  1053. VObject* Parse_MIME_FromFileName(const char *fname)
  1054. {
  1055. FILE *fp = fopen(fname,"r");
  1056. if (fp) {
  1057. VObject* o = Parse_MIME_FromFile(fp);
  1058. fclose(fp);
  1059. return o;
  1060. }
  1061. else {
  1062. char msg[255];
  1063. sprintf(msg, "can't open file '%s' for reading\n", fname);
  1064. mime_error_(msg);
  1065. return 0;
  1066. }
  1067. }
  1068. /****************************************************************************/
  1069. void YYDebug(const char *s)
  1070. {
  1071. /* Parse_Debug(s);*/
  1072. }
  1073. static MimeErrorHandler mimeErrorHandler;
  1074. void registerMimeErrorHandler(MimeErrorHandler me)
  1075. {
  1076. mimeErrorHandler = me;
  1077. }
  1078. static void mime_error(const char *s)
  1079. {
  1080. char msg[256];
  1081. if (mimeErrorHandler) {
  1082. sprintf(msg,"%s at line %d", s, mime_lineNum);
  1083. mimeErrorHandler(msg);
  1084. }
  1085. }
  1086. static void mime_error_(const char *s)
  1087. {
  1088. if (mimeErrorHandler) {
  1089. mimeErrorHandler(s);
  1090. }
  1091. }