From d46a01de16c8ad65b00c76beda547970f7972b62 Mon Sep 17 00:00:00 2001
From: zecke <zecke>
Date: Tue, 14 Sep 2004 22:50:22 +0000
Subject: Be able to properly import vCard from Cell Phones

---
(limited to 'library')

diff --git a/library/backend/vcc.y b/library/backend/vcc.y
index eca7c32..00e8fed 100644
--- a/library/backend/vcc.y
+++ b/library/backend/vcc.y
@@ -1,1219 +1,1248 @@
-%{
-
-/***************************************************************************
-(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
-Business Machines Corporation and Siemens Rolm Communications Inc.
-
-For purposes of this license notice, the term Licensors shall mean,
-collectively, Apple Computer, Inc., AT&T Corp., International
-Business Machines Corporation and Siemens Rolm Communications Inc.
-The term Licensor shall mean any of the Licensors.
-
-Subject to acceptance of the following conditions, permission is hereby
-granted by Licensors without the need for written agreement and without
-license or royalty fees, to use, copy, modify and distribute this
-software for any purpose.
-
-The above copyright notice and the following four paragraphs must be
-reproduced in all copies of this software and any software including
-this software.
-
-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
-ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
-MODIFICATIONS.
-
-IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
-INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
-OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.
-
-The software is provided with RESTRICTED RIGHTS.  Use, duplication, or
-disclosure by the government are subject to restrictions set forth in
-DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
-
-***************************************************************************/
-
-/*
- * src: vcc.c
- * doc: Parser for vCard and vCalendar. Note that this code is
- * generated by a yacc parser generator. Generally it should not
- * be edited by hand. The real source is vcc.y. The #line directives
- * can be commented out here to make it easier to trace through
- * in a debugger. However, if a bug is found it should
- * be fixed in vcc.y and this file regenerated.
- */
-
-
-/* debugging utilities */
-#if __DEBUG
-#define DBG_(x) printf x
-#else
-#define DBG_(x)
-#endif
-
-/****  External Functions  ****/
-
-/* assign local name to parser variables and functions so that
-   we can use more than one yacc based parser.
-*/
-
-#if 0
-#define yyparse mime_parse
-#define yylex mime_lex
-#define yyerror mime_error
-#define yychar mime_char
-/* #define p_yyval p_mime_val */
-#undef yyval
-#define yyval mime_yyval
-/* #define p_yylval p_mime_lval */
-#undef yylval
-#define yylval mime_yylval
-#define yydebug mime_debug
-#define yynerrs mime_nerrs
-#define yyerrflag mime_errflag
-#define yyss mime_ss
-#define yyssp mime_ssp
-#define yyvs mime_vs
-#define yyvsp mime_vsp
-#define yylhs mime_lhs
-#define yylen mime_len
-#define yydefred mime_defred
-#define yydgoto mime_dgoto
-#define yysindex mime_sindex
-#define yyrindex mime_rindex
-#define yygindex mime_gindex
-#define yytable mime_table
-#define yycheck mime_check
-#define yyname mime_name
-#define yyrule mime_rule
-#ifdef YYPREFIX
-#undef YYPREFIX
-#endif
-#define YYPREFIX "mime_"
-#endif
-
-
-#ifndef _NO_LINE_FOLDING
-#define _SUPPORT_LINE_FOLDING 1
-#endif
-
-/* undef below if compile with MFC */
-/* #define INCLUDEMFC 1 */
-
-#if defined(WIN32) || defined(_WIN32)
-#ifdef INCLUDEMFC
-#include <afx.h>
-#endif
-#endif
-
-#include <string.h>
-#ifndef __MWERKS__
-#include <stdlib.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-//#ifdef PALMTOPCENTER
-//#include <qpe/vobject_p.h>
-//#else
-#include "vobject_p.h"
-//#endif
-
-/****  Types, Constants  ****/
-
-#define YYDEBUG		0	/* 1 to compile in some debugging code */
-#define MAXTOKEN	256	/* maximum token (line) length */
-#define YYSTACKSIZE 	100	// ~unref ?
-#define MAXLEVEL	10	/* max # of nested objects parseable */
-				/* (includes outermost) */
-
-
-/****  Global Variables  ****/
-int mime_lineNum, mime_numErrors; /* yyerror() can use these */
-static VObject* vObjList;
-static VObject *curProp;
-static VObject *curObj;
-static VObject* ObjStack[MAXLEVEL];
-static int ObjStackTop;
-
-
-/* A helpful utility for the rest of the app. */
-#if __CPLUSPLUS__
-extern "C" {
-#endif
-
-    extern void yyerror(char *s);
-
-#if __CPLUSPLUS__
-    };
-#endif
-
-int yyparse();
-
-enum LexMode {
-	L_NORMAL,
-	L_VCARD,
-	L_VCAL,
-	L_VEVENT,
-	L_VTODO,
-	L_VALUES,
-	L_BASE64,
-	L_QUOTED_PRINTABLE
-	};
-
-/****  Private Forward Declarations  ****/
-static int pushVObject(const char *prop);
-static VObject* popVObject();
-static void lexPopMode(int top);
-static int lexWithinMode(enum LexMode mode);
-static void lexPushMode(enum LexMode mode);
-static void enterProps(const char *s);
-static void enterAttr(const char *s1, const char *s2);
-static void enterValues(const char *value);
-#define mime_error yyerror
-void mime_error(char *s);
-void mime_error_(char *s);
-
-%}
-
-/***************************************************************************/
-/***                           The grammar                              ****/
-/***************************************************************************/
-
-%union {
-    char *str;
-    VObject *vobj;
-    }
-
-%token
-	EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
-	BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
-	BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
-	ID
-
-/*
- * NEWLINE is the token that would occur outside a vCard,
- * while LINESEP is the token that would occur inside a vCard.
- */
-
-%token <str>
-	STRING ID
-
-%type <str> name value
-
-%type <vobj> vcard vcal vobject
-
-%start mime
-
-%%
-
-
-mime: vobjects
-	;
-
-vobjects: vobjects vobject
-	{ addList(&vObjList, $2); curObj = 0; }
-	| vobject
-		{ addList(&vObjList, $1); curObj = 0; }
-	;
-
-vobject: vcard
-	| vcal
-	;
-
-vcard:
-	BEGIN_VCARD
-	{
-	lexPushMode(L_VCARD);
-	if (!pushVObject(VCCardProp)) YYERROR;
-	}
-	items END_VCARD
-	{
-	lexPopMode(0);
-	$$ = popVObject();
-	}
-	| BEGIN_VCARD
-	{
-	lexPushMode(L_VCARD);
-	if (!pushVObject(VCCardProp)) YYERROR;
-	}
-	END_VCARD
-	{
-	lexPopMode(0);
-	$$ = popVObject();
-	}
-	;
-
-items: items item
-	| item
-	;
-
-item: prop COLON
-	{
-	lexPushMode(L_VALUES);
-	}
-	values LINESEP
-	{
-	if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
-	   lexPopMode(0);
-	lexPopMode(0);
-	}
-	| error
-	;
-
-prop: name
-	{
-	enterProps($1);
-	}
-	attr_params
-	| name
-	{
-	enterProps($1);
-	}
-	;
-
-attr_params: attr_params attr_param
-	| attr_param
-	;
-
-attr_param: SEMICOLON attr
-	;
-
-attr: name
-	{
-	enterAttr($1,0);
-	}
-	| name EQ name
-	{
-	enterAttr($1,$3);
-
-	}
-	;
-	
-name: ID
-	;
-
-values: value SEMICOLON { enterValues($1); } values
-	| value
-	{ enterValues($1); }
-	;
-
-value: STRING
-	|
-	{ $$ = 0; }
-	;
-
-vcal:
-	BEGIN_VCAL
-	{ if (!pushVObject(VCCalProp)) YYERROR; }
-	calitems
-	END_VCAL
-	{ $$ = popVObject(); }
-	| BEGIN_VCAL
-	{ if (!pushVObject(VCCalProp)) YYERROR; }
-	END_VCAL
-	{ $$ = popVObject(); }
-	;
-
-calitems: calitems calitem
-	| calitem
-	;
-
-calitem:
-	eventitem
-	| todoitem
-	| items
-	;
-
-eventitem:
-	BEGIN_VEVENT
-	{
-	lexPushMode(L_VEVENT);
-	if (!pushVObject(VCEventProp)) YYERROR;
-	}
-	items
-	END_VEVENT
-	{
-	lexPopMode(0);
-	popVObject();
-	}
-	| BEGIN_VEVENT
-	{
-	lexPushMode(L_VEVENT);
-	if (!pushVObject(VCEventProp)) YYERROR;
-	}
-	END_VEVENT
-	{
-	lexPopMode(0);
-	popVObject();
-	}
-	;
-
-todoitem:
-	BEGIN_VTODO
-	{
-	lexPushMode(L_VTODO);
-	if (!pushVObject(VCTodoProp)) YYERROR;
-	}
-	items
-	END_VTODO
-	{
-	lexPopMode(0);
-	popVObject();
-	}
-	| BEGIN_VTODO
-	{
-	lexPushMode(L_VTODO);
-	if (!pushVObject(VCTodoProp)) YYERROR;
-	}
-	END_VTODO
-	{
-	lexPopMode(0);
-	popVObject();
-	}
-	;
-
-%%
-/*------------------------------------*/
-static int pushVObject(const char *prop)
-    {
-    VObject *newObj;
-    if (ObjStackTop == MAXLEVEL)
-	return FALSE;
-
-    ObjStack[++ObjStackTop] = curObj;
-
-    if (curObj) {
-        newObj = addProp(curObj,prop);
-        curObj = newObj;
-	}
-    else
-	curObj = newVObject(prop);
-
-    return TRUE;
-    }
-
-
-/*---------------------------------------*/
-/* This pops the recently built vCard off the stack and returns it. */
-static VObject* popVObject()
-    {
-    VObject *oldObj;
-    if (ObjStackTop < 0) {
-	yyerror("pop on empty Object Stack\n");
-	return 0;
-	}
-    oldObj = curObj;
-    curObj = ObjStack[ObjStackTop--];
-
-    return oldObj;
-    }
-
-
-static void enterValues(const char *value)
-    {
-    if (fieldedProp && *fieldedProp) {
-	if (value) {
-	    addPropValue(curProp,*fieldedProp,value);
-	    }
-	/* else this field is empty, advance to next field */
-	fieldedProp++;
-	}
-    else {
-	if (value) {
-	    setVObjectStringZValue_(curProp,strdup( value ));
-	    }
-	}
-    deleteStr(value);
-    }
-
-static void enterProps(const char *s)
-    {
-    curProp = addGroup(curObj,s);
-    deleteStr(s);
-    }
-
-static void enterAttr(const char *s1, const char *s2)
-    {
-    const char *p1, *p2=0;
-    p1 = lookupProp_(s1);
-    if (s2) {
-	VObject *a;
-	p2 = lookupProp_(s2);
-	a = addProp(curProp,p1);
-	setVObjectStringZValue(a,p2);
-	}
-    else
-	addProp(curProp,p1);
-    if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
-	lexPushMode(L_BASE64);
-    else if (qstricmp(p1,VCQuotedPrintableProp) == 0
-	    || (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
-	lexPushMode(L_QUOTED_PRINTABLE);
-    deleteStr(s1); deleteStr(s2);
-    }
-
-
-#define MAX_LEX_LOOKAHEAD_0 32
-#define MAX_LEX_LOOKAHEAD 64
-#define MAX_LEX_MODE_STACK_SIZE 10
-#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
-
-struct LexBuf {
-	/* input */
-#ifdef INCLUDEMFC
-    CFile *inputFile;
-#else
-    FILE *inputFile;
-#endif
-    char *inputString;
-    unsigned long curPos;
-    unsigned long inputLen;
-	/* lookahead buffer */
-	/*   -- lookahead buffer is short instead of char so that EOF
-	 /      can be represented correctly.
-	*/
-    unsigned long len;
-    short buf[MAX_LEX_LOOKAHEAD];
-    unsigned long getPtr;
-	/* context stack */
-    unsigned long lexModeStackTop;
-    enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
-	/* token buffer */
-    unsigned long maxToken;
-    char *strs;
-    unsigned long strsLen;
-    } lexBuf;
-
-static void lexPushMode(enum LexMode mode)
-    {
-    if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
-	yyerror("lexical context stack overflow");
-    else {
-	lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
-	}
-    }
-
-static void lexPopMode(int top)
-    {
-    /* special case of pop for ease of error recovery -- this
-	version will never underflow */
-    if (top)
-	lexBuf.lexModeStackTop = 0;
-    else
-	if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
-    }
-
-static int lexWithinMode(enum LexMode mode) {
-    unsigned long i;
-    for (i=0;i<lexBuf.lexModeStackTop;i++)
-	if (mode == lexBuf.lexModeStack[i]) return 1;
-    return 0;
-    }
-
-static int lexGetc_()
-    {
-    /* get next char from input, no buffering. */
-    if (lexBuf.curPos == lexBuf.inputLen)
-	return EOF;
-    else if (lexBuf.inputString)
-	return *(lexBuf.inputString + lexBuf.curPos++);
-    else {
-#ifdef INCLUDEMFC
-	char result;
-	return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
-#else
-	return fgetc(lexBuf.inputFile);
-#endif
-	}
-    }
-
-static int lexGeta()
-    {
-    ++lexBuf.len;
-    return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
-    }
-
-static int lexGeta_(int i)
-    {
-    ++lexBuf.len;
-    return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
-    }
-
-static void lexSkipLookahead() {
-    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
-	/* don't skip EOF. */
-        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
-	lexBuf.len--;
-        }
-    }
-
-static int lexLookahead() {
-    int c = (lexBuf.len)?
-	lexBuf.buf[lexBuf.getPtr]:
-	lexGeta();
-    /* do the \r\n -> \n or \r -> \n translation here */
-    if (c == '\r') {
-	int a = (lexBuf.len>1)?
-	    lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
-	    lexGeta_(1);
-	if (a == '\n') {
-	    lexSkipLookahead();
-	    }
-	lexBuf.buf[lexBuf.getPtr] = c = '\n';
-	}
-    else if (c == '\n') {
-	int a = (lexBuf.len>1)?
-	    lexBuf.buf[lexBuf.getPtr+1]:
-	    lexGeta_(1);
-	if (a == '\r') {
-	    lexSkipLookahead();
-	    }
-	lexBuf.buf[lexBuf.getPtr] = '\n';
-	}
-    return c;
-    }
-
-static int lexGetc() {
-    int c = lexLookahead();
-    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
-	/* EOF will remain in lookahead buffer */
-        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
-	lexBuf.len--;
-        }
-    return c;
-    }
-
-static void lexSkipLookaheadWord() {
-    if (lexBuf.strsLen <= lexBuf.len) {
-	lexBuf.len -= lexBuf.strsLen;
-	lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
-	}
-    }
-
-static void lexClearToken()
-    {
-    lexBuf.strsLen = 0;
-    }
-
-static void lexAppendc(int c)
-    {
-    lexBuf.strs[lexBuf.strsLen] = c;
-    /* append up to zero termination */
-    if (c == 0) return;
-    lexBuf.strsLen++;
-    if (lexBuf.strsLen > lexBuf.maxToken) {
-	/* double the token string size */
-	lexBuf.maxToken <<= 1;
-	lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
-	}
-    }
-
-static char* lexStr() {
-    return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
-    }
-
-static void lexSkipWhite() {
-    int c = lexLookahead();
-    while (c == ' ' || c == '\t') {
-	lexSkipLookahead();
-	c = lexLookahead();
-	}
-    }
-
-static char* lexGetWord() {
-    int c;
-    lexSkipWhite();
-    lexClearToken();
-    c = lexLookahead();
-    while (c != EOF && !strchr("\t\n ;:=",c)) {
-	lexAppendc(c);
-	lexSkipLookahead();
-	c = lexLookahead();
-	}
-    lexAppendc(0);
-    return lexStr();
-    }
-
-static void lexPushLookaheadc(int c) {
-    int putptr;
-    /* can't putback EOF, because it never leaves lookahead buffer */
-    if (c == EOF) return;
-    putptr = (int)lexBuf.getPtr - 1;
-    if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
-    lexBuf.getPtr = putptr;
-    lexBuf.buf[putptr] = c;
-    lexBuf.len += 1;
-    }
-
-static char* lexLookaheadWord() {
-    /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
-     /  and thing bigger than that will stop the lookahead and return 0;
-     / leading white spaces are not recoverable.
-     */
-    int c;
-    int len = 0;
-    int curgetptr = 0;
-    lexSkipWhite();
-    lexClearToken();
-    curgetptr = (int)lexBuf.getPtr;	// remember!
-    while (len < (MAX_LEX_LOOKAHEAD_0)) {
-	c = lexGetc();
-	len++;
-	if (c == EOF || strchr("\t\n ;:=", c)) {
-	    lexAppendc(0);
-	    /* restore lookahead buf. */
-	    lexBuf.len += len;
-	    lexBuf.getPtr = curgetptr;
-	    return lexStr();
-	    }
-        else
-	    lexAppendc(c);
-	}
-    lexBuf.len += len;	/* char that has been moved to lookahead buffer */
-    lexBuf.getPtr = curgetptr;
-    return 0;
-    }
-
-#ifdef _SUPPORT_LINE_FOLDING
-static void handleMoreRFC822LineBreak(int c) {
-    /* suport RFC 822 line break in cases like
-     *	ADR: foo;
-     *    morefoo;
-     *    more foo;
-     */
-    if (c == ';') {
-	int a;
-	lexSkipLookahead();
-	/* skip white spaces */
-	a = lexLookahead();
-	while (a == ' ' || a == '\t') {
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    }
-	if (a == '\n') {
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    if (a == ' ' || a == '\t') {
-		/* continuation, throw away all the \n and spaces read so
-		 * far
-		 */
-		lexSkipWhite();
-		lexPushLookaheadc(';');
-		}
-	    else {
-		lexPushLookaheadc('\n');
-		lexPushLookaheadc(';');
-		}
-	    }
-	else {
-	    lexPushLookaheadc(';');
-	    }
-	}
-    }
-
-static char* lexGet1Value() {
-    int c;
-    lexSkipWhite();
-    c = lexLookahead();
-    lexClearToken();
-    while (c != EOF && (c != ';' || !fieldedProp)) {
-	if (c == '\\' ) {
-	    int a;
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    if ( a == ';' ) {
-		lexAppendc( ';' );
-		lexSkipLookahead();
-	    } else if ( a == '\n' ) {
-		lexAppendc( '\n' );
-		lexSkipLookahead();
-	    } else if ( a == '\\' ) {
-		lexAppendc( '\\' );
-		lexSkipLookahead();
-	    } else {
-		lexAppendc('\\');
-	    }
-	} else if (c == '\n') {
-	    int a;
-	    lexSkipLookahead();
-	    a  = lexLookahead();
-	    if (a == ' ' || a == '\t') {
-		lexAppendc(' ');
-		lexSkipLookahead();
-		}
-	    else {
-		lexPushLookaheadc('\n');
-		break;
-		}
-	    }
-	else {
-	    lexAppendc(c);
-	    lexSkipLookahead();
-	    }
-	c = lexLookahead();
-	}
-    lexAppendc(0);
-    handleMoreRFC822LineBreak(c);
-    return c==EOF?0:lexStr();
-    }
-#endif
-
-static int match_begin_name(int end) {
-    char *n = lexLookaheadWord();
-    int token = ID;
-    if (n) {
-	if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
-	else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
-	else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
-	else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
-	deleteStr(n);
-	return token;
-	}
-    return 0;
-    }
-
-
-#ifdef INCLUDEMFC
-void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
-#else
-void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
-#endif
-    {
-    // initialize lex mode stack
-    lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
-
-    // iniatialize lex buffer.
-    lexBuf.inputString = (char*) inputstring;
-    lexBuf.inputLen = inputlen;
-    lexBuf.curPos = 0;
-    lexBuf.inputFile = inputfile;
-
-    lexBuf.len = 0;
-    lexBuf.getPtr = 0;
-
-    lexBuf.maxToken = MAXTOKEN;
-    lexBuf.strs = (char*)malloc(MAXTOKEN);
-    lexBuf.strsLen = 0;
-
-    }
-
-static void finiLex() {
-    free(lexBuf.strs);
-    }
-
-
-/*-----------------------------------*/
-/* This parses and converts the base64 format for binary encoding into
- * a decoded buffer (allocated with new).  See RFC 1521.
- */
-static int lexGetDataFromBase64()
-    {
-    unsigned long bytesLen = 0, bytesMax = 0;
-    int quadIx = 0, pad = 0;
-    unsigned long trip = 0;
-    unsigned char b;
-    int c;
-    unsigned char *bytes = NULL;
-    unsigned char *oldBytes = NULL;
-
-    DBG_(("db: lexGetDataFromBase64\n"));
-    while (1) {
-	c = lexGetc();
-	lexSkipWhite();
-	if (c == '\n') {
-	    ++mime_lineNum;
-	    if (lexLookahead() == '\n') {
-		/* a '\n' character by itself means end of data */
-		break;
-		}
-	    else continue; /* ignore '\n' */
-	    }
-	else {
-	    if ((c >= 'A') && (c <= 'Z'))
-		b = (unsigned char)(c - 'A');
-	    else if ((c >= 'a') && (c <= 'z'))
-		b = (unsigned char)(c - 'a') + 26;
-	    else if ((c >= '0') && (c <= '9'))
-		b = (unsigned char)(c - '0') + 52;
-	    else if (c == '+')
-		b = 62;
-	    else if (c == '/')
-		b = 63;
-	    else if (c == '=') {
-		b = 0;
-		pad++;
-	    } else { /* error condition */
-		if (bytes) free(bytes);
-		else if (oldBytes) free(oldBytes);
-		// error recovery: skip until 2 adjacent newlines.
-		DBG_(("db: invalid character 0x%x '%c'\n", c,c));
-		if (c != EOF)  {
-		    c = lexGetc();
-		    while (c != EOF) {
-			if (c == '\n') {
-			    lexSkipWhite();
-			    if(lexLookahead() == '\n') {
-				++mime_lineNum;
-				break;
-				}
-			    }
-			c = lexGetc();
-			}
-		    }
-		return c != EOF;
-		}
-	    trip = (trip << 6) | b;
-	    if (++quadIx == 4) {
-		unsigned char outBytes[3];
-		int numOut;
-		int i;
-		for (i = 0; i < 3; i++) {
-		    outBytes[2-i] = (unsigned char)(trip & 0xFF);
-		    trip >>= 8;
-		    }
-		numOut = 3 - pad;
-		if (bytesLen + numOut > bytesMax) {
-		    if (!bytes) {
-			bytesMax = 1024;
-			bytes = (unsigned char*)malloc((size_t)bytesMax);
-			}
-		    else {
-			bytesMax <<= 2;
-			oldBytes = bytes;
-			bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
-			}
-		    if (bytes == 0) {
-			mime_error("out of memory while processing BASE64 data\n");
-			}
-		    }
-		if (bytes) {
-		    memcpy(bytes + bytesLen, outBytes, numOut);
-		    bytesLen += numOut;
-		    }
-		trip = 0;
-		quadIx = 0;
-		}
-	    }
-	} /* while */
-    DBG_(("db: bytesLen = %d\n",  bytesLen));
-    /* kludge: all this won't be necessary if we have tree form
-	representation */
-    if (bytes) {
-	setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
-	free(bytes);
-	}
-    else if (oldBytes) {
-	setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
-	free(oldBytes);
-	}
-    return bytesLen;
-    }
-
-static int match_begin_end_name(int end) {
-    int token;
-    lexSkipWhite();
-    if (lexLookahead() != ':') return ID;
-    lexSkipLookahead();
-    lexSkipWhite();
-    token = match_begin_name(end);
-    if (token == ID) {
-	lexPushLookaheadc(':');
-	DBG_(("db: ID '%s'\n", yylval.str));
-	return ID;
-	}
-    else if (token != 0) {
-	lexSkipLookaheadWord();
-	deleteStr(yylval.str);
-	DBG_(("db: begin/end %d\n", token));
-	return token;
-	}
-    return 0;
-    }
-
-static char* lexGetQuotedPrintable()
-{
-    int c;
-    lexSkipWhite();
-    c = lexLookahead();
-    lexClearToken();
-
-    while (c != EOF && (c != ';' || !fieldedProp)) {
-	if (c == '\n') {
-	    // break, leave '\n' on remaining chars.
-	    break;
-	} else if (c == '=') {
-	    int cur = 0;
-	    int next;
-
-	    lexSkipLookahead(); // skip '='
-	    next = lexLookahead();
-
-	    if (next == '\n') {
-		// skip and only skip the \n
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		++mime_lineNum; // aid in error reporting
-		continue;
-	    } else if (next >= '0' && next <= '9') {
-		cur = next - '0';
-	    } else if (next >= 'A' && next <= 'F') {
-		cur = next - 'A' + 10;
-	    } else {
-		// we have been sent buggy stuff. doesn't matter
-		// what we do so long as we keep going.
-		// should probably spit an error here
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		continue;
-	    }
-
-	    lexSkipLookahead(); // skip A-Z0-9
-	    next = lexLookahead();
-
-	    cur = cur * 16;
-	    // this time really just expecting 0-9A-F
-	    if (next >= '0' && next <= '9') {
-		cur += next - '0';
-	    } else if (next >= 'A' && next <= 'F') {
-		cur += next - 'A' + 10;
-	    } else {
-		// we have been sent buggy stuff. doesn't matter
-		// what we do so long as we keep going.
-		// should probably spit an error here
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		continue;
-	    }
-
-	    // got a valid escaped =.  append it.
-	    lexSkipLookahead(); // skip second 0-9A-F
-	    lexAppendc(cur);
-	} else {
-	    lexSkipLookahead(); // skip whatever we just read.
-	    lexAppendc(c); // and append it.
-	}
-	c = lexLookahead();
-    }
-    lexAppendc(0);
-    return c==EOF?0:lexStr();
-}
-
-static int yylex() {
-
-    int lexmode = LEXMODE();
-    if (lexmode == L_VALUES) {
-	int c = lexGetc();
-	if (c == ';' && fieldedProp) {
-	    DBG_(("db: SEMICOLON\n"));
-	    lexPushLookaheadc(c);
-	    handleMoreRFC822LineBreak(c);
-	    lexSkipLookahead();
-	    return SEMICOLON;
-	    }
-	else if (strchr("\n",c)) {
-	    ++mime_lineNum;
-	    /* consume all line separator(s) adjacent to each other */
-	    c = lexLookahead();
-	    while (strchr("\n",c)) {
-		lexSkipLookahead();
-		c = lexLookahead();
-		++mime_lineNum;
-		}
-	    DBG_(("db: LINESEP\n"));
-	    return LINESEP;
-	    }
-	else {
-	    char *p = 0;
-	    lexPushLookaheadc(c);
-	    if (lexWithinMode(L_BASE64)) {
-		/* get each char and convert to bin on the fly... */
-		yylval.str = NULL;
-		return lexGetDataFromBase64() ? STRING : 0;
-		}
-	    else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
-		p = lexGetQuotedPrintable();
-		}
-	    else {
-#ifdef _SUPPORT_LINE_FOLDING
-		p = lexGet1Value();
-#else
-		p = lexGetStrUntil(";\n");
-#endif
-		}
-	    if (p) {
-		DBG_(("db: STRING: '%s'\n", p));
-		yylval.str = p;
-		return STRING;
-		}
-	    else return 0;
-	    }
-	}
-    else {
-	/* normal mode */
-	while (1) {
-	    int c = lexGetc();
-	    switch(c) {
-		case ':': {
-		    /* consume all line separator(s) adjacent to each other */
-		    /* ignoring linesep immediately after colon. */
-		    /* I don't see this in the spec, and it breaks null values -- WA
-		    c = lexLookahead();
-		    while (strchr("\n",c)) {
-			lexSkipLookahead();
-			c = lexLookahead();
-			++mime_lineNum;
-			}
-		    */
-		    DBG_(("db: COLON\n"));
-		    return COLON;
-		    }
-		case ';':
-		    DBG_(("db: SEMICOLON\n"));
-		    return SEMICOLON;
-		case '=':
-		    DBG_(("db: EQ\n"));
-		    return EQ;
-		/* ignore whitespace in this mode */
-		case '\t':
-		case ' ': continue;
-		case '\n': {
-		    ++mime_lineNum;
-		    continue;
-		    }
-		case EOF: return 0;
-		    break;
-		default: {
-		    lexPushLookaheadc(c);
-		    if (isalnum(c)) {
-			char *t = lexGetWord();
-			yylval.str = t;
-			if (!qstricmp(t, "begin")) {
-			    return match_begin_end_name(0);
-			    }
-			else if (!qstricmp(t,"end")) {
-			    return match_begin_end_name(1);
-			    }
-		        else {
-			    DBG_(("db: ID '%s'\n", t));
-			    return ID;
-			    }
-			}
-		    else {
-			/* unknow token */
-			return 0;
-			}
-		    break;
-		    }
-		}
-	    }
-	}
-    return 0;
-    }
-
-
-/***************************************************************************/
-/***							Public Functions						****/
-/***************************************************************************/
-
-static VObject* Parse_MIMEHelper()
-    {
-    ObjStackTop = -1;
-    mime_numErrors = 0;
-    mime_lineNum = 1;
-    vObjList = 0;
-    curObj = 0;
-
-    if (yyparse() != 0)
-	return 0;
-
-    finiLex();
-    return vObjList;
-    }
-
-/*--------------------------------------------*/
-DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
-    {
-    initLex(input, len, 0);
-    return Parse_MIMEHelper();
-    }
-
-
-#if INCLUDEMFC
-
-DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
-    {
-    unsigned long startPos;
-    VObject *result;	
-
-    initLex(0,-1,file);
-    startPos = file->GetPosition();
-    if (!(result = Parse_MIMEHelper()))
-	file->Seek(startPos, CFile::begin);
-    return result;
-    }
-
-#else
-
-VObject* Parse_MIME_FromFile(FILE *file)
-    {
-    VObject *result;	
-    long startPos;
-
-    initLex(0,(unsigned long)-1,file);
-    startPos = ftell(file);
-    if (!(result = Parse_MIMEHelper())) {
-	fseek(file,startPos,SEEK_SET);
-	}
-    return result;
-    }
-
-DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
-    {
-    FILE *fp = fopen(fname,"r");
-    if (fp) {
-	VObject* o = Parse_MIME_FromFile(fp);
-	fclose(fp);
-	return o;
-	}
-    else {
-	char msg[80];
-	sprintf(msg, "can't open file '%s' for reading\n", fname);
-	mime_error_(msg);
-	return 0;
-	}
-    }
-
-#endif
-
-/*-------------------------------------*/
-
-static MimeErrorHandler mimeErrorHandler;
-
-DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
-    {
-    mimeErrorHandler = me;
-    }
-
-void mime_error(char *s)
-    {
-    char msg[256];
-    if (mimeErrorHandler) {
-	sprintf(msg,"%s at line %d", s, mime_lineNum);
-	mimeErrorHandler(msg);
-	}
-    }
-
-void mime_error_(char *s)
-    {
-    if (mimeErrorHandler) {
-	mimeErrorHandler(s);
-	}
-    }
-
+%{
+
+/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS.  Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+ * src: vcc.c
+ * doc: Parser for vCard and vCalendar. Note that this code is
+ * generated by a yacc parser generator. Generally it should not
+ * be edited by hand. The real source is vcc.y. The #line directives
+ * can be commented out here to make it easier to trace through
+ * in a debugger. However, if a bug is found it should
+ * be fixed in vcc.y and this file regenerated.
+ */
+
+
+/* debugging utilities */
+#define __DEBUG 1
+
+#if __DEBUG
+#define DBG_(x) printf x
+#else
+#define DBG_(x)
+#endif
+
+/****  External Functions  ****/
+
+/* assign local name to parser variables and functions so that
+   we can use more than one yacc based parser.
+*/
+
+#if 0
+#define yyparse mime_parse
+#define yylex mime_lex
+#define yyerror mime_error
+#define yychar mime_char
+/* #define p_yyval p_mime_val */
+#undef yyval
+#define yyval mime_yyval
+/* #define p_yylval p_mime_lval */
+#undef yylval
+#define yylval mime_yylval
+#define yydebug mime_debug
+#define yynerrs mime_nerrs
+#define yyerrflag mime_errflag
+#define yyss mime_ss
+#define yyssp mime_ssp
+#define yyvs mime_vs
+#define yyvsp mime_vsp
+#define yylhs mime_lhs
+#define yylen mime_len
+#define yydefred mime_defred
+#define yydgoto mime_dgoto
+#define yysindex mime_sindex
+#define yyrindex mime_rindex
+#define yygindex mime_gindex
+#define yytable mime_table
+#define yycheck mime_check
+#define yyname mime_name
+#define yyrule mime_rule
+#ifdef YYPREFIX
+#undef YYPREFIX
+#endif
+#define YYPREFIX "mime_"
+#endif
+
+
+#ifndef _NO_LINE_FOLDING
+#define _SUPPORT_LINE_FOLDING 1
+#endif
+
+/* undef below if compile with MFC */
+/* #define INCLUDEMFC 1 */
+
+#if defined(WIN32) || defined(_WIN32)
+#ifdef INCLUDEMFC
+#include <afx.h>
+#endif
+#endif
+
+#include <string.h>
+#ifndef __MWERKS__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+//#ifdef PALMTOPCENTER
+//#include <qpe/vobject_p.h>
+//#else
+#include "vobject_p.h"
+//#endif
+
+/****  Types, Constants  ****/
+
+#define YYDEBUG		0	/* 1 to compile in some debugging code */
+#define MAXTOKEN	256	/* maximum token (line) length */
+#define YYSTACKSIZE 	100	// ~unref ?
+#define MAXLEVEL	10	/* max # of nested objects parseable */
+				/* (includes outermost) */
+
+
+/****  Global Variables  ****/
+int q_DontDecodeBase64Photo = 0;
+int mime_lineNum, mime_numErrors; /* yyerror() can use these */
+static VObject* vObjList;
+static VObject *curProp;
+static VObject *curObj;
+static VObject* ObjStack[MAXLEVEL];
+static int ObjStackTop;
+
+
+/* A helpful utility for the rest of the app. */
+#if __CPLUSPLUS__
+extern "C" {
+#endif
+
+    extern void yyerror(char *s);
+
+#if __CPLUSPLUS__
+    };
+#endif
+
+int yyparse();
+
+enum LexMode {
+	L_NORMAL,
+	L_PARAMWORD,
+	L_VCARD,
+	L_VCAL,
+	L_VEVENT,
+	L_VTODO,
+	L_VALUES,
+	L_BASE64,
+	L_QUOTED_PRINTABLE
+	};
+
+/****  Private Forward Declarations  ****/
+static int pushVObject(const char *prop);
+static VObject* popVObject();
+static void lexPopMode(int top);
+static int lexWithinMode(enum LexMode mode);
+static void lexPushMode(enum LexMode mode);
+static void enterProps(const char *s);
+static void enterAttr(const char *s1, const char *s2);
+static void enterValues(const char *value);
+#define mime_error yyerror
+void mime_error(char *s);
+void mime_error_(char *s);
+
+%}
+
+/***************************************************************************/
+/***                           The grammar                              ****/
+/***************************************************************************/
+
+%union {
+    char *str;
+    VObject *vobj;
+    }
+
+%token
+	EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
+	BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
+	BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
+	ID
+
+/*
+ * NEWLINE is the token that would occur outside a vCard,
+ * while LINESEP is the token that would occur inside a vCard.
+ */
+
+%token <str>
+	STRING ID
+
+%type <str> name value
+
+%type <vobj> vcard vcal vobject
+
+%start mime
+
+%%
+
+
+mime: vobjects
+	;
+
+vobjects: vobjects vobject
+	{ addList(&vObjList, $2); curObj = 0; }
+	| vobject
+		{ addList(&vObjList, $1); curObj = 0; }
+	;
+
+vobject: vcard
+	| vcal
+	;
+
+vcard:
+	BEGIN_VCARD
+	{
+	lexPushMode(L_VCARD);
+	if (!pushVObject(VCCardProp)) YYERROR;
+	}
+	items END_VCARD
+	{
+	lexPopMode(0);
+	$$ = popVObject();
+	}
+	| BEGIN_VCARD
+	{
+	lexPushMode(L_VCARD);
+	if (!pushVObject(VCCardProp)) YYERROR;
+	}
+	END_VCARD
+	{
+	lexPopMode(0);
+	$$ = popVObject();
+	}
+	;
+
+items: items item
+	| item
+	;
+
+item: prop COLON
+	{
+	lexPushMode(L_VALUES);
+	}
+	values LINESEP
+	{
+	if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
+	   lexPopMode(0);
+	lexPopMode(0);
+	}
+	| error
+	;
+
+prop: name
+	{
+	enterProps($1);
+	}
+	attr_params
+	| name
+	{
+	enterProps($1);
+	}
+	;
+
+attr_params: attr_params attr_param
+	| attr_param
+	;
+
+attr_param: SEMICOLON attr
+	;
+
+attr: name
+	{
+	enterAttr($1,0);
+	}
+	| name EQ
+	{
+	lexPushMode(L_PARAMWORD);
+	}
+	    name
+	{
+	lexPopMode(0);
+	enterAttr($1,$4);
+	}
+	;
+	
+name: ID
+	;
+
+values: value SEMICOLON { enterValues($1); } values
+	| value
+	{ enterValues($1); }
+	;
+
+value: STRING
+	|
+	{ $$ = 0; }
+	;
+
+vcal:
+	BEGIN_VCAL
+	{ if (!pushVObject(VCCalProp)) YYERROR; }
+	calitems
+	END_VCAL
+	{ $$ = popVObject(); }
+	| BEGIN_VCAL
+	{ if (!pushVObject(VCCalProp)) YYERROR; }
+	END_VCAL
+	{ $$ = popVObject(); }
+	;
+
+calitems: calitems calitem
+	| calitem
+	;
+
+calitem:
+	eventitem
+	| todoitem
+	| items
+	;
+
+eventitem:
+	BEGIN_VEVENT
+	{
+	lexPushMode(L_VEVENT);
+	if (!pushVObject(VCEventProp)) YYERROR;
+	}
+	items
+	END_VEVENT
+	{
+	lexPopMode(0);
+	popVObject();
+	}
+	| BEGIN_VEVENT
+	{
+	lexPushMode(L_VEVENT);
+	if (!pushVObject(VCEventProp)) YYERROR;
+	}
+	END_VEVENT
+	{
+	lexPopMode(0);
+	popVObject();
+	}
+	;
+
+todoitem:
+	BEGIN_VTODO
+	{
+	lexPushMode(L_VTODO);
+	if (!pushVObject(VCTodoProp)) YYERROR;
+	}
+	items
+	END_VTODO
+	{
+	lexPopMode(0);
+	popVObject();
+	}
+	| BEGIN_VTODO
+	{
+	lexPushMode(L_VTODO);
+	if (!pushVObject(VCTodoProp)) YYERROR;
+	}
+	END_VTODO
+	{
+	lexPopMode(0);
+	popVObject();
+	}
+	;
+
+%%
+/*------------------------------------*/
+static int pushVObject(const char *prop)
+    {
+    VObject *newObj;
+    if (ObjStackTop == MAXLEVEL)
+	return FALSE;
+
+    ObjStack[++ObjStackTop] = curObj;
+
+    if (curObj) {
+        newObj = addProp(curObj,prop);
+        curObj = newObj;
+	}
+    else
+	curObj = newVObject(prop);
+
+    return TRUE;
+    }
+
+
+/*---------------------------------------*/
+/* This pops the recently built vCard off the stack and returns it. */
+static VObject* popVObject()
+    {
+    VObject *oldObj;
+    if (ObjStackTop < 0) {
+	yyerror("pop on empty Object Stack\n");
+	return 0;
+	}
+    oldObj = curObj;
+    curObj = ObjStack[ObjStackTop--];
+
+    return oldObj;
+    }
+
+
+static void enterValues(const char *value)
+    {
+    if (fieldedProp && *fieldedProp) {
+	if (value) {
+	    addPropValue(curProp,*fieldedProp,value);
+	    }
+	/* else this field is empty, advance to next field */
+	fieldedProp++;
+	}
+    else {
+	if (value) {
+	    setVObjectStringZValue_(curProp,strdup( value ));
+	    }
+	}
+    deleteStr(value);
+    }
+
+static void enterProps(const char *s)
+    {
+    curProp = addGroup(curObj,s);
+    deleteStr(s);
+    }
+
+static void enterAttr(const char *s1, const char *s2)
+    {
+    const char *p1, *p2=0;
+    p1 = lookupProp_(s1);
+    if (s2) {
+	VObject *a;
+	p2 = lookupProp_(s2);
+	a = addProp(curProp,p1);
+	setVObjectStringZValue(a,p2);
+	}
+    else
+	addProp(curProp,p1);
+    /* Lookup strings so we can quickly use pointer comparison */
+    static const char* base64 = lookupProp_(VCBase64Prop);
+    static const char* qp = lookupProp_(VCQuotedPrintableProp);
+    static const char* photo = lookupProp_(VCPhotoProp);
+    static const char* encoding = lookupProp_(VCEncodingProp);
+    if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo)
+	&& (p1 == base64 || p1 == encoding && p2 == base64))
+	lexPushMode(L_BASE64);
+    else if (p1 == qp || p1 == encoding && p2 == qp)
+	lexPushMode(L_QUOTED_PRINTABLE);
+    deleteStr(s1); deleteStr(s2);
+    }
+
+
+#define MAX_LEX_LOOKAHEAD_0 32
+#define MAX_LEX_LOOKAHEAD 64
+#define MAX_LEX_MODE_STACK_SIZE 10
+#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
+
+struct LexBuf {
+	/* input */
+#ifdef INCLUDEMFC
+    CFile *inputFile;
+#else
+    FILE *inputFile;
+#endif
+    char *inputString;
+    unsigned long curPos;
+    unsigned long inputLen;
+	/* lookahead buffer */
+	/*   -- lookahead buffer is short instead of char so that EOF
+	 /      can be represented correctly.
+	*/
+    unsigned long len;
+    short buf[MAX_LEX_LOOKAHEAD];
+    unsigned long getPtr;
+	/* context stack */
+    unsigned long lexModeStackTop;
+    enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
+	/* token buffer */
+    unsigned long maxToken;
+    char *strs;
+    unsigned long strsLen;
+    } lexBuf;
+
+static void lexPushMode(enum LexMode mode)
+    {
+    if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
+	yyerror("lexical context stack overflow");
+    else {
+	lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
+	}
+    }
+
+static void lexPopMode(int top)
+    {
+    /* special case of pop for ease of error recovery -- this
+	version will never underflow */
+    if (top)
+	lexBuf.lexModeStackTop = 0;
+    else
+	if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
+    }
+
+static int lexWithinMode(enum LexMode mode) {
+    unsigned long i;
+    for (i=0;i<lexBuf.lexModeStackTop;i++)
+	if (mode == lexBuf.lexModeStack[i]) return 1;
+    return 0;
+    }
+
+static int lexGetc_()
+    {
+    /* get next char from input, no buffering. */
+    if (lexBuf.curPos == lexBuf.inputLen)
+	return EOF;
+    else if (lexBuf.inputString)
+	return *(lexBuf.inputString + lexBuf.curPos++);
+    else {
+#ifdef INCLUDEMFC
+	char result;
+	return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
+#else
+	return fgetc(lexBuf.inputFile);
+#endif
+	}
+    }
+
+static int lexGeta()
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
+    }
+
+static int lexGeta_(int i)
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
+    }
+
+static void lexSkipLookahead() {
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+	/* don't skip EOF. */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+	lexBuf.len--;
+        }
+    }
+
+static int lexLookahead() {
+    int c = (lexBuf.len)?
+	lexBuf.buf[lexBuf.getPtr]:
+	lexGeta();
+    /* do the \r\n -> \n or \r -> \n translation here */
+    if (c == '\r') {
+	int a = (lexBuf.len>1)?
+	    lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
+	    lexGeta_(1);
+	if (a == '\n') {
+	    lexSkipLookahead();
+	    }
+	lexBuf.buf[lexBuf.getPtr] = c = '\n';
+	}
+    else if (c == '\n') {
+	int a = (lexBuf.len>1)?
+	    lexBuf.buf[lexBuf.getPtr+1]:
+	    lexGeta_(1);
+	if (a == '\r') {
+	    lexSkipLookahead();
+	    }
+	lexBuf.buf[lexBuf.getPtr] = '\n';
+	}
+    return c;
+    }
+
+static int lexGetc() {
+    int c = lexLookahead();
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+	/* EOF will remain in lookahead buffer */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+	lexBuf.len--;
+        }
+    return c;
+    }
+
+static void lexSkipLookaheadWord() {
+    if (lexBuf.strsLen <= lexBuf.len) {
+	lexBuf.len -= lexBuf.strsLen;
+	lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
+	}
+    }
+
+static void lexClearToken()
+    {
+    lexBuf.strsLen = 0;
+    }
+
+static void lexAppendc(int c)
+    {
+    lexBuf.strs[lexBuf.strsLen] = c;
+    /* append up to zero termination */
+    if (c == 0) return;
+    lexBuf.strsLen++;
+    if (lexBuf.strsLen > lexBuf.maxToken) {
+	/* double the token string size */
+	lexBuf.maxToken <<= 1;
+	lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
+	}
+    }
+
+static char* lexStr() {
+    return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
+    }
+
+static void lexSkipWhite() {
+    int c = lexLookahead();
+    while (c == ' ' || c == '\t') {
+	lexSkipLookahead();
+	c = lexLookahead();
+	}
+    }
+
+static char* lexGetWord() {
+    int c;
+    lexSkipWhite();
+    lexClearToken();
+    c = lexLookahead();
+    while (c != EOF && !strchr("\t\n ;:=",c)) {
+	lexAppendc(c);
+	lexSkipLookahead();
+	c = lexLookahead();
+	}
+    lexAppendc(0);
+    return lexStr();
+    }
+
+static char* lexGetParamWord()
+{
+    int c;
+    lexClearToken();
+    c = lexLookahead();
+    while (c >= ' ' && c < 127 && !strchr("[]:=,.;",c)) {
+	lexAppendc(c);
+	lexSkipLookahead();
+	c = lexLookahead();
+    }
+    lexAppendc(0);
+    return lexStr();
+}
+
+static void lexPushLookaheadc(int c) {
+    int putptr;
+    /* can't putback EOF, because it never leaves lookahead buffer */
+    if (c == EOF) return;
+    putptr = (int)lexBuf.getPtr - 1;
+    if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
+    lexBuf.getPtr = putptr;
+    lexBuf.buf[putptr] = c;
+    lexBuf.len += 1;
+    }
+
+static char* lexLookaheadWord() {
+    /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
+     /  and thing bigger than that will stop the lookahead and return 0;
+     / leading white spaces are not recoverable.
+     */
+    int c;
+    int len = 0;
+    int curgetptr = 0;
+    lexSkipWhite();
+    lexClearToken();
+    curgetptr = (int)lexBuf.getPtr;	// remember!
+    while (len < (MAX_LEX_LOOKAHEAD_0)) {
+	c = lexGetc();
+	len++;
+	if (c == EOF || strchr("\t\n ;:=", c)) {
+	    lexAppendc(0);
+	    /* restore lookahead buf. */
+	    lexBuf.len += len;
+	    lexBuf.getPtr = curgetptr;
+	    return lexStr();
+	    }
+        else
+	    lexAppendc(c);
+	}
+    lexBuf.len += len;	/* char that has been moved to lookahead buffer */
+    lexBuf.getPtr = curgetptr;
+    return 0;
+    }
+
+#ifdef _SUPPORT_LINE_FOLDING
+static void handleMoreRFC822LineBreak(int c) {
+    /* suport RFC 822 line break in cases like
+     *	ADR: foo;
+     *    morefoo;
+     *    more foo;
+     */
+    if (c == ';') {
+	int a;
+	lexSkipLookahead();
+	/* skip white spaces */
+	a = lexLookahead();
+	while (a == ' ' || a == '\t') {
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    }
+	if (a == '\n') {
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    if (a == ' ' || a == '\t') {
+		/* continuation, throw away all the \n and spaces read so
+		 * far
+		 */
+		lexSkipWhite();
+		lexPushLookaheadc(';');
+		}
+	    else {
+		lexPushLookaheadc('\n');
+		lexPushLookaheadc(';');
+		}
+	    }
+	else {
+	    lexPushLookaheadc(';');
+	    }
+	}
+    }
+
+static char* lexGet1Value() {
+    int c;
+    lexSkipWhite();
+    c = lexLookahead();
+    lexClearToken();
+    while (c != EOF && (c != ';' || !fieldedProp)) {
+	if (c == '\\' ) {
+	    int a;
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    if ( a == ';' ) {
+		lexAppendc( ';' );
+		lexSkipLookahead();
+	    } else if ( a == '\n' ) {
+		lexAppendc( '\n' );
+		lexSkipLookahead();
+	    } else if ( a == '\\' ) {
+		lexAppendc( '\\' );
+		lexSkipLookahead();
+	    } else {
+		lexAppendc('\\');
+	    }
+	} else if (c == '\n') {
+	    int a;
+	    lexSkipLookahead();
+	    a  = lexLookahead();
+	    if (a == ' ' || a == '\t') {
+		lexAppendc(' ');
+		lexSkipLookahead();
+		}
+	    else {
+		lexPushLookaheadc('\n');
+		break;
+		}
+	    }
+	else {
+	    lexAppendc(c);
+	    lexSkipLookahead();
+	    }
+	c = lexLookahead();
+	}
+    lexAppendc(0);
+    handleMoreRFC822LineBreak(c);
+    return c==EOF?0:lexStr();
+    }
+#endif
+
+static int match_begin_name(int end) {
+    char *n = lexLookaheadWord();
+    int token = ID;
+    if (n) {
+	if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
+	else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
+	else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
+	else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
+	deleteStr(n);
+	return token;
+	}
+    return 0;
+    }
+
+
+#ifdef INCLUDEMFC
+void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
+#else
+void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
+#endif
+    {
+    // initialize lex mode stack
+    lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
+
+    // iniatialize lex buffer.
+    lexBuf.inputString = (char*) inputstring;
+    lexBuf.inputLen = inputlen;
+    lexBuf.curPos = 0;
+    lexBuf.inputFile = inputfile;
+
+    lexBuf.len = 0;
+    lexBuf.getPtr = 0;
+
+    lexBuf.maxToken = MAXTOKEN;
+    lexBuf.strs = (char*)malloc(MAXTOKEN);
+    lexBuf.strsLen = 0;
+
+    }
+
+static void finiLex() {
+    free(lexBuf.strs);
+    }
+
+
+/*-----------------------------------*/
+/* This parses and converts the base64 format for binary encoding into
+ * a decoded buffer (allocated with new).  See RFC 1521.
+ */
+static int lexGetDataFromBase64()
+    {
+    unsigned long bytesLen = 0, bytesMax = 0;
+    int quadIx = 0, pad = 0;
+    unsigned long trip = 0;
+    unsigned char b;
+    int c;
+    unsigned char *bytes = NULL;
+    unsigned char *oldBytes = NULL;
+
+    DBG_(("db: lexGetDataFromBase64\n"));
+    while (1) {
+	c = lexGetc();
+	lexSkipWhite();
+	if (c == '\n') {
+	    ++mime_lineNum;
+	    if (lexLookahead() == '\n') {
+		/* a '\n' character by itself means end of data */
+		break;
+		}
+	    else continue; /* ignore '\n' */
+	    }
+	else {
+	    if ((c >= 'A') && (c <= 'Z'))
+		b = (unsigned char)(c - 'A');
+	    else if ((c >= 'a') && (c <= 'z'))
+		b = (unsigned char)(c - 'a') + 26;
+	    else if ((c >= '0') && (c <= '9'))
+		b = (unsigned char)(c - '0') + 52;
+	    else if (c == '+')
+		b = 62;
+	    else if (c == '/')
+		b = 63;
+	    else if (c == '=') {
+		b = 0;
+		pad++;
+	    } else { /* error condition */
+		if (bytes) free(bytes);
+		else if (oldBytes) free(oldBytes);
+		// error recovery: skip until 2 adjacent newlines.
+		DBG_(("db: invalid character 0x%x '%c'\n", c,c));
+		if (c != EOF)  {
+		    c = lexGetc();
+		    while (c != EOF) {
+			if (c == '\n') {
+			    lexSkipWhite();
+			    if(lexLookahead() == '\n') {
+				++mime_lineNum;
+				break;
+				}
+			    }
+			c = lexGetc();
+			}
+		    }
+		return c != EOF;
+		}
+	    trip = (trip << 6) | b;
+	    if (++quadIx == 4) {
+		unsigned char outBytes[3];
+		int numOut;
+		int i;
+		for (i = 0; i < 3; i++) {
+		    outBytes[2-i] = (unsigned char)(trip & 0xFF);
+		    trip >>= 8;
+		    }
+		numOut = 3 - pad;
+		if (bytesLen + numOut > bytesMax) {
+		    if (!bytes) {
+			bytesMax = 1024;
+			bytes = (unsigned char*)malloc((size_t)bytesMax);
+			}
+		    else {
+			bytesMax <<= 2;
+			oldBytes = bytes;
+			bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
+			}
+		    if (bytes == 0) {
+			mime_error("out of memory while processing BASE64 data\n");
+			}
+		    }
+		if (bytes) {
+		    memcpy(bytes + bytesLen, outBytes, numOut);
+		    bytesLen += numOut;
+		    }
+		trip = 0;
+		quadIx = 0;
+		}
+	    }
+	} /* while */
+    DBG_(("db: bytesLen = %d\n",  bytesLen));
+    /* kludge: all this won't be necessary if we have tree form
+	representation */
+    if (bytes) {
+	setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
+	free(bytes);
+	}
+    else if (oldBytes) {
+	setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
+	free(oldBytes);
+	}
+    return bytesLen;
+    }
+
+static int match_begin_end_name(int end) {
+    int token;
+    lexSkipWhite();
+    if (lexLookahead() != ':') return ID;
+    lexSkipLookahead();
+    lexSkipWhite();
+    token = match_begin_name(end);
+    if (token == ID) {
+	lexPushLookaheadc(':');
+	DBG_(("db: ID '%s'\n", yylval.str));
+	return ID;
+	}
+    else if (token != 0) {
+	lexSkipLookaheadWord();
+	deleteStr(yylval.str);
+	DBG_(("db: begin/end %d\n", token));
+	return token;
+	}
+    return 0;
+    }
+
+static char* lexGetQuotedPrintable()
+{
+    int c;
+    lexSkipWhite();
+    c = lexLookahead();
+    lexClearToken();
+
+    while (c != EOF && (c != ';' || !fieldedProp)) {
+	if (c == '\n') {
+	    // break, leave '\n' on remaining chars.
+	    break;
+	} else if (c == '=') {
+	    int cur = 0;
+	    int next;
+
+	    lexSkipLookahead(); // skip '='
+	    next = lexLookahead();
+
+	    if (next == '\n') {
+		// skip and only skip the \n
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		++mime_lineNum; // aid in error reporting
+		continue;
+	    } else if (next >= '0' && next <= '9') {
+		cur = next - '0';
+	    } else if (next >= 'A' && next <= 'F') {
+		cur = next - 'A' + 10;
+	    } else {
+		// we have been sent buggy stuff. doesn't matter
+		// what we do so long as we keep going.
+		// should probably spit an error here
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		continue;
+	    }
+
+	    lexSkipLookahead(); // skip A-Z0-9
+	    next = lexLookahead();
+
+	    cur = cur * 16;
+	    // this time really just expecting 0-9A-F
+	    if (next >= '0' && next <= '9') {
+		cur += next - '0';
+	    } else if (next >= 'A' && next <= 'F') {
+		cur += next - 'A' + 10;
+	    } else {
+		// we have been sent buggy stuff. doesn't matter
+		// what we do so long as we keep going.
+		// should probably spit an error here
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		continue;
+	    }
+
+	    // got a valid escaped =.  append it.
+	    lexSkipLookahead(); // skip second 0-9A-F
+	    lexAppendc(cur);
+	} else {
+	    lexSkipLookahead(); // skip whatever we just read.
+	    lexAppendc(c); // and append it.
+	}
+	c = lexLookahead();
+    }
+    lexAppendc(0);
+    return c==EOF?0:lexStr();
+}
+
+static int yylex() {
+
+    int lexmode = LEXMODE();
+    if (lexmode == L_VALUES) {
+	int c = lexGetc();
+	int c2;
+	if (c == ';' && fieldedProp) {
+	    DBG_(("db: SEMICOLON\n"));
+	    lexPushLookaheadc(c);
+	    handleMoreRFC822LineBreak(c);
+	    lexSkipLookahead();
+	    return SEMICOLON;
+	    }
+	else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') {
+	    ++mime_lineNum;
+	    /* consume all line separator(s) adjacent to each other */
+	    while (strchr("\n",c2)) {
+		lexSkipLookahead();
+		c2 = lexLookahead();
+		++mime_lineNum;
+		}
+	    DBG_(("db: LINESEP\n"));
+	    return LINESEP;
+	    }
+	else {
+	    char *p = 0;
+	    lexPushLookaheadc(c);
+	    if (lexWithinMode(L_BASE64)) {
+		/* get each char and convert to bin on the fly... */
+		yylval.str = NULL;
+		return lexGetDataFromBase64() ? STRING : 0;
+		}
+	    else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
+		p = lexGetQuotedPrintable();
+		}
+	    else {
+#ifdef _SUPPORT_LINE_FOLDING
+		p = lexGet1Value();
+#else
+		p = lexGetStrUntil(";\n");
+#endif
+		}
+	    if (p) {
+		DBG_(("db: STRING: '%s'\n", p));
+		yylval.str = p;
+		return STRING;
+		}
+	    else return 0;
+	    }
+    } else if (lexmode == L_PARAMWORD) {
+	yylval.str = lexGetParamWord();
+	return ID;
+    } else {
+	/* normal mode */
+	while (1) {
+	    int c = lexGetc();
+	    switch(c) {
+		case ':': {
+		    /* consume all line separator(s) adjacent to each other */
+		    /* ignoring linesep immediately after colon. */
+		    /* I don't see this in the spec, and it breaks null values -- WA
+		    c = lexLookahead();
+		    while (strchr("\n",c)) {
+			lexSkipLookahead();
+			c = lexLookahead();
+			++mime_lineNum;
+			}
+		    */
+		    DBG_(("db: COLON\n"));
+		    return COLON;
+		    }
+		case ';':
+		    DBG_(("db: SEMICOLON\n"));
+		    return SEMICOLON;
+		case '=':
+		    DBG_(("db: EQ\n"));
+		    return EQ;
+		/* ignore whitespace in this mode */
+		case '\t':
+		case ' ': continue;
+		case '\n': {
+		    ++mime_lineNum;
+		    continue;
+		    }
+		case EOF: return 0;
+		    break;
+		default: {
+		    lexPushLookaheadc(c);
+		    if (isalnum(c)) {
+			char *t = lexGetWord();
+			yylval.str = t;
+			if (!qstricmp(t, "begin")) {
+			    return match_begin_end_name(0);
+			    }
+			else if (!qstricmp(t,"end")) {
+			    return match_begin_end_name(1);
+			    }
+		        else {
+			    DBG_(("db: ID '%s'\n", t));
+			    return ID;
+			    }
+			}
+		    else {
+			/* unknow token */
+			return 0;
+			}
+		    break;
+		    }
+		}
+	    }
+	}
+    return 0;
+    }
+
+
+/***************************************************************************/
+/***							Public Functions						****/
+/***************************************************************************/
+
+static VObject* Parse_MIMEHelper()
+    {
+    ObjStackTop = -1;
+    mime_numErrors = 0;
+    mime_lineNum = 1;
+    vObjList = 0;
+    curObj = 0;
+
+    if (yyparse() != 0)
+	return 0;
+
+    finiLex();
+    return vObjList;
+    }
+
+/*--------------------------------------------*/
+DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
+    {
+    initLex(input, len, 0);
+    return Parse_MIMEHelper();
+    }
+
+
+#if INCLUDEMFC
+
+DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
+    {
+    unsigned long startPos;
+    VObject *result;	
+
+    initLex(0,-1,file);
+    startPos = file->GetPosition();
+    if (!(result = Parse_MIMEHelper()))
+	file->Seek(startPos, CFile::begin);
+    return result;
+    }
+
+#else
+
+VObject* Parse_MIME_FromFile(FILE *file)
+    {
+    VObject *result;	
+    long startPos;
+
+    initLex(0,(unsigned long)-1,file);
+    startPos = ftell(file);
+    if (!(result = Parse_MIMEHelper())) {
+	fseek(file,startPos,SEEK_SET);
+	}
+    return result;
+    }
+
+DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
+    {
+    FILE *fp = fopen(fname,"r");
+    if (fp) {
+	VObject* o = Parse_MIME_FromFile(fp);
+	fclose(fp);
+	return o;
+	}
+    else {
+	char msg[80];
+	sprintf(msg, "can't open file '%s' for reading\n", fname);
+	mime_error_(msg);
+	return 0;
+	}
+    }
+
+#endif
+
+/*-------------------------------------*/
+
+static MimeErrorHandler mimeErrorHandler;
+
+DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
+    {
+    mimeErrorHandler = me;
+    }
+
+void mime_error(char *s)
+    {
+    char msg[256];
+    if (mimeErrorHandler) {
+	sprintf(msg,"%s at line %d", s, mime_lineNum);
+	mimeErrorHandler(msg);
+	}
+    }
+
+void mime_error_(char *s)
+    {
+    if (mimeErrorHandler) {
+	mimeErrorHandler(s);
+	}
+    }
+
diff --git a/library/backend/vcc_yacc.cpp b/library/backend/vcc_yacc.cpp
index bc05f87..68f11b5 100644
--- a/library/backend/vcc_yacc.cpp
+++ b/library/backend/vcc_yacc.cpp
@@ -1,6 +1,5 @@
 #ifndef lint
