2011-12-31 [mir] 0.6.0cvs64
authorMichael Rasmussen <mir@datanom.net>
Sat, 31 Dec 2011 14:41:22 +0000 (14:41 +0000)
committerMichael Rasmussen <mir@datanom.net>
Sat, 31 Dec 2011 14:41:22 +0000 (14:41 +0000)
* extensions/vcard/.cvsignore
* extensions/vcard/AUTHORS
* extensions/vcard/ChangeLog
* extensions/vcard/Makefile.am
* extensions/vcard/NEWS
* extensions/vcard/README
* extensions/vcard/TODO
* extensions/vcard/configure.ac
* extensions/vcard/src/.cvsignore
* extensions/vcard/src/Makefile.am
* extensions/vcard/src/vcard-extension.c
* extensions/vcard/src/vcard-utils.c
* extensions/vcard/src/vcard-utils.h
* extensions/vcard/src/libversit/.cvsignore
* extensions/vcard/src/libversit/Makefile.am
* extensions/vcard/src/libversit/README.TXT
* extensions/vcard/src/libversit/port.h
* extensions/vcard/src/libversit/vcc.y
* extensions/vcard/src/libversit/vobject.c
* extensions/vcard/src/libversit/vobject.h
    Initial upload of extension to support
    import and export for contacts in vCard format.

23 files changed:
ChangeLog
PATCHSETS
configure.ac
extensions/vcard/.cvsignore [new file with mode: 0644]
extensions/vcard/AUTHORS [new file with mode: 0644]
extensions/vcard/ChangeLog [new file with mode: 0644]
extensions/vcard/Makefile.am [new file with mode: 0644]
extensions/vcard/NEWS [new file with mode: 0644]
extensions/vcard/README [new file with mode: 0644]
extensions/vcard/TODO [new file with mode: 0644]
extensions/vcard/configure.ac [new file with mode: 0644]
extensions/vcard/src/.cvsignore [new file with mode: 0644]
extensions/vcard/src/Makefile.am [new file with mode: 0644]
extensions/vcard/src/libversit/.cvsignore [new file with mode: 0644]
extensions/vcard/src/libversit/Makefile.am [new file with mode: 0644]
extensions/vcard/src/libversit/README.TXT [new file with mode: 0644]
extensions/vcard/src/libversit/port.h [new file with mode: 0644]
extensions/vcard/src/libversit/vcc.y [new file with mode: 0644]
extensions/vcard/src/libversit/vobject.c [new file with mode: 0644]
extensions/vcard/src/libversit/vobject.h [new file with mode: 0644]
extensions/vcard/src/vcard-extension.c [new file with mode: 0644]
extensions/vcard/src/vcard-utils.c [new file with mode: 0644]
extensions/vcard/src/vcard-utils.h [new file with mode: 0644]

index ef0363e7d082c2eabfe064e217d8fc8a41419188..99d176b6ae2511e089727cba59e00a57aa632c1b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2011-12-31 [mir]       0.6.0cvs64
+
+       * extensions/vcard/.cvsignore
+       * extensions/vcard/AUTHORS
+       * extensions/vcard/ChangeLog
+       * extensions/vcard/Makefile.am
+       * extensions/vcard/NEWS
+       * extensions/vcard/README
+       * extensions/vcard/TODO
+       * extensions/vcard/configure.ac
+       * extensions/vcard/src/.cvsignore
+       * extensions/vcard/src/Makefile.am
+       * extensions/vcard/src/vcard-extension.c
+       * extensions/vcard/src/vcard-utils.c
+       * extensions/vcard/src/vcard-utils.h
+       * extensions/vcard/src/libversit/.cvsignore
+       * extensions/vcard/src/libversit/Makefile.am
+       * extensions/vcard/src/libversit/README.TXT
+       * extensions/vcard/src/libversit/port.h
+       * extensions/vcard/src/libversit/vcc.y
+       * extensions/vcard/src/libversit/vobject.c
+       * extensions/vcard/src/libversit/vobject.h
+           Initial upload of extension to support
+           import and export for contacts in vCard format.
+
 2011-12-31 [mir]       0.6.0cvs63
 
        * extensions/example/src/example-extension.c
index d743ebad590c86dc9c6756a842ed7590da782972..012eaa541264b054e91c83b70bc05f79d258d2e9 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
@@ -61,3 +61,4 @@
 ( cvs diff -u -r 1.8 -r 1.9 src/mainwindow.c;  ) > 0.6.0cvs61.patchset
 ( cvs diff -u -r 1.17 -r 1.18 src/callbacks.c;  cvs diff -u -r 1.3 -r 1.4 src/callbacks.h;  cvs diff -u -r 1.7 -r 1.8 src/gtk-utils.c;  cvs diff -u -r 1.3 -r 1.4 src/gtk-utils.h;  ) > 0.6.0cvs62.patchset
 ( cvs diff -u -r 1.4 -r 1.5 extensions/example/src/example-extension.c;  cvs diff -u -r 1.6 -r 1.7 extensions/export/ldifexport_extension.c;  cvs diff -u -r 1.2 -r 1.3 extensions/export/wizard.c;  cvs diff -u -r 1.1 -r 1.2 extensions/export/wizard.h;  cvs diff -u -r 1.3 -r 1.4 extensions/import/ldifimport_extension.c;  cvs diff -u -r 1.2 -r 1.3 src/extension.h;  ) > 0.6.0cvs63.patchset
