diff options
Diffstat (limited to 'src/libicalvcal')
-rw-r--r-- | src/libicalvcal/CMakeLists.txt | 92 | ||||
-rw-r--r-- | src/libicalvcal/Makefile.am | 45 | ||||
-rw-r--r-- | src/libicalvcal/Makefile.in | 586 | ||||
-rw-r--r-- | src/libicalvcal/README.TXT | 951 | ||||
-rw-r--r-- | src/libicalvcal/icalvcal.c | 1650 | ||||
-rw-r--r-- | src/libicalvcal/icalvcal.h | 54 | ||||
-rw-r--r-- | src/libicalvcal/libicalvcal.dsp | 132 | ||||
-rw-r--r-- | src/libicalvcal/port.h | 88 | ||||
-rw-r--r-- | src/libicalvcal/vcaltest.c | 118 | ||||
-rw-r--r-- | src/libicalvcal/vcaltmp.c | 337 | ||||
-rw-r--r-- | src/libicalvcal/vcaltmp.h | 128 | ||||
-rw-r--r-- | src/libicalvcal/vcc.c | 2820 | ||||
-rw-r--r-- | src/libicalvcal/vcc.h | 80 | ||||
-rw-r--r-- | src/libicalvcal/vcc.y | 1213 | ||||
-rw-r--r-- | src/libicalvcal/vctest.c | 95 | ||||
-rw-r--r-- | src/libicalvcal/vobject.c | 1455 | ||||
-rw-r--r-- | src/libicalvcal/vobject.h | 366 |
17 files changed, 10210 insertions, 0 deletions
diff --git a/src/libicalvcal/CMakeLists.txt b/src/libicalvcal/CMakeLists.txt new file mode 100644 index 0000000..7ef6fb2 --- /dev/null +++ b/src/libicalvcal/CMakeLists.txt @@ -0,0 +1,92 @@ +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src + ${CMAKE_SOURCE_DIR}/src/libicalss ${CMAKE_BINARY_DIR}/src/libicalss + ${CMAKE_SOURCE_DIR}/src/libical ${CMAKE_BINARY_DIR}/src/libical + ${CMAKE_SOURCE_DIR}/src/libicalvcal ${CMAKE_BINARY_DIR}/src/libicalvcal +) + +#these are generated sources, but we keep them in the repo +set(icalvcal_LIB_DEVSRCS vcc.c) + +########### next target ############### + +SET(icalvcal_LIB_SRCS + icalvcal.h + icalvcal.c + port.h + vcc.h + vobject.h + vobject.c + vcaltmp.h + vcaltmp.c + ${icalvcal_LIB_DEVSRCS} +) + +if(MSVC) + list(APPEND icalvcal_LIB_SRCS ../icalvcal.def) +endif(MSVC) + +add_library(icalvcal SHARED ${icalvcal_LIB_SRCS}) + +target_link_libraries(icalvcal ical) + +set_target_properties(icalvcal PROPERTIES VERSION ${LIBICAL_LIB_VERSION_STRING} SOVERSION ${LIBICAL_LIB_MAJOR_VERSION}) +install(TARGETS icalvcal ${INSTALL_TARGETS_DEFAULT_ARGS}) + +########### install files ############### + +install(FILES + icalvcal.h port.h vcc.h vobject.h vcaltmp.h + DESTINATION + ${INCLUDE_INSTALL_DIR}/libical) + + + +#original Makefile.am contents follow: + +#lib_LTLIBRARIES = libicalvcal.la +# +#INCLUDES = \ +# -I$(top_srcdir) \ +# -I$(top_srcdir)/src \ +# -I$(top_builddir)/src \ +# -I$(top_srcdir)/src/libical \ +# -I$(top_builddir)/src/libical \ +# -I$(top_srcdir)/src/libicalss +# +#libicalvcal_la_LDFLAGS = -version-info 43:0:43 +#libicalvcal_la_LIBADD = ../libical/.libs/libical.la +# +#if DEV +#libicalvcal_la_DEVSOURCES = vcc.y +#else +#libicalvcal_la_DEVSOURCES = vcc.c +#endif +# +# +#libicalvcal_la_SOURCES = \ +# icalvcal.h \ +# icalvcal.c \ +# port.h \ +# vcc.h \ +# vobject.h \ +# vobject.c \ +# vcaltmp.h \ +# vcaltmp.c \ +# $(libicalvcal_la_DEVSOURCES) +# +#libicalvcalincludedir = $(includedir)/libicalvcal +# +#libicalvcalinclude_HEADERS = \ +# icalvcal.h \ +# port.h \ +# vcc.h \ +# vobject.h \ +# vcaltmp.h +# +#EXTRA_DIST = \ +# README.TXT \ +# vcaltest.c \ +# vctest.c +# diff --git a/src/libicalvcal/Makefile.am b/src/libicalvcal/Makefile.am new file mode 100644 index 0000000..b2f977c --- /dev/null +++ b/src/libicalvcal/Makefile.am @@ -0,0 +1,45 @@ +lib_LTLIBRARIES = libicalvcal.la + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src/libical \ + -I$(top_builddir)/src/libical \ + -I$(top_srcdir)/src/libicalss + +libicalvcal_la_LDFLAGS = -version-info 43:0:43 +libicalvcal_la_LIBADD = ../libical/.libs/libical.la + +if DEV +libicalvcal_la_DEVSOURCES = vcc.y +else +libicalvcal_la_DEVSOURCES = vcc.c +endif + + +libicalvcal_la_SOURCES = \ + icalvcal.h \ + icalvcal.c \ + port.h \ + vcc.h \ + vobject.h \ + vobject.c \ + vcaltmp.h \ + vcaltmp.c \ + $(libicalvcal_la_DEVSOURCES) + +libicalvcalincludedir = $(includedir)/libical + +libicalvcalinclude_HEADERS = \ + icalvcal.h \ + port.h \ + vcc.h \ + vobject.h \ + vcaltmp.h + +EXTRA_DIST = \ + README.TXT \ + vcaltest.c \ + vctest.c + diff --git a/src/libicalvcal/Makefile.in b/src/libicalvcal/Makefile.in new file mode 100644 index 0000000..df038cd --- /dev/null +++ b/src/libicalvcal/Makefile.in @@ -0,0 +1,586 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +SOURCES = $(libicalvcal_la_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/libicalvcal +DIST_COMMON = $(libicalvcalinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in vcc.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(libicalvcalincludedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libicalvcal_la_DEPENDENCIES = ../libical/.libs/libical.la +am__libicalvcal_la_SOURCES_DIST = icalvcal.h icalvcal.c port.h vcc.h \ + vobject.h vobject.c vcaltmp.h vcaltmp.c vcc.c vcc.y +@DEV_FALSE@am__objects_1 = vcc.lo +@DEV_TRUE@am__objects_1 = vcc.lo +am_libicalvcal_la_OBJECTS = icalvcal.lo vobject.lo vcaltmp.lo \ + $(am__objects_1) +libicalvcal_la_OBJECTS = $(am_libicalvcal_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +LTYACCCOMPILE = $(LIBTOOL) --mode=compile $(YACC) $(YFLAGS) \ + $(AM_YFLAGS) +SOURCES = $(libicalvcal_la_SOURCES) +DIST_SOURCES = $(am__libicalvcal_la_SOURCES_DIST) +libicalvcalincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(libicalvcalinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BDB_DIR = @BDB_DIR@ +BDB_DIR_INCLUDE = @BDB_DIR_INCLUDE@ +BDB_DIR_LIB = @BDB_DIR_LIB@ +BDB_LIB = @BDB_LIB@ +BDB_VERSION = @BDB_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DEV_FALSE = @DEV_FALSE@ +DEV_TRUE = @DEV_TRUE@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +HAVE_PTHREAD_FALSE = @HAVE_PTHREAD_FALSE@ +HAVE_PTHREAD_TRUE = @HAVE_PTHREAD_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAR = @JAR@ +JAVA = @JAVA@ +JAVAC = @JAVAC@ +JAVAH = @JAVAH@ +JAVA_PLATFORM = @JAVA_PLATFORM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +OS_WIN32_FALSE = @OS_WIN32_FALSE@ +OS_WIN32_TRUE = @OS_WIN32_TRUE@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PY_CFLAGS = @PY_CFLAGS@ +PY_EXTRA_LIBS = @PY_EXTRA_LIBS@ +PY_LIBS = @PY_LIBS@ +PY_LIB_LOC = @PY_LIB_LOC@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WITH_BDB4_FALSE = @WITH_BDB4_FALSE@ +WITH_BDB4_TRUE = @WITH_BDB4_TRUE@ +WITH_CXX_BINDINGS_FALSE = @WITH_CXX_BINDINGS_FALSE@ +WITH_CXX_BINDINGS_TRUE = @WITH_CXX_BINDINGS_TRUE@ +WITH_JAVA_FALSE = @WITH_JAVA_FALSE@ +WITH_JAVA_TRUE = @WITH_JAVA_TRUE@ +WITH_PYTHON_FALSE = @WITH_PYTHON_FALSE@ +WITH_PYTHON_TRUE = @WITH_PYTHON_TRUE@ +YACC = @YACC@ +ZONE_INFO = @ZONE_INFO@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +python_val = @python_val@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +lib_LTLIBRARIES = libicalvcal.la +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src/libical \ + -I$(top_builddir)/src/libical \ + -I$(top_srcdir)/src/libicalss + +libicalvcal_la_LDFLAGS = -version-info 43:0:43 +libicalvcal_la_LIBADD = ../libical/.libs/libical.la +@DEV_FALSE@libicalvcal_la_DEVSOURCES = vcc.c +@DEV_TRUE@libicalvcal_la_DEVSOURCES = vcc.y +libicalvcal_la_SOURCES = \ + icalvcal.h \ + icalvcal.c \ + port.h \ + vcc.h \ + vobject.h \ + vobject.c \ + vcaltmp.h \ + vcaltmp.c \ + $(libicalvcal_la_DEVSOURCES) + +libicalvcalincludedir = $(includedir)/libical +libicalvcalinclude_HEADERS = \ + icalvcal.h \ + port.h \ + vcc.h \ + vobject.h \ + vcaltmp.h + +EXTRA_DIST = \ + README.TXT \ + vcaltest.c \ + vctest.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj .y +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libicalvcal/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libicalvcal/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libicalvcal.la: $(libicalvcal_la_OBJECTS) $(libicalvcal_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libicalvcal_la_LDFLAGS) $(libicalvcal_la_OBJECTS) $(libicalvcal_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icalvcal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcaltmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vobject.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.y.c: + $(YACCCOMPILE) $< + if test -f y.tab.h; then \ + to=`echo "$*_H" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`; \ + sed -e "/^#/!b" -e "s/Y_TAB_H/$$to/g" -e "s|y\.tab\.h|$*.h|" \ + y.tab.h >$*.ht; \ + rm -f y.tab.h; \ + if cmp -s $*.ht $*.h; then \ + rm -f $*.ht ;\ + else \ + mv $*.ht $*.h; \ + fi; \ + fi + if test -f y.output; then \ + mv y.output $*.output; \ + fi + sed '/^#/ s|y\.tab\.c|$@|' y.tab.c >$@t && mv $@t $@ + rm -f y.tab.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-libicalvcalincludeHEADERS: $(libicalvcalinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(libicalvcalincludedir)" || $(mkdir_p) "$(DESTDIR)$(libicalvcalincludedir)" + @list='$(libicalvcalinclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(libicalvcalincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libicalvcalincludedir)/$$f'"; \ + $(libicalvcalincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libicalvcalincludedir)/$$f"; \ + done + +uninstall-libicalvcalincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libicalvcalinclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(libicalvcalincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(libicalvcalincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libicalvcalincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f vcc.c +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-libicalvcalincludeHEADERS + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \ + uninstall-libicalvcalincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-libicalvcalincludeHEADERS \ + install-man install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-libLTLIBRARIES \ + uninstall-libicalvcalincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libicalvcal/README.TXT b/src/libicalvcal/README.TXT new file mode 100644 index 0000000..01b6549 --- /dev/null +++ b/src/libicalvcal/README.TXT @@ -0,0 +1,951 @@ +NOTE: If you used the earlier APIs released by Versit
+then you will want to look at the document "migrate.doc"
+included with this package. It contains a discussion of
+the differences between the old API and this one.
+
+----------------------------------------------------------------
+
+The vCard/vCalendar C interface is implemented in the set
+of files as follows:
+
+vcc.y, yacc source, and vcc.c, the yacc output you will use
+implements the core parser
+
+vobject.c implements an API that insulates the caller from
+the parser and changes in the vCard/vCalendar BNF
+
+port.h defines compilation environment dependent stuff
+
+vcc.h and vobject.h are header files for their .c counterparts
+
+vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions
+which you may find useful.
+
+test.c is a standalone test driver that exercises some of
+the features of the APIs provided. Invoke test.exe on a
+VCARD/VCALENDAR input text file and you will see the pretty
+print output of the internal representation (this pretty print
+output should give you a good idea of how the internal
+representation looks like -- there is one such output in the
+following too). Also, a file with the .out suffix is generated
+to show that the internal representation can be written back
+in the original text format.
+
+-----------------------------------------------------------------
+
+
+ VObject for VCard/VCalendar
+
+Table of Contents
+=================
+1. VObject
+2. Internal Representations of VCard/VCalendar
+3. Iterating Through VObject's Properties or Values
+4. Pretty Printing a VObject Tree
+5. Building A VObject Representation of A VCard/VCalendar
+6. Converting A VObject Representation Into Its Textual Representation
+7. Miscellaneous Notes On VObject APIs usages
+8. Brief descriptions of each APIs
+9. Additional Programming Notes.
+
+This document is mainly about the VObject and its APIs. The main
+use of a VObject is to represent a VCard or a VCalendar inside
+a program. However, its use is not limited to aforemention as it
+can represent an arbitrary information that makes up of a tree or
+forest of properties/values.
+
+1. VObject
+ =======
+A VObject can have a name (id) and a list of associated properties and
+a value. Each property is itself a VObject.
+
+2. Internal Representations of VCard/VCalendar
+ ===========================================
+A list of VCard or a VCalendar is represented by a list of VObjects.
+The name (id) of the VObjects in the list is either VCCardProp or
+VCCalProp. Each of these VObjects can have a list of properties.
+Since a property is represented as a VObject, each of these properties
+can have a name, a list of properties, and a value.
+
+For example, the input file "vobject.vcf":
+
+BEGIN:VCARD
+N:Alden;Roland
+FN:Roland H. Alden
+ORG:AT&T;Versit Project Office
+TITLE:Consultant
+EMAIL;WORK;PREF;INTERNET:sf!rincon!ralden@alden.attmail.com
+EMAIL;INTERNET:ralden@sfgate.com
+EMAIL;MCIMail:242-2200
+LABEL;DOM;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A=
+Suite 2208=0A=
+One Pine Street=0A=
+San Francisco, CA 94111
+LABEL;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A=
+Suite 2208=0A=
+One Pine Street=0A=
+San Francisco, CA 94111=0A=
+U.S.A.
+TEL;WORK;PREF;MSG:+1 415 296 9106
+TEL;WORK;FAX:+1 415 296 9016
+TEL;MSG;CELL:+1 415 608 5981
+ADR:;Suite 2208;One Pine Street;San Francisco;CA;94111;U.S.A.
+SOUND:ROW-LAND H ALL-DIN
+LOGO;GIF;BASE64:
+ R0lGODdhpgBOAMQAAP///+/v797e3s7Ozr29va2trZycnIyMjHt7e2NjY1JSUkJC
+ QjExMSEhIRAQEO///87v9973/73n95zW71K13jGl1nvG50Kt3iGc1gCMzq3e94zO
+ 7xCU1nO952O15wAAACwAAAAApgBOAAAF/yAgjmRpnmiqrmzrvnAsz3Rt33iu73zv
+ /8CgcEj8QTaeywWTyWCUno2kSK0KI5tLc8vtNi+WiHVMlj0mFK96nalsxOW4fPSw
+ cNj4tQc+7xcjGh4WExJTJYUTFkp3eU0eEH6RkpOUlTARhRoWm5ydFpCWoS0QEqAu
+ ARKaHRcVjV0borEoFl0cSre4Sq67FA+yvwAeTU8XHZ7HmxS6u2wVfMCVpAE3pJoW
+ ylrMptDcOqSF4OHg3eQ5pInInb7lcc86mNbLzBXsZbRfUOn6ucyNHvVWJHCpQFDf
+ MWwEEzLqx2YCQCqF3OnItClJNmYcJD7cSAKTuI/gtnEcOQKkyVIk6/+ds5CkFcMM
+ 61LiENikwi1jBnNyuvUSjwWZOS5uIZarqNFcNl32XMMB6I06GgoJ+bZp1ZKeDl8E
+ +MC1K1cBIhZ4HUu2LAsCZdOWRQDt20lxIlccSHsgrNq7Xc/ixcsWmNu34WKyYJCW
+ gQjCe9XqTZy2L4pv04gg2sSKSc8OLgTcBSuWsdkVaD2TdXyiQxebFyjo1Gnx6tJm
+ LuaqrdtZtNfFtruSNmF5IKujwIsmJbjwtRqNJhrcNVw79wcRAgogmE4ArIjQzj/s
+ JvHAGCFDQR4UqigPK4sBe62XwO51OwADiMcqUG+iOdcFAL+hW20BfAoEexlwAnu6
+ mZDAXQ1EVh//WfhxJB5gIbHgwFgOTOiVAgOuVQKAfKFg3weGwSBYFZMp4hpDGKyA
+ 3lgJKECWgiMQyBVpW+0V4oJjNfhCNkR1IgWEb21QlRK9GdfFCgeOZYBsXgm4noYj
+ GEBhAQHYh0J8XenoQnFGdrkUciJY6FUAK15ogozakcBhliKsyZWHDMZQ0wWC/Aim
+ DB6h01KRr/lXQgFxAqDcWDACgCZpUnrVQJtjwTnWjS6MWAYqqfDnSaEkJOlVXQBo
+ 2pWTMUJ53WgAuPncCR9q6VQMAYjZlXWJmknCoSUM2p4BC+SaKwG88hoZlvfFMM4f
+ hQh5TXkv+RklWYtC91mopJIAKFkJlDAW/wF25ShnLbeo5gmQ+1FGkJdrKCuCi2OR
+ BuwHBcwqKgABrMtVAgpem61XkLbAJ7n8uiIpvGVhO4KpH1QLbbpqLheZvQCkGoNL
+ thSzSTg2UGVBBzbtaxwKsYrmgLvRAlCmWgwMAADD66rKAgR3XlGspcdkZYK8ibU7
+ asgEl+XAyB8I7PCqMWiWncGGimpfAgO4ypXSPpOVLwsRCDJxRD2AoyeRRv5kApO5
+ fXwzwvfOKLKtaTWtbQxccmGLTZy8xYlVSvXbhbk0M2YzrYfJJ0K8m+V9NgxpyC04
+ UycI/aiuiH9Y8NftDUwWp1Wm5UABnAUKwwRsPFGBt4Oc9PZvGvNLwf8JOZt8Arpe
+ eY23yDovwIDiBX74NAsPVLDJj3Hh4JEExsKcjrlKf9DsCVx3ZfLqAKBuG1s/A90C
+ z2KjYHjjyPOdG1spz6BBUr+BcUxUb1nDCTa/VZD2Uv+YkLPAKJC9dNEh7628WgqI
+ ybzlaA+ufxMa6bxC6ciLUQLcx5UGIAAsAkDA6wQkOxrcY39yo4cQMNWCAPTKV1R4
+ wPkgaBxzOc8FtMiF1NoGoXBRJjgoPApmPsjCFlbMdzCM4TFy50IXxI2DPcHAv2rY
+ gghsEIeu8CAPW6ABIPYEFkOsAeaMyIz0JfGJUExBBGRIRX0IMYovWCIT1eBELNpA
+ i1vcgta8iANPCIQOghzQABl30J0tXqBla4wjFLFQxZzAUY42CIAd5OYBCuKxB2c4
+ I0b28EcrQKADgmSKB9RYyDhA4BqCxIBqrtjIMTwoFeCjYSU3KZMQAAA7
+
+BEGIN:VCALENDAR
+DCREATED:19960523T100522
+PRODID:-//Alden Roland/Hand Crafted In North Carolina//NONSGML Made By Hand//EN
+VERSION:0.3
+BEGIN:VEVENT
+START:19960523T120000
+END:19960523T130000
+SUBTYPE:PHONE CALL
+SUMMARY:VERSIT PDI PR Teleconference/Interview
+DESCRIPTION:VERSIT PDI PR Teleconference/Interview With Tom Streeter and Alden Roland
+END:VEVENT
+BEGIN:VEVENT
+START:19960523T113000
+END:19960523T115500
+SUBTYPE:LUNCH
+SUMMARY:Eat in the cafeteria today
+END:VEVENT
+END:VCALENDAR
+
+END:VCARD
+
+
+will conceptually be be represented as
+ vcard
+ VCNameProp
+ VCFamilyNameProp=Alden
+ VCGivenNameProp=Roland
+ VCFullNameProp=Roland H.Alden
+ ....
+
+note that
+ EMAIL;WORK;PREF;INTERNET:sf!rincon!ralden@alden.attmail.com
+will be represented as:
+ VCEmailAddress=sf!rincon!ralden@alden.attmail.com
+ VCWork
+ VCPreferred
+ VCInternet
+where the lower level properties are properties of the property
+VCEmailAddress.
+
+Groupings are flattened out in the VObject representation such
+that:
+ a.b:blah
+ a.c:blahblah
+are represented as:
+ b=blah
+ VCGrouping=a
+ c=blahblah
+ VCGrouping=a
+i.e. one can read the above as:
+ the property "b" has value "blah" and property "VCGrouping"
+ with the value "a".
+ the property "c" has value "blahblah" and property "VCGrouping"
+ with the value "a".
+likewise, multi-level groupings are flatten similarly. e.g.
+ a.b.c:blah
+ a.b.e:blahblah
+-->
+ c=blah
+ VCGrouping=b
+ VCGrouping=a
+ e=blahblah
+ VCGrouping=b
+ VCGrouping=a
+which read:
+ the property "c" has value "blah" and property "VCGrouping"
+ with the value "b" which has property "VCGrouping"
+ with value "a".
+ the property "e" has value "blahblah" and property "VCGrouping"
+ with the value "b" which has property "VCGrouping"
+ with value "a".
+
+3. Iterating Through VObject's Properties or Values
+ ================================================
+The following is a skeletal form of iterating through
+all properties of a vobject, o:
+
+ // assume the object of interest, o, is of type VObject
+ VObjectIterator i;
+ initPropIterator(&i,o);
+ while (moreIteration(&i)) {
+ VObject *each = nextVObject(&i);
+ // ... do something with "each" property
+ }
+
+Use the API vObjectName() to access a VObject's name.
+Use the API vObjectValueType() to determine if a VObject has
+ a value. For VCard/VCalendar application, you
+ should not need this function as practically
+ all values are either of type VCVT_USTRINGZ or
+ VCVT_RAW (i.e set by setVObjectUStringZValue and
+ setVObjectAnyValue APIs respectively), and the
+ value returned by calls to vObjectUStringZValue
+ and vObjectAnyValue are 0 if a VObject has no
+ value. (There is a minor exception where VObject with
+ VCDataSizeProp has value that is set by
+ setVObjectLongValue).
+Use the APIs vObject???Value() to access a VObject's value.
+ where ??? is the expected type.
+Use the APIs setvObject???Value() to set or modify a VObject's value.
+ where ??? is the expected type.
+Use the API isAPropertyOf() to query if a name match the name of
+ a property of a VObject. Since isAPropertyOf() return
+ the matching property, we can use that to retrieve
+ a property and subsequently the value of the property.
+
+4. Pretty Printing a VObject Tree
+ ==============================
+VObject tree can be pretty printed with the printVObject() function.
+The output of pretty printing a VObject representation of the input
+test file "vobject.vcf" is shown below. Note that the indentation
+indicates the tree hirerarchy where the immediate children nodes
+of a parent node is all at the same indentation level and the
+immediate children nodes are the immediate properties of the
+associated parent nodes. In the following, {N,FN,ORG,TITLE,...}
+are immediate properties of VCARD. {F and G} are properties of N
+with value {"Alden" and "Roland"} respectively; FN has no property
+but has the value "Roland H. Alden"; EMAIL has value and
+the properties WORK, PREF, and INTERNET.
+
+
+VCARD
+ N
+ F="Alden"
+ G="Roland"
+ FN="Roland H. Alden"
+ ORG
+ ORGNAME="AT&T"
+ OUN="Versit Project Office"
+ TITLE="Consultant"
+ EMAIL="sf!rincon!ralden@alden.attmail.com"
+ WORK
+ PREF
+ INTERNET
+ EMAIL="ralden@sfgate.com"
+ INTERNET
+ EMAIL="242-2200"
+ MCIMail
+ LABEL="Roland H. Alden
+ Suite 2208
+ One Pine Street
+ San Francisco, CA 94111"
+ DOM
+ POSTAL
+ PARCEL
+ HOME
+ WORK
+ QP
+ LABEL="Roland H. Alden
+ Suite 2208
+ One Pine Street
+ San Francisco, CA 94111
+ U.S.A."
+ POSTAL
+ PARCEL
+ HOME
+ WORK
+ QP
+ TEL="+1 415 296 9106"
+ WORK
+ PREF
+ MSG
+ TEL="+1 415 296 9016"
+ WORK
+ FAX
+ TEL="+1 415 608 5981"
+ MSG
+ CELL
+ ADR
+ EXT ADD="Suite 2208"
+ STREET="One Pine Street"
+ L="San Francisco"
+ R="CA"
+ PC="94111"
+ C="U.S.A."
+ SOUND="ROW-LAND H ALL-DIN"
+ LOGO=[raw data]
+ GIF
+ BASE64
+ DataSize=1482
+VCALENDAR
+ DCREATED="19960523T100522"
+ PRODID="-//Alden Roland/Hand Crafted In North Carolina//NONSGML Made By Hand//EN"
+ VERSION="0.3"
+ VEVENT
+ START="19960523T120000"
+ END="19960523T130000"
+ SUBTYPE="PHONE CALL"
+ SUMMARY="VERSIT PDI PR Teleconference/Interview"
+ DESCRIPTION="VERSIT PDI PR Teleconference/Interview With Tom Streeter and Alden Roland"
+ VEVENT
+ START="19960523T113000"
+ END="19960523T115500"
+ SUBTYPE="LUNCH"
+ SUMMARY="Eat in the cafeteria today"
+
+5. Building A VObject Representation of A VCard/VCalendar
+ ======================================================
+The parser in vcc.y converts an input file with one or more
+VCard/VCalendar that is in their textual representation
+into their corresponding VObject representation.
+
+VObject representation of a VCard/VCalendar can also be built
+directly with calls to the VObject building APIs. e.g.
+
+ VObject *prop;
+ VObject *vcard = newVObject(VCCardProp);
+ prop = addProp(vcard,VCNameProp);
+ addPropValue(prop,VCFamilyNameProp,"Alden");
+ addPropValue(prop,VCGivenNameProp,"Roland");
+ addPropValue(vcard,VCFullNameProp,"Roland H. Alden");
+ ....
+
+6. Converting A VObject Representation Into Its Textual Representation
+ ===================================================================
+The VObject representation can be converted back to its textual
+representation via the call to writeVObject() or writeMemVObject()
+API. e.g.
+ a. to write to a file:
+ // assume vcard is of type VObject
+ FILE *fp = fopen("alden.vcf","w");
+ writeVObject(fp,vcard);
+ a. to write to memory, and let the API allocate the required memory.
+ char* clipboard = writeVObject(0,0,vcard);
+ ... do something to clipboard
+ free(clipboard);
+ b. to write to a user allocated buffer:
+ char clipboard[16384];
+ int len = 16384;
+ char *buf = writeVObject(clipboard,&len,vcard);
+ ... buf will be equal to clipboard if the write
+ is successful otherwise 0.
+
+In the case of writing to memory, the memory buffer can be either
+allocated by the API or the user. If the user allocate the
+memory for the buffer, then the length of the buffer needs to be
+communicated to the API via a variable. The variable passed as
+the length argument will be overwritten with the actual size
+of the text output. A 0 return value from writeMemVObject()
+indicates an error which could be caused by overflowing the
+size of the buffer or lack of heap memory.
+
+7. Miscellaneous Notes On VObject APIs usages
+ ==========================================
+a. vcc.h -- contains basic interfaces to the parser:
+ VObject* Parse_MIME(const char *input, unsigned long len);
+ VObject* Parse_MIME_FromFile(FILE *file);
+ -- both of this return a null-terminated list of
+ VObject that is either a VCARD or VCALENDAR.
+ To iterate through this list, do
+ VObject *t, *v;
+ v = Parse_Mime_FromFile(fp);
+ while (v) {
+ // ... do something to v.
+ t = v;
+ v = nextVObjectInList(v);
+ cleanVObject(t);
+ }
+ note that call to cleanVObject will release
+ resource used to represent the VObject.
+
+b. vobject.h -- contains basic interfaces to the VObject APIs.
+ see the header for more details.
+ The structure of VObject is purposely (hiddened) not exposed
+ to the user. Every access has to be done via
+ the APIs. This way, if we need to change the
+ structure or implementation, the client need not
+ recompile as long as the interfaces remain the
+ same.
+
+c. values of a property is determined by the property definition
+ itself. The vobject APIs does not attempt to enforce
+ any of such definition. It is the consumer responsibility
+ to know what value is expected from a property. e.g
+ most properties have unicode string value, so to access
+ the value of these type of properties, you will use
+ the vObjectUStringZValue() to read the value and
+ setVObjectUStringZValue() to set or modify the value.
+ Refer to the VCard and VCalendar specifications for
+ the definition of each property.
+
+d. properties name (id) are case incensitive.
+
+8. Brief descriptions of each APIs
+ ===============================
+ * the predefined properties' names (id) are listed under vobject.h
+ each is of the form VC*Prop. e.g.
+ #define VC7bitProp "7BIT"
+ #define VCAAlarmProp "AALARM"
+ ....
+
+ * consumer of a VObject can only define pointers to VObject.
+
+ * a variable of type VObjectIterator, say "i", can be used to iterate
+ through a VObject's properties, say "o". The APIs related to
+ VObjectIterator are:
+ void initPropIterator(VObjectIterator *i, VObject *o);
+ -- e.g. usage
+ initPropIterator(&i,o);
+ int moreIteration(VObjectIterator *i);
+ -- e.g. usage
+ while (moreIteration(&i)) { ... }
+ VObject* nextVObject(VObjectIterator *i);
+ -- e.g. usage
+ while (moreIteration(&i)) {
+ VObject *each = nextVObject(&i);
+ }
+
+ * VObject can be chained together to form a list. e.g. of such
+ use is in the parser where the return value of the parser is
+ a link list of VObject. A link list of VObject can be
+ built by:
+ void addList(VObject **o, VObject *p);
+ and iterated by
+ VObject* nextVObjectInList(VObject *o);
+ -- next VObjectInList return 0 if the list
+ is exhausted.
+
+ * the following APIs are mainly used to construct a VObject tree:
+ VObject* newVObject(const char *id);
+ -- used extensively internally by VObject APIs but when
+ used externally, its use is mainly limited to the
+ construction of top level object (e.g. an object
+ with VCCardProp or VCCalendarProp id).
+
+ void deleteVObject(VObject *p);
+ -- to deallocate single VObject, for most user, use
+ cleanVObject(VObject *o) instead for freeing all
+ resources associated with the VObject.
+
+ char* dupStr(const char *s, unsigned int size);
+ -- duplicate a string s. If size is 0, the string is
+ assume to be a null-terminated.
+
+ void deleteStr(const char *p);
+ -- used to deallocate a string allocated by dupStr();
+
+ void setVObjectName(VObject *o, const char* id);
+ -- set the id of VObject o. This function is not
+ normally used by the user. The setting of id
+ is normally done as part of other APIs (e.g.
+ addProp()).
+
+ void setVObjectStringZValue(VObject *o, const char *s);
+ -- set a string value of a VObject.
+
+ void setVObjectUStringZValue(VObject *o, const wchar_t *s);
+ -- set a Unicode string value of a VObject.
+
+ void setVObjectIntegerValue(VObject *o, unsigned int i);
+ -- set an integer value of a VObject.
+
+ void setVObjectLongValue(VObject *o, unsigned long l);
+ -- set an long integer value of a VObject.
+
+ void setVObjectAnyValue(VObject *o, void *t);
+ -- set any value of a VObject. The value type is
+ unspecified.
+
+ VObject* setValueWithSize(VObject *prop, void *val, unsigned int size);
+ -- set a raw data (stream of bytes) value of a VObject
+ whose size is size. The internal VObject representation
+ is
+ this object = val
+ VCDataSizeProp=size
+ i.e. the value val will be attached to the VObject prop
+ and a property of VCDataSize whose value is size
+ is also added to the object.
+
+ void setVObjectVObjectValue(VObject *o, VObject *p);
+ -- set a VObject as the value of another VObject.
+
+ const char* vObjectName(VObject *o);
+ -- retrieve the VObject's Name (i.e. id).
+
+ const char* vObjectStringZValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ null-terminated string.
+
+ const wchar_t* vObjectUStringZValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ null-terminated unicode string.
+
+ unsigned int vObjectIntegerValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ integer.
+
+ unsigned long vObjectLongValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ long integer.
+
+ void* vObjectAnyValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ any value.
+
+ VObject* vObjectVObjectValue(VObject *o);
+ -- retrieve the VObject's value interpreted as
+ a VObject.
+
+ VObject* addVObjectProp(VObject *o, VObject *p);
+ -- add a VObject p as a property of VObject o.
+ (not normally used externally for building a
+ VObject).
+
+ VObject* addProp(VObject *o, const char *id);
+ -- add a property whose name is id to VObject o.
+
+ VObject* addPropValue(VObject *o, const char *id, const char *v);
+ -- add a property whose name is id and whose value
+ is a null-terminated string to VObject o.
+
+ VObject* addPropSizedValue(VObject *o, const char *id,
+ const char *v, unsigned int size);
+ -- add a property whose name is id and whose value
+ is a stream of bytes of size size, to VObject o.
+
+ VObject* addGroup(VObject *o, const char *g);
+ -- add a group g to VObject o.
+ e.g. if g is a.b.c, you will have
+ o
+ c
+ VCGroupingProp=b
+ VCGroupingProp=a
+ and the object c is returned.
+
+ VObject* isAPropertyOf(VObject *o, const char *id);
+ -- query if a property by the name id is in o and
+ return the VObject that represent that property.
+
+ void printVObject(VObject *o);
+ -- pretty print VObject o to stdout (for debugging use).
+
+ void writeVObject(FILE *fp, VObject *o);
+ -- convert VObject o to its textual representation and
+ write it to file.
+
+ char* writeMemVObject(char *s, int *len, VObject *o);
+ -- convert VObject o to its textual representation and
+ write it to memory. If s is 0, then memory required
+ to hold the textual representation will be allocated
+ by this API. If a variable len is passed, len will
+ be overwriten with the byte size of the textual
+ representation. If s is non-zero, then s has to
+ be a user allocated buffer whose size has be passed
+ in len as a variable. Memory allocated by the API
+ has to be freed with call to free. The return value
+ of this API is either the user supplied buffer,
+ the memory allocated by the API, or 0 (in case of
+ failure).
+
+ void cleanStrTbl();
+ -- this function has to be called when all
+ VObject has been destroyed.
+
+ void cleanVObject(VObject *o);
+ -- release all resources used by VObject o.
+
+ wchar_t* fakeUnicode(const char *ps, int *bytes);
+ -- convert char* to wchar_t*.
+
+ extern int uStrLen(const wchar_t *u);
+ -- length of unicode u.
+
+ char *fakeCString(const wchar_t *u);
+ -- convert wchar_t to CString (blindly assumes that
+ this could be done).
+
+9. Additional Programming Notes
+ ============================
+In the following notes, please refers to the listing
+of Example.vcf and its VObject Representation
+(shown at the end of this section).
+
+* Handling the Return Value of the VCard/VCalendar Parser
+ The example input text file contains two root VObjects
+ (a VCalendar and a VCard). The output of the VCard/VCalendar
+ parser is a null-terminated list of VObjects. For this
+ particular input file, the list will have two VObjects.
+ The following shows a template for iterating through the
+ output of the Parser:
+
+ VObject *t, *v;
+ v = Parse_Mime_fromFileName("example.vcf");
+ while (v) {
+ // currently, v will either be a VCard or a VCalendar
+ // do whatever your application need to do to
+ // v here ...
+ t = v;
+ v = nextVObjectInList(v);
+ cleanVObject(t);
+ }
+
+* Iterating Through a VCard/VCalendar VObject
+ From the VObject APIs point of view, a VCard VObject
+ is the same as a VCalendar VObject. However, the application
+ needs to know what are in a VCard or a VCalendar.
+ For example, A VCalendar VObject can have VCDCreatedProp,
+ a VCGEOLocationProp, etc, and one or more VCEventProp and
+ or VCTodoProp. The VCEventProp and VCTodoProp can have
+ many properties of their own, which in turn could have
+ more properties (e.g. VCDAlarmProp can be a VCEventProp
+ VObject's property, and VCRunTimeProp can be a
+ VCDAlarmProp VObject's property. Because a VObject tree
+ can be arbitrarily complex, in general, to process all
+ properties and values of a VObject tree, a recursive walk
+ is desirable. An example recursive VObject tree walk
+ can be found in the vobject.c source lines for printVObject*
+ and writeVObject* APIs. Depending on what the application need
+ to do with a VCard or a VCalendar, a recursive walk
+ of the VObject tree may or may not be desirable. An example
+ template of a non-recursive walk is shown below:
+
+ void processVCardVCalendar(char *inputFile)
+ {
+ VObject *t, *v;
+ v = Parse_Mime_fromFileName(inputFile);
+ while (v) {
+ char *n = vObjectName(v);
+ if (strcmp(n,VCCardProp) == 0) {
+ do_VCard(v);
+ }
+ else if (strcmp(n,VCCalendarProp) == 0) {
+ do_VCalendar(v);
+ }
+ else {
+ // don't know how to handle anything else!
+ }
+ t = v;
+ v = nextVObjectInList(v);
+ cleanVObject(t);
+ }
+ }
+
+ void do_VCard(VObject *vcard)
+ {
+ VObjectIterator t;
+ initPropIterator(&t,vcard);
+ while (moreIteration(&t)) {
+ VObject *eachProp = nextVObject(&t);
+ // The primarly purpose of this example is to
+ // show how to iterate through a VCard VObject,
+ // it is not meant to be efficient at all.
+ char *n = vObjectName(eachProp);
+ if (strcmp(n,VCNameProp)==0) {
+ do_name(eachProp);
+ }
+ else if (strcmp(n,VCEmailProp)==0) {
+ do_email(eachProp);
+ }
+ else if (strcmp(n,VCLabelProp)==0) {
+ do_label(eachProp);
+ }
+ else if ....
+ }
+ }
+
+ void do_VCalendar(VObject *vcal)
+ {
+ VObjectIterator t;
+ initPropIterator(&t,vcard);
+ while (moreIteration(&t)) {
+ VObject *eachProp = nextVObject(&t);
+ // The primarly purpose of this example is to
+ // show how to iterate through a VCalendar VObject,
+ // it is not meant to be efficient at all.
+ char *n = vObjectName(eachProp);
+ if (strcmp(n,VCDCreatedProp)==0) {
+ do_DCreated(eachProp);
+ }
+ else if (strcmp(n,VCVersionProp)==0) {
+ do_Version(eachProp);
+ }
+ else if (strcmp(n,VCTodoProp)==0) {
+ do_Todo(eachProp);
+ }
+ else if (strcmp(n,VCEventProp)==0) {
+ do_Event(eachProp);
+ }
+ else if ....
+ }
+ }
+
+ void do_Todo(VObject *vtodo) { ... }
+
+ void do_Event(VObject *vevent) { ... }
+
+ ...
+
+* Property's Values and Properties
+ The VObject APIs do not attempt to check for the
+ correctness of the values of a property. Nor do they
+ will prevent the user from attaching a non-VCard/VCalendar
+ standard property to a VCard/VCalendar property. Take
+ the example of line [11] of the example, "O.K" is not
+ a valid value of VCStatusProp. It is up to the application
+ to accept or reject the value of a property.
+
+* Output of printVObject
+ PrintVObject pretty prints a VObject tree in human
+ readable form. See the listing at the end of the file
+ for an example output of printVObject on the example
+ input file "Example.vcf".
+
+ Note that binary data are not shown in the output of
+ printVObject. Instead, a note is made ([raw data]) to
+ indicate that there exists such a binary data.
+
+* Note on Binary Data
+ When the value of a property is a binary data, it is only
+ useful to know the size of the binary data.
+
+ In the case of the VCard/VCalendar parser, it chooses
+ to represent the size information as a separate property
+ called VCDataSizeProp whose value is the size of the binary
+ data. The APIs sequence to construct the VObject subtree
+ of line [44] of Example.vcf is
+
+ // VObject *vcard;
+ VObject *p1 = addProp(vcard,VCLogoProp);
+ (void) addProp(p1,VCGIFProp);
+ (void) addProp(p1,VCBASE64Prop);
+ VObject *p2 = addProp(p1,VCDataSizeProp);
+ (void) setVObjectLongValue(p2,1482);
+ setVObjectAnyValue(vcard,...pointer to binary data);
+
+ Note the presence of VCBase64Prop will cause the
+ writeVObject API to output the binary data as BASE64 text.
+ For VCard/VCalendar application, having the VCBase64Prop
+ property is practically always necessary for property with
+ binary data as its value.
+
+* Note on Quoted-Printable String
+ String value with embedded newline are written out as
+ quoted-prinatable string. It is therefore important
+ to mark a property with a string value that has
+ one or more embedded newlines, with the VCQutedPrintableProp
+ property. e.g.
+
+ // VObject *root;
+ char *msg="To be\nor\nnot to be";
+ VObject *p = addPropValue(root,VCDescriptionProp,msg);
+ // the following is how you mark a property with
+ // a property. In this case, the marker is
+ // VCQuotedPrintableProp
+ addProp(p,VCQuotedPrintableProp);
+
+* Note on Unicode
+ Although, the current parser takes ASCII text file only,
+ string values are all stored as Unicode in the VObject tree.
+ For now, when using the VObject APIs to construct a
+ VObject tree, one should always convert ASCII string value
+ to a Unicode string value:
+
+ // VObject *root;
+ VObject *p = addProp(root,VCSomeProp);
+ setVObjectUStringZValue(p,fakeUnicode(someASCIIStringZvalue));
+
+ An API is provided to simplify the above process:
+
+ addPropValue(root,VCSomeProp,someASCIIStringZValue);
+
+ Note that someASCIISTringZValue is automatically converted to
+ Unicode by addPropValue API, where as, the former code
+ sequence do an explicit call to fakeUnicode.
+
+ To read back the value, one should use the vObjectUStringZValue
+ API not vObjectStringZValue API. The value returned by the
+ vObjectUStringZValue API is a Unicode string. If the application
+ do not know how to handle Unicode string, it can use the
+ fakeCString API to convert it back to ASCII string (as long
+ as the conversion is meaningful).
+
+ Note that fakeCString return a heap allocated memory. It is
+ important to call deleteStr on fakeCString return value if
+ it is not longer required (or there will be memory leak).
+
+ NOTE: Unfortunately, at the point when this document is written,
+ there is still no consensus on how Unicode is to be handled
+ in the textual representation of VCard/VCalendar. So, there
+ is no version of writeVObject and the parser to output and
+ input Unicode textual representation of VCard/VCalendar.
+
+
+Example.vcf
+-----------
+line
+number Input Text (example.vcf)
+------ ----------
+1 BEGIN:VCALENDAR
+2 DCREATED:19961102T100522
+3 GEO:0,0
+4 VERSION:1.0
+5 BEGIN:VEVENT
+6 DTSTART:19961103T000000
+7 DTEND:20000101T000000
+8 DESCRIPTION;QUOTED-PRINTABLE:To be =0A=
+9 or =0A=
+10 not to be
+11 STATUS:O.K.
+12 X-ACTION:No action required
+13 DALARM:19961103T114500;5;3;Enjoy
+14 MALARM:19970101T120000;;;johny@nowhere.com;Call Mom.
+15 END:VEVENT
+16
+17 BEGIN:VTODO
+18 DUE:19960614T0173000
+19 DESCRIPTION:Relex.
+20 END:VTODO
+21
+22 END:VCALENDAR
+23
+24 BEGIN:VCARD
+25 N:Alden;Roland
+26 FN:Roland H. Alden
+27 ORG:AT&T;Versit Project Office
+28 TITLE:Consultant
+29 EMAIL;WORK;PREF;INTERNET:ralden@ralden.com
+30 LABEL;DOM;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A=
+31 Suite 2208=0A=
+32 One Pine Street=0A=
+33 San Francisco, CA 94111
+34 LABEL;POSTAL;PARCEL;HOME;WORK;QUOTED-PRINTABLE:Roland H. Alden=0A=
+35 Suite 2208=0A=
+36 One Pine Street=0A=
+37 San Francisco, CA 94111=0A=
+38 U.S.A.
+39 TEL;WORK;PREF;MSG:+1 415 296 9106
+40 TEL;WORK;FAX:+1 415 296 9016
+41 TEL;MSG;CELL:+1 415 608 5981
+42 ADR:;Suite 2208;One Pine Street;San Francisco;CA;94111;U.S.A.
+43 SOUND:ROW-LAND H ALL-DIN
+44 LOGO;GIF;BASE64:
+45 R0lGODdhpgBOAMQAAP///+/v797e3s7Ozr29va2trZycnIyMjHt7e2NjY1JSUkJC
+ ... 30 lines of BASE64 data not shown here.
+76 END:VCARD
+
+
+VObject Representation of Example.vcf:
+-------------------------------------
+line
+in
+text
+file VObject Tree as Printed by printVObject API
+---- -------------------------------------------
+1 VCALENDAR
+2 DCREATED="19961102T100522"
+3 GEO="0,0"
+4 VERSION="1.0"
+5 VEVENT
+6 DTSTART="19961103T000000"
+7 DTEND="20000101T000000"
+8 DESCRIPTION="To be
+9 or
+10 not to be"
+8 QUOTED-PRINTABLE
+11 STATUS="O.K."
+12 X-ACTION="No action required"
+13 DALARM
+13 RUNTIME="19961103T114500"
+13 SNOOZETIME="5"
+13 REPEATCOUNT="3"
+13 DISPLAYSTRING="Enjoy"
+14 MALARM
+14 RUNTIME="19970101T120000"
+14 EMAIL="johny@nowhere.com"
+14 NOTE="Call Mom"
+17 VTODO
+18 DUE="19960614T0173000"
+19 DESCRIPTION="Relex."
+24 VCARD
+25 N
+25 F="Alden"
+25 G="Roland"
+26 FN="Roland H. Alden"
+27 ORG
+27 ORGNAME="AT&T"
+27 OUN="Versit Project Office"
+28 TITLE="Consultant"
+29 EMAIL="ralden@alden.com"
+29 WORK
+29 PREF
+29 INTERNET
+30 LABEL="Roland H. Alden
+31 Suite 2208
+32 One Pine Street
+33 San Francisco, CA 94111"
+30 DOM
+30 POSTAL
+30 PARCEL
+30 HOME
+30 WORK
+30 QUOTED-PRINTABLE
+34 LABEL="Roland H. Alden
+35 Suite 2208
+36 One Pine Street
+37 San Francisco, CA 94111
+38 U.S.A."
+34 POSTAL
+34 PARCEL
+34 HOME
+34 WORK
+34 QUOTED-PRINTABLE
+39 TEL="+1 415 296 9106"
+39 WORK
+39 PREF
+39 MSG
+40 TEL="+1 415 296 9016"
+40 WORK
+40 FAX
+41 TEL="+1 415 608 5981"
+41 MSG
+41 CELL
+42 ADR
+42 EXT ADD="Suite 2208"
+42 STREET="One Pine Street"
+42 L="San Francisco"
+42 R="CA"
+42 PC="94111"
+42 C="U.S.A."
+43 SOUND="ROW-LAND H ALL-DIN"
+44 LOGO=[raw data]
+44 GIF
+44 BASE64
+44 DATASIZE=1482
+
diff --git a/src/libicalvcal/icalvcal.c b/src/libicalvcal/icalvcal.c new file mode 100644 index 0000000..f495af2 --- /dev/null +++ b/src/libicalvcal/icalvcal.c @@ -0,0 +1,1650 @@ +/*====================================================================== + FILE: icalvcal.c + CREATOR: eric 25 May 00 + + $Id: icalvcal.c,v 1.9 2008-02-03 16:10:46 dothebart Exp $ + + + (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org + + This program is free software; you can redistribute it and/or modify + it under the terms of either: + + The LGPL as published by the Free Software Foundation, version + 2.1, available at: http://www.fsf.org/copyleft/lesser.html + + Or: + + The Mozilla Public License Version 1.0. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + The original code is icalvcal.c + + + + The icalvcal_convert routine calls icalvcal_traverse_objects to do + its work.s his routine steps through through all of the properties + and components of a VObject. For each name of a property or a + component, icalvcal_traverse_objects looks up the name in + conversion_table[]. This table indicates wether the name is of a + component or a property, lists a routine to handle conversion, and + has extra data for the conversion. + + The conversion routine will create new iCal components or properties + and add them to the iCal component structure. + + The most common conversion routine is dc_prop. This routine converts + properties for which the text representation of the vCal component + is identical the iCal representation. + + ======================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "icalvcal.h" +#include <string.h> + +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp +#endif + +enum datatype { + COMPONENT, + PROPERTY, + PARAMETER, + UNSUPPORTED, + IGNORE +}; + +/* The indices must match between the strings and the codes. */ +char *weekdays[] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; +int weekday_codes[] = { + ICAL_SUNDAY_WEEKDAY, + ICAL_MONDAY_WEEKDAY, + ICAL_TUESDAY_WEEKDAY, + ICAL_WEDNESDAY_WEEKDAY, + ICAL_THURSDAY_WEEKDAY, + ICAL_FRIDAY_WEEKDAY, + ICAL_SATURDAY_WEEKDAY +}; + + +struct conversion_table_struct { + char* vcalname; + enum datatype type; + void* (*conversion_func)(int icaltype, VObject *o, icalcomponent *comp, + icalvcal_defaults *defaults); + int icaltype; +}; + +void* dc_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults); + + + +/* Creates an error property with the given message. */ +static icalproperty* create_parse_error_property (const char *message, + const char *property_name, + const char *property_value) +{ + char temp[4096]; + icalparameter *error_param; + icalproperty *error_prop; + + snprintf (temp, 1024, "%s: %s:%s", message, property_name, property_value); + + error_param = icalparameter_new_xlicerrortype (ICAL_XLICERRORTYPE_VCALPROPPARSEERROR); + error_prop = icalproperty_new_xlicerror (temp); + icalproperty_add_parameter (error_prop, error_param); + + return error_prop; +} + + +char* get_string_value (VObject *object, int *free_string) +{ + switch (vObjectValueType(object)) { + case VCVT_USTRINGZ: + *free_string = 1; + return fakeCString(vObjectUStringZValue(object)); + + case VCVT_STRINGZ: + *free_string = 0; + return (char*) vObjectStringZValue(object); + } + + *free_string = 0; + + /* We return "" here, to cut down on the risk of crashing. */ + return ""; +} + + +static void convert_floating_time_to_utc (struct icaltimetype *itt) +{ + struct tm tmp_tm = { 0 }, *utc_tm; + time_t t; + + /* We assume the floating time is using the current Unix timezone. + So we convert to a time_t using mktime(), and then back to a struct tm + using gmtime, so it is the UTC time. */ + tmp_tm.tm_year = itt->year - 1900; + tmp_tm.tm_mon = itt->month - 1; + tmp_tm.tm_mday = itt->day; + tmp_tm.tm_hour = itt->hour; + tmp_tm.tm_min = itt->minute; + tmp_tm.tm_sec = itt->second; + tmp_tm.tm_isdst = -1; + + /* Convert to a time_t. */ + t = mktime (&tmp_tm); + + /* Now convert back to a struct tm, but with a UTC time. */ + utc_tm = gmtime (&t); + + /* Now put it back into the icaltime. */ + itt->year = utc_tm->tm_year + 1900; + itt->month = utc_tm->tm_mon + 1; + itt->day = utc_tm->tm_mday; + itt->hour = utc_tm->tm_hour; + itt->minute = utc_tm->tm_min; + itt->second = utc_tm->tm_sec; + + /* Set the is_utc flag. */ + itt->is_utc = 1; +} + +static void icalvcal_traverse_objects(VObject *, + icalcomponent *, + icalproperty *, + icalvcal_defaults *); + +icalcomponent* icalvcal_convert_with_defaults (VObject *object, + icalvcal_defaults *defaults) +{ + + char* name = (char*)vObjectName(object); + icalcomponent* container = icalcomponent_new(ICAL_XROOT_COMPONENT); + icalcomponent* root; + icalproperty *prop; + + icalerror_check_arg_rz( (object!=0),"Object"); + + /* The root object must be a VCALENDAR */ + if(*name==0 || strcmp(name,VCCalProp) != 0){ + return 0; /* HACK. Should return an error */ + } + +#if 0 + /* Just for testing. */ + printf ("This is the internal VObject representation:\n"); + printf ("===========================================\n"); + printVObject(stdout, object); + printf ("===========================================\n"); +#endif + + icalvcal_traverse_objects(object,container,0,defaults); + + /* HACK. I am using the extra 'container' component because I am + lazy. I know there is a way to get rid of it, but I did not care + to find it. */ + + root = icalcomponent_get_first_component(container,ICAL_ANY_COMPONENT); + + icalcomponent_remove_component(container, root); + icalcomponent_free(container); + + /* We add a VERSION and PRODID here, to make it a valid iCalendar object, + but the application may change them if necessary. */ + prop = icalproperty_new_prodid ("-//Softwarestudio.org//" ICAL_PACKAGE + " version " ICAL_VERSION "//EN"); + icalcomponent_add_property (root, prop); + + prop = icalproperty_new_version ("2.0"); + icalcomponent_add_property (root, prop); + + return root; + +} + +icalcomponent* icalvcal_convert (VObject *object) +{ + return icalvcal_convert_with_defaults (object, NULL); +} + + +/* comp() is useful for most components, but alarm, daylight and + * timezone are different. In vcal, they are properties, and in ical, + * they are components. Although because of the way that vcal treats + * everything as a property, alarm_comp() daylight_comp() and + * timezone_comp() may not really be necessary, I think it would be + * easier to use them. */ + +void* comp(int icaltype, VObject *o, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalcomponent_kind kind = (icalcomponent_kind)icaltype; + + icalcomponent* c = icalcomponent_new(kind); + + return (void* )c; +} + +/* vCalendar has 4 properties for alarms: AALARM, DALARM, MALARM, PALARM + (for audio, display, mail, and procedure alarms). + + AALARM has Run Time, Snooze Time, Repeat Count, Audio Content. + It may also have a TYPE parameter specifying the MIME type, e.g. + AALARM;TYPE=WAVE;VALUE=URL:19960415T235959; ; ; file:///mmedia/taps.wav + AALARM;TYPE=WAVE;VALUE=CONTENT-ID:19960903T060000;PT15M;4;<jsmith.part2.= + 960901T083000.xyzMail@host1.com> + + DALARM has Run Time, Snooze Time, Repeat Count, Display String. + DALARM:19960415T235000;PT5M;2;Your Taxes Are Due !!! + + MALARM has Run Time, Snooze Time, Repeat Count, Email Address, Note. + MALARM:19960416T000000;PT1H;24;IRS@us.gov;The Check Is In The Mail! + + PALARM has Run Time, Snooze Time, Repeat Count, Procedure Name. + PALARM;VALUE=URL:19960415T235000;PT5M;2;file:///myapps/shockme.exe + + AALARM and PALARM: Check the VALUE is a URL. We won't support CONTENT-ID. + + + iCalendar uses one component, VALARM, for all of these, and uses an ACTION + property of "AUDIO", "DISPLAY", "EMAIL" or "PROCEDURE". + + The Run Time value can be copied into the iCalendar TRIGGER property, + except it must be UTC in iCalendar. If it is floating, we'll convert to + UTC using the current Unix timezone. + + The Snooze Time becomes DURATION, and the Repeat Count becomes REPEAT. + + For AALARM, the Audio Content becomes the ATTACH property, and the TYPE + becomes a FMTTYPE of this property (PCM -> 'audio/basic' (?), + WAVE -> 'audio/x-wav', AIFF -> 'audio/x-aiff'), e.g. + ATTACH;FMTTYPE=audio/basic:ftp://host.com/pub/sounds/bell-01.aud + + For DALARM, Display String becomes the DESCRIPTION property. + + For MALARM, Email Address becomes an ATTENDEE property, e.g. + ATTENDEE:MAILTO:john_doe@host.com + + For PALARM, the Procedure Name becomes an ATTACH property, like AALARM, e.g. + ATTACH;FMTTYPE=application/binary:ftp://host.com/novo-procs/felizano.exe +*/ + +/* This converts the vCalendar alarm properties into iCalendar properties and + adds them to the component. It returns 1 if the alarm is valid, 0 if not. */ +static int get_alarm_properties (icalcomponent *comp, VObject *object, + int icaltype, icalvcal_defaults *defaults) +{ + VObjectIterator iterator; + icalproperty *trigger_prop = NULL, *duration_prop = NULL; + icalproperty *repeat_prop = NULL, *attach_prop = NULL; + icalproperty *summary_prop = NULL, *description_prop = NULL; + icalproperty *action_prop, *attendee_prop = NULL; + icalparameter *fmttype_param = NULL; + enum icalproperty_action action; + int value_is_url = 0, is_valid_alarm = 1; + + initPropIterator (&iterator, object); + while (moreIteration (&iterator)) { + VObject *eachProp = nextVObject (&iterator); + const char *name = vObjectName (eachProp); + char *s; + int free_string; + + s = get_string_value (eachProp, &free_string); + + /* Common properties. */ + if (!strcmp (name, VCRunTimeProp)) { + if (*s) { + struct icaltriggertype t; + icalparameter *param; + + /* Convert it to an icaltimetype. */ + t.time = icaltime_from_string (s); + + /* If it is a floating time, convert it to a UTC time. */ + if (!t.time.is_utc) + convert_floating_time_to_utc (&t.time); + + /* Create a TRIGGER property. */ + trigger_prop = icalproperty_new_trigger (t); + + /* vCalendar triggers are always specific DATE-TIME values. */ + param = icalparameter_new_value (ICAL_VALUE_DATETIME); + icalproperty_add_parameter (trigger_prop, param); + + icalcomponent_add_property (comp, trigger_prop); + } + + } else if (!strcmp (name, VCSnoozeTimeProp)) { + struct icaldurationtype d; + + /* Parse the duration string. + FIXME: vCalendar also permits 'Y' (Year) and 'M' (Month) here, + which we don't handle at present. Though it is unlikely they + will be used as a snooze time between repeated alarms! */ + d = icaldurationtype_from_string (s); + + duration_prop = icalproperty_new_duration (d); + icalcomponent_add_property (comp, duration_prop); + + } else if (!strcmp (name, VCRepeatCountProp)) { + /* If it starts with a digit convert it into a REPEAT property. */ + if (*s && *s >= '0' && *s <= '9') { + repeat_prop = icalproperty_new_repeat (atoi (s)); + icalcomponent_add_property (comp, repeat_prop); + } + + } else if (!strcmp (name, VCValueProp)) { + /* We just remember if the value is a URL. */ + if (!strcmp (s, "URL")) { + value_is_url = 1; + } + + /* Audio properties && Procedure properties. */ + } else if (!strcmp (name, VCAudioContentProp) + || !strcmp (name, VCProcedureNameProp)) { + if (*s && !attach_prop) { + icalattach *attach; + + attach = icalattach_new_from_url (s); + attach_prop = icalproperty_new_attach (attach); + icalcomponent_add_property (comp, attach_prop); + + /* We output a "application/binary" FMTTYPE for Procedure + alarms. */ + if (!strcmp (name, VCProcedureNameProp) && !fmttype_param) + fmttype_param = icalparameter_new_fmttype ("application/binary"); + } + + } else if (!strcmp (name, "TYPE")) { + char *fmttype = NULL; + + if (!strcmp (s, "PCM")) + fmttype = "audio/basic"; + else if (!strcmp (s, "AIFF")) + fmttype = "audio/x-aiff"; + else if (!strcmp (s, "WAVE")) + fmttype = "audio/x-wav"; + + if (fmttype) + fmttype_param = icalparameter_new_fmttype (fmttype); + + /* Display properties. */ + } else if (!strcmp (name, VCDisplayStringProp)) { + if (!description_prop) { + description_prop = icalproperty_new_description (s); + icalcomponent_add_property (comp, description_prop); + } + + /* Mail properties. */ + } else if (!strcmp (name, VCEmailAddressProp)) { + if (*s && strlen (s) < 1000) { + char buffer[1024]; + + /* We need to add 'MAILTO:' before the email address, to make + it valid iCalendar. */ + sprintf (buffer, "MAILTO:%s", s); + attendee_prop = icalproperty_new_attendee (buffer); + icalcomponent_add_property (comp, attendee_prop); + } + + } else if (!strcmp (name, VCNoteProp)) { + if (!description_prop) { + description_prop = icalproperty_new_description (s); + icalcomponent_add_property (comp, description_prop); + } + + /* We also copy the Note to the SUMMARY property, since that is + required in iCalendar. */ + if (!summary_prop) { + summary_prop = icalproperty_new_summary (s); + icalcomponent_add_property (comp, summary_prop); + } + } + + if (free_string) + deleteStr (s); + } + + /* Add the FMTTYPE parameter to the ATTACH property if it exists. */ + if (fmttype_param) { + if (attach_prop) { + icalproperty_add_parameter (attach_prop, fmttype_param); + } else { + icalparameter_free (fmttype_param); + } + } + + + /* Now check if the alarm is valid, i.e. it has the required properties + according to its type. */ + + /* All alarms must have a trigger. */ + if (!trigger_prop) + is_valid_alarm = 0; + + /* If there is a Duration but not a Repeat Count, we just remove the + Duration so the alarm only occurs once. */ + if (duration_prop && !repeat_prop) { + icalcomponent_remove_property (comp, duration_prop); + icalproperty_free (duration_prop); + duration_prop = NULL; + } + + /* Similarly if we have a Repeat Count but no Duration, we remove it. */ + if (repeat_prop && !duration_prop) { + icalcomponent_remove_property (comp, repeat_prop); + icalproperty_free (repeat_prop); + repeat_prop = NULL; + } + + switch (icaltype) { + case ICAL_XAUDIOALARM_COMPONENT: + action = ICAL_ACTION_AUDIO; + + /* Audio alarms must have an ATTACH property, which is a URL. + If they don't have one, we use the default alarm URL. */ + if (!attach_prop || !value_is_url) { + if (defaults && defaults->alarm_audio_url + && defaults->alarm_audio_fmttype) { + icalattach *attach; + + if (attach_prop) { + icalcomponent_remove_property (comp, attach_prop); + icalproperty_free (attach_prop); + } + + attach = icalattach_new_from_url (defaults->alarm_audio_url); + attach_prop = icalproperty_new_attach (attach); + icalcomponent_add_property (comp, attach_prop); + + fmttype_param = icalparameter_new_fmttype (defaults->alarm_audio_fmttype); + icalproperty_add_parameter (attach_prop, fmttype_param); + } else { + is_valid_alarm = 0; + } + } + break; + + case ICAL_XDISPLAYALARM_COMPONENT: + action = ICAL_ACTION_DISPLAY; + + /* Display alarms must have a DESCRIPTION. */ + if (!description_prop) { + if (defaults && defaults->alarm_description) { + description_prop = icalproperty_new_description (defaults->alarm_description); + icalcomponent_add_property (comp, description_prop); + } else { + is_valid_alarm = 0; + } + } + break; + + case ICAL_XEMAILALARM_COMPONENT: + action = ICAL_ACTION_EMAIL; + + /* Email alarms must have a SUMMARY, a DESCRIPTION, and an ATTENDEE. */ + if (!attendee_prop) { + is_valid_alarm = 0; + } else if (!summary_prop || !description_prop) { + if (!summary_prop && defaults->alarm_description) { + summary_prop = icalproperty_new_summary (defaults->alarm_description); + icalcomponent_add_property (comp, summary_prop); + } + + if (!description_prop && defaults->alarm_description) { + description_prop = icalproperty_new_description (defaults->alarm_description); + icalcomponent_add_property (comp, description_prop); + } + + if (!summary_prop || !description_prop) + is_valid_alarm = 0; + } + break; + + case ICAL_XPROCEDUREALARM_COMPONENT: + action = ICAL_ACTION_PROCEDURE; + + /* Procedure alarms must have an ATTACH property, which is a URL. + We don't support inline data. */ + if (!attach_prop) { + is_valid_alarm = 0; + } else if (!value_is_url) { + icalattach *attach; + const char *url; + + attach = icalproperty_get_attach (attach_prop); + url = icalattach_get_url (attach); + + /* Check for Gnome Calendar, which will just save a pathname. */ + if (url && url[0] == '/') { + int len; + char *new_url; + icalattach *new_attach; + + /* Turn it into a proper file: URL. */ + len = strlen (url) + 12; + + new_url = malloc (len); + strcpy (new_url, "file://"); + strcat (new_url, url); + + new_attach = icalattach_new_from_url (new_url); + free (new_url); + + icalproperty_set_attach (attach_prop, new_attach); + + } else { + is_valid_alarm = 0; + } + } + break; + + default: + /* Shouldn't reach here ever. */ + assert(0); + break; + } + + action_prop = icalproperty_new_action (action); + icalcomponent_add_property (comp, action_prop); + + return is_valid_alarm; +} + + +void* alarm_comp(int icaltype, VObject *o, icalcomponent *comp, + icalvcal_defaults *defaults) +{ +/* icalcomponent_kind kind = (icalcomponent_kind)icaltype; */ + int is_valid_alarm; + + icalcomponent* c = icalcomponent_new(ICAL_VALARM_COMPONENT); + + is_valid_alarm = get_alarm_properties (c, o, icaltype, defaults); + + if (is_valid_alarm) { + return (void*)c; + } else { + icalcomponent_free (c); + return NULL; + } +} + + +/* These #defines indicate conversion routines that are not defined yet. */ + +#define parameter 0 +#define rsvp_parameter 0 + +void* transp_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty *prop = NULL; + char *s; + int free_string; + + s = get_string_value (object, &free_string); + + + /* In vCalendar "0" means opaque, "1" means transparent, and >1 is + implementation-specific. So we just check for "1" and output + TRANSPARENT. For anything else, the default OPAQUE will be used. */ + if (!strcmp (s, "1")) { + prop = icalproperty_new_transp (ICAL_TRANSP_TRANSPARENT); + } + + if (free_string) + deleteStr (s); + + return (void*)prop; +} + +void* sequence_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty *prop = NULL; + char *s; + int free_string, sequence; + + s = get_string_value (object, &free_string); + + /* GnomeCalendar outputs '-1' for this. I have no idea why. + So we just check it is a valid +ve integer, and output 0 if it isn't. */ + sequence = atoi (s); + if (sequence < 0) + sequence = 0; + + prop = icalproperty_new_sequence (sequence); + + if (free_string) + deleteStr (s); + + return (void*)prop; +} + + +/* This handles properties which have multiple values, which are separated by + ';' in vCalendar but ',' in iCalendar. So we just switch those. */ +void* multivalued_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty_kind kind = (icalproperty_kind)icaltype; + icalproperty *prop = NULL; + icalvalue *value; + icalvalue_kind value_kind; + char *s, *tmp_copy, *p; + int free_string; + + s = get_string_value (object, &free_string); + + tmp_copy = strdup (s); + + if (free_string) + deleteStr (s); + + if (tmp_copy) { + prop = icalproperty_new(kind); + + value_kind = icalenum_property_kind_to_value_kind (icalproperty_isa (prop)); + + for (p = tmp_copy; *p; p++) { + if (*p == ';') + *p = ','; + } + + value = icalvalue_new_from_string (value_kind, tmp_copy); + icalproperty_set_value (prop, value); + + free (tmp_copy); + } + + return (void*)prop; +} + + +void* status_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty *prop = NULL; + char *s; + int free_string; + icalcomponent_kind kind; + + kind = icalcomponent_isa (comp); + + s = get_string_value (object, &free_string); + + /* In vCalendar: + VEVENT can have: "NEEDS ACTION" (default), "SENT", "TENTATIVE", + "CONFIRMED", "DECLINED", "DELEGATED". + VTODO can have: "ACCEPTED", "NEEDS ACTION" (default), "SENT", + "DECLINED", "COMPLETED", "DELEGATED". + (Those are the only 2 components - there is no VJOURNAL) + + In iCalendar: + VEVENT can have: "TENTATIVE", "CONFIRMED", "CANCELLED". + VTODO can have: "NEEDS-ACTION", "COMPLETED", "IN-PROCESS", "CANCELLED". + + So for VEVENT if it is "TENTATIVE" or "CONFIRMED" we keep it, otherwise + we skip it. + + For a VTODO if it is "NEEDS ACTION" we convert to "NEEDS-ACTION", if it + is "COMPLETED" we keep it, otherwise we skip it. + */ + if (kind == ICAL_VEVENT_COMPONENT) { + if (!strcmp (s, "TENTATIVE")) + prop = icalproperty_new_status (ICAL_STATUS_TENTATIVE); + else if (!strcmp (s, "CONFIRMED")) + prop = icalproperty_new_status (ICAL_STATUS_CONFIRMED); + + } else if (kind == ICAL_VTODO_COMPONENT) { + if (!strcmp (s, "NEEDS ACTION")) + prop = icalproperty_new_status (ICAL_STATUS_NEEDSACTION); + else if (!strcmp (s, "COMPLETED")) + prop = icalproperty_new_status (ICAL_STATUS_COMPLETED); + + } + + if (free_string) + deleteStr (s); + + return (void*)prop; +} + + +void* utc_datetime_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty_kind kind = (icalproperty_kind)icaltype; + icalproperty *prop; + icalvalue *value; + icalvalue_kind value_kind; + char *s; + int free_string; + struct icaltimetype itt; + + prop = icalproperty_new(kind); + + value_kind = icalenum_property_kind_to_value_kind (icalproperty_isa(prop)); + + s = get_string_value (object, &free_string); + + /* Convert it to an icaltimetype. */ + itt = icaltime_from_string (s); + + /* If it is a floating time, convert it to a UTC time. */ + if (!itt.is_utc) + convert_floating_time_to_utc (&itt); + + value = icalvalue_new_datetime (itt); + icalproperty_set_value(prop,value); + + if (free_string) + deleteStr (s); + + return (void*)prop; +} + + +/* Parse the interval from the RRULE, returning a pointer to the first char + after the interval and any whitespace. s points to the start of the + interval. error_message is set if an error occurs. */ +static char* rrule_parse_interval (char *s, struct icalrecurrencetype *recur, + char **error_message) +{ + int interval = 0; + + /* It must start with a digit. */ + if (*s < '0' || *s > '9') { + *error_message = "Invalid Interval"; + return NULL; + } + + while (*s >= '0' && *s <= '9') + interval = (interval * 10) + (*s++ - '0'); + + /* It must be followed by whitespace. I'm not sure if anything else is + allowed. */ + if (*s != ' ' && *s != '\t') { + *error_message = "Invalid Interval"; + return NULL; + } + + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + + recur->interval = interval; + return s; +} + + +/* Parse the duration from the RRULE, either a COUNT, e.g. '#5', or an UNTIL + date, e.g. 20020124T000000. error_message is set if an error occurs. + If no duration is given, '#2' is assumed. */ +static char* rrule_parse_duration (char *s, struct icalrecurrencetype *recur, + char **error_message) +{ + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + if (!s || *s == '\0') { + /* If we are at the end of the string, assume '#2'. */ + recur->count = 2; + + } else if (*s == '#') { + /* If it starts with a '#' it is the COUNT. Note that in vCalendar + #0 means forever, and setting recur->count to 0 means the same. */ + int count = 0; + + s++; + while (*s >= '0' && *s <= '9') + count = (count * 10) + (*s++ - '0'); + + recur->count = count; + + } else if (*s >= '0' && *s <= '9') { + /* If it starts with a digit it must be the UNTIL date. */ + char *e, buffer[20]; + int len; + + /* Find the end of the date. */ + e = s; + while ((*e >= '0' && *e <= '9') || *e == 'T' || *e == 'Z') + e++; + + /* Check it is a suitable length. */ + len = e - s; + if (len != 8 && len != 15 && len != 16) { + *error_message = "Invalid End Date"; + return NULL; + } + + /* Copy the date to our buffer and null-terminate it. */ + strncpy (buffer, s, len); + buffer[len] = '\0'; + + /* Parse it into the until field. */ + recur->until = icaltime_from_string (buffer); + + /* In iCalendar UNTIL must be UTC if it is a DATE-TIME. But we + don't really know what timezone the vCalendar times are in. So if + it can be converted to a DATE value, we do that. Otherwise we just + use the current Unix timezone. Should be OK 99% of the time. */ + if (!recur->until.is_utc) { + if (recur->until.hour == 0 && recur->until.minute == 0 + && recur->until.second == 0) + recur->until.is_date = 1; + else + convert_floating_time_to_utc (&recur->until); + } + + s = e; + + } else { + *error_message = "Invalid Duration"; + return NULL; + } + + + /* It must be followed by whitespace or the end of the string. + I'm not sure if anything else is allowed. */ + if (*s != '\0' && *s != ' ' && *s != '\t') { + *error_message = "Invalid Duration"; + return NULL; + } + + return s; +} + + +static char* rrule_parse_weekly_days (char *s, + struct icalrecurrencetype *recur, + char **error_message) +{ + int i; + + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + for (i = 0; i < ICAL_BY_DAY_SIZE; i++) { + char *e = s; + int found_day, day; + + found_day = -1; + for (day = 0; day < 7; day++) { + if (!strncmp (weekdays[day], s, 2)) { + /* Check the next char is whitespace or the end of string. */ + e = s + 2; + if (*e == ' ' || *e == '\t' || *e == '\0') { + found_day = day; + break; + } + } + } + + if (found_day == -1) + break; + + recur->by_day[i] = weekday_codes[day]; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + + /* Terminate the array, if it isn't full. */ + if (i < ICAL_BY_DAY_SIZE) + recur->by_day[i] = ICAL_RECURRENCE_ARRAY_MAX; + + return s; +} + + +static char* rrule_parse_monthly_days (char *s, + struct icalrecurrencetype *recur, + char **error_message) +{ + int i; + + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + for (i = 0; i < ICAL_BY_MONTHDAY_SIZE; i++) { + char *e; + int month_day; + + if (!strncmp (s, "LD", 2)) { + month_day = -1; + e = s + 2; + } else { + month_day = strtol (s, &e, 10); + + /* Check we got a valid day. */ + if (month_day < 1 || month_day > 31) + break; + + /* See if it is followed by a '+' or '-'. */ + if (*e == '+') { + e++; + } else if (*e == '-') { + e++; + month_day = -month_day; + } + } + + /* Check the next char is whitespace or the end of the string. */ + if (*e != ' ' && *e != '\t' && *e != '\0') + break; + + recur->by_month_day[i] = month_day; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + + /* Terminate the array, if it isn't full. */ + if (i < ICAL_BY_MONTHDAY_SIZE) + recur->by_month_day[i] = ICAL_RECURRENCE_ARRAY_MAX; + + return s; +} + + +static char* rrule_parse_monthly_positions (char *s, + struct icalrecurrencetype *recur, + char **error_message) +{ + int occurrences[ICAL_BY_DAY_SIZE]; + int found_weekdays[7] = { 0 }; + int i, num_positions, elems, month_position, day; + int num_weekdays, only_weekday = 0; + char *e; + + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + /* First read the month position into our local occurrences array. */ + for (i = 0; i < ICAL_BY_DAY_SIZE; i++) { + int month_position; + + /* Check we got a valid position number. */ + month_position = *s - '0'; + if (month_position < 0 || month_position > 5) + break; + + /* See if it is followed by a '+' or '-'. */ + e = s + 1; + if (*e == '+') { + e++; + } else if (*e == '-') { + e++; + month_position = -month_position; + } + + /* Check the next char is whitespace or the end of the string. */ + if (*e != ' ' && *e != '\t' && *e != '\0') + break; + + occurrences[i] = month_position; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + num_positions = i; + + /* Now read the weekdays in. */ + for (;;) { + char *e = s; + int found_day, day; + + found_day = -1; + for (day = 0; day < 7; day++) { + if (!strncmp (weekdays[day], s, 2)) { + /* Check the next char is whitespace or the end of string. */ + e = s + 2; + if (*e == ' ' || *e == '\t' || *e == '\0') { + found_day = day; + break; + } + } + } + + if (found_day == -1) + break; + + found_weekdays[found_day] = 1; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + + /* Now merge them together into the recur->by_day array. If there is a + single position & weekday we output something like + 'BYDAY=TU;BYSETPOS=2', so Outlook will understand it. */ + num_weekdays = 0; + for (day = 0; day < 7; day++) { + if (found_weekdays[day]) { + num_weekdays++; + only_weekday = day; + } + } + if (num_positions == 1 && num_weekdays == 1) { + recur->by_day[0] = weekday_codes[only_weekday]; + recur->by_day[1] = ICAL_RECURRENCE_ARRAY_MAX; + + recur->by_set_pos[0] = occurrences[0]; + recur->by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX; + } else { + elems = 0; + for (i = 0; i < num_positions; i++) { + month_position = occurrences[i]; + + for (day = 0; day < 7; day++) { + if (found_weekdays[day]) { + recur->by_day[elems] = (abs (month_position) * 8 + weekday_codes[day]) * ((month_position < 0) ? -1 : 1); + elems++; + if (elems == ICAL_BY_DAY_SIZE) + break; + } + } + + if (elems == ICAL_BY_DAY_SIZE) + break; + } + + /* Terminate the array, if it isn't full. */ + if (elems < ICAL_BY_DAY_SIZE) + recur->by_day[elems] = ICAL_RECURRENCE_ARRAY_MAX; + } + + return s; +} + + +static char* rrule_parse_yearly_months (char *s, + struct icalrecurrencetype *recur, + char **error_message) +{ + int i; + + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + for (i = 0; i < ICAL_BY_MONTH_SIZE; i++) { + char *e; + int month; + + month = strtol (s, &e, 10); + + /* Check we got a valid month. */ + if (month < 1 || month > 12) + break; + + /* Check the next char is whitespace or the end of the string. */ + if (*e != ' ' && *e != '\t' && *e != '\0') + break; + + recur->by_month[i] = month; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + + /* Terminate the array, if it isn't full. */ + if (i < ICAL_BY_MONTH_SIZE) + recur->by_month[i] = ICAL_RECURRENCE_ARRAY_MAX; + + return s; +} + + +static char* rrule_parse_yearly_days (char *s, + struct icalrecurrencetype *recur, + char **error_message) +{ + int i; + + /* If we've already found an error, just return. */ + if (*error_message) + return NULL; + + for (i = 0; i < ICAL_BY_YEARDAY_SIZE; i++) { + char *e; + int year_day; + + year_day = strtol (s, &e, 10); + + /* Check we got a valid year_day. */ + if (year_day < 1 || year_day > 366) + break; + + /* Check the next char is whitespace or the end of the string. */ + if (*e != ' ' && *e != '\t' && *e != '\0') + break; + + recur->by_year_day[i] = year_day; + + s = e; + /* Skip any whitespace. */ + while (*s == ' ' || *s == '\t') + s++; + } + + /* Terminate the array, if it isn't full. */ + if (i < ICAL_BY_YEARDAY_SIZE) + recur->by_year_day[i] = ICAL_RECURRENCE_ARRAY_MAX; + + return s; +} + + + + +/* Converts an RRULE/EXRULE property. + NOTE: There are a few things that this doesn't handle: + 1) vCalendar RRULE properties can contain an UNTIL date and a COUNT, and + the first to occur specifies the end of the recurrence. However they + are mutually exclusive in iCalendar. For now we just use the COUNT. + 2) For MONTHLY By Position recurrences, if no modifiers are given they + are to be calculated based on the DTSTART, e.g. if DTSTART is on the + 3rd Wednesday of the month then all occurrences are on the 3rd Wed. + This is awkward to do as we need to access the DTSTART property, which + may be after the RRULE property. So we don't do this at present. + 3) The Extended Recurrence Rule Grammar - we only support the Basic rules. + The extended grammar supports rules embedded in other rules, MINUTELY + recurrences, time modifiers in DAILY rules and maybe other stuff. +*/ + +void* rule_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ +/* icalproperty_kind kind = (icalproperty_kind)icaltype;*/ + icalproperty *prop = NULL; +/* icalvalue *value; */ +/* icalvalue_kind value_kind; */ + char *s, *p, *error_message = NULL; + const char *property_name; + int free_string; + struct icalrecurrencetype recur; + + s = get_string_value (object, &free_string); + + property_name = vObjectName (object); + + icalrecurrencetype_clear (&recur); + + if (*s == 'D') { + /* The DAILY RRULE only has an interval and duration (COUNT/UNTIL). */ + recur.freq = ICAL_DAILY_RECURRENCE; + p = rrule_parse_interval (s + 1, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else if (*s == 'W') { + /* The WEEKLY RRULE has weekday modifiers - MO TU WE. */ + recur.freq = ICAL_WEEKLY_RECURRENCE; + p = rrule_parse_interval (s + 1, &recur, &error_message); + p = rrule_parse_weekly_days (p, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else if (*s == 'M' && *(s + 1) == 'D') { + /* The MONTHLY By Day RRULE has day number modifiers - 1 1- LD. */ + recur.freq = ICAL_MONTHLY_RECURRENCE; + p = rrule_parse_interval (s + 2, &recur, &error_message); + p = rrule_parse_monthly_days (p, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else if (*s == 'M' && *(s + 1) == 'P') { + /* The MONTHLY By Position RRULE has position modifiers - 1 2- and + weekday modifiers - MO TU. */ + recur.freq = ICAL_MONTHLY_RECURRENCE; + p = rrule_parse_interval (s + 2, &recur, &error_message); + p = rrule_parse_monthly_positions (p, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else if (*s == 'Y' && *(s + 1) == 'M') { + /* The YEARLY By Month RRULE has month modifiers - 1 3 12. */ + recur.freq = ICAL_YEARLY_RECURRENCE; + p = rrule_parse_interval (s + 2, &recur, &error_message); + p = rrule_parse_yearly_months (p, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else if (*s == 'Y' && *(s + 1) == 'D') { + /* The YEARLY By Day RRULE has day number modifiers - 100 200. */ + recur.freq = ICAL_YEARLY_RECURRENCE; + p = rrule_parse_interval (s + 2, &recur, &error_message); + p = rrule_parse_yearly_days (p, &recur, &error_message); + p = rrule_parse_duration (p, &recur, &error_message); + } else { + error_message = "Invalid RRULE Frequency"; + } + + if (error_message) { + prop = create_parse_error_property (error_message, property_name, s); + } else { + if (!strcmp (property_name, "RRULE")) + prop = icalproperty_new_rrule (recur); + else + prop = icalproperty_new_exrule (recur); + } + + if (free_string) + deleteStr (s); + + return (void*)prop; +} + + + +/* directly convertable property. The string representation of vcal is + the same as ical */ + +void* dc_prop(int icaltype, VObject *object, icalcomponent *comp, + icalvcal_defaults *defaults) +{ + icalproperty_kind kind = (icalproperty_kind)icaltype; + icalproperty *prop; + icalvalue *value; + icalvalue_kind value_kind; + char *s; +/*/,*t=0; */ + int free_string; + + + prop = icalproperty_new(kind); + + value_kind = icalenum_property_kind_to_value_kind (icalproperty_isa(prop)); + + s = get_string_value (object, &free_string); + + value = icalvalue_new_from_string(value_kind,s); + + if (free_string) + deleteStr (s); + + icalproperty_set_value(prop,value); + + return (void*)prop; +} + + +/* My extraction program screwed up, so this table does not have all +of the vcal properties in it. I didn't feel like re-doing the entire +table, so you'll have to find the missing properties the hard way -- +the code will assert */ + +static const struct conversion_table_struct conversion_table[] = +{ +{VCCalProp, COMPONENT, comp, ICAL_VCALENDAR_COMPONENT}, +{VCTodoProp, COMPONENT, comp, ICAL_VTODO_COMPONENT}, +{VCEventProp, COMPONENT, comp, ICAL_VEVENT_COMPONENT}, +{VCAAlarmProp, COMPONENT, alarm_comp, ICAL_XAUDIOALARM_COMPONENT}, +{VCDAlarmProp, COMPONENT, alarm_comp, ICAL_XDISPLAYALARM_COMPONENT}, +{VCMAlarmProp, COMPONENT, alarm_comp, ICAL_XEMAILALARM_COMPONENT}, +{VCPAlarmProp, COMPONENT, alarm_comp, ICAL_XPROCEDUREALARM_COMPONENT}, + +/* These can all be converted directly by parsing the string into a libical + value. */ +{VCClassProp, PROPERTY, dc_prop, ICAL_CLASS_PROPERTY}, +{VCDescriptionProp, PROPERTY, dc_prop, ICAL_DESCRIPTION_PROPERTY}, +{VCAttendeeProp, PROPERTY, dc_prop, ICAL_ATTENDEE_PROPERTY}, +{VCDTendProp, PROPERTY, dc_prop, ICAL_DTEND_PROPERTY}, +{VCDTstartProp, PROPERTY, dc_prop, ICAL_DTSTART_PROPERTY}, +{VCDueProp, PROPERTY, dc_prop, ICAL_DUE_PROPERTY}, +{VCLocationProp, PROPERTY, dc_prop, ICAL_LOCATION_PROPERTY}, +{VCSummaryProp, PROPERTY, dc_prop, ICAL_SUMMARY_PROPERTY}, +{VCUniqueStringProp, PROPERTY, dc_prop, ICAL_UID_PROPERTY}, +{VCURLProp, PROPERTY, dc_prop, ICAL_URL_PROPERTY}, +{VCPriorityProp, PROPERTY, dc_prop, ICAL_PRIORITY_PROPERTY}, + +/* These can contain multiple values, which are separated in ';' in vCalendar + but ',' in iCalendar. */ +{VCCategoriesProp, PROPERTY, multivalued_prop,ICAL_CATEGORIES_PROPERTY}, +{VCRDateProp, PROPERTY, multivalued_prop,ICAL_RDATE_PROPERTY}, +{VCExpDateProp, PROPERTY, multivalued_prop,ICAL_EXDATE_PROPERTY}, + +/* These can be in floating time in vCalendar, but must be in UTC in iCalendar. + */ +{VCDCreatedProp, PROPERTY, utc_datetime_prop,ICAL_CREATED_PROPERTY}, +{VCLastModifiedProp, PROPERTY, utc_datetime_prop,ICAL_LASTMODIFIED_PROPERTY}, +{VCCompletedProp, PROPERTY, utc_datetime_prop,ICAL_COMPLETED_PROPERTY}, + +{VCTranspProp, PROPERTY, transp_prop, ICAL_TRANSP_PROPERTY}, +{VCSequenceProp, PROPERTY, sequence_prop, ICAL_SEQUENCE_PROPERTY}, +{VCStatusProp, PROPERTY, status_prop, ICAL_STATUS_PROPERTY}, +{VCRRuleProp, PROPERTY, rule_prop, ICAL_RRULE_PROPERTY}, +{VCXRuleProp, PROPERTY, rule_prop, ICAL_EXRULE_PROPERTY}, + +{VCRSVPProp, UNSUPPORTED, rsvp_parameter,ICAL_RSVP_PARAMETER }, +{VCEncodingProp, UNSUPPORTED, parameter, ICAL_ENCODING_PARAMETER}, +{VCRoleProp, UNSUPPORTED, parameter, ICAL_ROLE_PARAMETER}, + +/* We don't want the old VERSION or PRODID properties copied across as they + are now incorrect. New VERSION & PRODID properties are added instead. */ +{VCVersionProp, IGNORE, 0, 0}, +{VCProdIdProp, IGNORE, 0, 0}, + +/* We ignore DAYLIGHT and TZ properties of the toplevel object, since we can't + really do much with them. */ +{VCDayLightProp, IGNORE, 0, 0}, +{VCTimeZoneProp, IGNORE, 0, 0}, + +/* These are all alarm properties. We handle these when the alarm component + is created, so we ignore them when doing the automatic conversions. + "TYPE" is used in AALARM, but doesn't seem to have a name in vobject.h. */ +{"TYPE", IGNORE,0, 0}, +{VCRunTimeProp, IGNORE,0, 0}, +{VCSnoozeTimeProp, IGNORE,0, 0}, +{VCRepeatCountProp, IGNORE,0, 0}, +{VCValueProp, IGNORE,0, 0}, +{VCProcedureNameProp, IGNORE,0, 0}, +{VCDisplayStringProp, IGNORE,0, 0}, +{VCEmailAddressProp, IGNORE,0, 0}, +{VCNoteProp, IGNORE,0, 0}, + +{VCQuotedPrintableProp,UNSUPPORTED,0, 0}, +{VC7bitProp, UNSUPPORTED,0, 0}, +{VC8bitProp, UNSUPPORTED,0, 0}, +{VCAdditionalNamesProp,UNSUPPORTED,0, 0}, +{VCAdrProp, UNSUPPORTED,0, 0}, +{VCAgentProp, UNSUPPORTED,0, 0}, +{VCAIFFProp, UNSUPPORTED,0, 0}, +{VCAOLProp, UNSUPPORTED,0, 0}, +{VCAppleLinkProp, UNSUPPORTED,0, 0}, +{VCAttachProp, UNSUPPORTED,0, 0}, +{VCATTMailProp, UNSUPPORTED,0, 0}, +{VCAudioContentProp, UNSUPPORTED,0, 0}, +{VCAVIProp, UNSUPPORTED,0, 0}, +{VCBase64Prop, UNSUPPORTED,0, 0}, +{VCBBSProp, UNSUPPORTED,0, 0}, +{VCBirthDateProp, UNSUPPORTED,0, 0}, +{VCBMPProp, UNSUPPORTED,0, 0}, +{VCBodyProp, UNSUPPORTED,0, 0}, +{VCCaptionProp, UNSUPPORTED,0, 0}, +{VCCarProp, UNSUPPORTED,0, 0}, +{VCCellularProp, UNSUPPORTED,0, 0}, +{VCCGMProp, UNSUPPORTED,0, 0}, +{VCCharSetProp, UNSUPPORTED,0, 0}, +{VCCIDProp, UNSUPPORTED,0, 0}, +{VCCISProp, UNSUPPORTED,0, 0}, +{VCCityProp, UNSUPPORTED,0, 0}, +{VCCommentProp, UNSUPPORTED,0, 0}, +{VCCountryNameProp, UNSUPPORTED,0, 0}, +{VCDataSizeProp, UNSUPPORTED,0, 0}, +{VCDeliveryLabelProp, UNSUPPORTED,0, 0}, +{VCDIBProp, UNSUPPORTED,0, 0}, +{VCDomesticProp, UNSUPPORTED,0, 0}, +{VCEndProp, UNSUPPORTED,0, 0}, +{VCEWorldProp, UNSUPPORTED,0, 0}, +{VCExNumProp, UNSUPPORTED,0, 0}, +{VCExpectProp, UNSUPPORTED,0, 0}, +{VCFamilyNameProp, UNSUPPORTED,0, 0}, +{VCFaxProp, UNSUPPORTED,0, 0}, +{VCFullNameProp, UNSUPPORTED,0, 0}, +{VCGeoProp, UNSUPPORTED,0, 0}, +{VCGeoLocationProp, UNSUPPORTED,0, 0}, +{VCGIFProp, UNSUPPORTED,0, 0}, +{VCGivenNameProp, UNSUPPORTED,0, 0}, +{VCGroupingProp, UNSUPPORTED,0, 0}, +{VCHomeProp, UNSUPPORTED,0, 0}, +{VCIBMMailProp, UNSUPPORTED,0, 0}, +{VCInlineProp, UNSUPPORTED,0, 0}, +{VCInternationalProp, UNSUPPORTED,0, 0}, +{VCInternetProp, UNSUPPORTED,0, 0}, +{VCISDNProp, UNSUPPORTED,0, 0}, +{VCJPEGProp, UNSUPPORTED,0, 0}, +{VCLanguageProp, UNSUPPORTED,0, 0}, +{VCLastRevisedProp, UNSUPPORTED,0, 0}, +{VCLogoProp, UNSUPPORTED,0, 0}, +{VCMailerProp, UNSUPPORTED,0, 0}, +{VCMCIMailProp, UNSUPPORTED,0, 0}, +{VCMessageProp, UNSUPPORTED,0, 0}, +{VCMETProp, UNSUPPORTED,0, 0}, +{VCModemProp, UNSUPPORTED,0, 0}, +{VCMPEG2Prop, UNSUPPORTED,0, 0}, +{VCMPEGProp, UNSUPPORTED,0, 0}, +{VCMSNProp, UNSUPPORTED,0, 0}, +{VCNamePrefixesProp, UNSUPPORTED,0, 0}, +{VCNameProp, UNSUPPORTED,0, 0}, +{VCNameSuffixesProp, UNSUPPORTED,0, 0}, +{VCOrgNameProp, UNSUPPORTED,0, 0}, +{VCOrgProp, UNSUPPORTED,0, 0}, +{VCOrgUnit2Prop, UNSUPPORTED,0, 0}, +{VCOrgUnit3Prop, UNSUPPORTED,0, 0}, +{VCOrgUnit4Prop, UNSUPPORTED,0, 0}, +{VCOrgUnitProp, UNSUPPORTED,0, 0}, +{VCPagerProp, UNSUPPORTED,0, 0}, +{VCParcelProp, UNSUPPORTED,0, 0}, +{VCPartProp, UNSUPPORTED,0, 0}, +{VCPCMProp, UNSUPPORTED,0, 0}, +{VCPDFProp, UNSUPPORTED,0, 0}, +{VCPGPProp, UNSUPPORTED,0, 0}, +{VCPhotoProp, UNSUPPORTED,0, 0}, +{VCPICTProp, UNSUPPORTED,0, 0}, +{VCPMBProp, UNSUPPORTED,0, 0}, +{VCPostalBoxProp, UNSUPPORTED,0, 0}, +{VCPostalCodeProp, UNSUPPORTED,0, 0}, +{VCPostalProp, UNSUPPORTED,0, 0}, +{VCPowerShareProp, UNSUPPORTED,0, 0}, +{VCPreferredProp, UNSUPPORTED,0, 0}, +{VCProdigyProp, UNSUPPORTED,0, 0}, +{VCPronunciationProp, UNSUPPORTED,0, 0}, +{VCPSProp, UNSUPPORTED,0, 0}, +{VCPublicKeyProp, UNSUPPORTED,0, 0}, +{VCQPProp, UNSUPPORTED,0, 0}, +{VCQuickTimeProp, UNSUPPORTED,0, 0}, +{VCRegionProp, UNSUPPORTED,0, 0}, +{VCResourcesProp, UNSUPPORTED,0, 0}, +{VCRNumProp, UNSUPPORTED,0, 0}, +{VCStartProp, UNSUPPORTED,0, 0}, +{VCStreetAddressProp, UNSUPPORTED,0, 0}, +{VCSubTypeProp, UNSUPPORTED,0, 0}, +{VCTelephoneProp, UNSUPPORTED,0, 0}, +{VCTIFFProp, UNSUPPORTED,0, 0}, +{VCTitleProp, UNSUPPORTED,0, 0}, +{VCTLXProp, UNSUPPORTED,0, 0}, +{VCURLValueProp, UNSUPPORTED,0, 0}, +{VCVideoProp, UNSUPPORTED,0, 0}, +{VCVoiceProp, UNSUPPORTED,0, 0}, +{VCWAVEProp, UNSUPPORTED,0, 0}, +{VCWMFProp, UNSUPPORTED,0, 0}, +{VCWorkProp, UNSUPPORTED,0, 0}, +{VCX400Prop, UNSUPPORTED,0, 0}, +{VCX509Prop, UNSUPPORTED,0, 0}, + +{0,0,0,0} +}; + + +static void icalvcal_traverse_objects(VObject *object, + icalcomponent* last_comp, + icalproperty* last_prop, + icalvcal_defaults *defaults) +{ + VObjectIterator iterator; + char* name = "[No Name]"; + icalcomponent* subc = 0; + int i; + + if ( vObjectName(object)== 0){ + printf("ERROR, object has no name"); + assert(0); + return; + } + + name = (char*)vObjectName(object); + + /* Lookup this object in the conversion table */ + for (i = 0; conversion_table[i].vcalname != 0; i++){ + if(strcmp(conversion_table[i].vcalname, name) == 0){ + break; + } + } + + /* Did not find the object. It may be an X-property, or an unknown + property */ + if (conversion_table[i].vcalname == 0){ + + /* Handle X properties */ + if(strncmp(name, "X-",2) == 0){ + icalproperty* prop = (icalproperty*)dc_prop(ICAL_X_PROPERTY,object, + last_comp, defaults); + icalproperty_set_x_name(prop,name); + icalcomponent_add_property(last_comp,prop); + } else { + return; + } + + } else { + + /* The vCal property is in the table, and it is not an X + property, so try to convert it to an iCal component, + property or parameter. */ + + switch(conversion_table[i].type){ + + + case COMPONENT: { + subc = + (icalcomponent*)(conversion_table[i].conversion_func + (conversion_table[i].icaltype, + object, last_comp, defaults)); + + if (subc) { + icalcomponent_add_component(last_comp,subc); + } + break; + } + + case PROPERTY: { + + if (vObjectValueType(object) && + conversion_table[i].conversion_func != 0 ) { + + icalproperty* prop = + (icalproperty*)(conversion_table[i].conversion_func + (conversion_table[i].icaltype, + object, last_comp, defaults)); + + if (prop) + icalcomponent_add_property(last_comp,prop); + + last_prop = prop; + + } + break; + } + + case PARAMETER: { + break; + } + + case UNSUPPORTED: { + + /* If the property is listed as UNSUPPORTED, insert a + X_LIC_ERROR property to note this fact. */ + + char temp[1024]; + char* message = "Unsupported vCal property"; + icalparameter *error_param; + icalproperty *error_prop; + + snprintf(temp,1024,"%s: %s",message,name); + + error_param = icalparameter_new_xlicerrortype( + ICAL_XLICERRORTYPE_UNKNOWNVCALPROPERROR + ); + + error_prop = icalproperty_new_xlicerror(temp); + icalproperty_add_parameter(error_prop, error_param); + + icalcomponent_add_property(last_comp,error_prop); + + break; + } + + case IGNORE: { + /* Do Nothing. */ + break; + } + + } + } + + + /* Now, step down into the next vCalproperty */ + + initPropIterator(&iterator,object); + while (moreIteration(&iterator)) { + VObject *eachProp = nextVObject(&iterator); + + /* If 'object' is a component, then the next traversal down + should use it as the 'last_comp' */ + + if(subc!=0){ + icalvcal_traverse_objects(eachProp,subc,last_prop,defaults); + + } else { + icalvcal_traverse_objects(eachProp,last_comp,last_prop,defaults); + } + } +} + +#if 0 + switch (vObjectValueType(object)) { + case VCVT_USTRINGZ: { + char c; + char *t,*s; + s = t = fakeCString(vObjectUStringZValue(object)); + printf(" ustringzstring:%s\n",s); + deleteStr(s); + break; + } + case VCVT_STRINGZ: { + char c; + const char *s = vObjectStringZValue(object); + printf(" stringzstring:%s\n",s); + break; + } + case VCVT_UINT: + { + int i = vObjectIntegerValue(object); + printf(" int:%d\n",i); + break; + } + case VCVT_ULONG: + { + long l = vObjectLongValue(object); + printf(" int:%d\n",l); + break; + } + case VCVT_VOBJECT: + { + printf("ERROR, should not get here\n"); + break; + } + case VCVT_RAW: + case 0: + default: + break; + } + +#endif diff --git a/src/libicalvcal/icalvcal.h b/src/libicalvcal/icalvcal.h new file mode 100644 index 0000000..e5e0be7 --- /dev/null +++ b/src/libicalvcal/icalvcal.h @@ -0,0 +1,54 @@ +/* -*- Mode: C -*-*/ +/*====================================================================== + FILE: icalvcal.h + CREATOR: eric 25 May 00 + + + + (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org + + This program is free software; you can redistribute it and/or modify + it under the terms of either: + + The LGPL as published by the Free Software Foundation, version + 2.1, available at: http://www.fsf.org/copyleft/lesser.html + + Or: + + The Mozilla Public License Version 1.0. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + The original code is icalvcal.h + + +======================================================================*/ + +#ifndef ICALVCAL_H +#define ICALVCAL_H + +#include <libical/ical.h> +#include "vcc.h" + +/* These are used as default values if the values are missing in the vCalendar + file. Gnome Calendar, for example, does not save the URL of the audio alarm, + so we have to add a value here to make a valid iCalendar object. */ +typedef struct _icalvcal_defaults icalvcal_defaults; +struct _icalvcal_defaults { + char *alarm_audio_url; + char *alarm_audio_fmttype; + char *alarm_description; +}; + + +/* Convert a vObject into an icalcomponent */ + +icalcomponent* icalvcal_convert(VObject *object); + + +icalcomponent* icalvcal_convert_with_defaults (VObject *object, + icalvcal_defaults *defaults); + +#endif /* !ICALVCAL_H */ + + + diff --git a/src/libicalvcal/libicalvcal.dsp b/src/libicalvcal/libicalvcal.dsp new file mode 100644 index 0000000..3d01396 --- /dev/null +++ b/src/libicalvcal/libicalvcal.dsp @@ -0,0 +1,132 @@ +# Microsoft Developer Studio Project File - Name="libicalvcal" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=libicalvcal - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libicalvcal.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libicalvcal.mak" CFG="libicalvcal - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libicalvcal - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "libicalvcal - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libicalvcal - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\libical" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "libicalvcal - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libical" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "libicalvcal - Win32 Release" +# Name "libicalvcal - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\icalvcal.c +# End Source File +# Begin Source File + +SOURCE=.\vcaltest.c +# End Source File +# Begin Source File + +SOURCE=.\vcaltmp.c +# End Source File +# Begin Source File + +SOURCE=.\vcc.c +# End Source File +# Begin Source File + +SOURCE=.\vobject.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\icalvcal.h +# End Source File +# Begin Source File + +SOURCE=.\port.h +# End Source File +# Begin Source File + +SOURCE=.\vcaltmp.h +# End Source File +# Begin Source File + +SOURCE=.\vcc.h +# End Source File +# Begin Source File + +SOURCE=.\vobject.h +# End Source File +# End Group +# End Target +# End Project diff --git a/src/libicalvcal/port.h b/src/libicalvcal/port.h new file mode 100644 index 0000000..1768bee --- /dev/null +++ b/src/libicalvcal/port.h @@ -0,0 +1,88 @@ +/*************************************************************************** +(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. + +***************************************************************************/ + +#ifndef __PORT_H__ +#define __PORT_H__ 1 + + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + +/* some of these #defines are commented out because */ +/* Visual C++ sets them on the compiler command line instead */ + +/* #define _DEBUG */ +/* #define WIN32 */ +/* #define WIN16 */ +/* #define _WINDOWS */ +/* #define __MWERKS__ */ +/* #define INCLUDEMFC */ + +#define vCardClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCard" +#define vCalendarClipboardFormat "+//ISBN 1-887687-00-9::versit::PDI//vCalendar" + +/* The above strings vCardClipboardFormat and vCalendarClipboardFormat +are globally unique IDs which can be used to generate clipboard format +ID's as per the requirements of a specific platform. For example, in +Windows they are used as the parameter in a call to RegisterClipboardFormat. +For example: + + CLIPFORMAT foo = RegisterClipboardFormat(vCardClipboardFormat); + +*/ + +#define vCardMimeType "text/x-vCard" +#define vCalendarMimeType "text/x-vCalendar" + +#define DLLEXPORT(t) t + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#define stricmp strcasecmp + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __PORT_H__ */ diff --git a/src/libicalvcal/vcaltest.c b/src/libicalvcal/vcaltest.c new file mode 100644 index 0000000..5528aab --- /dev/null +++ b/src/libicalvcal/vcaltest.c @@ -0,0 +1,118 @@ +#include <stdio.h> +#include <string.h> +#include "vcaltmp.h" + +#if 0 +This testcase would generate a file call "frankcal.vcf" with +the following content: + +BEGIN:VCALENDAR +DCREATED:19960523T100522 +GEO:37.24,-17.87 +PRODID:-//Frank Dawson/Hand Crafted In North Carolina//NONSGML Made By Hand//EN +VERSION:0.3 +BEGIN:VEVENT +DTSTART:19960523T120000 +DTEND:19960523T130000 +DESCRIPTION;QUOTED-PRINTABLE:VERSIT PDI PR Teleconference/Interview =0A= +With Tom Streeter and Frank Dawson - Discuss VERSIT PDI project and vCard and vCalendar=0A= +activities with European Press representatives. +SUMMARY:VERSIT PDI PR Teleconference/Interview +SUBTYPE:PHONE CALL +STATUS:CONFIRMED +TRANSP:19960523T100522-4000F100582713-009251 +UID:http://www.ibm.com/raleigh/fdawson/~c:\or2\orgfiles\versit.or2 +DALARM:19960523T114500;5;3;Your Telecon Starts At Noon!!!; +MALARM:19960522T120000;;;fdawson@raleigh.ibm.com;Remember 05/23 Noon Telecon!!!; +PALARM:19960523T115500;;;c:\or2\organize.exe c:\or2\orgfiles\versit.or2; +X-LDC-OR2-OLE:c:\temp\agenda.doc +END:VEVENT + +BEGIN:VTODO +DUE:19960614T0173000 +DESCRIPTION:Review VCalendar helper API. +END:VTODO + +END:VCALENDAR + +#endif + +FILE *cfp; + +void testVcalAPIs() { + FILE *fp; + VObject *vcal, *vevent; +#if _CONSOLE + cfp = stdout; +#else + cfp = fopen("vcaltest.out","w"); +#endif + if (cfp == 0) return; + vcal = vcsCreateVCal( + "19960523T100522", + "37.24,-17.87", + "-//Frank Dawson/Hand Crafted In North Carolina//NONSGML Made By Hand//EN", + 0, + "0.3" + ); + + vevent = vcsAddEvent( + vcal, + "19960523T120000", + "19960523T130000", + "VERSIT PDI PR Teleconference/Interview \nWith Tom Streeter and Frank Dawson - Discuss VERSIT PDI project and vCard and vCalendar\nactivities with European Press representatives.", + "VERSIT PDI PR Teleconference/Interview", + "PHONE CALL", + 0, + "CONFIRMED", + "19960523T100522-4000F100582713-009251", + "http://www.ibm.com/raleigh/fdawson/~c:\\or2\\orgfiles\\versit.or2", + 0 + ); + + vcsAddDAlarm(vevent, "19960523T114500", "5", "3", + "Your Telecon Starts At Noon!!!"); + vcsAddMAlarm(vevent, "19960522T120000", 0, 0, "fdawson@raleigh.ibm.com", + "Remember 05/23 Noon Telecon!!!"); + vcsAddPAlarm(vevent, "19960523T115500", 0 ,0, + "c:\\or2\\organize.exe c:\\or2\\orgfiles\\versit.or2"); + + addPropValue(vevent, "X-LDC-OR2-OLE", "c:\\temp\\agenda.doc"); + + vcsAddTodo( + vcal, + 0, + "19960614T0173000", + 0, + "Review VCalendar helper API.", + 0, + 0, + 0, + 0, + 0, + 0 + ); + + /* now do something to the resulting VObject */ + /* pretty print on stdout for fun */ + printVObject(cfp,vcal); + /* open the output text file */ + +#define OUTFILE "frankcal.vcf" + + fp = fopen(OUTFILE, "w"); + if (fp) { + /* write it in text form */ + writeVObject(fp,vcal); + fclose(fp); + } + else { + fprintf(cfp,"open output file '%s' failed\n", OUTFILE); + } + if (cfp != stdout) fclose(cfp); + } + +void main() { + testVcalAPIs(); + } + diff --git a/src/libicalvcal/vcaltmp.c b/src/libicalvcal/vcaltmp.c new file mode 100644 index 0000000..ccb21a6 --- /dev/null +++ b/src/libicalvcal/vcaltmp.c @@ -0,0 +1,337 @@ +/* +This module provides some helper APIs for creating +a VCalendar object. + +Note on APIs: + 1. The APIs does not attempt to verify if the arguments + passed are correct. + 2. Where the argument to an API is not applicable, pass + the value 0. + 3. See the test program at the bottom of this file as an + example of usage. + 4. This code calls APIs in vobject.c. + +*/ + +/*************************************************************************** +(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. + +***************************************************************************/ + + +#include <stdio.h> +#include <string.h> +#include "vcaltmp.h" + + +DLLEXPORT(VObject*) vcsCreateVCal( + char *date_created, + char *location, + char *product_id, + char *time_zone, + char *version + ) + { + VObject *vcal = newVObject(VCCalProp); +#define Z(p,v) if (v) addPropValue(vcal,p,v); + Z(VCDCreatedProp, date_created); + Z(VCLocationProp, location) + Z(VCProdIdProp, product_id) + Z(VCTimeZoneProp, time_zone) + Z(VCVersionProp, version) +#undef Z + return vcal; + } + + +DLLEXPORT(VObject*) vcsAddEvent( + VObject *vcal, + char *start_date_time, + char *end_date_time, + char *description, + char *summary, + char *categories, + char *classification, + char *status, + char *transparency, + char *uid, + char *url + ) + { + VObject *vevent = addProp(vcal,VCEventProp); +#define Z(p,v) if (v) addPropValue(vevent,p,v); + Z(VCDTstartProp,start_date_time); + Z(VCDTendProp,end_date_time); + if (description) { + VObject *p = addPropValue(vevent,VCDescriptionProp,description); + if (strchr(description,'\n')) + addProp(p,VCQuotedPrintableProp); + } + Z(VCSummaryProp,summary); + Z(VCCategoriesProp,categories); + Z(VCClassProp,classification); + Z(VCStatusProp,status); + Z(VCTranspProp,transparency); + Z(VCUniqueStringProp,uid); + Z(VCURLProp,url); +#undef Z + return vevent; + } + + +DLLEXPORT(VObject*) vcsAddTodo( + VObject *vcal, + char *start_date_time, + char *due_date_time, + char *date_time_complete, + char *description, + char *summary, + char *priority, + char *classification, + char *status, + char *uid, + char *url + ) + { + VObject *vtodo = addProp(vcal,VCTodoProp); +#define Z(p,v) if (v) addPropValue(vtodo,p,v); + Z(VCDTstartProp,start_date_time); + Z(VCDueProp,due_date_time); + Z(VCCompletedProp,date_time_complete); + if (description) { + VObject *p = addPropValue(vtodo,VCDescriptionProp,description); + if (strchr(description,'\n')) + addProp(p,VCQuotedPrintableProp); + } + Z(VCSummaryProp,summary); + Z(VCPriorityProp,priority); + Z(VCClassProp,classification); + Z(VCStatusProp,status); + Z(VCUniqueStringProp,uid); + Z(VCURLProp,url); +#undef Z + return vtodo; + } + + +DLLEXPORT(VObject*) vcsAddAAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *audio_content + ) + { + VObject *aalarm= addProp(vevent,VCAAlarmProp); +#define Z(p,v) if (v) addPropValue(aalarm,p,v); + Z(VCRunTimeProp,run_time); + Z(VCSnoozeTimeProp,snooze_time); + Z(VCRepeatCountProp,repeat_count); + Z(VCAudioContentProp,audio_content); +#undef Z + return aalarm; + } + + +DLLEXPORT(VObject*) vcsAddMAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *email_address, + char *note + ) + { + VObject *malarm= addProp(vevent,VCMAlarmProp); +#define Z(p,v) if (v) addPropValue(malarm,p,v); + Z(VCRunTimeProp,run_time); + Z(VCSnoozeTimeProp,snooze_time); + Z(VCRepeatCountProp,repeat_count); + Z(VCEmailAddressProp,email_address); + Z(VCNoteProp,note); +#undef Z + return malarm; + } + + +DLLEXPORT(VObject*) vcsAddDAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *display_string + ) + { + VObject *dalarm= addProp(vevent,VCDAlarmProp); +#define Z(p,v) if (v) addPropValue(dalarm,p,v); + Z(VCRunTimeProp,run_time); + Z(VCSnoozeTimeProp,snooze_time); + Z(VCRepeatCountProp,repeat_count); + Z(VCDisplayStringProp,display_string); +#undef Z + return dalarm; + } + + +DLLEXPORT(VObject*) vcsAddPAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *procedure_name + ) + { + VObject *palarm= addProp(vevent,VCPAlarmProp); +#define Z(p,v) if (v) addPropValue(palarm,p,v); + Z(VCRunTimeProp,run_time); + Z(VCSnoozeTimeProp,snooze_time); + Z(VCRepeatCountProp,repeat_count); + Z(VCProcedureNameProp,procedure_name); +#undef Z + return palarm; + } + + +#ifdef _TEST + +#if 0 +This testcase would generate a file call "frankcal.vcf" with +the following content: + +BEGIN:VCALENDAR +DCREATED:19960523T100522 +GEO:37.24,-17.87 +PRODID:-//Frank Dawson/Hand Crafted In North Carolina//NONSGML Made By Hand//EN +VERSION:0.3 +BEGIN:VEVENT +DTSTART:19960523T120000 +DTEND:19960523T130000 +DESCRIPTION;QUOTED-PRINTABLE:VERSIT PDI PR Teleconference/Interview =0A= +With Tom Streeter and Frank Dawson - Discuss VERSIT PDI project and vCard and vCalendar=0A= +activities with European Press representatives. +SUMMARY:VERSIT PDI PR Teleconference/Interview +CATEGORIES:PHONE CALL +STATUS:CONFIRMED +TRANSP:19960523T100522-4000F100582713-009251 +UID:http://www.ibm.com/raleigh/fdawson/~c:\or2\orgfiles\versit.or2 +DALARM:19960523T114500;5;3;Your Telecon Starts At Noon!!!; +MALARM:19960522T120000;;;fdawson@raleigh.ibm.com;Remember 05/23 Noon Telecon!!!; +PALARM:19960523T115500;;;c:\or2\organize.exe c:\or2\orgfiles\versit.or2; +X-LDC-OR2-OLE:c:\temp\agenda.doc +END:VEVENT + +BEGIN:VTODO +DUE:19960614T0173000 +DESCRIPTION:Review VCalendar helper API. +END:VTODO + +END:VCALENDAR + +#endif + +void testVcalAPIs() { + FILE *fp; + VObject *vcal = vcsCreateVCal( + "19960523T100522", + "37.24,-17.87", + "-//Frank Dawson/Hand Crafted In North Carolina//NONSGML Made By Hand//EN", + 0, + "0.3" + ); + + VObject *vevent = vcsAddEvent( + vcal, + "19960523T120000", + "19960523T130000", + "VERSIT PDI PR Teleconference/Interview \nWith Tom Streeter and Frank Dawson - Discuss VERSIT PDI project and vCard and vCalendar\nactivities with European Press representatives.", + "VERSIT PDI PR Teleconference/Interview", + "PHONE CALL", + 0, + "CONFIRMED", + "19960523T100522-4000F100582713-009251", + "http://www.ibm.com/raleigh/fdawson/~c:\\or2\\orgfiles\\versit.or2", + 0 + ); + + vcsAddDAlarm(vevent, "19960523T114500", "5", "3", + "Your Telecon Starts At Noon!!!"); + vcsAddMAlarm(vevent, "19960522T120000", 0, 0, "fdawson@raleigh.ibm.com", + "Remember 05/23 Noon Telecon!!!"); + vcsAddPAlarm(vevent, "19960523T115500", 0 ,0, + "c:\\or2\\organize.exe c:\\or2\\orgfiles\\versit.or2"); + + addPropValue(vevent, "X-LDC-OR2-OLE", "c:\\temp\\agenda.doc"); + + vcsAddTodo( + vcal, + 0, + "19960614T0173000", + 0, + "Review VCalendar helper API.", + 0, + 0, + 0, + 0, + 0, + 0 + ); + + /* now do something to the resulting VObject */ + /* pretty print on stdout for fun */ + printVObject(vcal); + /* open the output text file */ + +#define OUTFILE "frankcal.vcf" + + fp = fopen(OUTFILE, "w"); + if (fp) { + /* write it in text form */ + writeVObject(fp,vcal); + fclose(fp); + } + else { + printf("open output file '%s' failed\n", OUTFILE); + } + } + +void main() { + testVcalAPIs(); + } + +#endif + + +/* end of source file vcaltmp.c */ diff --git a/src/libicalvcal/vcaltmp.h b/src/libicalvcal/vcaltmp.h new file mode 100644 index 0000000..4c4afde --- /dev/null +++ b/src/libicalvcal/vcaltmp.h @@ -0,0 +1,128 @@ +/*************************************************************************** +(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. + +***************************************************************************/ + +#include "vcc.h" + +#ifndef __VCALTMP_H__ +#define __VCALTMP_H__ + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + +extern DLLEXPORT(VObject*) vcsCreateVCal( + char *date_created, + char *location, + char *product_id, + char *time_zone, + char *version + ); + +extern DLLEXPORT(VObject*) vcsAddEvent( + VObject *vcal, + char *start_date_time, + char *end_date_time, + char *description, + char *summary, + char *categories, + char *classification, + char *status, + char *transparency, + char *uid, + char *url + ); + + +extern DLLEXPORT(VObject*) vcsAddTodo( + VObject *vcal, + char *start_date_time, + char *due_date_time, + char *date_time_complete, + char *description, + char *summary, + char *priority, + char *classification, + char *status, + char *uid, + char *url + ); + + +extern DLLEXPORT(VObject*) vcsAddAAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *audio_content + ); + + +extern DLLEXPORT(VObject*) vcsAddMAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *email_address, + char *note + ); + + +extern DLLEXPORT(VObject*) vcsAddDAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *display_string + ); + + +extern DLLEXPORT(VObject*) vcsAddPAlarm( + VObject *vevent, + char *run_time, + char *snooze_time, + char *repeat_count, + char *procedure_name + ); + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __VCALTMP_H__ */ + + diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c new file mode 100644 index 0000000..7f41ffe --- /dev/null +++ b/src/libicalvcal/vcc.c @@ -0,0 +1,2820 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + EQ = 258, + COLON = 259, + DOT = 260, + SEMICOLON = 261, + SPACE = 262, + HTAB = 263, + LINESEP = 264, + NEWLINE = 265, + BEGIN_VCARD = 266, + END_VCARD = 267, + BEGIN_VCAL = 268, + END_VCAL = 269, + BEGIN_VEVENT = 270, + END_VEVENT = 271, + BEGIN_VTODO = 272, + END_VTODO = 273, + ID = 274, + STRING = 275 + }; +#endif +/* Tokens. */ +#define EQ 258 +#define COLON 259 +#define DOT 260 +#define SEMICOLON 261 +#define SPACE 262 +#define HTAB 263 +#define LINESEP 264 +#define NEWLINE 265 +#define BEGIN_VCARD 266 +#define END_VCARD 267 +#define BEGIN_VCAL 268 +#define END_VCAL 269 +#define BEGIN_VEVENT 270 +#define END_VEVENT 271 +#define BEGIN_VTODO 272 +#define END_VTODO 273 +#define ID 274 +#define STRING 275 + + + + +/* Copy the first part of user declarations. */ +#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 */ +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#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 +#define YYPREFIX "mime_" + + +#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> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "vcc.h" + +/**** Types, Constants ****/ + +#define YYDEBUG 1 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 50 /* ~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 Parse_Debug(const char *s); + static void yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yylex(void); +int yyparse(void); + +enum LexMode { + L_NORMAL, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static void lexClearToken(void); +static char* lexGet1Value(void); +static int lexGeta(void); +static int lexGetc(void); +static char lexGetc_(void); +static char* lexGetDataFromBase64(void); +static char* lexGetQuotedPrintable(void); +static char* lexGetWord(void); +static int lexLookahead(void); +static char* lexLookaheadWord(void); +static void lexPopMode(int top); +static void lexPushMode(enum LexMode mode); +static void lexSkipLookahead(void); +static void lexSkipLookaheadWord(void); +static void lexSkipWhite(void); +static char* lexStr(void); +static int lexWithinMode(enum LexMode mode); +static void enterAttr(const char *s1, const char *s2); +static void enterProps(const char *s); +static void enterValues(const char *value); +static void finiLex(void); +static void mime_error_(char *s); +static VObject* Parse_MIMEHelper(void); +static VObject* popVObject(void); +static int pushVObject(const char *prop); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 197 "vcc.y" +{ + char *str; + VObject *vobj; + } +/* Line 187 of yacc.c. */ +#line 333 "vcc.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 346 "vcc.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 12 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 56 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 21 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 31 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 47 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 62 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 275 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 6, 10, 12, 14, 16, 17, + 22, 23, 27, 30, 32, 33, 39, 41, 42, 46, + 48, 51, 53, 56, 58, 62, 64, 65, 70, 72, + 74, 75, 76, 81, 82, 86, 89, 91, 93, 95, + 97, 98, 103, 104, 108, 109, 114, 115 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 22, 0, -1, 23, -1, -1, 25, 24, 23, -1, + 25, -1, 26, -1, 41, -1, -1, 11, 27, 29, + 12, -1, -1, 11, 28, 12, -1, 30, 29, -1, + 30, -1, -1, 32, 4, 31, 38, 9, -1, 1, + -1, -1, 37, 33, 34, -1, 37, -1, 35, 34, + -1, 35, -1, 6, 36, -1, 37, -1, 37, 3, + 37, -1, 19, -1, -1, 40, 6, 39, 38, -1, + 40, -1, 20, -1, -1, -1, 13, 42, 44, 14, + -1, -1, 13, 43, 14, -1, 45, 44, -1, 45, + -1, 46, -1, 49, -1, 29, -1, -1, 15, 47, + 29, 16, -1, -1, 15, 48, 16, -1, -1, 17, + 50, 29, 18, -1, -1, 17, 51, 18, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 225, 225, 229, 228, 231, 235, 236, 241, 240, + 251, 250, 262, 263, 267, 266, 276, 280, 279, 284, + 290, 291, 294, 297, 301, 308, 311, 311, 312, 316, + 317, 322, 321, 327, 326, 332, 333, 337, 338, 339, + 344, 343, 355, 354, 368, 367, 379, 378 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "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", "STRING", "$accept", "mime", "vobjects", "@1", + "vobject", "vcard", "@2", "@3", "items", "item", "@4", "prop", "@5", + "attr_params", "attr_param", "attr", "name", "values", "@6", "value", + "vcal", "@7", "@8", "calitems", "calitem", "eventitem", "@9", "@10", + "todoitem", "@11", "@12", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 21, 22, 24, 23, 23, 25, 25, 27, 26, + 28, 26, 29, 29, 31, 30, 30, 33, 32, 32, + 34, 34, 35, 36, 36, 37, 39, 38, 38, 40, + 40, 42, 41, 43, 41, 44, 44, 45, 45, 45, + 47, 46, 48, 46, 50, 49, 51, 49 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 0, 3, 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 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 8, 31, 0, 2, 3, 6, 7, 0, 0, + 0, 0, 1, 0, 16, 25, 0, 0, 0, 17, + 11, 40, 44, 39, 0, 0, 37, 38, 34, 4, + 9, 12, 14, 0, 0, 0, 0, 0, 32, 35, + 30, 0, 18, 21, 0, 43, 0, 47, 29, 0, + 28, 22, 23, 20, 41, 45, 15, 26, 0, 30, + 24, 27 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 3, 4, 13, 5, 6, 8, 9, 23, 17, + 40, 18, 33, 42, 43, 51, 19, 49, 59, 50, + 7, 10, 11, 24, 25, 26, 34, 35, 27, 36, + 37 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -18 +static const yytype_int8 yypact[] = +{ + -5, -10, -11, 5, -18, 10, -18, -18, 3, -1, + 12, 16, -18, -5, -18, -18, 20, 0, 29, 30, + -18, 19, 18, -18, 23, 6, -18, -18, -18, -18, + -18, -18, -18, 32, 3, 24, 3, 21, -18, -18, + 22, 25, -18, 32, 27, -18, 28, -18, -18, 36, + 41, -18, 45, -18, -18, -18, -18, -18, 25, 22, + -18, -18 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -18, -18, 37, -18, -18, -18, -18, -18, -8, -18, + -18, -18, -18, 8, -18, -18, -17, -7, -18, -18, + -18, -18, -18, 31, -18, -18, -18, -18, -18, -18, + -18 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -47 +static const yytype_int8 yytable[] = +{ + 16, 14, -10, -33, 14, 12, 1, 14, 2, 31, + -5, 20, -13, 14, -13, -13, -13, -13, -13, 15, + -36, 21, 15, 22, 52, 15, 44, 21, 46, 22, + 28, 15, 30, 32, -19, -42, -46, 38, 41, 47, + 45, 60, 48, 54, 15, 56, 55, 57, 58, 0, + 29, 53, 61, 0, 0, 0, 39 +}; + +static const yytype_int8 yycheck[] = +{ + 8, 1, 12, 14, 1, 0, 11, 1, 13, 17, + 0, 12, 12, 1, 14, 15, 16, 17, 18, 19, + 14, 15, 19, 17, 41, 19, 34, 15, 36, 17, + 14, 19, 12, 4, 4, 16, 18, 14, 6, 18, + 16, 58, 20, 16, 19, 9, 18, 6, 3, -1, + 13, 43, 59, -1, -1, -1, 25 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 11, 13, 22, 23, 25, 26, 41, 27, 28, + 42, 43, 0, 24, 1, 19, 29, 30, 32, 37, + 12, 15, 17, 29, 44, 45, 46, 49, 14, 23, + 12, 29, 4, 33, 47, 48, 50, 51, 14, 44, + 31, 6, 34, 35, 29, 16, 29, 18, 20, 38, + 40, 36, 37, 34, 16, 18, 9, 6, 3, 39, + 37, 38 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 3: +#line 229 "vcc.y" + { addList(&vObjList, (yyvsp[(1) - (1)].vobj)); curObj = 0; } + break; + + case 5: +#line 232 "vcc.y" + { addList(&vObjList, (yyvsp[(1) - (1)].vobj)); curObj = 0; } + break; + + case 8: +#line 241 "vcc.y" + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + break; + + case 9: +#line 246 "vcc.y" + { + lexPopMode(0); + (yyval.vobj) = popVObject(); + } + break; + + case 10: +#line 251 "vcc.y" + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + break; + + case 11: +#line 256 "vcc.y" + { + lexPopMode(0); + (yyval.vobj) = popVObject(); + } + break; + + case 14: +#line 267 "vcc.y" + { + lexPushMode(L_VALUES); + } + break; + + case 15: +#line 271 "vcc.y" + { + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); + } + break; + + case 17: +#line 280 "vcc.y" + { + enterProps((yyvsp[(1) - (1)].str)); + } + break; + + case 19: +#line 285 "vcc.y" + { + enterProps((yyvsp[(1) - (1)].str)); + } + break; + + case 23: +#line 298 "vcc.y" + { + enterAttr((yyvsp[(1) - (1)].str),0); + } + break; + + case 24: +#line 302 "vcc.y" + { + enterAttr((yyvsp[(1) - (3)].str),(yyvsp[(3) - (3)].str)); + + } + break; + + case 26: +#line 311 "vcc.y" + { enterValues((yyvsp[(1) - (2)].str)); } + break; + + case 28: +#line 313 "vcc.y" + { enterValues((yyvsp[(1) - (1)].str)); } + break; + + case 30: +#line 317 "vcc.y" + { (yyval.str) = 0; } + break; + + case 31: +#line 322 "vcc.y" + { if (!pushVObject(VCCalProp)) YYERROR; } + break; + + case 32: +#line 325 "vcc.y" + { (yyval.vobj) = popVObject(); } + break; + + case 33: +#line 327 "vcc.y" + { if (!pushVObject(VCCalProp)) YYERROR; } + break; + + case 34: +#line 329 "vcc.y" + { (yyval.vobj) = popVObject(); } + break; + + case 40: +#line 344 "vcc.y" + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + break; + + case 41: +#line 350 "vcc.y" + { + lexPopMode(0); + popVObject(); + } + break; + + case 42: +#line 355 "vcc.y" + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + break; + + case 43: +#line 360 "vcc.y" + { + lexPopMode(0); + popVObject(); + } + break; + + case 44: +#line 368 "vcc.y" + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + break; + + case 45: +#line 374 "vcc.y" + { + lexPopMode(0); + popVObject(); + } + break; + + case 46: +#line 379 "vcc.y" + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + break; + + case 47: +#line 384 "vcc.y" + { + lexPopMode(0); + popVObject(); + } + break; + + +/* Line 1267 of yacc.c. */ +#line 1782 "vcc.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#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) { + char *p1, *p2; + wchar_t *p3; + int i; + + /* If the property already has a string value, we append this one, + using ';' to separate the values. */ + if (vObjectUStringZValue(curProp)) { + p1 = fakeCString(vObjectUStringZValue(curProp)); + i = strlen(p1)+strlen(value)+2; + p2 = malloc(i); + snprintf(p2,i,"%s;%s",p1,value); + deleteStr(p1); + p3 = (wchar_t *) vObjectUStringZValue(curProp); + free(p3); + setVObjectUStringZValue_(curProp,fakeUnicode(p2,0)); + deleteStr(p2); + } else { + setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); + } + } + } + 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 = NULL; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + if (stricmp(p1,VCBase64Prop) == 0 || (s2 && stricmp(p2,VCBase64Prop)==0)) + lexPushMode(L_BASE64); + else if (stricmp(p1,VCQuotedPrintableProp) == 0 + || (s2 && stricmp(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 char 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 != ';') { + 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 (!stricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!stricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!stricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!stricmp(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 char * 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(); + 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 if ((c == ' ') || (c == '\t')) { + continue; + } 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' && lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + c = lexGetc(); + } + } + return NULL; + } + 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 0; + } + +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() + { + char cur; + + lexClearToken(); + do { + cur = lexGetc(); + switch (cur) { + case '=': { + int c = 0; + int next[2]; + int i; + for (i = 0; i < 2; i++) { + next[i] = lexGetc(); + if (next[i] >= '0' && next[i] <= '9') + c = c * 16 + next[i] - '0'; + else if (next[i] >= 'A' && next[i] <= 'F') + c = c * 16 + next[i] - 'A' + 10; + else + break; + } + if (i == 0) { + /* single '=' follow by LINESEP is continuation sign? */ + if (next[0] == '\n') { + ++mime_lineNum; + } + else { + lexPushLookaheadc('='); + goto EndString; + } + } + else if (i == 1) { + lexPushLookaheadc(next[1]); + lexPushLookaheadc(next[0]); + lexAppendc('='); + } else { + lexAppendc(c); + } + break; + } /* '=' */ + case '\n': { + lexPushLookaheadc('\n'); + goto EndString; + } + case (char)EOF: + break; + default: + lexAppendc(cur); + break; + } /* switch */ + } while (cur != (char)EOF); + +EndString: + lexAppendc(0); + return lexStr(); + } /* LexQuotedPrintable */ + +int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + if (c == ';') { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); +#ifdef _SUPPORT_LINE_FOLDING + handleMoreRFC822LineBreak(c); +#endif + 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... */ + p = lexGetDataFromBase64(); + yylval.str = p; + return STRING; + } + 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. */ +/* 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 (isalpha(c)) { + char *t = lexGetWord(); + yylval.str = t; + if (!stricmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!stricmp(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[256]; + snprintf(msg, sizeof(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; + } + +static void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + snprintf(msg,sizeof(msg),"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +static void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + + diff --git a/src/libicalvcal/vcc.h b/src/libicalvcal/vcc.h new file mode 100644 index 0000000..0e52034 --- /dev/null +++ b/src/libicalvcal/vcc.h @@ -0,0 +1,80 @@ +/*************************************************************************** +(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. + +***************************************************************************/ + +#ifndef __VCC_H__ +#define __VCC_H__ 1 + +#include "vobject.h" + + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + +typedef void (*MimeErrorHandler)(char *); + +extern DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler); + +extern DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len); +extern DLLEXPORT(VObject*) Parse_MIME_FromFileName(char* fname); + + +/* NOTE regarding Parse_MIME_FromFile +The function above, Parse_MIME_FromFile, comes in two flavors, +neither of which is exported from the DLL. Each version takes +a CFile or FILE* as a parameter, neither of which can be +passed across a DLL interface (at least that is my experience). +If you are linking this code into your build directly then +you may find them a more convenient API that the other flavors +that take a file name. If you use them with the DLL LIB you +will get a link error. +*/ + + +#if INCLUDEMFC +extern VObject* Parse_MIME_FromFile(CFile *file); +#else +extern VObject* Parse_MIME_FromFile(FILE *file); +#endif + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __VCC_H__ */ + diff --git a/src/libicalvcal/vcc.y b/src/libicalvcal/vcc.y new file mode 100644 index 0000000..34bcfaf --- /dev/null +++ b/src/libicalvcal/vcc.y @@ -0,0 +1,1213 @@ +%{ + +/*************************************************************************** +(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 + +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#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 +#define YYPREFIX "mime_" + + +#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> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "vcc.h" + +/**** Types, Constants ****/ + +#define YYDEBUG 1 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 50 /* ~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 Parse_Debug(const char *s); + static void yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yylex(void); +int yyparse(void); + +enum LexMode { + L_NORMAL, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static void lexClearToken(void); +static char* lexGet1Value(void); +static int lexGeta(void); +static int lexGetc(void); +static char lexGetc_(void); +static char* lexGetDataFromBase64(void); +static char* lexGetQuotedPrintable(void); +static char* lexGetWord(void); +static int lexLookahead(void); +static char* lexLookaheadWord(void); +static void lexPopMode(int top); +static void lexPushMode(enum LexMode mode); +static void lexSkipLookahead(void); +static void lexSkipLookaheadWord(void); +static void lexSkipWhite(void); +static char* lexStr(void); +static int lexWithinMode(enum LexMode mode); +static void enterAttr(const char *s1, const char *s2); +static void enterProps(const char *s); +static void enterValues(const char *value); +static void finiLex(void); +static void mime_error_(char *s); +static VObject* Parse_MIMEHelper(void); +static VObject* popVObject(void); +static int pushVObject(const char *prop); + +%} + +/***************************************************************************/ +/*** 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: vobject + { addList(&vObjList, $1); curObj = 0; } + vobjects + | 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: item items + | 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_param attr_params + | 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: calitem calitems + | 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) { + char *p1, *p2; + wchar_t *p3; + int i; + + /* If the property already has a string value, we append this one, + using ';' to separate the values. */ + if (vObjectUStringZValue(curProp)) { + p1 = fakeCString(vObjectUStringZValue(curProp)); + i = strlen(p1)+strlen(value)+2; + p2 = malloc(i); + snprintf(p2,i,"%s;%s",p1,value); + deleteStr(p1); + p3 = (wchar_t *) vObjectUStringZValue(curProp); + free(p3); + setVObjectUStringZValue_(curProp,fakeUnicode(p2,0)); + deleteStr(p2); + } else { + setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); + } + } + } + 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 = NULL; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + if (stricmp(p1,VCBase64Prop) == 0 || (s2 && stricmp(p2,VCBase64Prop)==0)) + lexPushMode(L_BASE64); + else if (stricmp(p1,VCQuotedPrintableProp) == 0 + || (s2 && stricmp(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 char 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 != ';') { + 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 (!stricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!stricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!stricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!stricmp(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 char * 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(); + 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 if ((c == ' ') || (c == '\t')) { + continue; + } 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' && lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + c = lexGetc(); + } + } + return NULL; + } + 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 0; + } + +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() + { + char cur; + + lexClearToken(); + do { + cur = lexGetc(); + switch (cur) { + case '=': { + int c = 0; + int next[2]; + int i; + for (i = 0; i < 2; i++) { + next[i] = lexGetc(); + if (next[i] >= '0' && next[i] <= '9') + c = c * 16 + next[i] - '0'; + else if (next[i] >= 'A' && next[i] <= 'F') + c = c * 16 + next[i] - 'A' + 10; + else + break; + } + if (i == 0) { + /* single '=' follow by LINESEP is continuation sign? */ + if (next[0] == '\n') { + ++mime_lineNum; + } + else { + lexPushLookaheadc('='); + goto EndString; + } + } + else if (i == 1) { + lexPushLookaheadc(next[1]); + lexPushLookaheadc(next[0]); + lexAppendc('='); + } else { + lexAppendc(c); + } + break; + } /* '=' */ + case '\n': { + lexPushLookaheadc('\n'); + goto EndString; + } + case (char)EOF: + break; + default: + lexAppendc(cur); + break; + } /* switch */ + } while (cur != (char)EOF); + +EndString: + lexAppendc(0); + return lexStr(); + } /* LexQuotedPrintable */ + +int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + if (c == ';') { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); +#ifdef _SUPPORT_LINE_FOLDING + handleMoreRFC822LineBreak(c); +#endif + 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... */ + p = lexGetDataFromBase64(); + yylval.str = p; + return STRING; + } + 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. */ +/* 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 (isalpha(c)) { + char *t = lexGetWord(); + yylval.str = t; + if (!stricmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!stricmp(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[256]; + snprintf(msg, sizeof(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; + } + +static void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + snprintf(msg,sizeof(msg),"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +static void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + diff --git a/src/libicalvcal/vctest.c b/src/libicalvcal/vctest.c new file mode 100644 index 0000000..7975d1e --- /dev/null +++ b/src/libicalvcal/vctest.c @@ -0,0 +1,95 @@ + +#include <stdio.h> +#include <string.h> +#include "vcc.h" + +FILE *cfp; + +void myMimeErrorHandler(char *s) +{ + printf("%s\n", s); +} + +void main(int argc, char **argv) +{ + int testmem = 0; + + char * foo[2] = {"foo","alden.vcf"}; + +argc = 2; +argv = foo; + +#ifdef _CONSOLE + cfp = stdout; + registerMimeErrorHandler(myMimeErrorHandler); +#else + cfp = fopen("vctest.out", "w"); + if (!cfp) return; +#endif + ++argv; + while (--argc) { + FILE *fp; + if (strcmp(*argv,"-testmem") == 0) { + testmem = 1; + argv++; + continue; + } + fprintf(cfp,"processing %s\n",*argv); + fp = fopen(*argv,"r"); + if (!fp) { + fprintf(cfp,"error opening file\n"); + } + else { + VObject *v, *t; + FILE *ofp; + char buf[256]; + char *p; + strcpy(buf,*argv); + p = strchr(buf,'.'); + if (p) *p = 0; + strcat(buf,".out"); + fprintf(cfp,"reading text input from '%s'...\n", *argv); + /*v = Parse_MIME_FromFile(fp); */ + v = Parse_MIME_FromFileName(*argv); + writeVObjectToFile(buf,v); + cleanVObject(v); + + /* + fprintf(cfp,"pretty print internal format of '%s'...\n", *argv); + ofp = fopen(buf,"w"); + while (v) { + printVObject(cfp,v); + if (testmem) { + char *s, *p; + fprintf(cfp,"test writing to mem...\n"); + p = s = writeMemVObject(0,0,v); + if (s) { + while (*s) { + fputc(*s,ofp); + s++; + } + free(p); + } + } + else { + writeVObject(ofp,v); + } + t = v; + v = nextVObjectInList(v); + cleanVObject(t); + } + + fclose(ofp); + fclose(fp); + */ + } + + cleanStrTbl(); + argv++; + + } + + if (cfp != stdout) fclose(cfp); + +} + diff --git a/src/libicalvcal/vobject.c b/src/libicalvcal/vobject.c new file mode 100644 index 0000000..e4fc7ad --- /dev/null +++ b/src/libicalvcal/vobject.c @@ -0,0 +1,1455 @@ +/*************************************************************************** +(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: vobject.c + * doc: vobject and APIs to construct vobject, APIs pretty print + * vobject, and convert a vobject into its textual representation. + */ + +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp +#endif + +#include "vobject.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> + + +#define NAME_OF(o) o->id +#define VALUE_TYPE(o) o->valType +#define STRINGZ_VALUE_OF(o) o->val.strs +#define USTRINGZ_VALUE_OF(o) o->val.ustrs +#define INTEGER_VALUE_OF(o) o->val.i +#define LONG_VALUE_OF(o) o->val.l +#define ANY_VALUE_OF(o) o->val.any +#define VOBJECT_VALUE_OF(o) o->val.vobj + +typedef union ValueItem { + const char *strs; + const wchar_t *ustrs; + unsigned int i; + unsigned long l; + void *any; + VObject *vobj; + } ValueItem; + +struct VObject { + VObject *next; + const char *id; + VObject *prop; + unsigned short valType; + ValueItem val; + }; + +typedef struct StrItem StrItem; + +struct StrItem { + StrItem *next; + const char *s; + unsigned int refCnt; + }; + +const char** fieldedProp; + + + +/*---------------------------------------------------------------------- + The following functions involve with memory allocation: + newVObject + deleteVObject + dupStr + deleteStr + newStrItem + deleteStrItem + ----------------------------------------------------------------------*/ + +DLLEXPORT(VObject*) newVObject_(const char *id) +{ + VObject *p = (VObject*)malloc(sizeof(VObject)); + p->next = 0; + p->id = id; + p->prop = 0; + VALUE_TYPE(p) = 0; + ANY_VALUE_OF(p) = 0; + return p; +} + +DLLEXPORT(VObject*) newVObject(const char *id) +{ + return newVObject_(lookupStr(id)); +} + +DLLEXPORT(void) deleteVObject(VObject *p) +{ + unUseStr(p->id); + free(p); +} + +DLLEXPORT(char*) dupStr(const char *s, unsigned int size) +{ + char *t; + if (size == 0) { + size = strlen(s); + } + t = (char*)malloc(size+1); + if (t) { + memcpy(t,s,size); + t[size] = 0; + return t; + } + else { + return (char*)0; + } +} + +DLLEXPORT(void) deleteStr(const char *p) +{ + if (p) free((void*)p); +} + + +static StrItem* newStrItem(const char *s, StrItem *next) +{ + StrItem *p = (StrItem*)malloc(sizeof(StrItem)); + p->next = next; + p->s = s; + p->refCnt = 1; + return p; +} + +static void deleteStrItem(StrItem *p) +{ + free((void*)p); +} + + +/*---------------------------------------------------------------------- + The following function provide accesses to VObject's value. + ----------------------------------------------------------------------*/ + +DLLEXPORT(const char*) vObjectName(VObject *o) +{ + return NAME_OF(o); +} + +DLLEXPORT(void) setVObjectName(VObject *o, const char* id) +{ + NAME_OF(o) = id; +} + +DLLEXPORT(const char*) vObjectStringZValue(VObject *o) +{ + return STRINGZ_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s) +{ + STRINGZ_VALUE_OF(o) = dupStr(s,0); + VALUE_TYPE(o) = VCVT_STRINGZ; +} + +DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s) +{ + STRINGZ_VALUE_OF(o) = s; + VALUE_TYPE(o) = VCVT_STRINGZ; +} + +DLLEXPORT(const wchar_t*) vObjectUStringZValue(VObject *o) +{ + return USTRINGZ_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectUStringZValue(VObject *o, const wchar_t *s) +{ + USTRINGZ_VALUE_OF(o) = (wchar_t*) dupStr((char*)s,(uStrLen(s)+1)*2); + VALUE_TYPE(o) = VCVT_USTRINGZ; +} + +DLLEXPORT(void) setVObjectUStringZValue_(VObject *o, const wchar_t *s) +{ + USTRINGZ_VALUE_OF(o) = s; + VALUE_TYPE(o) = VCVT_USTRINGZ; +} + +DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o) +{ + return INTEGER_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i) +{ + INTEGER_VALUE_OF(o) = i; + VALUE_TYPE(o) = VCVT_UINT; +} + +DLLEXPORT(unsigned long) vObjectLongValue(VObject *o) +{ + return LONG_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l) +{ + LONG_VALUE_OF(o) = l; + VALUE_TYPE(o) = VCVT_ULONG; +} + +DLLEXPORT(void*) vObjectAnyValue(VObject *o) +{ + return ANY_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t) +{ + ANY_VALUE_OF(o) = t; + VALUE_TYPE(o) = VCVT_RAW; +} + +DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o) +{ + return VOBJECT_VALUE_OF(o); +} + +DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p) +{ + VOBJECT_VALUE_OF(o) = p; + VALUE_TYPE(o) = VCVT_VOBJECT; +} + +DLLEXPORT(int) vObjectValueType(VObject *o) +{ + return VALUE_TYPE(o); +} + + +/*---------------------------------------------------------------------- + The following functions can be used to build VObject. + ----------------------------------------------------------------------*/ + +DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p) +{ + /* circular link list pointed to tail */ + /* + o {next,id,prop,val} + V + pn {next,id,prop,val} + V + ... + p1 {next,id,prop,val} + V + pn + --> + o {next,id,prop,val} + V + pn {next,id,prop,val} + V + p {next,id,prop,val} + ... + p1 {next,id,prop,val} + V + pn + */ + + VObject *tail = o->prop; + if (tail) { + p->next = tail->next; + o->prop = tail->next = p; + } + else { + o->prop = p->next = p; + } + return p; +} + +DLLEXPORT(VObject*) addProp(VObject *o, const char *id) +{ + return addVObjectProp(o,newVObject(id)); +} + +DLLEXPORT(VObject*) addProp_(VObject *o, const char *id) +{ + return addVObjectProp(o,newVObject_(id)); +} + +DLLEXPORT(void) addList(VObject **o, VObject *p) +{ + p->next = 0; + if (*o == 0) { + *o = p; + } + else { + VObject *t = *o; + while (t->next) { + t = t->next; + } + t->next = p; + } +} + +DLLEXPORT(VObject*) nextVObjectInList(VObject *o) +{ + return o->next; +} + +DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size) +{ + VObject *sizeProp; + setVObjectAnyValue(prop, val); + sizeProp = addProp(prop,VCDataSizeProp); + setVObjectLongValue(sizeProp, size); + return prop; +} + +DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size) +{ + void *p = dupStr((const char *)val,size); + return setValueWithSize_(prop,p,p?size:0); +} + +DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o) +{ + i->start = o->prop; + i->next = 0; +} + +DLLEXPORT(void) initVObjectIterator(VObjectIterator *i, VObject *o) +{ + i->start = o->next; + i->next = 0; +} + +DLLEXPORT(int) moreIteration(VObjectIterator *i) +{ + return (i->start && (i->next==0 || i->next!=i->start)); +} + +DLLEXPORT(VObject*) nextVObject(VObjectIterator *i) +{ + if (i->start && i->next != i->start) { + if (i->next == 0) { + i->next = i->start->next; + return i->next; + } + else { + i->next = i->next->next; + return i->next; + } + } + else return (VObject*)0; +} + +DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id) +{ + VObjectIterator i; + initPropIterator(&i,o); + while (moreIteration(&i)) { + VObject *each = nextVObject(&i); + if (!stricmp(id,each->id)) + return each; + } + return (VObject*)0; +} + +DLLEXPORT(VObject*) addGroup(VObject *o, const char *g) +{ + /* + a.b.c + --> + prop(c) + prop(VCGrouping=b) + prop(VCGrouping=a) + */ + char *dot = strrchr(g,'.'); + if (dot) { + VObject *p, *t; + char *gs, *n = dot+1; + gs = dupStr(g,0); /* so we can write to it. */ + /* used to be + * t = p = addProp_(o,lookupProp_(n)); + */ + t = p = addProp_(o,lookupProp(n)); + dot = strrchr(gs,'.'); + *dot = 0; + do { + dot = strrchr(gs,'.'); + if (dot) { + n = dot+1; + *dot=0; + } + else + n = gs; + /* property(VCGroupingProp=n); + * and the value may have VCGrouping property + */ + t = addProp(t,VCGroupingProp); + setVObjectStringZValue(t,lookupProp_(n)); + } while (n != gs); + deleteStr(gs); + return p; + } + else + return addProp_(o,lookupProp(g)); +} + +DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v) +{ + VObject *prop; + prop = addProp(o,p); + setVObjectUStringZValue_(prop, fakeUnicode(v,0)); + return prop; +} + +DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, + unsigned int size) +{ + VObject *prop; + prop = addProp(o,p); + setValueWithSize_(prop, (void*)v, size); + return prop; +} + +DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, + unsigned int size) +{ + return addPropSizedValue_(o,p,dupStr(v,size),size); +} + + + +/*---------------------------------------------------------------------- + The following pretty print a VObject + ----------------------------------------------------------------------*/ + +static void printVObject_(FILE *fp, VObject *o, int level); + +static void indent(FILE *fp, int level) +{ + int i; + for (i=0;i<level*4;i++) { + fputc(' ', fp); + } +} + +static void printValue(FILE *fp, VObject *o, int level) +{ + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: { + char c; + char *t,*s; + s = t = fakeCString(USTRINGZ_VALUE_OF(o)); + fputc('"',fp); + while (c=*t,c) { + fputc(c,fp); + if (c == '\n') indent(fp,level+2); + t++; + } + fputc('"',fp); + deleteStr(s); + break; + } + case VCVT_STRINGZ: { + char c; + const char *s = STRINGZ_VALUE_OF(o); + fputc('"',fp); + while (c=*s,c) { + fputc(c,fp); + if (c == '\n') indent(fp,level+2); + s++; + } + fputc('"',fp); + break; + } + case VCVT_UINT: + fprintf(fp,"%d", INTEGER_VALUE_OF(o)); break; + case VCVT_ULONG: + fprintf(fp,"%ld", LONG_VALUE_OF(o)); break; + case VCVT_RAW: + fprintf(fp,"[raw data]"); break; + case VCVT_VOBJECT: + fprintf(fp,"[vobject]\n"); + printVObject_(fp,VOBJECT_VALUE_OF(o),level+1); + break; + case 0: + fprintf(fp,"[none]"); break; + default: + fprintf(fp,"[unknown]"); break; + } +} + +static void printNameValue(FILE *fp,VObject *o, int level) +{ + indent(fp,level); + if (NAME_OF(o)) { + fprintf(fp,"%s", NAME_OF(o)); + } + if (VALUE_TYPE(o)) { + fputc('=',fp); + printValue(fp,o, level); + } + fprintf(fp,"\n"); +} + +static void printVObject_(FILE *fp, VObject *o, int level) + { + VObjectIterator t; + if (o == 0) { + fprintf(fp,"[NULL]\n"); + return; + } + printNameValue(fp,o,level); + initPropIterator(&t,o); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + printVObject_(fp,eachProp,level+1); + } + } + +void printVObject(FILE *fp,VObject *o) +{ + printVObject_(fp,o,0); +} + +DLLEXPORT(void) printVObjectToFile(char *fname,VObject *o) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + printVObject(fp,o); + fclose(fp); + } +} + +DLLEXPORT(void) printVObjectsToFile(char *fname,VObject *list) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + while (list) { + printVObject(fp,list); + list = nextVObjectInList(list); + } + fclose(fp); + } +} + +DLLEXPORT(void) cleanVObject(VObject *o) +{ + if (o == 0) return; + if (o->prop) { + /* destroy time: cannot use the iterator here. + Have to break the cycle in the circular link + list and turns it into regular NULL-terminated + list -- since at some point of destruction, + the reference entry for the iterator to work + will not longer be valid. + */ + VObject *p; + p = o->prop->next; + o->prop->next = 0; + do { + VObject *t = p->next; + cleanVObject(p); + p = t; + } while (p); + } + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: + case VCVT_STRINGZ: + case VCVT_RAW: + /* assume they are all allocated by malloc. */ + free((char*)STRINGZ_VALUE_OF(o)); + break; + case VCVT_VOBJECT: + cleanVObject(VOBJECT_VALUE_OF(o)); + break; + } + deleteVObject(o); +} + +DLLEXPORT(void) cleanVObjects(VObject *list) +{ + while (list) { + VObject *t = list; + list = nextVObjectInList(list); + cleanVObject(t); + } +} + +/*---------------------------------------------------------------------- + The following is a String Table Facilities. + ----------------------------------------------------------------------*/ + +#define STRTBLSIZE 255 + +static StrItem *strTbl[STRTBLSIZE]; + +static unsigned int hashStr(const char *s) +{ + unsigned int h = 0; + int i; + for (i=0;s[i];i++) { + h += s[i]*i; + } + return h % STRTBLSIZE; +} + +DLLEXPORT(const char*) lookupStr(const char *s) +{ + StrItem *t; + unsigned int h = hashStr(s); + if ((t = strTbl[h]) != 0) { + do { + if (stricmp(t->s,s) == 0) { + t->refCnt++; + return t->s; + } + t = t->next; + } while (t); + } + s = dupStr(s,0); + strTbl[h] = newStrItem(s,strTbl[h]); + return s; +} + +DLLEXPORT(void) unUseStr(const char *s) +{ + StrItem *t, *p; + unsigned int h = hashStr(s); + if ((t = strTbl[h]) != 0) { + p = t; + do { + if (stricmp(t->s,s) == 0) { + t->refCnt--; + if (t->refCnt == 0) { + if (p == strTbl[h]) { + strTbl[h] = t->next; + } + else { + p->next = t->next; + } + deleteStr(t->s); + deleteStrItem(t); + return; + } + } + p = t; + t = t->next; + } while (t); + } +} + +DLLEXPORT(void) cleanStrTbl() +{ + int i; + for (i=0; i<STRTBLSIZE;i++) { + StrItem *t = strTbl[i]; + while (t) { + StrItem *p; + deleteStr(t->s); + p = t; + t = t->next; + deleteStrItem(p); + } while (t); + strTbl[i] = 0; + } +} + + +struct PreDefProp { + const char *name; + const char *alias; + const char** fields; + unsigned int flags; + }; + +/* flags in PreDefProp */ +#define PD_BEGIN 0x1 +#define PD_INTERNAL 0x2 + +static const char *adrFields[] = { + VCPostalBoxProp, + VCExtAddressProp, + VCStreetAddressProp, + VCCityProp, + VCRegionProp, + VCPostalCodeProp, + VCCountryNameProp, + 0 +}; + +static const char *nameFields[] = { + VCFamilyNameProp, + VCGivenNameProp, + VCAdditionalNamesProp, + VCNamePrefixesProp, + VCNameSuffixesProp, + NULL + }; + +static const char *orgFields[] = { + VCOrgNameProp, + VCOrgUnitProp, + VCOrgUnit2Prop, + VCOrgUnit3Prop, + VCOrgUnit4Prop, + NULL + }; + +static const char *AAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCAudioContentProp, + 0 + }; + +/* ExDate -- has unamed fields */ +/* RDate -- has unamed fields */ + +static const char *DAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCDisplayStringProp, + 0 + }; + +static const char *MAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCEmailAddressProp, + VCNoteProp, + 0 + }; + +static const char *PAlarmFields[] = { + VCRunTimeProp, + VCSnoozeTimeProp, + VCRepeatCountProp, + VCProcedureNameProp, + 0 + }; + +static const struct PreDefProp propNames[] = { + { VC7bitProp, 0, 0, 0 }, + { VC8bitProp, 0, 0, 0 }, + { VCAAlarmProp, 0, AAlarmFields, 0 }, + { VCAdditionalNamesProp, 0, 0, 0 }, + { VCAdrProp, 0, adrFields, 0 }, + { VCAgentProp, 0, 0, 0 }, + { VCAIFFProp, 0, 0, 0 }, + { VCAOLProp, 0, 0, 0 }, + { VCAppleLinkProp, 0, 0, 0 }, + { VCAttachProp, 0, 0, 0 }, + { VCAttendeeProp, 0, 0, 0 }, + { VCATTMailProp, 0, 0, 0 }, + { VCAudioContentProp, 0, 0, 0 }, + { VCAVIProp, 0, 0, 0 }, + { VCBase64Prop, 0, 0, 0 }, + { VCBBSProp, 0, 0, 0 }, + { VCBirthDateProp, 0, 0, 0 }, + { VCBMPProp, 0, 0, 0 }, + { VCBodyProp, 0, 0, 0 }, + { VCBusinessRoleProp, 0, 0, 0 }, + { VCCalProp, 0, 0, PD_BEGIN }, + { VCCaptionProp, 0, 0, 0 }, + { VCCardProp, 0, 0, PD_BEGIN }, + { VCCarProp, 0, 0, 0 }, + { VCCategoriesProp, 0, 0, 0 }, + { VCCellularProp, 0, 0, 0 }, + { VCCGMProp, 0, 0, 0 }, + { VCCharSetProp, 0, 0, 0 }, + { VCCIDProp, VCContentIDProp, 0, 0 }, + { VCCISProp, 0, 0, 0 }, + { VCCityProp, 0, 0, 0 }, + { VCClassProp, 0, 0, 0 }, + { VCCommentProp, 0, 0, 0 }, + { VCCompletedProp, 0, 0, 0 }, + { VCContentIDProp, 0, 0, 0 }, + { VCCountryNameProp, 0, 0, 0 }, + { VCDAlarmProp, 0, DAlarmFields, 0 }, + { VCDataSizeProp, 0, 0, PD_INTERNAL }, + { VCDayLightProp, 0, 0, 0 }, + { VCDCreatedProp, 0, 0, 0 }, + { VCDeliveryLabelProp, 0, 0, 0 }, + { VCDescriptionProp, 0, 0, 0 }, + { VCDIBProp, 0, 0, 0 }, + { VCDisplayStringProp, 0, 0, 0 }, + { VCDomesticProp, 0, 0, 0 }, + { VCDTendProp, 0, 0, 0 }, + { VCDTstartProp, 0, 0, 0 }, + { VCDueProp, 0, 0, 0 }, + { VCEmailAddressProp, 0, 0, 0 }, + { VCEncodingProp, 0, 0, 0 }, + { VCEndProp, 0, 0, 0 }, + { VCEventProp, 0, 0, PD_BEGIN }, + { VCEWorldProp, 0, 0, 0 }, + { VCExNumProp, 0, 0, 0 }, + { VCExpDateProp, 0, 0, 0 }, + { VCExpectProp, 0, 0, 0 }, + { VCExtAddressProp, 0, 0, 0 }, + { VCFamilyNameProp, 0, 0, 0 }, + { VCFaxProp, 0, 0, 0 }, + { VCFullNameProp, 0, 0, 0 }, + { VCGeoLocationProp, 0, 0, 0 }, + { VCGeoProp, 0, 0, 0 }, + { VCGIFProp, 0, 0, 0 }, + { VCGivenNameProp, 0, 0, 0 }, + { VCGroupingProp, 0, 0, 0 }, + { VCHomeProp, 0, 0, 0 }, + { VCIBMMailProp, 0, 0, 0 }, + { VCInlineProp, 0, 0, 0 }, + { VCInternationalProp, 0, 0, 0 }, + { VCInternetProp, 0, 0, 0 }, + { VCISDNProp, 0, 0, 0 }, + { VCJPEGProp, 0, 0, 0 }, + { VCLanguageProp, 0, 0, 0 }, + { VCLastModifiedProp, 0, 0, 0 }, + { VCLastRevisedProp, 0, 0, 0 }, + { VCLocationProp, 0, 0, 0 }, + { VCLogoProp, 0, 0, 0 }, + { VCMailerProp, 0, 0, 0 }, + { VCMAlarmProp, 0, MAlarmFields, 0 }, + { VCMCIMailProp, 0, 0, 0 }, + { VCMessageProp, 0, 0, 0 }, + { VCMETProp, 0, 0, 0 }, + { VCModemProp, 0, 0, 0 }, + { VCMPEG2Prop, 0, 0, 0 }, + { VCMPEGProp, 0, 0, 0 }, + { VCMSNProp, 0, 0, 0 }, + { VCNamePrefixesProp, 0, 0, 0 }, + { VCNameProp, 0, nameFields, 0 }, + { VCNameSuffixesProp, 0, 0, 0 }, + { VCNoteProp, 0, 0, 0 }, + { VCOrgNameProp, 0, 0, 0 }, + { VCOrgProp, 0, orgFields, 0 }, + { VCOrgUnit2Prop, 0, 0, 0 }, + { VCOrgUnit3Prop, 0, 0, 0 }, + { VCOrgUnit4Prop, 0, 0, 0 }, + { VCOrgUnitProp, 0, 0, 0 }, + { VCPagerProp, 0, 0, 0 }, + { VCPAlarmProp, 0, PAlarmFields, 0 }, + { VCParcelProp, 0, 0, 0 }, + { VCPartProp, 0, 0, 0 }, + { VCPCMProp, 0, 0, 0 }, + { VCPDFProp, 0, 0, 0 }, + { VCPGPProp, 0, 0, 0 }, + { VCPhotoProp, 0, 0, 0 }, + { VCPICTProp, 0, 0, 0 }, + { VCPMBProp, 0, 0, 0 }, + { VCPostalBoxProp, 0, 0, 0 }, + { VCPostalCodeProp, 0, 0, 0 }, + { VCPostalProp, 0, 0, 0 }, + { VCPowerShareProp, 0, 0, 0 }, + { VCPreferredProp, 0, 0, 0 }, + { VCPriorityProp, 0, 0, 0 }, + { VCProcedureNameProp, 0, 0, 0 }, + { VCProdIdProp, 0, 0, 0 }, + { VCProdigyProp, 0, 0, 0 }, + { VCPronunciationProp, 0, 0, 0 }, + { VCPSProp, 0, 0, 0 }, + { VCPublicKeyProp, 0, 0, 0 }, + { VCQPProp, VCQuotedPrintableProp, 0, 0 }, + { VCQuickTimeProp, 0, 0, 0 }, + { VCQuotedPrintableProp, 0, 0, 0 }, + { VCRDateProp, 0, 0, 0 }, + { VCRegionProp, 0, 0, 0 }, + { VCRelatedToProp, 0, 0, 0 }, + { VCRepeatCountProp, 0, 0, 0 }, + { VCResourcesProp, 0, 0, 0 }, + { VCRNumProp, 0, 0, 0 }, + { VCRoleProp, 0, 0, 0 }, + { VCRRuleProp, 0, 0, 0 }, + { VCRSVPProp, 0, 0, 0 }, + { VCRunTimeProp, 0, 0, 0 }, + { VCSequenceProp, 0, 0, 0 }, + { VCSnoozeTimeProp, 0, 0, 0 }, + { VCStartProp, 0, 0, 0 }, + { VCStatusProp, 0, 0, 0 }, + { VCStreetAddressProp, 0, 0, 0 }, + { VCSubTypeProp, 0, 0, 0 }, + { VCSummaryProp, 0, 0, 0 }, + { VCTelephoneProp, 0, 0, 0 }, + { VCTIFFProp, 0, 0, 0 }, + { VCTimeZoneProp, 0, 0, 0 }, + { VCTitleProp, 0, 0, 0 }, + { VCTLXProp, 0, 0, 0 }, + { VCTodoProp, 0, 0, PD_BEGIN }, + { VCTranspProp, 0, 0, 0 }, + { VCUniqueStringProp, 0, 0, 0 }, + { VCURLProp, 0, 0, 0 }, + { VCURLValueProp, 0, 0, 0 }, + { VCValueProp, 0, 0, 0 }, + { VCVersionProp, 0, 0, 0 }, + { VCVideoProp, 0, 0, 0 }, + { VCVoiceProp, 0, 0, 0 }, + { VCWAVEProp, 0, 0, 0 }, + { VCWMFProp, 0, 0, 0 }, + { VCWorkProp, 0, 0, 0 }, + { VCX400Prop, 0, 0, 0 }, + { VCX509Prop, 0, 0, 0 }, + { VCXRuleProp, 0, 0, 0 }, + { 0,0,0,0 } + }; + + +static const struct PreDefProp* lookupPropInfo(const char* str) +{ + /* brute force for now, could use a hash table here. */ + int i; + + for (i = 0; propNames[i].name; i++) + if (stricmp(str, propNames[i].name) == 0) { + return &propNames[i]; + } + + return 0; +} + + +DLLEXPORT(const char*) lookupProp_(const char* str) +{ + int i; + + for (i = 0; propNames[i].name; i++) + if (stricmp(str, propNames[i].name) == 0) { + const char* s; + s = propNames[i].alias?propNames[i].alias:propNames[i].name; + return lookupStr(s); + } + return lookupStr(str); +} + + +DLLEXPORT(const char*) lookupProp(const char* str) +{ + int i; + + for (i = 0; propNames[i].name; i++) + if (stricmp(str, propNames[i].name) == 0) { + const char *s; + fieldedProp = propNames[i].fields; + s = propNames[i].alias?propNames[i].alias:propNames[i].name; + return lookupStr(s); + } + fieldedProp = 0; + return lookupStr(str); +} + + +/*---------------------------------------------------------------------- + APIs to Output text form. + ----------------------------------------------------------------------*/ +#define OFILE_REALLOC_SIZE 256 +typedef struct OFile { + FILE *fp; + char *s; + int len; + int limit; + int alloc:1; + int fail:1; + } OFile; + +#if 0 +static void appendsOFile(OFile *fp, const char *s) +{ + int slen; + if (fp->fail) return; + slen = strlen(s); + if (fp->fp) { + fwrite(s,1,slen,fp->fp); + } + else { +stuff: + if (fp->len + slen < fp->limit) { + memcpy(fp->s+fp->len,s,slen); + fp->len += slen; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen; + fp->s = (char *) realloc(fp->s,fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} + +static void appendcOFile(OFile *fp, char c) +{ + if (fp->fail) return; + if (fp->fp) { + fputc(c,fp->fp); + } + else { +stuff: + if (fp->len+1 < fp->limit) { + fp->s[fp->len] = c; + fp->len++; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + fp->s = (char *) realloc(fp->s,fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} +#else +static void appendcOFile_(OFile *fp, char c) +{ + if (fp->fail) return; + if (fp->fp) { + fputc(c,fp->fp); + } + else { +stuff: + if (fp->len+1 < fp->limit) { + fp->s[fp->len] = c; + fp->len++; + return; + } + else if (fp->alloc) { + fp->limit = fp->limit + OFILE_REALLOC_SIZE; + fp->s = realloc(fp->s,fp->limit); + if (fp->s) goto stuff; + } + if (fp->alloc) + free(fp->s); + fp->s = 0; + fp->fail = 1; + } +} + +static void appendcOFile(OFile *fp, char c) +{ + if (c == '\n') { + /* write out as <CR><LF> */ + appendcOFile_(fp,0xd); + appendcOFile_(fp,0xa); + } + else + appendcOFile_(fp,c); +} + +static void appendsOFile(OFile *fp, const char *s) +{ + int i, slen; + slen = strlen(s); + for (i=0; i<slen; i++) { + appendcOFile(fp,s[i]); + } +} + +#endif + +static void initOFile(OFile *fp, FILE *ofp) +{ + fp->fp = ofp; + fp->s = 0; + fp->len = 0; + fp->limit = 0; + fp->alloc = 0; + fp->fail = 0; +} + +static void initMemOFile(OFile *fp, char *s, int len) +{ + fp->fp = 0; + fp->s = s; + fp->len = 0; + fp->limit = s?len:0; + fp->alloc = s?0:1; + fp->fail = 0; +} + + +static int writeBase64(OFile *fp, unsigned char *s, long len) +{ + long cur = 0; + int i, numQuads = 0; + unsigned long trip; + unsigned char b; + char quad[5]; +#define MAXQUADS 16 + + quad[4] = 0; + + while (cur < len) { + /* collect the triplet of bytes into 'trip' */ + trip = 0; + for (i = 0; i < 3; i++) { + b = (cur < len) ? *(s + cur) : 0; + cur++; + trip = trip << 8 | b; + } + /* fill in 'quad' with the appropriate four characters */ + for (i = 3; i >= 0; i--) { + b = (unsigned char)(trip & 0x3F); + trip = trip >> 6; + if ((3 - i) < (cur - len)) + quad[i] = '='; /* pad char */ + else if (b < 26) quad[i] = (char)b + 'A'; + else if (b < 52) quad[i] = (char)(b - 26) + 'a'; + else if (b < 62) quad[i] = (char)(b - 52) + '0'; + else if (b == 62) quad[i] = '+'; + else quad[i] = '/'; + } + /* now output 'quad' with appropriate whitespace and line ending */ + appendsOFile(fp, (numQuads == 0 ? " " : "")); + appendsOFile(fp, quad); + appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : ""))); + numQuads = (numQuads + 1) % MAXQUADS; + } + appendcOFile(fp,'\n'); + + return 1; +} + +static void writeString(OFile *fp, const char *s) +{ + appendsOFile(fp,s); +} + +static void writeQPString(OFile *fp, const char *s) +{ + char buf[4]; + int count=0; + const char *p = s; + + while (*p) { + /* break up lines biggger than 75 chars */ + if(count >=74){ + count=0; + appendsOFile(fp,"=\n"); + } + + /* escape any non ASCII characters and '=' as per rfc1521 */ + if (*p<= 0x1f || *p >=0x7f || *p == '=' ) { + snprintf(buf,sizeof(buf),"=%02X",(unsigned char)*p); + appendsOFile(fp,buf); + count+=3; + } else { + appendcOFile(fp,*p); + count++; + } + p++; + } +} + + + +static void writeVObject_(OFile *fp, VObject *o); + +static void writeValue(OFile *fp, VObject *o, unsigned long size,int quote) +{ + if (o == 0) return; + switch (VALUE_TYPE(o)) { + case VCVT_USTRINGZ: { + char *s = fakeCString(USTRINGZ_VALUE_OF(o)); + if(quote) writeQPString(fp, s); + else writeString(fp,s); + deleteStr(s); + break; + } + case VCVT_STRINGZ: { + if(quote) writeQPString(fp, STRINGZ_VALUE_OF(o)); + else writeString(fp,STRINGZ_VALUE_OF(o)); + break; + } + case VCVT_UINT: { + char buf[16]; + snprintf(buf,sizeof(buf),"%u", INTEGER_VALUE_OF(o)); + appendsOFile(fp,buf); + break; + } + case VCVT_ULONG: { + char buf[16]; + snprintf(buf,sizeof(buf),"%lu", LONG_VALUE_OF(o)); + appendsOFile(fp,buf); + break; + } + case VCVT_RAW: { + appendcOFile(fp,'\n'); + writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size); + break; + } + case VCVT_VOBJECT: + appendcOFile(fp,'\n'); + writeVObject_(fp,VOBJECT_VALUE_OF(o)); + break; + } +} + +static void writeAttrValue(OFile *fp, VObject *o) +{ + if (NAME_OF(o)) { + const struct PreDefProp *pi; + pi = lookupPropInfo(NAME_OF(o)); + if (pi && ((pi->flags & PD_INTERNAL) != 0)) return; + appendcOFile(fp,';'); + appendsOFile(fp,NAME_OF(o)); + } + else + appendcOFile(fp,';'); + if (VALUE_TYPE(o)) { + appendcOFile(fp,'='); + writeValue(fp,o,0,0); + } +} + +static void writeGroup(OFile *fp, VObject *o) +{ + char buf1[256]; + char buf2[256]; + strcpy(buf1,NAME_OF(o)); + while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) { + strncpy(buf2,STRINGZ_VALUE_OF(o),sizeof(buf2)); + buf2[sizeof(buf2)-1] = '\0'; + strncat(buf2,".",sizeof(buf2)-strlen(buf2)-1); + strncat(buf2,buf1,sizeof(buf2)-strlen(buf2)-1); + strcpy(buf1,buf2); + } + appendsOFile(fp,buf1); +} + +static int inList(const char **list, const char *s) +{ + if (list == 0) return 0; + while (*list) { + if (stricmp(*list,s) == 0) return 1; + list++; + } + return 0; +} + +static void writeProp(OFile *fp, VObject *o) +{ + int isQuoted=0; + if (NAME_OF(o)) { + const struct PreDefProp *pi; + VObjectIterator t; + const char **fields_ = 0; + pi = lookupPropInfo(NAME_OF(o)); + if (pi && ((pi->flags & PD_BEGIN) != 0)) { + writeVObject_(fp,o); + return; + } + if (isAPropertyOf(o,VCGroupingProp)) + writeGroup(fp,o); + else + appendsOFile(fp,NAME_OF(o)); + if (pi) fields_ = pi->fields; + initPropIterator(&t,o); + while (moreIteration(&t)) { + const char *s; + VObject *eachProp = nextVObject(&t); + s = NAME_OF(eachProp); + if (stricmp(VCGroupingProp,s) && !inList(fields_,s)) + writeAttrValue(fp,eachProp); + if (stricmp(VCQPProp,s)==0 || stricmp(VCQuotedPrintableProp,s)==0) + isQuoted=1; + } + if (fields_) { + int i = 0, n = 0; + const char** fields = fields_; + /* output prop as fields */ + appendcOFile(fp,':'); + while (*fields) { + VObject *t = isAPropertyOf(o,*fields); + i++; + if (t) n = i; + fields++; + } + fields = fields_; + for (i=0;i<n;i++) { + writeValue(fp,isAPropertyOf(o,*fields),0,isQuoted); + fields++; + if (i<(n-1)) appendcOFile(fp,';'); + } + } + } + + if (VALUE_TYPE(o)) { + unsigned long size = 0; + VObject *p = isAPropertyOf(o,VCDataSizeProp); + if (p) size = LONG_VALUE_OF(p); + appendcOFile(fp,':'); + writeValue(fp,o,size,isQuoted); + } + + appendcOFile(fp,'\n'); +} + +static void writeVObject_(OFile *fp, VObject *o) +{ + if (NAME_OF(o)) { + const struct PreDefProp *pi; + pi = lookupPropInfo(NAME_OF(o)); + + if (pi && ((pi->flags & PD_BEGIN) != 0)) { + VObjectIterator t; + const char *begin = NAME_OF(o); + appendsOFile(fp,"BEGIN:"); + appendsOFile(fp,begin); + appendcOFile(fp,'\n'); + initPropIterator(&t,o); + while (moreIteration(&t)) { + VObject *eachProp = nextVObject(&t); + writeProp(fp, eachProp); + } + appendsOFile(fp,"END:"); + appendsOFile(fp,begin); + appendsOFile(fp,"\n\n"); + } + } +} + +void writeVObject(FILE *fp, VObject *o) +{ + OFile ofp; + initOFile(&ofp,fp); + writeVObject_(&ofp,o); +} + +DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + writeVObject(fp,o); + fclose(fp); + } +} + +DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list) +{ + FILE *fp = fopen(fname,"w"); + if (fp) { + while (list) { + writeVObject(fp,list); + list = nextVObjectInList(list); + } + fclose(fp); + } +} + +DLLEXPORT(char*) writeMemVObject(char *s, int *len, VObject *o) +{ + OFile ofp; + initMemOFile(&ofp,s,len?*len:0); + writeVObject_(&ofp,o); + if (len) *len = ofp.len; + appendcOFile(&ofp,0); + return ofp.s; +} + +DLLEXPORT(char*) writeMemVObjects(char *s, int *len, VObject *list) +{ + OFile ofp; + initMemOFile(&ofp,s,len?*len:0); + while (list) { + writeVObject_(&ofp,list); + list = nextVObjectInList(list); + } + if (len) *len = ofp.len; + appendcOFile(&ofp,0); + return ofp.s; +} + +/*---------------------------------------------------------------------- + APIs to do fake Unicode stuff. + ----------------------------------------------------------------------*/ +DLLEXPORT(wchar_t*) fakeUnicode(const char *ps, int *bytes) +{ + wchar_t *r, *pw; + int len = strlen(ps)+1; + + pw = r = (wchar_t*)malloc(sizeof(wchar_t)*len); + if (bytes) + *bytes = len * sizeof(wchar_t); + + while (*ps) { + if (*ps == '\n') + *pw = (wchar_t)0x2028; + else if (*ps == '\r') + *pw = (wchar_t)0x2029; + else + *pw = (wchar_t)(unsigned char)*ps; + ps++; pw++; + } + *pw = (wchar_t)0; + + return r; +} + +DLLEXPORT(int) uStrLen(const wchar_t *u) +{ + int i = 0; + while (*u != (wchar_t)0) { u++; i++; } + return i; +} + +DLLEXPORT(char*) fakeCString(const wchar_t *u) +{ + char *s, *t; + int len = uStrLen(u) + 1; + t = s = (char*)malloc(len); + while (*u) { + if (*u == (wchar_t)0x2028) + *t = '\n'; + else if (*u == (wchar_t)0x2029) + *t = '\r'; + else + *t = (char)*u; + u++; t++; + } + *t = 0; + return s; +} + +/* end of source file vobject.c */ diff --git a/src/libicalvcal/vobject.h b/src/libicalvcal/vobject.h new file mode 100644 index 0000000..bc31dc8 --- /dev/null +++ b/src/libicalvcal/vobject.h @@ -0,0 +1,366 @@ +/*************************************************************************** +(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. + +***************************************************************************/ + +/* + +The vCard/vCalendar C interface is implemented in the set +of files as follows: + +vcc.y, yacc source, and vcc.c, the yacc output you will use +implements the core parser + +vobject.c implements an API that insulates the caller from +the parser and changes in the vCard/vCalendar BNF + +port.h defines compilation environment dependent stuff + +vcc.h and vobject.h are header files for their .c counterparts + +vcaltmp.h and vcaltmp.c implement vCalendar "macro" functions +which you may find useful. + +test.c is a standalone test driver that exercises some of +the features of the APIs provided. Invoke test.exe on a +VCARD/VCALENDAR input text file and you will see the pretty +print output of the internal representation (this pretty print +output should give you a good idea of how the internal +representation looks like -- there is one such output in the +following too). Also, a file with the .out suffix is generated +to show that the internal representation can be written back +in the original text format. + +For more information on this API see the readme.txt file +which accompanied this distribution. + + Also visit: + + http://www.versit.com + http://www.ralden.com + +*/ + + +#ifndef __VOBJECT_H__ +#define __VOBJECT_H__ 1 + + +#include "port.h" +#include <stdlib.h> +#include <stdio.h> + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +extern "C" { +#endif + + +#define VC7bitProp "7BIT" +#define VC8bitProp "8BIT" +#define VCAAlarmProp "AALARM" +#define VCAdditionalNamesProp "ADDN" +#define VCAdrProp "ADR" +#define VCAgentProp "AGENT" +#define VCAIFFProp "AIFF" +#define VCAOLProp "AOL" +#define VCAppleLinkProp "APPLELINK" +#define VCAttachProp "ATTACH" +#define VCAttendeeProp "ATTENDEE" +#define VCATTMailProp "ATTMAIL" +#define VCAudioContentProp "AUDIOCONTENT" +#define VCAVIProp "AVI" +#define VCBase64Prop "BASE64" +#define VCBBSProp "BBS" +#define VCBirthDateProp "BDAY" +#define VCBMPProp "BMP" +#define VCBodyProp "BODY" +#define VCBusinessRoleProp "ROLE" +#define VCCalProp "VCALENDAR" +#define VCCaptionProp "CAP" +#define VCCardProp "VCARD" +#define VCCarProp "CAR" +#define VCCategoriesProp "CATEGORIES" +#define VCCellularProp "CELL" +#define VCCGMProp "CGM" +#define VCCharSetProp "CS" +#define VCCIDProp "CID" +#define VCCISProp "CIS" +#define VCCityProp "L" +#define VCClassProp "CLASS" +#define VCCommentProp "NOTE" +#define VCCompletedProp "COMPLETED" +#define VCContentIDProp "CONTENT-ID" +#define VCCountryNameProp "C" +#define VCDAlarmProp "DALARM" +#define VCDataSizeProp "DATASIZE" +#define VCDayLightProp "DAYLIGHT" +#define VCDCreatedProp "DCREATED" +#define VCDeliveryLabelProp "LABEL" +#define VCDescriptionProp "DESCRIPTION" +#define VCDIBProp "DIB" +#define VCDisplayStringProp "DISPLAYSTRING" +#define VCDomesticProp "DOM" +#define VCDTendProp "DTEND" +#define VCDTstartProp "DTSTART" +#define VCDueProp "DUE" +#define VCEmailAddressProp "EMAIL" +#define VCEncodingProp "ENCODING" +#define VCEndProp "END" +#define VCEventProp "VEVENT" +#define VCEWorldProp "EWORLD" +#define VCExNumProp "EXNUM" +#define VCExpDateProp "EXDATE" +#define VCExpectProp "EXPECT" +#define VCExtAddressProp "EXT ADD" +#define VCFamilyNameProp "F" +#define VCFaxProp "FAX" +#define VCFullNameProp "FN" +#define VCGeoProp "GEO" +#define VCGeoLocationProp "GEO" +#define VCGIFProp "GIF" +#define VCGivenNameProp "G" +#define VCGroupingProp "Grouping" +#define VCHomeProp "HOME" +#define VCIBMMailProp "IBMMail" +#define VCInlineProp "INLINE" +#define VCInternationalProp "INTL" +#define VCInternetProp "INTERNET" +#define VCISDNProp "ISDN" +#define VCJPEGProp "JPEG" +#define VCLanguageProp "LANG" +#define VCLastModifiedProp "LAST-MODIFIED" +#define VCLastRevisedProp "REV" +#define VCLocationProp "LOCATION" +#define VCLogoProp "LOGO" +#define VCMailerProp "MAILER" +#define VCMAlarmProp "MALARM" +#define VCMCIMailProp "MCIMAIL" +#define VCMessageProp "MSG" +#define VCMETProp "MET" +#define VCModemProp "MODEM" +#define VCMPEG2Prop "MPEG2" +#define VCMPEGProp "MPEG" +#define VCMSNProp "MSN" +#define VCNamePrefixesProp "NPRE" +#define VCNameProp "N" +#define VCNameSuffixesProp "NSUF" +#define VCNoteProp "NOTE" +#define VCOrgNameProp "ORGNAME" +#define VCOrgProp "ORG" +#define VCOrgUnit2Prop "OUN2" +#define VCOrgUnit3Prop "OUN3" +#define VCOrgUnit4Prop "OUN4" +#define VCOrgUnitProp "OUN" +#define VCPagerProp "PAGER" +#define VCPAlarmProp "PALARM" +#define VCParcelProp "PARCEL" +#define VCPartProp "PART" +#define VCPCMProp "PCM" +#define VCPDFProp "PDF" +#define VCPGPProp "PGP" +#define VCPhotoProp "PHOTO" +#define VCPICTProp "PICT" +#define VCPMBProp "PMB" +#define VCPostalBoxProp "BOX" +#define VCPostalCodeProp "PC" +#define VCPostalProp "POSTAL" +#define VCPowerShareProp "POWERSHARE" +#define VCPreferredProp "PREF" +#define VCPriorityProp "PRIORITY" +#define VCProcedureNameProp "PROCEDURENAME" +#define VCProdIdProp "PRODID" +#define VCProdigyProp "PRODIGY" +#define VCPronunciationProp "SOUND" +#define VCPSProp "PS" +#define VCPublicKeyProp "KEY" +#define VCQPProp "QP" +#define VCQuickTimeProp "QTIME" +#define VCQuotedPrintableProp "QUOTED-PRINTABLE" +#define VCRDateProp "RDATE" +#define VCRegionProp "R" +#define VCRelatedToProp "RELATED-TO" +#define VCRepeatCountProp "REPEATCOUNT" +#define VCResourcesProp "RESOURCES" +#define VCRNumProp "RNUM" +#define VCRoleProp "ROLE" +#define VCRRuleProp "RRULE" +#define VCRSVPProp "RSVP" +#define VCRunTimeProp "RUNTIME" +#define VCSequenceProp "SEQUENCE" +#define VCSnoozeTimeProp "SNOOZETIME" +#define VCStartProp "START" +#define VCStatusProp "STATUS" +#define VCStreetAddressProp "STREET" +#define VCSubTypeProp "SUBTYPE" +#define VCSummaryProp "SUMMARY" +#define VCTelephoneProp "TEL" +#define VCTIFFProp "TIFF" +#define VCTimeZoneProp "TZ" +#define VCTitleProp "TITLE" +#define VCTLXProp "TLX" +#define VCTodoProp "VTODO" +#define VCTranspProp "TRANSP" +#define VCUniqueStringProp "UID" +#define VCURLProp "URL" +#define VCURLValueProp "URLVAL" +#define VCValueProp "VALUE" +#define VCVersionProp "VERSION" +#define VCVideoProp "VIDEO" +#define VCVoiceProp "VOICE" +#define VCWAVEProp "WAVE" +#define VCWMFProp "WMF" +#define VCWorkProp "WORK" +#define VCX400Prop "X400" +#define VCX509Prop "X509" +#define VCXRuleProp "XRULE" + +/* Extensions */ + +#define XPilotIdProp "X-PILOTID" +#define XPilotStatusProp "X-PILOTSTAT" + +typedef struct VObject VObject; + +typedef struct VObjectIterator { + VObject* start; + VObject* next; + } VObjectIterator; + +extern DLLEXPORT(VObject*) newVObject(const char *id); +extern DLLEXPORT(void) deleteVObject(VObject *p); +extern DLLEXPORT(char*) dupStr(const char *s, unsigned int size); +extern DLLEXPORT(void) deleteStr(const char *p); +extern DLLEXPORT(void) unUseStr(const char *s); + +extern DLLEXPORT(void) setVObjectName(VObject *o, const char* id); +extern DLLEXPORT(void) setVObjectStringZValue(VObject *o, const char *s); +extern DLLEXPORT(void) setVObjectStringZValue_(VObject *o, const char *s); +extern DLLEXPORT(void) setVObjectUStringZValue(VObject *o, const wchar_t *s); +extern DLLEXPORT(void) setVObjectUStringZValue_(VObject *o, const wchar_t *s); +extern DLLEXPORT(void) setVObjectIntegerValue(VObject *o, unsigned int i); +extern DLLEXPORT(void) setVObjectLongValue(VObject *o, unsigned long l); +extern DLLEXPORT(void) setVObjectAnyValue(VObject *o, void *t); +extern DLLEXPORT(VObject*) setValueWithSize(VObject *prop, void *val, unsigned int size); +extern DLLEXPORT(VObject*) setValueWithSize_(VObject *prop, void *val, unsigned int size); + +extern DLLEXPORT(const char*) vObjectName(VObject *o); +extern DLLEXPORT(const char*) vObjectStringZValue(VObject *o); +extern DLLEXPORT(const wchar_t*) vObjectUStringZValue(VObject *o); +extern DLLEXPORT(unsigned int) vObjectIntegerValue(VObject *o); +extern DLLEXPORT(unsigned long) vObjectLongValue(VObject *o); +extern DLLEXPORT(void*) vObjectAnyValue(VObject *o); +extern DLLEXPORT(VObject*) vObjectVObjectValue(VObject *o); +extern DLLEXPORT(void) setVObjectVObjectValue(VObject *o, VObject *p); + +extern DLLEXPORT(VObject*) addVObjectProp(VObject *o, VObject *p); +extern DLLEXPORT(VObject*) addProp(VObject *o, const char *id); +extern DLLEXPORT(VObject*) addProp_(VObject *o, const char *id); +extern DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v); +extern DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size); +extern DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size); +extern DLLEXPORT(VObject*) addGroup(VObject *o, const char *g); +extern DLLEXPORT(void) addList(VObject **o, VObject *p); + +extern DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id); + +extern DLLEXPORT(VObject*) nextVObjectInList(VObject *o); +extern DLLEXPORT(void) initPropIterator(VObjectIterator *i, VObject *o); +extern DLLEXPORT(int) moreIteration(VObjectIterator *i); +extern DLLEXPORT(VObject*) nextVObject(VObjectIterator *i); + +extern DLLEXPORT(char*) writeMemVObject(char *s, int *len, VObject *o); +extern DLLEXPORT(char*) writeMemVObjects(char *s, int *len, VObject *list); + +extern DLLEXPORT(const char*) lookupStr(const char *s); +extern DLLEXPORT(void) cleanStrTbl(); + +extern DLLEXPORT(void) cleanVObject(VObject *o); +extern DLLEXPORT(void) cleanVObjects(VObject *list); + +extern DLLEXPORT(const char*) lookupProp(const char* str); +extern DLLEXPORT(const char*) lookupProp_(const char* str); + +extern DLLEXPORT(wchar_t*) fakeUnicode(const char *ps, int *bytes); +extern DLLEXPORT(int) uStrLen(const wchar_t *u); +extern DLLEXPORT(char*) fakeCString(const wchar_t *u); + +extern DLLEXPORT(void) printVObjectToFile(char *fname,VObject *o); +extern DLLEXPORT(void) printVObjectsToFile(char *fname,VObject *list); +extern DLLEXPORT(void) writeVObjectToFile(char *fname, VObject *o); +extern DLLEXPORT(void) writeVObjectsToFile(char *fname, VObject *list); + +extern DLLEXPORT(int) vObjectValueType(VObject *o); + +/* return type of vObjectValueType: */ +#define VCVT_NOVALUE 0 + /* if the VObject has no value associated with it. */ +#define VCVT_STRINGZ 1 + /* if the VObject has value set by setVObjectStringZValue. */ +#define VCVT_USTRINGZ 2 + /* if the VObject has value set by setVObjectUStringZValue. */ +#define VCVT_UINT 3 + /* if the VObject has value set by setVObjectIntegerValue. */ +#define VCVT_ULONG 4 + /* if the VObject has value set by setVObjectLongValue. */ +#define VCVT_RAW 5 + /* if the VObject has value set by setVObjectAnyValue. */ +#define VCVT_VOBJECT 6 + /* if the VObject has value set by setVObjectVObjectValue. */ + +extern const char** fieldedProp; + +/* NOTE regarding printVObject and writeVObject + +The functions below are not exported from the DLL because they +take a FILE* as a parameter, which cannot be passed across a DLL +interface (at least that is my experience). Instead you can use +their companion functions which take file names or pointers +to memory. However, if you are linking this code into +your build directly then you may find them a more convenient API +and you can go ahead and use them. If you try to use them with +the DLL LIB you will get a link error. +*/ +extern void printVObject(FILE *fp,VObject *o); +extern void writeVObject(FILE *fp, VObject *o); + + +#if defined(__CPLUSPLUS__) || defined(__cplusplus) +} +#endif + +#endif /* __VOBJECT_H__ */ + + |