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