+( diff -u /dev/null extensions/vcard/.cvsignore;  diff -u /dev/null extensions/vcard/AUTHORS;  diff -u /dev/null extensions/vcard/ChangeLog;  diff -u /dev/null extensions/vcard/Makefile.am;  diff -u /dev/null extensions/vcard/NEWS;  diff -u /dev/null extensions/vcard/README;  diff -u /dev/null extensions/vcard/TODO;  diff -u /dev/null extensions/vcard/configure.ac;  diff -u /dev/null extensions/vcard/src/.cvsignore;  diff -u /dev/null extensions/vcard/src/Makefile.am;  diff -u /dev/null extensions/vcard/src/vcard-extension.c;  diff -u /dev/null extensions/vcard/src/vcard-utils.c;  diff -u /dev/null extensions/vcard/src/vcard-utils.h;  diff -u /dev/null extensions/vcard/src/libversit/.cvsignore;  diff -u /dev/null extensions/vcard/src/libversit/Makefile.am;  diff -u /dev/null extensions/vcard/src/libversit/README.TXT;  diff -u /dev/null extensions/vcard/src/libversit/port.h;  diff -u /dev/null extensions/vcard/src/libversit/vcc.y;  diff -u /dev/null extensions/vcard/src/libversit/vobject.c;  diff -u /dev/null extensions/vcard/src/libversit/vobject.h;  ) > 0.6.0cvs64.patchset
index 586e543595ff928c9237e8ad83f69673cb0769c2..bafd201bc70c23882009c5c80c25c116e23d9fbb 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=6
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=63
+EXTRA_VERSION=64
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
diff --git a/extensions/vcard/.cvsignore b/extensions/vcard/.cvsignore
new file mode 100644 (file)
index 0000000..38f2d1c
--- /dev/null
@@ -0,0 +1,27 @@
+COPYING
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+auxdir
+*.bz2
+claws-contacts.desktop
+claws-contacts.pc
+config
+config.h
+config.h.in
+config.log
+config.status
+configure
+libtool
+m4
+org.clawsmail.ClawsContact.service
+.deps
+.libs
+*.lo
+*.la
+claws-contacts
+server-bindings.h
+stamp-h1
+src/Makefile.in
diff --git a/extensions/vcard/AUTHORS b/extensions/vcard/AUTHORS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/extensions/vcard/ChangeLog b/extensions/vcard/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/extensions/vcard/Makefile.am b/extensions/vcard/Makefile.am
new file mode 100644 (file)
index 0000000..453873e
--- /dev/null
@@ -0,0 +1,15 @@
+# $Id$
+AUTOMAKE_OPTIONS = gnu
+
+SUBDIRS = src
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = \
+       AUTHORS \
+       COPYING \
+       ChangeLog \
+       INSTALL \
+       NEWS \
+       README \
+       TODO
diff --git a/extensions/vcard/NEWS b/extensions/vcard/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/extensions/vcard/README b/extensions/vcard/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/extensions/vcard/TODO b/extensions/vcard/TODO
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/extensions/vcard/configure.ac b/extensions/vcard/configure.ac
new file mode 100644 (file)
index 0000000..4be78c9
--- /dev/null
@@ -0,0 +1,153 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT(src/vcard-extension.c)
+AC_CONFIG_AUX_DIR(config)
+AM_MAINTAINER_MODE
+
+PACKAGE=vcard_extension
+
+dnl extension version
+
+MAJOR_VERSION=0
+MINOR_VERSION=1
+MICRO_VERSION=1
+EXTRA_VERSION=0
+
+if test \( $EXTRA_VERSION -eq 0 \); then
+    if test \( $MICRO_VERSION -eq 0 \); then
+        VERSION=${MAJOR_VERSION}.${MINOR_VERSION} 
+    else
+        VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}
+    fi
+else
+    if test \( $MICRO_VERSION -eq 0 \); then
+        VERSION=${MAJOR_VERSION}.${MINOR_VERSION}cvs${EXTRA_VERSION}
+    else
+        VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}cvs${EXTRA_VERSION}
+    fi
+fi
+
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
+AC_DEFINE_UNQUOTED(EXTENSIONVERSION, "$VERSION", [extension version])
+
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AM_PROG_CC_STDC
+AC_LANG_C
+AC_ISC_POSIX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+# Checks for libraries.
+dnl check if compiler pre-processor defines __FUNCTION__
+AC_MSG_CHECKING([if __FUNCTION__ is defined])
+AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
+[],
+[char* cp =  __FUNCTION__])],
+[
+ AC_MSG_RESULT([yes])
+ ac_cv_HAVE_FUNCTION_DEFINED=yes
+],
+[
+ AC_MSG_RESULT([no])
+ ac_cv_HAVE_FUNCTION_DEFINED=no
+])
+
+if test "x$ac_cv_HAVE_FUNCTION_DEFINED" = "xyes"; then
+    AC_DEFINE(HAVE_FUNCTION_DEFINED, [1], [Does current compiler support __FUNCTION__])
+fi
+
+# Find pkg-config
+AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+if test x$PKG_CONFIG = xno ; then
+  AC_MSG_ERROR([*** pkg-config not found. See http://www.freedesktop.org/software/pkgconfig/])
+fi
+
+# Check for claws-contacts
+if test "x$USE_MAINTAINER_MODE" = "xyes"; then
+    CLAWS_CONTACTS_CFLAGS="-I ../../../src -I ../../../src/dbus"
+    CLAWS_CONTACTS_LIBS=""
+else
+    PKG_CHECK_MODULES(CLAWS_CONTACTS, claws-contacts >= 0.6.0)
+fi
+AC_SUBST(CLAWS_CONTACTS_CFLAGS)
+AC_SUBST(CLAWS_CONTACTS_LIBS)
+if test -z $prefix || test "${prefix}" = "NONE" ; then
+  prefix=$( $PKG_CONFIG --variable=prefix claws-contacts )
+  CLAWS_CONTACTS_EXTENSIONDIR=$( $PKG_CONFIG --variable=extensiondir claws-contacts )
+else
+  CLAWS_CONTACTS_EXTENSIONDIR='${libdir}/claws-contacts/extensions'
+fi
+AC_SUBST(CLAWS_CONTACTS_EXTENSIONDIR)
+
+if test $USE_MAINTAINER_MODE = yes; then
+    CFLAGS="-g -Wall"
+else
+    CFLAGS="-g -O2 -Wall"
+fi
+
+#ALL_LINGUAS="ca cs es fi fr hu id it ja lt nl pt_BR ru sk uk"
+#AC_DEFINE_UNQUOTED(TEXTDOMAIN, "$PACKAGE", [Gettext textdomain])
+#AM_GNU_GETTEXT_VERSION([0.15])
+#AM_GNU_GETTEXT([external])
+
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.16])
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.16)
+AC_SUBST(GTK_CFLAGS)
+AC_SUBST(GTK_LIBS)
+
+# Checks for header files.
+AC_HEADER_STDC
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+
+# check the version of libarchive
+AC_SUBST(VERSION)
+AC_SUBST(EXTENSIONVERSION)
+AC_SUBST(MAJOR_VERSION)
+AC_SUBST(MINOR_VERSION)
+AC_SUBST(MICRO_VERSION)
+AC_SUBST(EXTRA_VERSION)
+
+AC_CONFIG_COMMANDS(
+    [summary],
+    [[echo ""
+    echo "${PACKAGE} will be compiled with these settings:"
+    echo ""
+    echo -e "CFLAGS: ${CFLAGS}"
+    echo -e "Extension version: ${EXTENSION_VER}"
+    echo ""
+    echo -e "Now run make to build ${PACKAGE}"
+    echo ""
+    echo -e "Please send bugs or feature requests to the maintainer(s)."
+    echo -e "Email addresses can be found in the AUTHORS file."
+    echo ""]],
+    [
+     CFLAGS="$CFLAGS"
+     PACKAGE="$PACKAGE"
+     EXTENSION_VER="$VERSION"
+    ]
+)
+
+AC_OUTPUT([
+    Makefile
+    src/Makefile
+    src/libversit/Makefile
+])
+
diff --git a/extensions/vcard/src/.cvsignore b/extensions/vcard/src/.cvsignore
new file mode 100644 (file)
index 0000000..38f2d1c
--- /dev/null
@@ -0,0 +1,27 @@
+COPYING
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+auxdir
+*.bz2
+claws-contacts.desktop
+claws-contacts.pc
+config
+config.h
+config.h.in
+config.log
+config.status
+configure
+libtool
+m4
+org.clawsmail.ClawsContact.service
+.deps
+.libs
+*.lo
+*.la
+claws-contacts
+server-bindings.h
+stamp-h1
+src/Makefile.in
diff --git a/extensions/vcard/src/Makefile.am b/extensions/vcard/src/Makefile.am
new file mode 100644 (file)
index 0000000..c0d092b
--- /dev/null
@@ -0,0 +1,38 @@
+# $Id$
+AUTOMAKE_OPTIONS = gnu
+
+SUBDIRS = libversit
+
+extensiondir = $(CLAWS_CONTACTS_EXTENSIONDIR)
+
+extension_LTLIBRARIES = vcard-extension.la
+
+vcard_extension_la_LDFLAGS = \
+       -avoid-version -module
+
+INCLUDES = \
+          -I${top_srcdir} \
+          -I${top_srcdir}/src \
+          -I${top_srcdir}/src/libversit \
+          -I${top_builddir} \
+          @GLIB_CFLAGS@ \
+          @GTK_CFLAGS@
+
+
+vcard_extensionincludedir = \
+               $(includedir)/claws-contacts/extensions/@PACKAGE@
+
+AM_CPPFLAGS = \
+               $(CLAWS_CONTACTS_CFLAGS) \
+               -DG_LOG_DOMAIN=\"Claws-Contacts\"
+
+vcard_extension_la_SOURCES = \
+                   vcard-extension.c \
+                   vcard-utils.h \
+                       vcard-utils.c
+
+vcard_extension_la_LIBADD = \
+                   @GLIB_LIBS@ \
+                   @GTK_LIBS@ \
+                   libversit/libversit.la
+
diff --git a/extensions/vcard/src/libversit/.cvsignore b/extensions/vcard/src/libversit/.cvsignore
new file mode 100644 (file)
index 0000000..38f2d1c
--- /dev/null
@@ -0,0 +1,27 @@
+COPYING
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+auxdir
+*.bz2
+claws-contacts.desktop
+claws-contacts.pc
+config
+config.h
+config.h.in
+config.log
+config.status
+configure
+libtool
+m4
+org.clawsmail.ClawsContact.service
+.deps
+.libs
+*.lo
+*.la
+claws-contacts
+server-bindings.h
+stamp-h1
+src/Makefile.in
diff --git a/extensions/vcard/src/libversit/Makefile.am b/extensions/vcard/src/libversit/Makefile.am
new file mode 100644 (file)
index 0000000..8163acc
--- /dev/null
@@ -0,0 +1,39 @@
+# $Id$
+AUTOMAKE_OPTIONS = gnu
+
+noinst_LTLIBRARIES = libversit.la
+
+INCLUDES = \
+          @GLIB_CFLAGS@
+
+AM_CPPFLAGS = \
+               -DG_LOG_DOMAIN=\"Claws-Contacts\"
+
+YACCFLAGS = \
+           -d
+
+libversit_la_SOURCES = \
+                   port.h \
+                   vobject.c \
+                   vobject.h \
+                   vcc.c \
+                   vcc.h
+
+libversit_la_LIBADD= \
+   @GLIB_LIBS@
+
+.y.c:
+       $(YACC) $(YACCFLAGS) -o$@ $<
+#yacc -o $@ -d $<
+
+.l.c:
+       lex -o$@ $<
+
+CLEANFILES = \
+            vcc.c \
+            vcc.h
+
+EXTRA_DIST = \
+       README.TXT \
+       vcc.y
+
diff --git a/extensions/vcard/src/libversit/README.TXT b/extensions/vcard/src/libversit/README.TXT
new file mode 100644 (file)
index 0000000..ae81080
--- /dev/null
@@ -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 pratically always neccessary 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/extensions/vcard/src/libversit/port.h b/extensions/vcard/src/libversit/port.h
new file mode 100644 (file)
index 0000000..1768bee
--- /dev/null
@@ -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/extensions/vcard/src/libversit/vcc.y b/extensions/vcard/src/libversit/vcc.y
new file mode 100644 (file)
index 0000000..17d534f
--- /dev/null
@@ -0,0 +1,1302 @@
+%{
+
+/***************************************************************************
+(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+
+For purposes of this license notice, the term Licensors shall mean,
+collectively, Apple Computer, Inc., AT&T Corp., International
+Business Machines Corporation and Siemens Rolm Communications Inc.
+The term Licensor shall mean any of the Licensors.
+
+Subject to acceptance of the following conditions, permission is hereby
+granted by Licensors without the need for written agreement and without
+license or royalty fees, to use, copy, modify and distribute this
+software for any purpose.
+
+The above copyright notice and the following four paragraphs must be
+reproduced in all copies of this software and any software including
+this software.
+
+THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
+ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
+MODIFICATIONS.
+
+IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+The software is provided with RESTRICTED RIGHTS.  Use, duplication, or
+disclosure by the government are subject to restrictions set forth in
+DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
+
+***************************************************************************/
+
+/*
+ * src: vcc.c
+ * doc: Parser for vCard and vCalendar. Note that this code is
+ * generated by a yacc parser generator. Generally it should not
+ * be edited by hand. The real source is vcc.y. The #line directives
+ * can be commented out here to make it easier to trace through
+ * in a debugger. However, if a bug is found it should
+ * be fixed in vcc.y and this file regenerated.
+ */
+
+
+/* debugging utilities */
+#if __DEBUG
+#define DBG_(x) printf x
+#else
+#define DBG_(x)
+#endif
+
+/****  External Functions  ****/
+
+/* assign local name to parser variables and functions so that
+   we can use more than one yacc based parser.
+*/
+
+#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 "vobject.h"
+
+static int yylex(void);
+static void yyerror(char *s);
+
+/****  Types, Constants  ****/
+
+#define YYDEBUG                1       /* 1 to compile in some debugging code */
+#define MAXTOKEN       256     /* maximum token (line) length */
+#define YYSTACKSIZE    4096    /* ~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);
+    extern void yyerror(char *s);
+
+#if __CPLUSPLUS__
+    };
+#endif
+
+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 int pushVObject(const char *prop);
+static VObject* popVObject(void);
+#ifndef _SUPPORT_LINE_FOLDING
+static char* lexDataFromBase64(void);
+#endif
+static void lexPopMode(int top);
+static int lexWithinMode(enum LexMode mode);
+static void lexPushMode(enum LexMode mode);
+static void enterProps(const char *s);
+static void enterAttr(const char *s1, const char *s2);
+#if 0
+static void enterValues(const char *value);
+#endif
+static void mime_error_(char *s);
+ static void appendValue(const char *value);
+
+static int
+ascii_tolower(const char i) {
+       if ('A' <= i && i <= 'Z')
+               return i - ('A' - 'a');
+       return i;
+}
+
+static int
+ascii_stricmp(const char* s1, const char* s2) {
+       const char *p = s1, *q = s2;
+       while (*p || *q) {
+               char c1 = ascii_tolower(*p++);
+               char c2 = ascii_tolower(*q++);
+               if (c1 < c2)
+                       return -1;
+               if (c1 > c2)
+                       return 1;
+       }
+       return 0;
+}
+
+%}
+
+/***************************************************************************/
+/***                           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 { appendValue($1); } values
+       | value
+       { appendValue($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 appendValue(const char *value)
+{
+  char *p1, *p2;
+  wchar_t *p3;
+  int i;
+
+  if (fieldedProp && *fieldedProp) {
+    if (value) {
+      addPropValue(curProp, *fieldedProp, value);
+    }
+    /* else this field is empty, advance to next field */
+    fieldedProp++;
+  } else {
+    if (value) {
+      if (vObjectUStringZValue(curProp)) {
+       p1 = fakeCString(vObjectUStringZValue(curProp));
+       p2 = malloc(sizeof(char *) * (strlen(p1)+strlen(value)+1));
+       strcpy(p2, p1);
+       deleteStr(p1);
+
+       i = strlen(p2);
+       p2[i] = ';';
+       p2[i+1] = '\0';
+       p2 = strcat(p2, value);
+       p3 = (wchar_t *) vObjectUStringZValue(curProp);
+       free(p3);
+       setVObjectUStringZValue_(curProp,fakeUnicode(p2,0));
+       deleteStr(p2);
+      } else {
+       setVObjectUStringZValue_(curProp,fakeUnicode(value,0));
+      }
+    }
+  }
+  deleteStr(value);
+}
+
+#if 0
+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) {
+           setVObjectUStringZValue_(curProp,fakeUnicode(value,0));
+           }
+       }
+    deleteStr(value);
+    }
+#endif
+
+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 (ascii_stricmp(p1,VCBase64Prop) == 0 || (s2 && ascii_stricmp(p2,VCBase64Prop)==0))
+       lexPushMode(L_BASE64);
+    else if (ascii_stricmp(p1,VCQuotedPrintableProp) == 0
+           || (s2 && ascii_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 int instead of char so that EOF
+        /      can be represented correctly.
+       */
+    unsigned long len;
+    int buf[MAX_LEX_LOOKAHEAD];
+    unsigned long getPtr;
+       /* context stack */
+    unsigned long lexModeStackTop;
+    enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
+       /* token buffer */
+    unsigned long maxToken;
+    char *strs;
+    unsigned long strsLen;
+    } lexBuf;
+
+static void lexPushMode(enum LexMode mode)
+    {
+    if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
+       yyerror("lexical context stack overflow");
+    else {
+       lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
+       }
+    }
+
+static void lexPopMode(int top)
+    {
+    /* special case of pop for ease of error recovery -- this
+       version will never underflow */
+    if (top)
+       lexBuf.lexModeStackTop = 0;
+    else
+       if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
+    }
+
+static int lexWithinMode(enum LexMode mode) {
+    unsigned long i;
+    for (i=0;i<lexBuf.lexModeStackTop;i++)
+       if (mode == lexBuf.lexModeStack[i]) return 1;
+    return 0;
+    }
+
+static int lexGetc_()
+    {
+    /* get next char from input, no buffering. */
+    if (lexBuf.curPos == lexBuf.inputLen)
+       return EOF;
+    else if (lexBuf.inputString)
+       return *(lexBuf.inputString + lexBuf.curPos++);
+    else {
+#ifdef INCLUDEMFC
+       char result;
+       return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
+#else
+       return fgetc(lexBuf.inputFile);
+#endif
+       }
+    }
+
+static int lexGeta()
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
+    }
+
+static int lexGeta_(int i)
+    {
+    ++lexBuf.len;
+    return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
+    }
+
+static void lexSkipLookahead() {
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+       /* don't skip EOF. */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+       lexBuf.len--;
+        }
+    }
+
+static int lexLookahead() {
+    int c = (lexBuf.len)?
+       lexBuf.buf[lexBuf.getPtr]:
+       lexGeta();
+    /* do the \r\n -> \n or \r -> \n translation here */
+    if (c == '\r') {
+       int a = (lexBuf.len>1)?
+           lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
+           lexGeta_(1);
+       if (a == '\n') {
+           lexSkipLookahead();
+           }
+       lexBuf.buf[lexBuf.getPtr] = c = '\n';
+       }
+    else if (c == '\n') {
+       int a = (lexBuf.len>1)?
+           lexBuf.buf[lexBuf.getPtr+1]:
+           lexGeta_(1);
+       if (a == '\r') {
+           lexSkipLookahead();
+           }
+       lexBuf.buf[lexBuf.getPtr] = '\n';
+       }
+    return c;
+    }
+
+static int lexGetc() {
+    int c = lexLookahead();
+    if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
+       /* EOF will remain in lookahead buffer */
+        lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
+       lexBuf.len--;
+        }
+    return c;
+    }
+
+static void lexSkipLookaheadWord() {
+    if (lexBuf.strsLen <= lexBuf.len) {
+       lexBuf.len -= lexBuf.strsLen;
+       lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
+       }
+    }
+
+static void lexClearToken()
+    {
+    lexBuf.strsLen = 0;
+    }
+
+static void lexAppendc(int c)
+    {
+    lexBuf.strs[lexBuf.strsLen] = c;
+    /* append up to zero termination */
+    if (c == 0) return;
+    lexBuf.strsLen++;
+    if (lexBuf.strsLen >= lexBuf.maxToken) {
+       /* double the token string size */
+       lexBuf.maxToken <<= 1;
+       lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
+       }
+    }
+
+static char* lexStr() {
+    return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
+    }
+
+static void lexSkipWhite() {
+    int c = lexLookahead();
+    while (c == ' ' || c == '\t') {
+       lexSkipLookahead();
+       c = lexLookahead();
+       }
+    }
+
+static char* lexGetWord() {
+    int c;
+    lexSkipWhite();
+    lexClearToken();
+    c = lexLookahead();
+    while (c != EOF && !strchr("\t\n ;:=",c)) {
+       lexAppendc(c);
+       lexSkipLookahead();
+       c = lexLookahead();
+       }
+    lexAppendc(0);
+    return lexStr();
+    }
+
+#if 0
+static void lexPushLookahead(char *s, int len) {
+    int putptr;
+    if (len == 0) len = strlen(s);
+    putptr = (int)lexBuf.getPtr - len;
+    /* this function assumes that length of word to push back
+     /  is not greater than MAX_LEX_LOOKAHEAD.
+     */
+    if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
+    lexBuf.getPtr = putptr;
+    while (*s) {
+       lexBuf.buf[putptr] = *s++;
+       putptr = (putptr + 1) % MAX_LEX_LOOKAHEAD;
+       }
+    lexBuf.len += len;
+    }
+#endif
+
+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
+
+#ifndef _SUPPORT_LINE_FOLDING
+static char* lexGetStrUntil(char *termset) {
+    int c = lexLookahead();
+    lexClearToken();
+    while (c != EOF && !strchr(termset,c)) {
+       lexAppendc(c);
+       lexSkipLookahead();
+       c = lexLookahead();
+       }
+    lexAppendc(0);
+    return c==EOF?0:lexStr();
+    }
+#endif
+
+static int match_begin_name(int end) {
+    char *n = lexLookaheadWord();
+    int token = ID;
+    if (n) {
+       if (!ascii_stricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
+       else if (!ascii_stricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
+       else if (!ascii_stricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
+       else if (!ascii_stricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
+       deleteStr(n);
+       return token;
+       }
+    return 0;
+    }
+
+
+#ifdef INCLUDEMFC
+static void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
+#else
+static 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;
+            c = lexLookahead();
+           if ((c == ' ') || (c == '\t')) {
+              /* rfc822 line folding */
+              lexSkipLookahead();
+              continue;
+            }
+            else {
+              lexPushLookaheadc('\n');
+              break;
+            }
+       }
+       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' at line %i\n", c,c, mime_lineNum));
+               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 = %ld\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()
+    {
+    int 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':
+           case ';':
+             {
+               lexPushLookaheadc(cur);
+               goto EndString;
+               }
+           case EOF:
+               break;
+           default:
+               lexAppendc(cur);
+               break;
+           } /* switch */
+       } while (cur != EOF);
+
+EndString:
+    lexAppendc(0);
+    return lexStr();
+    } /* LexQuotedPrintable */
+
+static 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)) {
+            c = lexLookahead();
+            if ((c == ' ') || (c == '\t')) {
+                /* rfc822 line folding */
+                c = '\n';
+            }
+            else {
+                /* other case */
+            
+                ++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;
+           }
+        }
+       {
+           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 (!ascii_stricmp(t, "begin")) {
+                           return match_begin_end_name(0);
+                           }
+                       else if (!ascii_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) {
+       finiLex();
+       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
+
+/* ///////////////////////////////////////////////////////////////////////// */
+/* 
+       added possibility to have user data send as part of mime error handler
+       2011-12-30 Michael Rasmussen <mir@datanom.net>
+*/
+
+typedef void (* MimeErrorHandler)(char *, void *);
+
+static MimeErrorHandler mimeErrorHandler;
+static void* user_data;
+
+DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me, void* data)
+    {
+    mimeErrorHandler = me;
+       user_data = data;
+    }
+
+static void mime_error(char *s)
+    {
+    char msg[256];
+    if (mimeErrorHandler) {
+       sprintf(msg,"%s at line %d", s, mime_lineNum);
+       mimeErrorHandler(msg, user_data);
+       }
+    }
+
+static void mime_error_(char *s)
+    {
+    if (mimeErrorHandler) {
+       mimeErrorHandler(s, user_data);
+       }
+    }
+
+
diff --git a/extensions/vcard/src/libversit/vobject.c b/extensions/vcard/src/libversit/vobject.c
new file mode 100644 (file)
index 0000000..fb78253
--- /dev/null
@@ -0,0 +1,1469 @@
+/***************************************************************************
+(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.
+ */
+
+#include "vobject.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#define USE_STRTBL
+
+#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);
+}
+
+
+#ifdef USE_STRTBL
+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);
+}
+#endif
+
+/*----------------------------------------------------------------------
+  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.
+  ----------------------------------------------------------------------*/
+#ifdef USE_STRTBL
+
+#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;
+}
+
+#endif
+
+DLLEXPORT(const char*) lookupStr(const char *s)
+{
+#ifdef USE_STRTBL
+    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;
+#else
+  return dupStr(s, 0);
+#endif
+}
+
+DLLEXPORT(void) unUseStr(const char *s)
+{
+#ifdef USE_STRTBL
+    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 (t == strTbl[h]) {
+                       strTbl[h] = t->next;
+                       }
+                   else {
+                       p->next = t->next;
+                       }
+                   deleteStr(t->s);
+                   deleteStrItem(t);
+                   return;
+                   }
+               }
+           p = t;
+           t = t->next;
+           } while (t);
+       }
+#else
+  deleteStr (s);
+#endif
+}
+
+DLLEXPORT(void) cleanStrTbl()
+{
+#ifdef USE_STRTBL
+    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;
+       }
+#endif
+}
+
+
+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 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 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 == '=' ) {
+               sprintf(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];
+           sprintf(buf,"%u", INTEGER_VALUE_OF(o));
+           appendsOFile(fp,buf);
+           break;
+           }
+       case VCVT_ULONG: {
+           char buf[16];
+           sprintf(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)) {
+       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) {
+       strcpy(buf2,STRINGZ_VALUE_OF(o));
+       strcat(buf2,".");
+       strcat(buf2,buf1);
+       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)) {
+       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)) {
+       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;
+
+    if (!u)
+       return strdup("");
+    
+    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/extensions/vcard/src/libversit/vobject.h b/extensions/vcard/src/libversit/vobject.h
new file mode 100644 (file)
index 0000000..4c8585e
--- /dev/null
@@ -0,0 +1,374 @@
+/***************************************************************************
+(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"
+#define XPilotNoTimeProp                        "X-PILOT-NOTIME"
+
+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);
+
+/* Forgotten functions added by Michael Rasmussen <mir@datanom.net> */
+DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len);
+VObject* Parse_MIME_FromFile(FILE *file);
+DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname);
+
+typedef void (* MimeErrorHandler)(char *, void *);
+DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me, void* data);
+
+#if defined(__CPLUSPLUS__) || defined(__cplusplus)
+}
+#endif
+
+#endif /* __VOBJECT_H__ */
+
+
diff --git a/extensions/vcard/src/vcard-extension.c b/extensions/vcard/src/vcard-extension.c
new file mode 100644 (file)
index 0000000..1f351a9
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * $Id$
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Claws-contacts is a proposed new design for the address book feature
+ * in Claws Mail. The goal for this new design was to create a
+ * solution more suitable for the term lightweight and to be more
+ * maintainable than the present implementation.
+ *
+ * More lightweight is achieved by design, in that sence that the whole
+ * structure is based on a plugable design.
+ *
+ * Claws Mail is Copyright (C) 1999-2011 by the Claws Mail Team and
+ * Claws-contacts is Copyright (C) 2011 by Michael Rasmussen.
+ *
+ * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+#ifdef HAVE_CONFIG_H
+#       include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "extension.h"
+#include "plugin-loader.h"
+#include "plugin.h"
+#include "utils.h"
+#include "gtk-utils.h"
+#include "vobject.h"
+#include "vcc.h"
+#include "vcard-utils.h"
+
+#define NAME "vCard extension"
+
+static guint my_id;
+
+static void mime_error_handler(char *s, void* user_data) {
+       MenuItem* item = (MenuItem *) user_data;
+       
+       gchar* msg = g_strdup_printf("vCard parser: %s", s);
+       show_message(item->mainwindow->window, GTK_UTIL_MESSAGE_WARNING, msg);
+       g_free(msg);
+}
+
+static void vcard_import(GtkWidget* widget, gpointer data) {
+       MenuItem* item = (MenuItem *) data;
+       FILE* fp = fopen("/home/mir/CDCARDS/list.vcf", "r");
+       VObject *t, *v;
+       gchar* error = NULL;
+       AddressBook* abook;
+       Plugin* plugin;
+       gint count = 0, total = 0;
+       gchar* leftover;
+       FILE* f = NULL;
+
+       abook = get_selected_address_book(GTK_TREE_VIEW(item->mainwindow->abook_list));
+       plugin = get_selected_plugin(GTK_TREE_VIEW(item->mainwindow->abook_list));
+       
+       if (!abook && !plugin) {
+               show_message(item->mainwindow->window, GTK_UTIL_MESSAGE_ERROR,
+                       _("Missing address book"));
+               return;
+       }
+       
+       gchar* filename = g_strdup_printf("vcard_rejected.%d", getpid());
+       leftover = g_build_filename(get_home(), filename, NULL);
+       g_free(filename);
+       registerMimeErrorHandler(mime_error_handler, data);
+       v = Parse_MIME_FromFile(fp);
+       while (v) {
+               total++;
+               const gchar* name = vObjectName(v);
+           if (name && strcmp(name,VCCardProp) == 0) {
+                       // ... do something to v.
+                       t = v;
+                       Contact* c = vcard2contact(t, plugin, &error);
+                       if (c)
+                               plugin->set_contact(abook, c, &error);
+                       if (error) {
+                               show_message(item->mainwindow->window, GTK_UTIL_MESSAGE_ERROR, error);
+                               g_free(error);
+                               error = NULL;
+                               if (! f)
+                                       f = g_fopen(leftover, "w");
+                               if (f) {
+                                       writeVObject(f, v);
+                               }
+                       }
+                       else {
+                               count++;
+                               abook->contacts = g_list_prepend(abook->contacts, c);
+                               list_view_append_contact(GTK_TREE_VIEW(item->mainwindow->contact_list), c);
+                       }
+               }
+               else
+                       mime_error_handler(_("Object is not in vCard format"), data);
+               v = nextVObjectInList(v);
+               cleanVObject(t);
+       }
+
+       if (f)
+               fclose(f);
+       abook->contacts = g_list_reverse(abook->contacts);
+       show_message(item->mainwindow->window, GTK_UTIL_MESSAGE_INFO,
+               _("%s: Imported %d contacts out of %d Objects.\n"
+                 "Rejected Objects can be found in %s"),
+                       abook->abook_name, count, total, leftover);
+       g_free(leftover);
+}
+
+static void vcard_export(GtkWidget* widget, gpointer data) {
+       MenuItem* item = (MenuItem *) data;
+       FILE* fp = fopen("/home/mir/CDCARDS/contacts.vcf", "r");
+       VObject *t, *v;
+
+       registerMimeErrorHandler(mime_error_handler, data);
+       v = Parse_MIME_FromFile(fp);
+       while (v) {
+               const gchar* name = vObjectName(v);
+           if (name && strcmp(name,VCCardProp) == 0) {
+                       // ... do something to v.
+                       t = v;
+                       printVObject(stderr, v);
+               }
+               else
+                       mime_error_handler("Object is not in vCard format", data);
+               v = nextVObjectInList(v);
+               cleanVObject(t);
+       }
+
+       show_message(item->mainwindow->window, GTK_UTIL_MESSAGE_INFO, "test");
+}
+
+static void setup(const MainWindow* mainwindow, gpointer object) {
+    GtkWidget *menu;
+    MenuItem* menu_item;
+       
+/*     menu = gtk_image_menu_item_new_with_mnemonic("_vCard");
+       gtk_widget_set_name(menu, "contextmenu");
+    g_signal_connect(menu, "activate",
+            G_CALLBACK(my_cb), (gpointer) mainwindow);
+    menu_item = menu_item_new();
+    menu_item->menu = CONTACTS_CONTACT_MENU;
+    menu_item->parent = "tools";
+       menu_item->sublabel = "_Import";
+    menu_item->submenu = FALSE;
+       add_menu_item(GTK_IMAGE_MENU_ITEM(menu), menu_item);*/
+       
+       // Add a menu item into the context menu of contact
+    menu = gtk_image_menu_item_new_with_mnemonic("_vCard");
+    menu_item = menu_item_new();
+    menu_item->menu = CONTACTS_CONTACT_MENU;
+    menu_item->sublabel = "_Export";
+    menu_item->submenu = TRUE;
+       menu_item->mainwindow = mainwindow;
+    g_signal_connect(menu, "activate",
+               G_CALLBACK(vcard_export), (gpointer) menu_item);
+    add_menu_item(GTK_IMAGE_MENU_ITEM(menu), menu_item);
+
+    // Add a menu item into the context menu of address book
+    menu = gtk_image_menu_item_new_with_mnemonic("_vCard");
+    menu_item = menu_item_new();
+    menu_item->menu = CONTACTS_ADDRESSBOOK_MENU;
+    menu_item->sublabel = "_Export";
+    menu_item->submenu = TRUE;
+       menu_item->mainwindow = mainwindow;
+    g_signal_connect(menu, "activate",
+               G_CALLBACK(vcard_export), (gpointer) menu_item);
+    add_menu_item(GTK_IMAGE_MENU_ITEM(menu), menu_item);
+
+    // Add a menu item into the context menu of address book
+    menu = gtk_image_menu_item_new_with_mnemonic("_vCard");
+    menu_item = menu_item_new();
+    menu_item->menu = CONTACTS_ADDRESSBOOK_MENU;
+    menu_item->sublabel = "_Import";
+    menu_item->submenu = TRUE;
+       menu_item->mainwindow = mainwindow;
+    g_signal_connect(menu, "activate",
+               G_CALLBACK(vcard_import), (gpointer) menu_item);
+    add_menu_item(GTK_IMAGE_MENU_ITEM(menu), menu_item);
+}
+
+/**
+ * The main application will call this function after loading the
+ * extension providing a uniq id for the extension which is to be
+ * used for further references
+ * @param id uniq id provided by main application
+ * @return 0 if success 1 otherwise
+ */
+gint extension_init(guint id) {
+       my_id = id;
+       gchar* error = NULL;
+       
+       register_hook_function(my_id, EXTENSION_AFTER_INIT_HOOK, setup, &error);
+       return 0;
+}
+
+/**
+ * Called by main application when the extension should be unloaded
+ * @return TRUE if success FALSE otherwise
+ */
+gboolean extension_done(void) {
+       return TRUE;
+}
+
+/**
+ * Called by main application to ensure extension license is compatible
+ * @return license
+ */
+const gchar* extension_license(void) {
+       return "GPL3+";
+}
+
+/**
+ * Called by main application to get name of extension
+ * @return name
+ */
+const gchar* extension_name(void) {
+       return NAME;
+}
+
+/**
+ * Called by main application to get extension's describtion
+ * @return description
+ */
+const gchar* extension_describtion(void) {
+       return _("Export and import contacts in vCard 2.1 format");
+}
diff --git a/extensions/vcard/src/vcard-utils.c b/extensions/vcard/src/vcard-utils.c
new file mode 100644 (file)
index 0000000..543e27a
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * $Id$
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Claws-contacts is a proposed new design for the address book feature
+ * in Claws Mail. The goal for this new design was to create a
+ * solution more suitable for the term lightweight and to be more
+ * maintainable than the present implementation.
+ *
+ * More lightweight is achieved by design, in that sence that the whole
+ * structure is based on a plugable design.
+ *
+ * Claws Mail is Copyright (C) 1999-2011 by the Claws Mail Team and
+ * Claws-contacts is Copyright (C) 2011 by Michael Rasmussen.
+ *
+ * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+#ifdef HAVE_CONFIG_H
+#       include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <string.h>
+#include "plugin.h"
+#include "extension.h"
+#include "utils.h"
+#include "gtk-utils.h"
+#include "vobject.h"
+#include "vcard-utils.h"
+
+enum {
+       VCARD2LDAP,
+       VCARD2XML,
+       NUMTYPES,
+};
+
+enum {
+       PHONEMOBILE,
+       PHONEHOME,
+       PHONEWORK,
+       NUMPHONES,
+};
+
+static const gchar* phone[NUMTYPES][NUMPHONES] =
+               { 
+                       {"mobile", "homePhone", "telephoneNumber"}, /* LDAP */
+                       {"mobile phone", "phone", "office phone"}   /* XML  */
+               };
+
+static void* vcard_value(VObject* o) {
+    switch (vObjectValueType(o)) {
+               case VCVT_USTRINGZ: {
+               gchar* s;
+               s = fakeCString(vObjectUStringZValue(o));
+               return (void *) s;
+           }
+               case VCVT_STRINGZ: {
+               const char* s = vObjectStringZValue(o);
+               gchar* v = g_strdup(s);
+               return (void *) v;
+           }
+               case VCVT_UINT:
+                       return GINT_TO_POINTER(vObjectIntegerValue(o));
+               case VCVT_ULONG:
+               return GUINT_TO_POINTER(vObjectLongValue(o));
+/*         case VCVT_NOVALUE:
+               return (void *) 0;*/
+           default: {
+               gchar* s;
+               const wchar_t* u = vObjectUStringZValue(o);
+               if (u)
+                       s = fakeCString(vObjectUStringZValue(o));
+               else
+                       s = g_strdup("");
+               return (void *) s;
+               }
+       }
+}
+
+static gchar* vcard_version(VObject* o) {
+       VObjectIterator iter;
+       VObject* prop;
+       const gchar* version = NULL;
+       
+       initPropIterator(&iter,o);
+       while (moreIteration(&iter) && !version) {
+               prop = nextVObject(&iter);
+               if (prop && vObjectName(prop))
+                       version = strcmp(vObjectName(prop), VCVersionProp) ? NULL :
+                               (gchar *) vcard_value(prop);
+       }
+       /* Assume version 2.1 if version is not specified */
+       return (version) ? g_strdup(version) : g_strdup("2.1"); 
+}
+       
+static gchar* vcard2native(VObject* v, gchar* version, const gchar* plugin_type) {
+       const gchar* name = vObjectName(v);
+       gchar* attr = NULL;
+       
+       if (strcmp(VCFullNameProp, name) == 0)
+               attr = g_strdup("cn");
+       else if (strcmp(VCGivenNameProp, name) == 0)
+               attr = g_strdup("first-name");
+       else if (strcmp(VCFamilyNameProp, name) == 0)
+               attr = g_strdup("last-name");
+       else if (strcmp(VCAdditionalNamesProp, name) == 0)
+               attr = g_strdup("addn");
+       else if (strcmp(VCCellularProp, name) == 0)
+               attr = g_strdup("mobile");
+       else if (strcmp(VCTelephoneProp, name) == 0) {
+               if (strcmp("2.1", version) == 0)
+                       attr = g_strdup("telephoneNumber");
+               else {
+                       VObjectIterator iter;
+                       initPropIterator(&iter,v);
+               while (moreIteration(&iter) && !attr) {
+                               VObject *prop = nextVObject(&iter);
+                               if (strcmp(vObjectName(prop), "TYPE") == 0) {
+                                       gchar* value = (gchar *) vcard_value(prop);
+                                       if (value) {
+                                               if (g_str_has_prefix(plugin_type, "LDAP")) {
+                                                       if (g_strstr_len(value, strlen(value), "CELL"))
+                                                               attr = g_strdup(phone[VCARD2LDAP][PHONEMOBILE]);
+                                                       else if (g_strstr_len(value, strlen(value), "HOME"))
+                                                               attr = g_strdup(phone[VCARD2LDAP][PHONEHOME]);
+                                                       else if (g_strstr_len(value, strlen(value), "WORK"))
+                                                               attr = g_strdup(phone[VCARD2LDAP][PHONEWORK]);
+                                               }
+                                               else if (g_str_has_prefix(plugin_type, "XML")) {
+                                                       if (g_strstr_len(value, strlen(value), "CELL"))
+                                                               attr = g_strdup(phone[VCARD2XML][PHONEMOBILE]);
+                                                       else if (g_strstr_len(value, strlen(value), "HOME"))
+                                                               attr = g_strdup(phone[VCARD2XML][PHONEHOME]);
+                                                       else if (g_strstr_len(value, strlen(value), "WORK"))                                                    
+                                                               attr = g_strdup(phone[VCARD2XML][PHONEWORK]);
+                                               }
+                                               else
+                                                       attr = g_strdup("telephoneNumber");
+                                       }
+                               }
+                       }
+                       if (! attr)
+                               attr = g_strdup("telephoneNumber");
+               }
+       }
+       else if (strcmp(VCEmailAddressProp, name) == 0)
+               attr = g_strdup("email");
+       else if (strcmp(VCPhotoProp, name) == 0)
+               attr = g_strdup("image");
+       /* Version 3.0 */
+       else if (strcasecmp("nickname", name) == 0)
+               attr = g_strdup("nick-name");
+       else
+               attr = g_ascii_strdown(name, -1);
+               
+       return attr;
+}
+
+Contact* vcard2contact(VObject* vcard, Plugin* plugin, gchar** error) {
+       Contact* contact = NULL;
+       VObjectIterator iter;
+       gchar* family = NULL;
+       void* value;
+/*     GSList *attribs, *abook_attribs;
+       gboolean found;*/
+       const gchar* type;
+       gchar* version;
+
+       cm_return_val_if_fail(plugin != NULL, NULL);
+       cm_return_val_if_fail(vcard != NULL, NULL);
+               
+/*     attribs = plugin->attrib_list();*/
+       type = plugin->name();
+       version = vcard_version(vcard);
+       
+       //fprintf(stderr, "=======================================\n");
+       //printVObject(stderr, vcard);
+       //fprintf(stderr, "=======================================\n");
+       contact = contact_new();
+       initPropIterator(&iter,vcard);
+       while (moreIteration(&iter)) {
+               VObject* prop = nextVObject(&iter);
+               gchar* attrib = vcard2native(prop, version, type);
+/*             if (strcmp(attrib, "mobile") == 0) {
+                       abook_attribs = attribs;
+                       found = FALSE;
+                       while (abook_attribs && !found) {
+                               AttribDef* attr = (AttribDef *) abook_attribs->data;
+                               if (attr->type == ATTRIB_TYPE_STRING) {
+                                       if (attr->attrib_name && g_strstr_len(attr->attrib_name,
+                                                       strlen(attr->attrib_name), attrib)) {
+                                               value = vcard_value(prop);
+                                               fprintf(stderr, "(mobile) adding: %s -> %s\n", attrib, (gchar *)value);
+                                               swap_data(contact->data, attr->attrib_name, value);
+                                               g_free(value);
+                                               found = TRUE;
+                                       }       
+                               }
+                               abook_attribs = abook_attribs->next;
+                       }
+               }
+               else if (strcmp(attrib, "telephoneNumber") == 0) {
+                       abook_attribs = attribs;
+                       found = FALSE;
+                       while (abook_attribs && !found) {
+                               AttribDef* attr = (AttribDef *) abook_attribs->data;
+                               if (attr->type == ATTRIB_TYPE_STRING) {
+                                       if (attr->attrib_name && g_strstr_len(attr->attrib_name,
+                                                       strlen(attr->attrib_name), "phone") &&
+                                                       ! g_strstr_len(attr->attrib_name,
+                                                       strlen(attr->attrib_name), "mobile")) {
+                                               value = vcard_value(prop);
+                                               fprintf(stderr, "(telephone) adding: %s -> %s\n", attrib, (gchar *)value);
+                                               swap_data(contact->data, attr->attrib_name, value);
+                                               g_free(value);
+                                               found = TRUE;
+                                       }       
+                               }
+                               abook_attribs = abook_attribs->next;
+                       }
+               }
+               else*/ if (strcmp(attrib, "last-name") == 0) {
+                       value = vcard_value(prop);
+                       if (family) {
+                               gchar* tmp = family;
+                               g_free(family);
+                               family = g_strconcat(tmp, " ", value, NULL);
+                               g_free(tmp);
+                       }
+                       else
+                               family = g_strdup(value);
+                       g_free(value);
+               }
+               else if (strcmp(attrib, "addn") == 0) {
+                       value = vcard_value(prop);
+                       if (family) {
+                               gchar* tmp = family;
+                               g_free(family);
+                               family = g_strconcat(value, " ", tmp, NULL);
+                               g_free(tmp);
+                       }
+                       else
+                               family = g_strdup(value);
+                       g_free(value);
+               }
+               else if (strcmp(attrib, "email") == 0) {
+                       Email* e = g_new0(Email, 1);
+                       value = vcard_value(prop);
+                       e->email = g_strdup(value);
+                       contact->emails = g_slist_append(contact->emails, e);
+                       g_free(value);
+               }
+               else if (strcmp(attrib, "image") == 0) {
+                       value = vcard_value(prop);
+                       gchar* image = jpeg_to_png_base64((guchar *) value, strlen((const gchar *) value));
+                       swap_data(contact->data, attrib, image);
+                       g_free(value);
+               }
+               else {
+                       value = vcard_value(prop);
+                       debug_print("adding: %s -> %s\n", attrib, value);
+                       fprintf(stderr, "(catch all) adding: %s -> %s\n", attrib, (gchar *)value);
+                       swap_data(contact->data, attrib, value);
+                       g_free(value);
+               }
+               g_free(attrib);
+       }
+       
+       if (family) {
+               swap_data(contact->data, "last-name", family);
+               g_free(family);
+       }
+       else {
+               if (g_str_has_prefix(type, "LDAP")) {
+                       extract_data(contact->data, "cn", (void *) &family);
+                       if (family) {
+                               gchar* pos = strrchr(family, ' ');
+                               if (pos && strlen(family) > pos - family) {
+                                       pos += 1;
+                                       swap_data(contact->data, "last-name", pos);
+                               }
+                               else
+                                       swap_data(contact->data, "last-name", "DUMMY");
+                       }
+                       else
+                               swap_data(contact->data, "last-name", "DUMMY");
+               }
+       }
+       
+/*     gslist_free(&attribs, attrib_def_free);*/
+
+       return contact;
+}
diff --git a/extensions/vcard/src/vcard-utils.h b/extensions/vcard/src/vcard-utils.h
new file mode 100644 (file)
index 0000000..fdda27a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * $Id$
+ */
+/* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
+
+/*
+ * Claws-contacts is a proposed new design for the address book feature
+ * in Claws Mail. The goal for this new design was to create a
+ * solution more suitable for the term lightweight and to be more
+ * maintainable than the present implementation.
+ *
+ * More lightweight is achieved by design, in that sence that the whole
+ * structure is based on a plugable design.
+ *
+ * Claws Mail is Copyright (C) 1999-2011 by the Claws Mail Team and
+ * Claws-contacts is Copyright (C) 2011 by Michael Rasmussen.
+ *
+ * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+
+#ifndef __VCARD_UTILS_H__
+#define __VCARD_UTILS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#include "mainwindow.h"
+#include "plugin.h"
+#include "vobject.h"
+
+Contact* vcard2contact(VObject* vcard, Plugin* plugin, gchar** error);
+
+G_END_DECLS
+
+#endif