-/*static char yysccsid[] = "from: @(#)yaccpar	1.9 (Berkeley) 02/21/93";*/
-static char yyrcsid[] = "$Id$";
+static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
 #endif
 #define YYBYACC 1
 #define YYMAJOR 1
@@ -8,225 +7,200 @@ static char yyrcsid[] = "$Id$";
 #define yyclearin (yychar=(-1))
 #define yyerrok (yyerrflag=0)
 #define YYRECOVERING (yyerrflag!=0)
-#define yyparse vccparse
-#define yylex vcclex
-#define yyerror vccerror
-#define yychar vccchar
-#define yyval vccval
-#define yylval vcclval
-#define yydebug vccdebug
-#define yynerrs vccnerrs
-#define yyerrflag vccerrflag
-#define yyss vccss
-#define yyssp vccssp
-#define yyvs vccvs
-#define yyvsp vccvsp
-#define yylhs vcclhs
-#define yylen vcclen
-#define yydefred vccdefred
-#define yydgoto vccdgoto
-#define yysindex vccsindex
-#define yyrindex vccrindex
-#define yygindex vccgindex
-#define yytable vcctable
-#define yycheck vcccheck
-#define yyname vccname
-#define yyrule vccrule
-#define YYPREFIX "vcc"
-#line 1 "backend/vcc.y"
-
-
-/***************************************************************************
-(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
-Business Machines Corporation and Siemens Rolm Communications Inc.
-
-For purposes of this license notice, the term Licensors shall mean,
-collectively, Apple Computer, Inc., AT&T Corp., International
-Business Machines Corporation and Siemens Rolm Communications Inc.
-The term Licensor shall mean any of the Licensors.
-
-Subject to acceptance of the following conditions, permission is hereby
-granted by Licensors without the need for written agreement and without
-license or royalty fees, to use, copy, modify and distribute this
-software for any purpose.
-
-The above copyright notice and the following four paragraphs must be
-reproduced in all copies of this software and any software including
-this software.
-
-THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
-ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
-MODIFICATIONS.
-
-IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
-INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
-OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.
-
-The software is provided with RESTRICTED RIGHTS.  Use, duplication, or
-disclosure by the government are subject to restrictions set forth in
-DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
-
-***************************************************************************/
-
-/*
- * src: vcc.c
- * doc: Parser for vCard and vCalendar. Note that this code is
- * generated by a yacc parser generator. Generally it should not
- * be edited by hand. The real source is vcc.y. The #line directives
- * can be commented out here to make it easier to trace through
- * in a debugger. However, if a bug is found it should
- * be fixed in vcc.y and this file regenerated.
- */
-
-
-/* debugging utilities */
-#if __DEBUG
-#define DBG_(x) printf x
-#else
-#define DBG_(x)
-#endif
-
-/****  External Functions  ****/
-
-/* assign local name to parser variables and functions so that
-   we can use more than one yacc based parser.
-*/
-
-#if 0
-#define yyparse mime_parse
-#define yylex mime_lex
-#define yyerror mime_error
-#define yychar mime_char
-/* #define p_yyval p_mime_val */
-#undef yyval
-#define yyval mime_yyval
-/* #define p_yylval p_mime_lval */
-#undef yylval
-#define yylval mime_yylval
-#define yydebug mime_debug
-#define yynerrs mime_nerrs
-#define yyerrflag mime_errflag
-#define yyss mime_ss
-#define yyssp mime_ssp
-#define yyvs mime_vs
-#define yyvsp mime_vsp
-#define yylhs mime_lhs
-#define yylen mime_len
-#define yydefred mime_defred
-#define yydgoto mime_dgoto
-#define yysindex mime_sindex
-#define yyrindex mime_rindex
-#define yygindex mime_gindex
-#define yytable mime_table
-#define yycheck mime_check
-#define yyname mime_name
-#define yyrule mime_rule
-#ifdef YYPREFIX
-#undef YYPREFIX
-#endif
-#define YYPREFIX "mime_"
-#endif
-
-
-#ifndef _NO_LINE_FOLDING
-#define _SUPPORT_LINE_FOLDING 1
-#endif
-
-/* undef below if compile with MFC */
-/* #define INCLUDEMFC 1 */
-
-#if defined(WIN32) || defined(_WIN32)
-#ifdef INCLUDEMFC
-#include <afx.h>
-#endif
-#endif
-
-#include <string.h>
-#ifndef __MWERKS__
-#include <stdlib.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-/*#ifdef PALMTOPCENTER
-*/
-/*#include <qpe/vobject_p.h>
-*/
-/*#else
-*/
-#include "vobject_p.h"
-/*#endif
-*/
-
-/****  Types, Constants  ****/
-
-#define YYDEBUG		0	/* 1 to compile in some debugging code */
-#define MAXTOKEN	256	/* maximum token (line) length */
-#define YYSTACKSIZE 	100	/* ~unref ?
-*/
-#define MAXLEVEL	10	/* max # of nested objects parseable */
-				/* (includes outermost) */
-
-
-/****  Global Variables  ****/
-int mime_lineNum, mime_numErrors; /* yyerror() can use these */
-static VObject* vObjList;
-static VObject *curProp;
-static VObject *curObj;
-static VObject* ObjStack[MAXLEVEL];
-static int ObjStackTop;
-
-
-/* A helpful utility for the rest of the app. */
-#if __CPLUSPLUS__
-extern "C" {
-#endif
-
-    extern void yyerror(char *s);
-
-#if __CPLUSPLUS__
-    };
-#endif
-
-int yyparse();
-
-enum LexMode {
-	L_NORMAL,
-	L_VCARD,
-	L_VCAL,
-	L_VEVENT,
-	L_VTODO,
-	L_VALUES,
-	L_BASE64,
-	L_QUOTED_PRINTABLE
-	};
-
-/****  Private Forward Declarations  ****/
-static int pushVObject(const char *prop);
-static VObject* popVObject();
-static void lexPopMode(int top);
-static int lexWithinMode(enum LexMode mode);
-static void lexPushMode(enum LexMode mode);
-static void enterProps(const char *s);
-static void enterAttr(const char *s1, const char *s2);
-static void enterValues(const char *value);
-#define mime_error yyerror
-void mime_error(char *s);
-void mime_error_(char *s);
-
-#line 189 "backend/vcc.y"
-typedef union {
-    char *str;
-    VObject *vobj;
+#define YYPREFIX "yy"
+#line 1 "vcc.y"
+
+
+/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS.  Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+ * src: vcc.c
+ * doc: Parser for vCard and vCalendar. Note that this code is
+ * generated by a yacc parser generator. Generally it should not
+ * be edited by hand. The real source is vcc.y. The #line directives
+ * can be commented out here to make it easier to trace through
+ * in a debugger. However, if a bug is found it should
+ * be fixed in vcc.y and this file regenerated.
+ */
+
+
+/* debugging utilities */
+#define __DEBUG 1
+
+#if __DEBUG
+#define DBG_(x) printf x
+#else
+#define DBG_(x)
+#endif
+
+/****  External Functions  ****/
+
+/* assign local name to parser variables and functions so that
+   we can use more than one yacc based parser.
+*/
+
+#if 0
+#define yyparse mime_parse
+#define yylex mime_lex
+#define yyerror mime_error
+#define yychar mime_char
+/* #define p_yyval p_mime_val */
+#undef yyval
+#define yyval mime_yyval
+/* #define p_yylval p_mime_lval */
+#undef yylval
+#define yylval mime_yylval
+#define yydebug mime_debug
+#define yynerrs mime_nerrs
+#define yyerrflag mime_errflag
+#define yyss mime_ss
+#define yyssp mime_ssp
+#define yyvs mime_vs
+#define yyvsp mime_vsp
+#define yylhs mime_lhs
+#define yylen mime_len
+#define yydefred mime_defred
+#define yydgoto mime_dgoto
+#define yysindex mime_sindex
+#define yyrindex mime_rindex
+#define yygindex mime_gindex
+#define yytable mime_table
+#define yycheck mime_check
+#define yyname mime_name
+#define yyrule mime_rule
+#ifdef YYPREFIX
+#undef YYPREFIX
+#endif
+#define YYPREFIX "mime_"
+#endif
+
+
+#ifndef _NO_LINE_FOLDING
+#define _SUPPORT_LINE_FOLDING 1
+#endif
+
+/* undef below if compile with MFC */
+/* #define INCLUDEMFC 1 */
+
+#if defined(WIN32) || defined(_WIN32)
+#ifdef INCLUDEMFC
+#include <afx.h>
+#endif
+#endif
+
+#include <string.h>
+#ifndef __MWERKS__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/*#ifdef PALMTOPCENTER
*/
+/*#include <qpe/vobject_p.h>
*/
+/*#else
*/
+#include "vobject_p.h"
+/*#endif
*/
+
+/****  Types, Constants  ****/
+
+#define YYDEBUG		0	/* 1 to compile in some debugging code */
+#define MAXTOKEN	256	/* maximum token (line) length */
+#define YYSTACKSIZE 	100	/* ~unref ?
*/
+#define MAXLEVEL	10	/* max # of nested objects parseable */
+				/* (includes outermost) */
+
+
+/****  Global Variables  ****/
+int q_DontDecodeBase64Photo = 0;
+int mime_lineNum, mime_numErrors; /* yyerror() can use these */
+static VObject* vObjList;
+static VObject *curProp;
+static VObject *curObj;
+static VObject* ObjStack[MAXLEVEL];
+static int ObjStackTop;
+
+
+/* A helpful utility for the rest of the app. */
+#if __CPLUSPLUS__
+extern "C" {
+#endif
+
+    extern void yyerror(char *s);
+
+#if __CPLUSPLUS__
+    };
+#endif
+
+int yyparse();
+
+enum LexMode {
+	L_NORMAL,
+	L_PARAMWORD,
+	L_VCARD,
+	L_VCAL,
+	L_VEVENT,
+	L_VTODO,
+	L_VALUES,
+	L_BASE64,
+	L_QUOTED_PRINTABLE
+	};
+
+/****  Private Forward Declarations  ****/
+static int pushVObject(const char *prop);
+static VObject* popVObject();
+static void lexPopMode(int top);
+static int lexWithinMode(enum LexMode mode);
+static void lexPushMode(enum LexMode mode);
+static void enterProps(const char *s);
+static void enterAttr(const char *s1, const char *s2);
+static void enterValues(const char *value);
+#define mime_error yyerror
+void mime_error(char *s);
+void mime_error_(char *s);
+
+#line 193 "vcc.y"
+typedef union {
+    char *str;
+    VObject *vobj;
     } YYSTYPE;
-#line 225 "y.tab.c"
+#line 204 "y.tab.c"
 #define EQ 257
 #define COLON 258
 #define DOT 259
@@ -246,73 +220,73 @@ typedef union {
 #define ID 273
 #define STRING 274
 #define YYERRCODE 256
-short vcclhs[] = {                                        -1,
+short yylhs[] = {                                        -1,
     0,    6,    6,    5,    5,    8,    3,    9,    3,    7,
     7,   13,   10,   10,   15,   11,   11,   14,   14,   16,
-   17,   17,    1,   18,   12,   12,    2,    2,   20,    4,
-   21,    4,   19,   19,   22,   22,   22,   25,   23,   26,
-   23,   27,   24,   28,   24,
+   17,   18,   17,    1,   19,   12,   12,    2,    2,   21,
+    4,   22,    4,   20,   20,   23,   23,   23,   26,   24,
+   27,   24,   28,   25,   29,   25,
 };
-short vcclen[] = {                                         2,
+short yylen[] = {                                         2,
     1,    2,    1,    1,    1,    0,    4,    0,    3,    2,
     1,    0,    5,    1,    0,    3,    1,    2,    1,    2,
-    1,    3,    1,    0,    4,    1,    1,    0,    0,    4,
-    0,    3,    2,    1,    1,    1,    1,    0,    4,    0,
-    3,    0,    4,    0,    3,
+    1,    0,    4,    1,    0,    4,    1,    1,    0,    0,
+    4,    0,    3,    2,    1,    1,    1,    1,    0,    4,
+    0,    3,    0,    4,    0,    3,
 };
-short vccdefred[] = {                                      0,
+short yydefred[] = {                                      0,
     0,    0,    0,    4,    5,    3,    0,    0,    0,    0,
-    0,    2,   14,   23,    0,    0,   11,    0,    9,    0,
-    0,    0,    0,   34,   35,   36,   32,    0,    7,   10,
-   12,    0,    0,    0,    0,   30,   33,    0,    0,   19,
-    0,    0,   41,    0,   45,    0,   20,   18,   27,    0,
-    0,   39,   43,    0,   24,   13,   22,    0,   25,
+    0,    2,   14,   24,    0,    0,   11,    0,    9,    0,
+    0,    0,    0,   35,   36,   37,   33,    0,    7,   10,
+   12,    0,    0,    0,    0,   31,   34,    0,    0,   19,
+    0,    0,   42,    0,   46,    0,   20,   18,   28,    0,
+    0,   40,   44,   22,   25,   13,    0,    0,   23,   26,
 };
-short vccdgoto[] = {                                       3,
+short yydgoto[] = {                                       3,
    15,   50,    4,    5,    6,    7,   22,    8,    9,   17,
-   18,   51,   41,   39,   28,   40,   47,   58,   23,   10,
-   11,   24,   25,   26,   32,   33,   34,   35,
+   18,   51,   41,   39,   28,   40,   47,   57,   58,   23,
+   10,   11,   24,   25,   26,   32,   33,   34,   35,
 };
-short vccsindex[] = {                                   -262,
-    0,    0,    0,    0,    0,    0, -262, -252, -219, -249,
- -256,    0,    0,    0,    0, -227,    0, -242,    0,    0,
-    0, -252, -254,    0,    0,    0,    0, -208,    0,    0,
-    0, -252, -228, -252, -213,    0,    0, -212, -208,    0,
- -214, -233,    0, -224,    0, -195,    0,    0,    0, -197,
- -199,    0,    0, -212,    0,    0,    0, -214,    0,
+short yysindex[] = {                                   -255,
+    0,    0,    0,    0,    0,    0, -255, -215, -257, -234,
+ -245,    0,    0,    0,    0, -242,    0, -210,    0,    0,
+    0, -215, -253,    0,    0,    0,    0, -247,    0,    0,
+    0, -215, -227, -215, -226,    0,    0, -221, -247,    0,
+ -211, -237,    0, -218,    0, -204,    0,    0,    0, -198,
+ -199,    0,    0,    0,    0,    0, -221, -211,    0,    0,
 };
-short vccrindex[] = {                                      0,
- -222, -238,    0,    0,    0,    0,   65,    0,    0,    0,
-    0,    0,    0,    0, -215,    0,    0,    0,    0, -220,
- -218, -260,    0,    0,    0,    0,    0,    0,    0,    0,
+short yyrindex[] = {                                      0,
+ -216, -239,    0,    0,    0,    0,   65,    0,    0,    0,
+    0,    0,    0,    0, -213,    0,    0,    0,    0, -214,
+ -212, -264,    0,    0,    0,    0,    0,    0,    0,    0,
     0,    0,    0,    0,    0,    0,    0,    0, -192,    0,
- -250,    0,    0,    0,    0, -202,    0,    0,    0, -196,
-    0,    0,    0,    0,    0,    0,    0, -250,    0,
+ -252,    0,    0,    0,    0, -209,    0,    0,    0, -196,
+    0,    0,    0,    0,    0,    0,    0, -252,    0,    0,
 };
-short vccgindex[] = {                                      0,
-    3,    0,    0,    0,   61,    0,   -7,    0,    0,  -16,
+short yygindex[] = {                                      0,
+  -36,    0,    0,    0,   61,    0,   -7,    0,    0,  -16,
     0,   11,    0,    0,    0,   31,    0,    0,    0,    0,
-    0,   48,    0,    0,    0,    0,    0,    0,
+    0,    0,   48,    0,    0,    0,    0,    0,    0,
 };
 #define YYTABLESIZE 71
-short vcctable[] = {                                      30,
-   16,   13,    1,   13,    2,   30,   13,   37,   37,   28,
-   37,   27,   28,   36,   20,   31,   21,   29,   14,   20,
-   14,   21,   13,   14,   42,   30,   44,   30,   13,   31,
-   29,   13,   29,    6,   29,   38,   52,   42,   29,   14,
-   46,   43,   17,    8,   15,   14,   19,   53,   14,   40,
-    6,   38,   38,   44,   42,   21,   57,   21,   45,   49,
-   14,   54,   55,   56,    1,   16,   26,   12,   59,   48,
+short yytable[] = {                                      30,
+   16,   46,   13,   38,   38,   30,   38,   29,   19,    1,
+   29,    2,   38,   13,   36,   20,   30,   21,   13,   14,
+   59,   13,   27,   29,   42,   30,   44,   30,   32,   30,
+   14,   30,   52,   30,   20,   14,   21,   13,   14,    6,
+   13,   39,   43,   43,   17,   45,   15,   31,   21,    8,
+   21,   14,   54,   53,   14,   41,    6,   14,   39,   45,
+   43,   55,   49,   56,    1,   16,   27,   12,   60,   48,
    37,
 };
-short vcccheck[] = {                                      16,
-    8,  256,  265,  256,  267,   22,  256,  268,  269,  260,
-  271,  268,  263,  268,  269,  258,  271,  256,  273,  269,
-  273,  271,  256,  273,   32,   42,   34,   44,  256,  268,
-  269,  256,  271,  256,  273,  256,  270,  256,  266,  273,
-   38,  270,  258,  266,  260,  273,  266,  272,  273,  270,
-  273,  260,  273,  272,  273,  258,   54,  260,  272,  274,
-  273,  257,  260,  263,    0,  258,  263,    7,   58,   39,
+short yycheck[] = {                                      16,
+    8,   38,  256,  268,  269,   22,  271,  260,  266,  265,
+  263,  267,  260,  256,  268,  269,  256,  271,  256,  273,
+   57,  256,  268,  266,   32,   42,   34,   44,  268,  269,
+  273,  271,  270,  273,  269,  273,  271,  256,  273,  256,
+  256,  256,  270,  256,  258,  272,  260,  258,  258,  266,
+  260,  273,  257,  272,  273,  270,  273,  273,  273,  272,
+  273,  260,  274,  263,    0,  258,  263,    7,   58,   39,
    23,
 };
 #define YYFINAL 3
@@ -321,7 +295,7 @@ short vcccheck[] = {                                      16,
 #endif
 #define YYMAXTOKEN 274
 #if YYDEBUG
-char *vccname[] = {
+char *yyname[] = {
 "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -332,7 +306,7 @@ char *vccname[] = {
 "SPACE","HTAB","LINESEP","NEWLINE","BEGIN_VCARD","END_VCARD","BEGIN_VCAL",
 "END_VCAL","BEGIN_VEVENT","END_VEVENT","BEGIN_VTODO","END_VTODO","ID","STRING",
 };
-char *vccrule[] = {
+char *yyrule[] = {
 "$accept : mime",
 "mime : vobjects",
 "vobjects : vobjects vobject",
@@ -355,30 +329,31 @@ char *vccrule[] = {
 "attr_params : attr_param",
 "attr_param : SEMICOLON attr",
 "attr : name",
-"attr : name EQ name",
-"name : ID",
 "$$5 :",
-"values : value SEMICOLON $$5 values",
+"attr : name EQ $$5 name",
+"name : ID",
+"$$6 :",
+"values : value SEMICOLON $$6 values",
 "values : value",
 "value : STRING",
 "value :",
-"$$6 :",
-"vcal : BEGIN_VCAL $$6 calitems END_VCAL",
 "$$7 :",
-"vcal : BEGIN_VCAL $$7 END_VCAL",
+"vcal : BEGIN_VCAL $$7 calitems END_VCAL",
+"$$8 :",
+"vcal : BEGIN_VCAL $$8 END_VCAL",
 "calitems : calitems calitem",
 "calitems : calitem",
 "calitem : eventitem",
 "calitem : todoitem",
 "calitem : items",
-"$$8 :",
-"eventitem : BEGIN_VEVENT $$8 items END_VEVENT",
 "$$9 :",
-"eventitem : BEGIN_VEVENT $$9 END_VEVENT",
+"eventitem : BEGIN_VEVENT $$9 items END_VEVENT",
 "$$10 :",
-"todoitem : BEGIN_VTODO $$10 items END_VTODO",
+"eventitem : BEGIN_VEVENT $$10 END_VEVENT",
 "$$11 :",
-"todoitem : BEGIN_VTODO $$11 END_VTODO",
+"todoitem : BEGIN_VTODO $$11 items END_VTODO",
+"$$12 :",
+"todoitem : BEGIN_VTODO $$12 END_VTODO",
 };
 #endif
 #ifdef YYSTACKSIZE
@@ -403,856 +378,873 @@ YYSTYPE yylval;
 short yyss[YYSTACKSIZE];
 YYSTYPE yyvs[YYSTACKSIZE];
 #define yystacksize YYSTACKSIZE
-#line 382 "backend/vcc.y"
-
-/*------------------------------------*/
-static int pushVObject(const char *prop)
-    {
-    VObject *newObj;
-    if (ObjStackTop == MAXLEVEL)
-	return FALSE;
-
-    ObjStack[++ObjStackTop] = curObj;
-
-    if (curObj) {
-        newObj = addProp(curObj,prop);
-        curObj = newObj;
-	}
-    else
-	curObj = newVObject(prop);
-
-    return TRUE;
-    }
-
-
-/*---------------------------------------*/
-/* This pops the recently built vCard off the stack and returns it. */
-static VObject* popVObject()
-    {
-    VObject *oldObj;
-    if (ObjStackTop < 0) {
-	yyerror("pop on empty Object Stack\n");
-	return 0;
-	}
-    oldObj = curObj;
-    curObj = ObjStack[ObjStackTop--];
-
-    return oldObj;
-    }
-
-
-static void enterValues(const char *value)
-    {
-    if (fieldedProp && *fieldedProp) {
-	if (value) {
-	    addPropValue(curProp,*fieldedProp,value);
-	    }
-	/* else this field is empty, advance to next field */
-	fieldedProp++;
-	}
-    else {
-	if (value) {
-	    setVObjectStringZValue_(curProp,strdup( value ));
-	    }
-	}
-    deleteStr(value);
-    }
-
-static void enterProps(const char *s)
-    {
-    curProp = addGroup(curObj,s);
-    deleteStr(s);
-    }
-
-static void enterAttr(const char *s1, const char *s2)
-    {
-    const char *p1, *p2=0;
-    p1 = lookupProp_(s1);
-    if (s2) {
-	VObject *a;
-	p2 = lookupProp_(s2);
-	a = addProp(curProp,p1);
-	setVObjectStringZValue(a,p2);
-	}
-    else
-	addProp(curProp,p1);
-    if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
-	lexPushMode(L_BASE64);
-    else if (qstricmp(p1,VCQuotedPrintableProp) == 0
-	    || (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
-	lexPushMode(L_QUOTED_PRINTABLE);
-    deleteStr(s1); deleteStr(s2);
-    }
-
-
-#define MAX_LEX_LOOKAHEAD_0 32
-#define MAX_LEX_LOOKAHEAD 64
-#define MAX_LEX_MODE_STACK_SIZE 10
-#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
-
-struct LexBuf {
-	/* input */
-#ifdef INCLUDEMFC
-    CFile *inputFile;
-#else
-    FILE *inputFile;
-#endif
-    char *inputString;
-    unsigned long curPos;
-    unsigned long inputLen;
-	/* lookahead buffer */
-	/*   -- lookahead buffer is short instead of char so that EOF
-	 /      can be represented correctly.
-	*/
-    unsigned long len;
-    short buf[MAX_LEX_LOOKAHEAD];
-    unsigned long getPtr;
-	/* context stack */
-    unsigned long lexModeStackTop;
-    enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
-	/* token buffer */
-    unsigned long maxToken;
-    char *strs;
-    unsigned long strsLen;
-    } lexBuf;
-
-static void lexPushMode(enum LexMode mode)
-    {
-    if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
-	yyerror("lexical context stack overflow");
-    else {
-	lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
-	}
-    }
-
-static void lexPopMode(int top)
-    {
-    /* special case of pop for ease of error recovery -- this
-	version will never underflow */
-    if (top)
-	lexBuf.lexModeStackTop = 0;
-    else
-	if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
-    }
-
-static int lexWithinMode(enum LexMode mode) {
-    unsigned long i;
-    for (i=0;i<lexBuf.lexModeStackTop;i++)
-	if (mode == lexBuf.lexModeStack[i]) return 1;
-    return 0;
-    }
-
-static int lexGetc_()
-    {
-    /* get next char from input, no buffering. */
-    if (lexBuf.curPos == lexBuf.inputLen)
-	return EOF;
-    else if (lexBuf.inputString)
-	return *(lexBuf.inputString + lexBuf.curPos++);
-    else {
-#ifdef INCLUDEMFC
-	char result;
-	return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
-#else
-	return fgetc(lexBuf.inputFile);
-#endif
-	}
-    }
-
-static int lexGeta()
-    {
-    ++lexBuf.len;
-    return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
-    }
-
-static int lexGeta_(int i)
-    {
-    ++lexBuf.len;
-    return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
-    }
-
-static void lexSkipLookahead() {
-    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
-	/* don't skip EOF. */
-        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
-	lexBuf.len--;
-        }
-    }
-
-static int lexLookahead() {
-    int c = (lexBuf.len)?
-	lexBuf.buf[lexBuf.getPtr]:
-	lexGeta();
-    /* do the \r\n -> \n or \r -> \n translation here */
-    if (c == '\r') {
-	int a = (lexBuf.len>1)?
-	    lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
-	    lexGeta_(1);
-	if (a == '\n') {
-	    lexSkipLookahead();
-	    }
-	lexBuf.buf[lexBuf.getPtr] = c = '\n';
-	}
-    else if (c == '\n') {
-	int a = (lexBuf.len>1)?
-	    lexBuf.buf[lexBuf.getPtr+1]:
-	    lexGeta_(1);
-	if (a == '\r') {
-	    lexSkipLookahead();
-	    }
-	lexBuf.buf[lexBuf.getPtr] = '\n';
-	}
-    return c;
-    }
-
-static int lexGetc() {
-    int c = lexLookahead();
-    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
-	/* EOF will remain in lookahead buffer */
-        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
-	lexBuf.len--;
-        }
-    return c;
-    }
-
-static void lexSkipLookaheadWord() {
-    if (lexBuf.strsLen <= lexBuf.len) {
-	lexBuf.len -= lexBuf.strsLen;
-	lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
-	}
-    }
-
-static void lexClearToken()
-    {
-    lexBuf.strsLen = 0;
-    }
-
-static void lexAppendc(int c)
-    {
-    lexBuf.strs[lexBuf.strsLen] = c;
-    /* append up to zero termination */
-    if (c == 0) return;
-    lexBuf.strsLen++;
-    if (lexBuf.strsLen > lexBuf.maxToken) {
-	/* double the token string size */
-	lexBuf.maxToken <<= 1;
-	lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
-	}
-    }
-
-static char* lexStr() {
-    return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
-    }
-
-static void lexSkipWhite() {
-    int c = lexLookahead();
-    while (c == ' ' || c == '\t') {
-	lexSkipLookahead();
-	c = lexLookahead();
-	}
-    }
-
-static char* lexGetWord() {
-    int c;
-    lexSkipWhite();
-    lexClearToken();
-    c = lexLookahead();
-    while (c != EOF && !strchr("\t\n ;:=",c)) {
-	lexAppendc(c);
-	lexSkipLookahead();
-	c = lexLookahead();
-	}
-    lexAppendc(0);
-    return lexStr();
-    }
-
-static void lexPushLookaheadc(int c) {
-    int putptr;
-    /* can't putback EOF, because it never leaves lookahead buffer */
-    if (c == EOF) return;
-    putptr = (int)lexBuf.getPtr - 1;
-    if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
-    lexBuf.getPtr = putptr;
-    lexBuf.buf[putptr] = c;
-    lexBuf.len += 1;
-    }
-
-static char* lexLookaheadWord() {
-    /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
-     /  and thing bigger than that will stop the lookahead and return 0;
-     / leading white spaces are not recoverable.
-     */
-    int c;
-    int len = 0;
-    int curgetptr = 0;
-    lexSkipWhite();
-    lexClearToken();
-    curgetptr = (int)lexBuf.getPtr;	// remember!
-    while (len < (MAX_LEX_LOOKAHEAD_0)) {
-	c = lexGetc();
-	len++;
-	if (c == EOF || strchr("\t\n ;:=", c)) {
-	    lexAppendc(0);
-	    /* restore lookahead buf. */
-	    lexBuf.len += len;
-	    lexBuf.getPtr = curgetptr;
-	    return lexStr();
-	    }
-        else
-	    lexAppendc(c);
-	}
-    lexBuf.len += len;	/* char that has been moved to lookahead buffer */
-    lexBuf.getPtr = curgetptr;
-    return 0;
-    }
-
-#ifdef _SUPPORT_LINE_FOLDING
-static void handleMoreRFC822LineBreak(int c) {
-    /* suport RFC 822 line break in cases like
-     *	ADR: foo;
-     *    morefoo;
-     *    more foo;
-     */
-    if (c == ';') {
-	int a;
-	lexSkipLookahead();
-	/* skip white spaces */
-	a = lexLookahead();
-	while (a == ' ' || a == '\t') {
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    }
-	if (a == '\n') {
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    if (a == ' ' || a == '\t') {
-		/* continuation, throw away all the \n and spaces read so
-		 * far
-		 */
-		lexSkipWhite();
-		lexPushLookaheadc(';');
-		}
-	    else {
-		lexPushLookaheadc('\n');
-		lexPushLookaheadc(';');
-		}
-	    }
-	else {
-	    lexPushLookaheadc(';');
-	    }
-	}
-    }
-
-static char* lexGet1Value() {
-    int c;
-    lexSkipWhite();
-    c = lexLookahead();
-    lexClearToken();
-    while (c != EOF && (c != ';' || !fieldedProp)) {
-	if (c == '\\' ) {
-	    int a;
-	    lexSkipLookahead();
-	    a = lexLookahead();
-	    if ( a == ';' ) {
-		lexAppendc( ';' );
-		lexSkipLookahead();
-	    } else if ( a == '\n' ) {
-		lexAppendc( '\n' );
-		lexSkipLookahead();
-	    } else if ( a == '\\' ) {
-		lexAppendc( '\\' );
-		lexSkipLookahead();
-	    } else {
-		lexAppendc('\\');
-	    }
-	} else if (c == '\n') {
-	    int a;
-	    lexSkipLookahead();
-	    a  = lexLookahead();
-	    if (a == ' ' || a == '\t') {
-		lexAppendc(' ');
-		lexSkipLookahead();
-		}
-	    else {
-		lexPushLookaheadc('\n');
-		break;
-		}
-	    }
-	else {
-	    lexAppendc(c);
-	    lexSkipLookahead();
-	    }
-	c = lexLookahead();
-	}
-    lexAppendc(0);
-    handleMoreRFC822LineBreak(c);
-    return c==EOF?0:lexStr();
-    }
-#endif
-
-static int match_begin_name(int end) {
-    char *n = lexLookaheadWord();
-    int token = ID;
-    if (n) {
-	if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
-	else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
-	else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
-	else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
-	deleteStr(n);
-	return token;
-	}
-    return 0;
-    }
-
-
-#ifdef INCLUDEMFC
-void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
-#else
-void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
-#endif
-    {
-    // initialize lex mode stack
-    lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
-
-    // iniatialize lex buffer.
-    lexBuf.inputString = (char*) inputstring;
-    lexBuf.inputLen = inputlen;
-    lexBuf.curPos = 0;
-    lexBuf.inputFile = inputfile;
-
-    lexBuf.len = 0;
-    lexBuf.getPtr = 0;
-
-    lexBuf.maxToken = MAXTOKEN;
-    lexBuf.strs = (char*)malloc(MAXTOKEN);
-    lexBuf.strsLen = 0;
-
-    }
-
-static void finiLex() {
-    free(lexBuf.strs);
-    }
-
-
-/*-----------------------------------*/
-/* This parses and converts the base64 format for binary encoding into
- * a decoded buffer (allocated with new).  See RFC 1521.
- */
-static int lexGetDataFromBase64()
-    {
-    unsigned long bytesLen = 0, bytesMax = 0;
-    int quadIx = 0, pad = 0;
-    unsigned long trip = 0;
-    unsigned char b;
-    int c;
-    unsigned char *bytes = NULL;
-    unsigned char *oldBytes = NULL;
-
-    DBG_(("db: lexGetDataFromBase64\n"));
-    while (1) {
-	c = lexGetc();
-	lexSkipWhite();
-	if (c == '\n') {
-	    ++mime_lineNum;
-	    if (lexLookahead() == '\n') {
-		/* a '\n' character by itself means end of data */
-		break;
-		}
-	    else continue; /* ignore '\n' */
-	    }
-	else {
-	    if ((c >= 'A') && (c <= 'Z'))
-		b = (unsigned char)(c - 'A');
-	    else if ((c >= 'a') && (c <= 'z'))
-		b = (unsigned char)(c - 'a') + 26;
-	    else if ((c >= '0') && (c <= '9'))
-		b = (unsigned char)(c - '0') + 52;
-	    else if (c == '+')
-		b = 62;
-	    else if (c == '/')
-		b = 63;
-	    else if (c == '=') {
-		b = 0;
-		pad++;
-	    } else { /* error condition */
-		if (bytes) free(bytes);
-		else if (oldBytes) free(oldBytes);
-		// error recovery: skip until 2 adjacent newlines.
-		DBG_(("db: invalid character 0x%x '%c'\n", c,c));
-		if (c != EOF)  {
-		    c = lexGetc();
-		    while (c != EOF) {
-			if (c == '\n') {
-			    lexSkipWhite();
-			    if(lexLookahead() == '\n') {
-				++mime_lineNum;
-				break;
-				}
-			    }
-			c = lexGetc();
-			}
-		    }
-		return c != EOF;
-		}
-	    trip = (trip << 6) | b;
-	    if (++quadIx == 4) {
-		unsigned char outBytes[3];
-		int numOut;
-		int i;
-		for (i = 0; i < 3; i++) {
-		    outBytes[2-i] = (unsigned char)(trip & 0xFF);
-		    trip >>= 8;
-		    }
-		numOut = 3 - pad;
-		if (bytesLen + numOut > bytesMax) {
-		    if (!bytes) {
-			bytesMax = 1024;
-			bytes = (unsigned char*)malloc((size_t)bytesMax);
-			}
-		    else {
-			bytesMax <<= 2;
-			oldBytes = bytes;
-			bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
-			}
-		    if (bytes == 0) {
-			mime_error("out of memory while processing BASE64 data\n");
-			}
-		    }
-		if (bytes) {
-		    memcpy(bytes + bytesLen, outBytes, numOut);
-		    bytesLen += numOut;
-		    }
-		trip = 0;
-		quadIx = 0;
-		}
-	    }
-	} /* while */
-    DBG_(("db: bytesLen = %d\n",  bytesLen));
-    /* kludge: all this won't be necessary if we have tree form
-	representation */
-    if (bytes) {
-	setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
-	free(bytes);
-	}
-    else if (oldBytes) {
-	setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
-	free(oldBytes);
-	}
-    return bytesLen;
-    }
-
-static int match_begin_end_name(int end) {
-    int token;
-    lexSkipWhite();
-    if (lexLookahead() != ':') return ID;
-    lexSkipLookahead();
-    lexSkipWhite();
-    token = match_begin_name(end);
-    if (token == ID) {
-	lexPushLookaheadc(':');
-	DBG_(("db: ID '%s'\n", yylval.str));
-	return ID;
-	}
-    else if (token != 0) {
-	lexSkipLookaheadWord();
-	deleteStr(yylval.str);
-	DBG_(("db: begin/end %d\n", token));
-	return token;
-	}
-    return 0;
-    }
-
-static char* lexGetQuotedPrintable()
-{
-    int c;
-    lexSkipWhite();
-    c = lexLookahead();
-    lexClearToken();
-
-    while (c != EOF && (c != ';' || !fieldedProp)) {
-	if (c == '\n') {
-	    // break, leave '\n' on remaining chars.
-	    break;
-	} else if (c == '=') {
-	    int cur = 0;
-	    int next;
-
-	    lexSkipLookahead(); // skip '='
-	    next = lexLookahead();
-
-	    if (next == '\n') {
-		// skip and only skip the \n
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		++mime_lineNum; // aid in error reporting
-		continue;
-	    } else if (next >= '0' && next <= '9') {
-		cur = next - '0';
-	    } else if (next >= 'A' && next <= 'F') {
-		cur = next - 'A' + 10;
-	    } else {
-		// we have been sent buggy stuff. doesn't matter
-		// what we do so long as we keep going.
-		// should probably spit an error here
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		continue;
-	    }
-
-	    lexSkipLookahead(); // skip A-Z0-9
-	    next = lexLookahead();
-
-	    cur = cur * 16;
-	    // this time really just expecting 0-9A-F
-	    if (next >= '0' && next <= '9') {
-		cur += next - '0';
-	    } else if (next >= 'A' && next <= 'F') {
-		cur += next - 'A' + 10;
-	    } else {
-		// we have been sent buggy stuff. doesn't matter
-		// what we do so long as we keep going.
-		// should probably spit an error here
-		lexSkipLookahead(); 
-		c = lexLookahead();
-		continue;
-	    }
-
-	    // got a valid escaped =.  append it.
-	    lexSkipLookahead(); // skip second 0-9A-F
-	    lexAppendc(cur);
-	} else {
-	    lexSkipLookahead(); // skip whatever we just read.
-	    lexAppendc(c); // and append it.
-	}
-	c = lexLookahead();
-    }
-    lexAppendc(0);
-    return c==EOF?0:lexStr();
-}
-
-static int yylex() {
-
-    int lexmode = LEXMODE();
-    if (lexmode == L_VALUES) {
-	int c = lexGetc();
-	if (c == ';' && fieldedProp) {
-	    DBG_(("db: SEMICOLON\n"));
-	    lexPushLookaheadc(c);
-	    handleMoreRFC822LineBreak(c);
-	    lexSkipLookahead();
-	    return SEMICOLON;
-	    }
-	else if (strchr("\n",c)) {
-	    ++mime_lineNum;
-	    /* consume all line separator(s) adjacent to each other */
-	    c = lexLookahead();
-	    while (strchr("\n",c)) {
-		lexSkipLookahead();
-		c = lexLookahead();
-		++mime_lineNum;
-		}
-	    DBG_(("db: LINESEP\n"));
-	    return LINESEP;
-	    }
-	else {
-	    char *p = 0;
-	    lexPushLookaheadc(c);
-	    if (lexWithinMode(L_BASE64)) {
-		/* get each char and convert to bin on the fly... */
-		yylval.str = NULL;
-		return lexGetDataFromBase64() ? STRING : 0;
-		}
-	    else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
-		p = lexGetQuotedPrintable();
-		}
-	    else {
-#ifdef _SUPPORT_LINE_FOLDING
-		p = lexGet1Value();
-#else
-		p = lexGetStrUntil(";\n");
-#endif
-		}
-	    if (p) {
-		DBG_(("db: STRING: '%s'\n", p));
-		yylval.str = p;
-		return STRING;
-		}
-	    else return 0;
-	    }
-	}
-    else {
-	/* normal mode */
-	while (1) {
-	    int c = lexGetc();
-	    switch(c) {
-		case ':': {
-		    /* consume all line separator(s) adjacent to each other */
-		    /* ignoring linesep immediately after colon. */
-		    /* I don't see this in the spec, and it breaks null values -- WA
-		    c = lexLookahead();
-		    while (strchr("\n",c)) {
-			lexSkipLookahead();
-			c = lexLookahead();
-			++mime_lineNum;
-			}
-		    */
-		    DBG_(("db: COLON\n"));
-		    return COLON;
-		    }
-		case ';':
-		    DBG_(("db: SEMICOLON\n"));
-		    return SEMICOLON;
-		case '=':
-		    DBG_(("db: EQ\n"));
-		    return EQ;
-		/* ignore whitespace in this mode */
-		case '\t':
-		case ' ': continue;
-		case '\n': {
-		    ++mime_lineNum;
-		    continue;
-		    }
-		case EOF: return 0;
-		    break;
-		default: {
-		    lexPushLookaheadc(c);
-		    if (isalnum(c)) {
-			char *t = lexGetWord();
-			yylval.str = t;
-			if (!qstricmp(t, "begin")) {
-			    return match_begin_end_name(0);
-			    }
-			else if (!qstricmp(t,"end")) {
-			    return match_begin_end_name(1);
-			    }
-		        else {
-			    DBG_(("db: ID '%s'\n", t));
-			    return ID;
-			    }
-			}
-		    else {
-			/* unknow token */
-			return 0;
-			}
-		    break;
-		    }
-		}
-	    }
-	}
-    return 0;
-    }
-
-
-/***************************************************************************/
-/***							Public Functions						****/
-/***************************************************************************/
-
-static VObject* Parse_MIMEHelper()
-    {
-    ObjStackTop = -1;
-    mime_numErrors = 0;
-    mime_lineNum = 1;
-    vObjList = 0;
-    curObj = 0;
-
-    if (yyparse() != 0)
-	return 0;
-
-    finiLex();
-    return vObjList;
-    }
-
-/*--------------------------------------------*/
-DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
-    {
-    initLex(input, len, 0);
-    return Parse_MIMEHelper();
-    }
-
-
-#if INCLUDEMFC
-
-DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
-    {
-    unsigned long startPos;
-    VObject *result;	
-
-    initLex(0,-1,file);
-    startPos = file->GetPosition();
-    if (!(result = Parse_MIMEHelper()))
-	file->Seek(startPos, CFile::begin);
-    return result;
-    }
-
-#else
-
-VObject* Parse_MIME_FromFile(FILE *file)
-    {
-    VObject *result;	
-    long startPos;
-
-    initLex(0,(unsigned long)-1,file);
-    startPos = ftell(file);
-    if (!(result = Parse_MIMEHelper())) {
-	fseek(file,startPos,SEEK_SET);
-	}
-    return result;
-    }
-
-DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
-    {
-    FILE *fp = fopen(fname,"r");
-    if (fp) {
-	VObject* o = Parse_MIME_FromFile(fp);
-	fclose(fp);
-	return o;
-	}
-    else {
-	char msg[80];
-	sprintf(msg, "can't open file '%s' for reading\n", fname);
-	mime_error_(msg);
-	return 0;
-	}
-    }
-
-#endif
-
-/*-------------------------------------*/
-
-static MimeErrorHandler mimeErrorHandler;
-
-DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
-    {
-    mimeErrorHandler = me;
-    }
-
-void mime_error(char *s)
-    {
-    char msg[256];
-    if (mimeErrorHandler) {
-	sprintf(msg,"%s at line %d", s, mime_lineNum);
-	mimeErrorHandler(msg);
-	}
-    }
-
-void mime_error_(char *s)
-    {
-    if (mimeErrorHandler) {
-	mimeErrorHandler(s);
-	}
-    }
-
-#line 1241 "y.tab.c"
+#line 390 "vcc.y"
+
+/*------------------------------------*/
+static int pushVObject(const char *prop)
+    {
+    VObject *newObj;
+    if (ObjStackTop == MAXLEVEL)
+	return FALSE;
+
+    ObjStack[++ObjStackTop] = curObj;
+
+    if (curObj) {
+        newObj = addProp(curObj,prop);
+        curObj = newObj;
+	}
+    else
+	curObj = newVObject(prop);
+
+    return TRUE;
+    }
+
+
+/*---------------------------------------*/
+/* This pops the recently built vCard off the stack and returns it. */
+static VObject* popVObject()
+    {
+    VObject *oldObj;
+    if (ObjStackTop < 0) {
+	yyerror("pop on empty Object Stack\n");
+	return 0;
+	}
+    oldObj = curObj;
+    curObj = ObjStack[ObjStackTop--];
+
+    return oldObj;
+    }
+
+
+static void enterValues(const char *value)
+    {
+    if (fieldedProp && *fieldedProp) {
+	if (value) {
+	    addPropValue(curProp,*fieldedProp,value);
+	    }
+	/* else this field is empty, advance to next field */
+	fieldedProp++;
+	}
+    else {
+	if (value) {
+	    setVObjectStringZValue_(curProp,strdup( value ));
+	    }
+	}
+    deleteStr(value);
+    }
+
+static void enterProps(const char *s)
+    {
+    curProp = addGroup(curObj,s);
+    deleteStr(s);
+    }
+
+static void enterAttr(const char *s1, const char *s2)
+    {
+    const char *p1, *p2=0;
+    p1 = lookupProp_(s1);
+    if (s2) {
+	VObject *a;
+	p2 = lookupProp_(s2);
+	a = addProp(curProp,p1);
+	setVObjectStringZValue(a,p2);
+	}
+    else
+	addProp(curProp,p1);
+    /* Lookup strings so we can quickly use pointer comparison */
+    static const char* base64 = lookupProp_(VCBase64Prop);
+    static const char* qp = lookupProp_(VCQuotedPrintableProp);
+    static const char* photo = lookupProp_(VCPhotoProp);
+    static const char* encoding = lookupProp_(VCEncodingProp);
+    if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo)
+	&& (p1 == base64 || p1 == encoding && p2 == base64))
+	lexPushMode(L_BASE64);
+    else if (p1 == qp || p1 == encoding && p2 == qp)
+	lexPushMode(L_QUOTED_PRINTABLE);
+    deleteStr(s1); deleteStr(s2);
+    }
+
+
+#define MAX_LEX_LOOKAHEAD_0 32
+#define MAX_LEX_LOOKAHEAD 64
+#define MAX_LEX_MODE_STACK_SIZE 10
+#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
+
+struct LexBuf {
+	/* input */
+#ifdef INCLUDEMFC
+    CFile *inputFile;
+#else
+    FILE *inputFile;
+#endif
+    char *inputString;
+    unsigned long curPos;
+    unsigned long inputLen;
+	/* lookahead buffer */
+	/*   -- lookahead buffer is short instead of char so that EOF
+	 /      can be represented correctly.
+	*/
+    unsigned long len;
+    short buf[MAX_LEX_LOOKAHEAD];
+    unsigned long getPtr;
+	/* context stack */
+    unsigned long lexModeStackTop;
+    enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
+	/* token buffer */
+    unsigned long maxToken;
+    char *strs;
+    unsigned long strsLen;
+    } lexBuf;
+
+static void lexPushMode(enum LexMode mode)
+    {
+    if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
+	yyerror("lexical context stack overflow");
+    else {
+	lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
+	}
+    }
+
+static void lexPopMode(int top)
+    {
+    /* special case of pop for ease of error recovery -- this
+	version will never underflow */
+    if (top)
+	lexBuf.lexModeStackTop = 0;
+    else
+	if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
+    }
+
+static int lexWithinMode(enum LexMode mode) {
+    unsigned long i;
+    for (i=0;i<lexBuf.lexModeStackTop;i++)
+	if (mode == lexBuf.lexModeStack[i]) return 1;
+    return 0;
+    }
+
+static int lexGetc_()
+    {
+    /* get next char from input, no buffering. */
+    if (lexBuf.curPos == lexBuf.inputLen)
+	return EOF;
+    else if (lexBuf.inputString)
+	return *(lexBuf.inputString + lexBuf.curPos++);
+    else {
+#ifdef INCLUDEMFC
+	char result;
+	return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
+#else
+	return fgetc(lexBuf.inputFile);
+#endif
+	}
+    }
+
+static int lexGeta()
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
+    }
+
+static int lexGeta_(int i)
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
+    }
+
+static void lexSkipLookahead() {
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+	/* don't skip EOF. */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+	lexBuf.len--;
+        }
+    }
+
+static int lexLookahead() {
+    int c = (lexBuf.len)?
+	lexBuf.buf[lexBuf.getPtr]:
+	lexGeta();
+    /* do the \r\n -> \n or \r -> \n translation here */
+    if (c == '\r') {
+	int a = (lexBuf.len>1)?
+	    lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
+	    lexGeta_(1);
+	if (a == '\n') {
+	    lexSkipLookahead();
+	    }
+	lexBuf.buf[lexBuf.getPtr] = c = '\n';
+	}
+    else if (c == '\n') {
+	int a = (lexBuf.len>1)?
+	    lexBuf.buf[lexBuf.getPtr+1]:
+	    lexGeta_(1);
+	if (a == '\r') {
+	    lexSkipLookahead();
+	    }
+	lexBuf.buf[lexBuf.getPtr] = '\n';
+	}
+    return c;
+    }
+
+static int lexGetc() {
+    int c = lexLookahead();
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+	/* EOF will remain in lookahead buffer */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+	lexBuf.len--;
+        }
+    return c;
+    }
+
+static void lexSkipLookaheadWord() {
+    if (lexBuf.strsLen <= lexBuf.len) {
+	lexBuf.len -= lexBuf.strsLen;
+	lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
+	}
+    }
+
+static void lexClearToken()
+    {
+    lexBuf.strsLen = 0;
+    }
+
+static void lexAppendc(int c)
+    {
+    lexBuf.strs[lexBuf.strsLen] = c;
+    /* append up to zero termination */
+    if (c == 0) return;
+    lexBuf.strsLen++;
+    if (lexBuf.strsLen > lexBuf.maxToken) {
+	/* double the token string size */
+	lexBuf.maxToken <<= 1;
+	lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
+	}
+    }
+
+static char* lexStr() {
+    return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
+    }
+
+static void lexSkipWhite() {
+    int c = lexLookahead();
+    while (c == ' ' || c == '\t') {
+	lexSkipLookahead();
+	c = lexLookahead();
+	}
+    }
+
+static char* lexGetWord() {
+    int c;
+    lexSkipWhite();
+    lexClearToken();
+    c = lexLookahead();
+    while (c != EOF && !strchr("\t\n ;:=",c)) {
+	lexAppendc(c);
+	lexSkipLookahead();
+	c = lexLookahead();
+	}
+    lexAppendc(0);
+    return lexStr();
+    }
+
+static char* lexGetParamWord()
+{
+    int c;
+    lexClearToken();
+    c = lexLookahead();
+    while (c >= ' ' && c < 127 && !strchr("[]:=,.;",c)) {
+	lexAppendc(c);
+	lexSkipLookahead();
+	c = lexLookahead();
+    }
+    lexAppendc(0);
+    return lexStr();
+}
+
+static void lexPushLookaheadc(int c) {
+    int putptr;
+    /* can't putback EOF, because it never leaves lookahead buffer */
+    if (c == EOF) return;
+    putptr = (int)lexBuf.getPtr - 1;
+    if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
+    lexBuf.getPtr = putptr;
+    lexBuf.buf[putptr] = c;
+    lexBuf.len += 1;
+    }
+
+static char* lexLookaheadWord() {
+    /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
+     /  and thing bigger than that will stop the lookahead and return 0;
+     / leading white spaces are not recoverable.
+     */
+    int c;
+    int len = 0;
+    int curgetptr = 0;
+    lexSkipWhite();
+    lexClearToken();
+    curgetptr = (int)lexBuf.getPtr;	// remember!
+    while (len < (MAX_LEX_LOOKAHEAD_0)) {
+	c = lexGetc();
+	len++;
+	if (c == EOF || strchr("\t\n ;:=", c)) {
+	    lexAppendc(0);
+	    /* restore lookahead buf. */
+	    lexBuf.len += len;
+	    lexBuf.getPtr = curgetptr;
+	    return lexStr();
+	    }
+        else
+	    lexAppendc(c);
+	}
+    lexBuf.len += len;	/* char that has been moved to lookahead buffer */
+    lexBuf.getPtr = curgetptr;
+    return 0;
+    }
+
+#ifdef _SUPPORT_LINE_FOLDING
+static void handleMoreRFC822LineBreak(int c) {
+    /* suport RFC 822 line break in cases like
+     *	ADR: foo;
+     *    morefoo;
+     *    more foo;
+     */
+    if (c == ';') {
+	int a;
+	lexSkipLookahead();
+	/* skip white spaces */
+	a = lexLookahead();
+	while (a == ' ' || a == '\t') {
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    }
+	if (a == '\n') {
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    if (a == ' ' || a == '\t') {
+		/* continuation, throw away all the \n and spaces read so
+		 * far
+		 */
+		lexSkipWhite();
+		lexPushLookaheadc(';');
+		}
+	    else {
+		lexPushLookaheadc('\n');
+		lexPushLookaheadc(';');
+		}
+	    }
+	else {
+	    lexPushLookaheadc(';');
+	    }
+	}
+    }
+
+static char* lexGet1Value() {
+    int c;
+    lexSkipWhite();
+    c = lexLookahead();
+    lexClearToken();
+    while (c != EOF && (c != ';' || !fieldedProp)) {
+	if (c == '\\' ) {
+	    int a;
+	    lexSkipLookahead();
+	    a = lexLookahead();
+	    if ( a == ';' ) {
+		lexAppendc( ';' );
+		lexSkipLookahead();
+	    } else if ( a == '\n' ) {
+		lexAppendc( '\n' );
+		lexSkipLookahead();
+	    } else if ( a == '\\' ) {
+		lexAppendc( '\\' );
+		lexSkipLookahead();
+	    } else {
+		lexAppendc('\\');
+	    }
+	} else if (c == '\n') {
+	    int a;
+	    lexSkipLookahead();
+	    a  = lexLookahead();
+	    if (a == ' ' || a == '\t') {
+		lexAppendc(' ');
+		lexSkipLookahead();
+		}
+	    else {
+		lexPushLookaheadc('\n');
+		break;
+		}
+	    }
+	else {
+	    lexAppendc(c);
+	    lexSkipLookahead();
+	    }
+	c = lexLookahead();
+	}
+    lexAppendc(0);
+    handleMoreRFC822LineBreak(c);
+    return c==EOF?0:lexStr();
+    }
+#endif
+
+static int match_begin_name(int end) {
+    char *n = lexLookaheadWord();
+    int token = ID;
+    if (n) {
+	if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
+	else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
+	else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
+	else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
+	deleteStr(n);
+	return token;
+	}
+    return 0;
+    }
+
+
+#ifdef INCLUDEMFC
+void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
+#else
+void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
+#endif
+    {
+    // initialize lex mode stack
+    lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
+
+    // iniatialize lex buffer.
+    lexBuf.inputString = (char*) inputstring;
+    lexBuf.inputLen = inputlen;
+    lexBuf.curPos = 0;
+    lexBuf.inputFile = inputfile;
+
+    lexBuf.len = 0;
+    lexBuf.getPtr = 0;
+
+    lexBuf.maxToken = MAXTOKEN;
+    lexBuf.strs = (char*)malloc(MAXTOKEN);
+    lexBuf.strsLen = 0;
+
+    }
+
+static void finiLex() {
+    free(lexBuf.strs);
+    }
+
+
+/*-----------------------------------*/
+/* This parses and converts the base64 format for binary encoding into
+ * a decoded buffer (allocated with new).  See RFC 1521.
+ */
+static int lexGetDataFromBase64()
+    {
+    unsigned long bytesLen = 0, bytesMax = 0;
+    int quadIx = 0, pad = 0;
+    unsigned long trip = 0;
+    unsigned char b;
+    int c;
+    unsigned char *bytes = NULL;
+    unsigned char *oldBytes = NULL;
+
+    DBG_(("db: lexGetDataFromBase64\n"));
+    while (1) {
+	c = lexGetc();
+	lexSkipWhite();
+	if (c == '\n') {
+	    ++mime_lineNum;
+	    if (lexLookahead() == '\n') {
+		/* a '\n' character by itself means end of data */
+		break;
+		}
+	    else continue; /* ignore '\n' */
+	    }
+	else {
+	    if ((c >= 'A') && (c <= 'Z'))
+		b = (unsigned char)(c - 'A');
+	    else if ((c >= 'a') && (c <= 'z'))
+		b = (unsigned char)(c - 'a') + 26;
+	    else if ((c >= '0') && (c <= '9'))
+		b = (unsigned char)(c - '0') + 52;
+	    else if (c == '+')
+		b = 62;
+	    else if (c == '/')
+		b = 63;
+	    else if (c == '=') {
+		b = 0;
+		pad++;
+	    } else { /* error condition */
+		if (bytes) free(bytes);
+		else if (oldBytes) free(oldBytes);
+		// error recovery: skip until 2 adjacent newlines.
+		DBG_(("db: invalid character 0x%x '%c'\n", c,c));
+		if (c != EOF)  {
+		    c = lexGetc();
+		    while (c != EOF) {
+			if (c == '\n') {
+			    lexSkipWhite();
+			    if(lexLookahead() == '\n') {
+				++mime_lineNum;
+				break;
+				}
+			    }
+			c = lexGetc();
+			}
+		    }
+		return c != EOF;
+		}
+	    trip = (trip << 6) | b;
+	    if (++quadIx == 4) {
+		unsigned char outBytes[3];
+		int numOut;
+		int i;
+		for (i = 0; i < 3; i++) {
+		    outBytes[2-i] = (unsigned char)(trip & 0xFF);
+		    trip >>= 8;
+		    }
+		numOut = 3 - pad;
+		if (bytesLen + numOut > bytesMax) {
+		    if (!bytes) {
+			bytesMax = 1024;
+			bytes = (unsigned char*)malloc((size_t)bytesMax);
+			}
+		    else {
+			bytesMax <<= 2;
+			oldBytes = bytes;
+			bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
+			}
+		    if (bytes == 0) {
+			mime_error("out of memory while processing BASE64 data\n");
+			}
+		    }
+		if (bytes) {
+		    memcpy(bytes + bytesLen, outBytes, numOut);
+		    bytesLen += numOut;
+		    }
+		trip = 0;
+		quadIx = 0;
+		}
+	    }
+	} /* while */
+    DBG_(("db: bytesLen = %d\n",  bytesLen));
+    /* kludge: all this won't be necessary if we have tree form
+	representation */
+    if (bytes) {
+	setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
+	free(bytes);
+	}
+    else if (oldBytes) {
+	setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
+	free(oldBytes);
+	}
+    return bytesLen;
+    }
+
+static int match_begin_end_name(int end) {
+    int token;
+    lexSkipWhite();
+    if (lexLookahead() != ':') return ID;
+    lexSkipLookahead();
+    lexSkipWhite();
+    token = match_begin_name(end);
+    if (token == ID) {
+	lexPushLookaheadc(':');
+	DBG_(("db: ID '%s'\n", yylval.str));
+	return ID;
+	}
+    else if (token != 0) {
+	lexSkipLookaheadWord();
+	deleteStr(yylval.str);
+	DBG_(("db: begin/end %d\n", token));
+	return token;
+	}
+    return 0;
+    }
+
+static char* lexGetQuotedPrintable()
+{
+    int c;
+    lexSkipWhite();
+    c = lexLookahead();
+    lexClearToken();
+
+    while (c != EOF && (c != ';' || !fieldedProp)) {
+	if (c == '\n') {
+	    // break, leave '\n' on remaining chars.
+	    break;
+	} else if (c == '=') {
+	    int cur = 0;
+	    int next;
+
+	    lexSkipLookahead(); // skip '='
+	    next = lexLookahead();
+
+	    if (next == '\n') {
+		// skip and only skip the \n
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		++mime_lineNum; // aid in error reporting
+		continue;
+	    } else if (next >= '0' && next <= '9') {
+		cur = next - '0';
+	    } else if (next >= 'A' && next <= 'F') {
+		cur = next - 'A' + 10;
+	    } else {
+		// we have been sent buggy stuff. doesn't matter
+		// what we do so long as we keep going.
+		// should probably spit an error here
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		continue;
+	    }
+
+	    lexSkipLookahead(); // skip A-Z0-9
+	    next = lexLookahead();
+
+	    cur = cur * 16;
+	    // this time really just expecting 0-9A-F
+	    if (next >= '0' && next <= '9') {
+		cur += next - '0';
+	    } else if (next >= 'A' && next <= 'F') {
+		cur += next - 'A' + 10;
+	    } else {
+		// we have been sent buggy stuff. doesn't matter
+		// what we do so long as we keep going.
+		// should probably spit an error here
+		lexSkipLookahead(); 
+		c = lexLookahead();
+		continue;
+	    }
+
+	    // got a valid escaped =.  append it.
+	    lexSkipLookahead(); // skip second 0-9A-F
+	    lexAppendc(cur);
+	} else {
+	    lexSkipLookahead(); // skip whatever we just read.
+	    lexAppendc(c); // and append it.
+	}
+	c = lexLookahead();
+    }
+    lexAppendc(0);
+    return c==EOF?0:lexStr();
+}
+
+static int yylex() {
+
+    int lexmode = LEXMODE();
+    if (lexmode == L_VALUES) {
+	int c = lexGetc();
+	int c2;
+	if (c == ';' && fieldedProp) {
+	    DBG_(("db: SEMICOLON\n"));
+	    lexPushLookaheadc(c);
+	    handleMoreRFC822LineBreak(c);
+	    lexSkipLookahead();
+	    return SEMICOLON;
+	    }
+	else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') {
+	    ++mime_lineNum;
+	    /* consume all line separator(s) adjacent to each other */
+	    while (strchr("\n",c2)) {
+		lexSkipLookahead();
+		c2 = lexLookahead();
+		++mime_lineNum;
+		}
+	    DBG_(("db: LINESEP\n"));
+	    return LINESEP;
+	    }
+	else {
+	    char *p = 0;
+	    lexPushLookaheadc(c);
+	    if (lexWithinMode(L_BASE64)) {
+		/* get each char and convert to bin on the fly... */
+		yylval.str = NULL;
+		return lexGetDataFromBase64() ? STRING : 0;
+		}
+	    else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
+		p = lexGetQuotedPrintable();
+		}
+	    else {
+#ifdef _SUPPORT_LINE_FOLDING
+		p = lexGet1Value();
+#else
+		p = lexGetStrUntil(";\n");
+#endif
+		}
+	    if (p) {
+		DBG_(("db: STRING: '%s'\n", p));
+		yylval.str = p;
+		return STRING;
+		}
+	    else return 0;
+	    }
+    } else if (lexmode == L_PARAMWORD) {
+	yylval.str = lexGetParamWord();
+	return ID;
+    } else {
+	/* normal mode */
+	while (1) {
+	    int c = lexGetc();
+	    switch(c) {
+		case ':': {
+		    /* consume all line separator(s) adjacent to each other */
+		    /* ignoring linesep immediately after colon. */
+		    /* I don't see this in the spec, and it breaks null values -- WA
+		    c = lexLookahead();
+		    while (strchr("\n",c)) {
+			lexSkipLookahead();
+			c = lexLookahead();
+			++mime_lineNum;
+			}
+		    */
+		    DBG_(("db: COLON\n"));
+		    return COLON;
+		    }
+		case ';':
+		    DBG_(("db: SEMICOLON\n"));
+		    return SEMICOLON;
+		case '=':
+		    DBG_(("db: EQ\n"));
+		    return EQ;
+		/* ignore whitespace in this mode */
+		case '\t':
+		case ' ': continue;
+		case '\n': {
+		    ++mime_lineNum;
+		    continue;
+		    }
+		case EOF: return 0;
+		    break;
+		default: {
+		    lexPushLookaheadc(c);
+		    if (isalnum(c)) {
+			char *t = lexGetWord();
+			yylval.str = t;
+			if (!qstricmp(t, "begin")) {
+			    return match_begin_end_name(0);
+			    }
+			else if (!qstricmp(t,"end")) {
+			    return match_begin_end_name(1);
+			    }
+		        else {
+			    DBG_(("db: ID '%s'\n", t));
+			    return ID;
+			    }
+			}
+		    else {
+			/* unknow token */
+			return 0;
+			}
+		    break;
+		    }
+		}
+	    }
+	}
+    return 0;
+    }
+
+
+/***************************************************************************/
+/***							Public Functions						****/
+/***************************************************************************/
+
+static VObject* Parse_MIMEHelper()
+    {
+    ObjStackTop = -1;
+    mime_numErrors = 0;
+    mime_lineNum = 1;
+    vObjList = 0;
+    curObj = 0;
+
+    if (yyparse() != 0)
+	return 0;
+
+    finiLex();
+    return vObjList;
+    }
+
+/*--------------------------------------------*/
+DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
+    {
+    initLex(input, len, 0);
+    return Parse_MIMEHelper();
+    }
+
+
+#if INCLUDEMFC
+
+DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
+    {
+    unsigned long startPos;
+    VObject *result;	
+
+    initLex(0,-1,file);
+    startPos = file->GetPosition();
+    if (!(result = Parse_MIMEHelper()))
+	file->Seek(startPos, CFile::begin);
+    return result;
+    }
+
+#else
+
+VObject* Parse_MIME_FromFile(FILE *file)
+    {
+    VObject *result;	
+    long startPos;
+
+    initLex(0,(unsigned long)-1,file);
+    startPos = ftell(file);
+    if (!(result = Parse_MIMEHelper())) {
+	fseek(file,startPos,SEEK_SET);
+	}
+    return result;
+    }
+
+DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
+    {
+    FILE *fp = fopen(fname,"r");
+    if (fp) {
+	VObject* o = Parse_MIME_FromFile(fp);
+	fclose(fp);
+	return o;
+	}
+    else {
+	char msg[80];
+	sprintf(msg, "can't open file '%s' for reading\n", fname);
+	mime_error_(msg);
+	return 0;
+	}
+    }
+
+#endif
+
+/*-------------------------------------*/
+
+static MimeErrorHandler mimeErrorHandler;
+
+DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
+    {
+    mimeErrorHandler = me;
+    }
+
+void mime_error(char *s)
+    {
+    char msg[256];
+    if (mimeErrorHandler) {
+	sprintf(msg,"%s at line %d", s, mime_lineNum);
+	mimeErrorHandler(msg);
+	}
+    }
+
+void mime_error_(char *s)
+    {
+    if (mimeErrorHandler) {
+	mimeErrorHandler(s);
+	}
+    }
+
+#line 1242 "y.tab.c"
 #define YYABORT goto yyabort
 #define YYREJECT goto yyabort
 #define YYACCEPT goto yyaccept
 #define YYERROR goto yyerrlab
 int
-#if defined(__STDC__)
-yyparse(void)
-#else
 yyparse()
-#endif
 {
     register int yym, yyn, yystate;
 #if YYDEBUG
@@ -1276,7 +1268,7 @@ yyparse()
     *yyssp = yystate = 0;
 
 yyloop:
-    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yyn = yydefred[yystate]) goto yyreduce;
     if (yychar < 0)
     {
         if ((yychar = yylex()) < 0) yychar = 0;
@@ -1316,6 +1308,10 @@ yyloop:
         goto yyreduce;
     }
     if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
     yyerror("syntax error");
 #ifdef lint
     goto yyerrlab;
@@ -1384,165 +1380,171 @@ yyreduce:
     switch (yyn)
     {
 case 2:
-#line 221 "backend/vcc.y"
+#line 225 "vcc.y"
 { addList(&vObjList, yyvsp[0].vobj); curObj = 0; }
 break;
 case 3:
-#line 223 "backend/vcc.y"
+#line 227 "vcc.y"
 { addList(&vObjList, yyvsp[0].vobj); curObj = 0; }
 break;
 case 6:
-#line 232 "backend/vcc.y"
-{
-	lexPushMode(L_VCARD);
-	if (!pushVObject(VCCardProp)) YYERROR;
+#line 236 "vcc.y"
+{
+	lexPushMode(L_VCARD);
+	if (!pushVObject(VCCardProp)) YYERROR;
 	}
 break;
 case 7:
-#line 237 "backend/vcc.y"
-{
-	lexPopMode(0);
-	yyval.vobj = popVObject();
+#line 241 "vcc.y"
+{
+	lexPopMode(0);
+	yyval.vobj = popVObject();
 	}
 break;
 case 8:
-#line 242 "backend/vcc.y"
-{
-	lexPushMode(L_VCARD);
-	if (!pushVObject(VCCardProp)) YYERROR;
+#line 246 "vcc.y"
+{
+	lexPushMode(L_VCARD);
+	if (!pushVObject(VCCardProp)) YYERROR;
 	}
 break;
 case 9:
-#line 247 "backend/vcc.y"
-{
-	lexPopMode(0);
-	yyval.vobj = popVObject();
+#line 251 "vcc.y"
+{
+	lexPopMode(0);
+	yyval.vobj = popVObject();
 	}
 break;
 case 12:
-#line 258 "backend/vcc.y"
-{
-	lexPushMode(L_VALUES);
+#line 262 "vcc.y"
+{
+	lexPushMode(L_VALUES);
 	}
 break;
 case 13:
-#line 262 "backend/vcc.y"
-{
-	if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
-	   lexPopMode(0);
-	lexPopMode(0);
+#line 266 "vcc.y"
+{
+	if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
+	   lexPopMode(0);
+	lexPopMode(0);
 	}
 break;
 case 15:
-#line 271 "backend/vcc.y"
-{
-	enterProps(yyvsp[0].str);
+#line 275 "vcc.y"
+{
+	enterProps(yyvsp[0].str);
 	}
 break;
 case 17:
-#line 276 "backend/vcc.y"
-{
-	enterProps(yyvsp[0].str);
+#line 280 "vcc.y"
+{
+	enterProps(yyvsp[0].str);
 	}
 break;
 case 21:
-#line 289 "backend/vcc.y"
-{
-	enterAttr(yyvsp[0].str,0);
+#line 293 "vcc.y"
+{
+	enterAttr(yyvsp[0].str,0);
 	}
 break;
 case 22:
-#line 293 "backend/vcc.y"
-{
-	enterAttr(yyvsp[-2].str,yyvsp[0].str);
-
+#line 297 "vcc.y"
+{
+	lexPushMode(L_PARAMWORD);
+	}
+break;
+case 23:
+#line 301 "vcc.y"
+{
+	lexPopMode(0);
+	enterAttr(yyvsp[-3].str,yyvsp[0].str);
 	}
 break;
-case 24:
-#line 302 "backend/vcc.y"
+case 25:
+#line 310 "vcc.y"
 { enterValues(yyvsp[-1].str); }
 break;
-case 26:
-#line 304 "backend/vcc.y"
+case 27:
+#line 312 "vcc.y"
 { enterValues(yyvsp[0].str); }
 break;
-case 28:
-#line 309 "backend/vcc.y"
+case 29:
+#line 317 "vcc.y"
 { yyval.str = 0; }
 break;
-case 29:
-#line 314 "backend/vcc.y"
+case 30:
+#line 322 "vcc.y"
 { if (!pushVObject(VCCalProp)) YYERROR; }
 break;
-case 30:
-#line 317 "backend/vcc.y"
+case 31:
+#line 325 "vcc.y"
 { yyval.vobj = popVObject(); }
 break;
-case 31:
-#line 319 "backend/vcc.y"
+case 32:
+#line 327 "vcc.y"
 { if (!pushVObject(VCCalProp)) YYERROR; }
 break;
-case 32:
-#line 321 "backend/vcc.y"
+case 33:
+#line 329 "vcc.y"
 { yyval.vobj = popVObject(); }
 break;
-case 38:
-#line 336 "backend/vcc.y"
-{
-	lexPushMode(L_VEVENT);
-	if (!pushVObject(VCEventProp)) YYERROR;
-	}
-break;
 case 39:
-#line 342 "backend/vcc.y"
-{
-	lexPopMode(0);
-	popVObject();
+#line 344 "vcc.y"
+{
+	lexPushMode(L_VEVENT);
+	if (!pushVObject(VCEventProp)) YYERROR;
 	}
 break;
 case 40:
-#line 347 "backend/vcc.y"
-{
-	lexPushMode(L_VEVENT);
-	if (!pushVObject(VCEventProp)) YYERROR;
+#line 350 "vcc.y"
+{
+	lexPopMode(0);
+	popVObject();
 	}
 break;
 case 41:
-#line 352 "backend/vcc.y"
-{
-	lexPopMode(0);
-	popVObject();
+#line 355 "vcc.y"
+{
+	lexPushMode(L_VEVENT);
+	if (!pushVObject(VCEventProp)) YYERROR;
 	}
 break;
 case 42:
-#line 360 "backend/vcc.y"
-{
-	lexPushMode(L_VTODO);
-	if (!pushVObject(VCTodoProp)) YYERROR;
+#line 360 "vcc.y"
+{
+	lexPopMode(0);
+	popVObject();
 	}
 break;
 case 43:
-#line 366 "backend/vcc.y"
-{
-	lexPopMode(0);
-	popVObject();
+#line 368 "vcc.y"
+{
+	lexPushMode(L_VTODO);
+	if (!pushVObject(VCTodoProp)) YYERROR;
 	}
 break;
 case 44:
-#line 371 "backend/vcc.y"
-{
-	lexPushMode(L_VTODO);
-	if (!pushVObject(VCTodoProp)) YYERROR;
+#line 374 "vcc.y"
+{
+	lexPopMode(0);
+	popVObject();
 	}
 break;
 case 45:
-#line 376 "backend/vcc.y"
-{
-	lexPopMode(0);
-	popVObject();
+#line 379 "vcc.y"
+{
+	lexPushMode(L_VTODO);
+	if (!pushVObject(VCTodoProp)) YYERROR;
+	}
+break;
+case 46:
+#line 384 "vcc.y"
+{
+	lexPopMode(0);
+	popVObject();
 	}
 break;
-#line 1541 "y.tab.c"
+#line 1548 "y.tab.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
diff --git a/library/backend/vobject.cpp b/library/backend/vobject.cpp
index 9263c3a..592d116 100644
--- a/library/backend/vobject.cpp
+++ b/library/backend/vobject.cpp
@@ -1103,7 +1103,7 @@ static void writeEncString(OFile *fp, const char *s, bool nosemi)
     }
 }
 
-static bool includesUnprintable(VObject *o)
+static bool includesUnprintable(VObject *o, bool nosemi)
 {
     if (o) {
 	if (VALUE_TYPE(o) == VCVT_STRINGZ) {
@@ -1111,7 +1111,8 @@ static bool includesUnprintable(VObject *o)
 	    if (p) {
 		while (*p) {
 		    if (*p==' ' && (!p[1] || p[1]=='\n') // RFC 1521: spaces at ends need quoting
-			     || qpReplaceChar(*p) )
+			    || qpReplaceChar(*p)
+			    || *p==';' && nosemi )
 			return TRUE;
 		    p++;
 		}
@@ -1161,7 +1162,7 @@ static void writeAttrValue(OFile *fp, VObject *o)
 	struct PreDefProp *pi;
 	pi = lookupPropInfo(NAME_OF(o));
 	if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
-	if ( includesUnprintable(o) )
+	if ( includesUnprintable(o,TRUE) )
 	    appendsOFileEncCs(fp);
 	appendcOFile(fp,';');
 	appendsOFile(fp,NAME_OF(o));
@@ -1229,7 +1230,7 @@ static void writeProp(OFile *fp, VObject *o)
 	    bool printable = TRUE;
 	    while (*fields && printable) {
 		VObject *t = isAPropertyOf(o,*fields);
-		if (includesUnprintable(t))
+		if (includesUnprintable(t,TRUE))
 		    printable = FALSE;
 		fields++;
 	    }
@@ -1254,7 +1255,7 @@ static void writeProp(OFile *fp, VObject *o)
 
 	
     if (VALUE_TYPE(o)) {
-	    if ( includesUnprintable(o) )
+	    if ( includesUnprintable(o,FALSE) )
 			appendsOFileEncCs(fp);
 	unsigned long size = 0;
         VObject *p = isAPropertyOf(o,VCDataSizeProp);
--
cgit v0.9.0.2