diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/AddingOrModifyingComponents.txt | 23 | ||||
-rw-r--r-- | doc/CMakeLists.txt | 3 | ||||
-rw-r--r-- | doc/Makefile.am | 1 | ||||
-rw-r--r-- | doc/Makefile.in | 419 | ||||
-rw-r--r-- | doc/UsingLibical.txt | 1378 |
5 files changed, 1824 insertions, 0 deletions
diff --git a/doc/AddingOrModifyingComponents.txt b/doc/AddingOrModifyingComponents.txt new file mode 100644 index 00000000..e9f46c27 --- /dev/null +++ b/doc/AddingOrModifyingComponents.txt @@ -0,0 +1,23 @@ + +How to add or change Components, Properties, Values or Parameters + + +Adding or modifying values +--------------------------- + +You may have to modify these files or data structures + +file design-data/value-c-types.txt +file design-data/prop-to-val.txt +table parameter_map[] in icalenums.c +enum icalvalue_kind in icalenum.h +table value_map[] in icalenums.c +enum icalparameter_value in icalenum.h +table propval_map[] in icalenums.c +function icalvalue_as_ical_string() in icalvalue.c +function icalvalue_new_from_string_with_error() in icalvalue.c + +When you are done, if you changed any files in the design-data +directory, regnerate derived datatypes in src/libical with "make +derived" or "make icalvalue" + diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 00000000..0b7b3433 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,3 @@ + +########### install files ############### + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..a2914c37 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = UsingLibical.txt diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..6a54cfb4 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,419 @@ +# Makefile.in generated by automake 1.12.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2012 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = doc +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(top_srcdir)/mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BDB_DIR = @BDB_DIR@ +BDB_DIR_INCLUDE = @BDB_DIR_INCLUDE@ +BDB_DIR_LIB = @BDB_DIR_LIB@ +BDB_LIB = @BDB_LIB@ +BDB_VERSION = @BDB_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAR = @JAR@ +JAVA = @JAVA@ +JAVAC = @JAVAC@ +JAVAH = @JAVAH@ +JAVA_PLATFORM = @JAVA_PLATFORM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_CFLAGS = @PY_CFLAGS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZONE_INFO = @ZONE_INFO@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +swig_val = @swig_val@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = UsingLibical.txt +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + +cscope cscopelist: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/UsingLibical.txt b/doc/UsingLibical.txt new file mode 100644 index 00000000..fb4b07ec --- /dev/null +++ b/doc/UsingLibical.txt @@ -0,0 +1,1378 @@ + + +Using Libical + +Eric Busboom (eric@softwarestudio.org) + +January 2001 + + + +1 Introduction + +Libical is an Open Source implementation of the iCalendar protocols +and protocol data units. The iCalendar specification describes how +calendar clients can communicate with calendar servers so users can +store their calendar data and arrange meetings with other users. + +Libical implements RFC2445, RFC2446 and some of RFC2447. + +This documentation assumes that you are familiar with the iCalendar +standards RFC2445 and RFC2446. these specifications are online on +the CALSCH webpage at: + +http://www.imc.org/ietf-calendar/ + +1.1 The libical project + +This code is under active development. If you would like to contribute +to the project, visit http://freeassociation.sourceforge.net + +1.2 License + +The code and datafiles in this distribution are licensed under the +Mozilla Public License. See http://www.mozilla.org/NPL/MPL-1.0.html +for a copy of the license. Alternately, you may use libical under +the terms of the GNU Library General Public License. See +http://www.fsf.org/copyleft/lesser.html for a copy of the LGPL. + +This dual license ensures that the library can be incorporated into +both proprietary code and GPL'd programs, and will benefit from improvements +made by programmers in both realms. I will only accept changes into +my version of the library if they are similarly dual-licensed. + +1.3 Example Code + +A lot of the documentation for this library is in the form of example +code. These examples are in the "examples" directory of the distribution. +Also look in "src/test" for additional annotated examples. + +2 Building the Library + +Libical uses autoconf to generate makefiles. It should built with no +adjustments on Linux, FreeBSD and Solaris under gcc. Some version +have been successfully been build on MacOS, Solaris, UnixWare, And +Tru64 UNIX without gcc, but you may run into problems with a particular +later version. + +For a more complete guide to building the library, see the README file +in the distribution. + +3 Structure + +The iCalendar data model is based on four types of objects: components, +properties, values and parameters. + +Properties are the fundamental unit of information in iCalendar, and they +work a bit like a hash entry, with a constant key and a variable value. +Properties may also have modifiers, called parameters. In the iCal +content line + +ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com + +The property name is "ORGANIZER," the value of the property is "mrbig@host.com" +and the "ROLE" parameter specifies that Mr Big is the chair of the +meetings associated with this property. + +Components are groups of properties that represent the core objects +of a calendar system, such as events or timezones. Components are +delimited by "BEGIN" and "END" tags. + +When a component is sent across a network, if it is un-encrypted, it +will look something like: + +BEGIN:VCALENDAR + +METHOD:REQUEST + +PRODID: -//hacksw/handcal//NONSGML v1.0//EN + +BEGIN:VEVENT + +DTSTAMP:19980309T231000Z + +UID:guid-1.host1.com + +ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com + +ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP: + + MAILTO:employee-A@host.com + +DESCRIPTION:Project XYZ Review Meeting + +CATEGORIES:MEETING + +CLASS:PUBLIC + +CREATED:19980309T130000Z + +SUMMARY:XYZ Project Review + +DTSTART;TZID=US-Eastern:19980312T083000 + +DTEND;TZID=US-Eastern:19980312T093000 + +LOCATION:1CP Conference Room 4350 + +END:VEVENT + +END:VCALENDAR + +Note that components can be nested; this example has both a VCALENDAR +and a VEVENT component, one nested inside the other. + +3.1 Core iCal classes + +Libical is an object-based, data-oriented library. Nearly all of the +routines in the library are associated with an opaque data types and +perform some operation on that data type. Although the library does +not actually have classes, we will use those terms since the behavior +of these associations of data and routines is very similar to a class. + +3.1.1 Properties + +Properties are represented with the icalproperty class and its many +"derived" classes with on "derived" class per property type in RFC2445. +Again, there is no actual inheritance relations, but there are clusters +of routines that make this term useful. A property is a container +for a single value and a set of parameters. + +3.1.2 Components + +In libical, components are represented with the icalcomponent class. +Icalcomponent is a container for a set of other components and properties. + +3.1.3 Values + +Values are represented in a similar way to properties; a base class +and many "derived " classes. A value is essentially a abstract handle +on a single fundamental type, a structure or a union. + +3.1.4 Parameters + +Parameters are represented in a similar way to properties, except that +they contain only one value + +3.2 Other elements of libical + +In addition to the core iCal classes, libical has many other types, +structures, classes that aid in creating and using iCal components. + +3.2.1 Enumerations and types + +Libical is strongly typed, so every component, property, parameter, +and value type has an enumeration, and some have an associated structure +or union. + +3.2.2 The parser + +The libical parser offers a variety of ways to convert RFC2445 text +into a libical internal component structure. the parser can parse +blocks of text as a string, or it can parse line-by-line. + +3.2.3 Error objects + +Libical has a substantial error reporting system for both programming +errors and component usage errors. + +3.2.4 Memory Management + +Since many of libicals interfaces return strings, the library has its +own memory management system to elimiate the need to free every string +returned from the library. + +3.2.5 Storage classes + +The library also offers several classes to store components to flies, +memory or databases. + +4 Differences From RFCs + +Libical has been designed to follow the standards as closely as possible, +so that the key objects in the standards are also key objects in the +library. However, there are a few areas where the specifications are +(arguably) irregular, and following them exactly would result in an +unfriendly interface. These deviations make libical easier to use +by maintaining a self-similar interface. + +4.1 Pseudo Components + +Libical defines components for groups of properties that look and act +like components, but are not defined as components in the specification. +XDAYLIGHT and XSTANDARD are notable examples. These pseudo components +group properties within the VTIMEZONE components. For instanace, the +timezone properties associated with daylight savings time starts with +"BEGIN:DAYLIGHT" and ends with "END:DAYLIGHT, just like other components, +but is not defined as a component in RFC2445 (see RFC2445, page +61). In Libical,this grouping is represented by the XDAYLIGHT component. +Standard iCAL components all start with the letter "V," while pseudo +components start with"X." + +There are also pseudo components that are conceptually derived classes +of VALARM. RFC2446 defines what properties may be included in each +component, and for VALARM, the set of properties it may have depends +on the value of the ACTION property. + +For instance, if a VALARM component has an ACTION property with the +value of "AUDIO," the component must also have an "ATTACH" property. +However, if the ACTION value is "DISPLAY," the component must have +a DESCRIPTION property. + +To handle these various, complex restrictions, libical has pseudo components +for each type of alarm: XAUDIOALARM, XDISPLAYALARM, XEMAILALARM and +XPROCEDUREALARM. + +4.2 Combined Values + +Many values can take more than one type. TRIGGER, for instance, can +have a value type of with DURATION or of DATE-TIME. These multiple +types make it difficult to create routines to return the value associated +with a property. + +It is natural to have interfaces that would return the value of a property, +but it is cumbersome for a single routine to return multiple types. +So, in libical, properties that can have multiple types are given +a single type that is the union of their RFC2445 types. For instance, +in libical, the value of the TRIGGER property resolves to struct icaltriggertype. +This type is a union of a DURATION and a DATE-TIME. + +4.3 Multi-Valued Properties + +Some properties, such as CATEGORIES have only one value type, but each +CATEGORIES property can have multiple value instances. This also results +in a cumbersome interface -- CATEGORIES accessors would have to return +a list while all other accessors returned a single value. In libical, +all properties have a single value, and multi-valued properties are +broken down into multiple single valued properties during parsing. +That is, an input line like, + +CATEGORIES: work, home + +becomes in libical's internal representation + +CATEGORIES: work + +CATEGORIES: home + +Oddly, RFC2445 allows some multi-valued properties (like FREEBUSY) +to exist as both a multi-values property and as multiple single +value properties, while others (like CATEGORIES) can only exist +as single multi-valued properties. This makes the internal representation +for CATEGORIES illegal. However when you convert a component to a +string, the library will collect all of the CATEGORIES properties +into one. + +5 Using libical + +5.1 Creating Components + +There are three ways to create components in Libical: creating individual +objects and assembling them, building entire objects in massive vaargs +calls, and parsing a text file containing iCalendar data. + +5.1.1 Constructor Interfaces + +Using constructor interfaces, you create each of the objects separately +and then assemble them in to components: + +icalcomponent *event; + +icalproperty *prop; + +icalparameter *param; + +struct icaltimetype atime; + +event = icalcomponent_new(ICAL_VEVENT_COMPONENT); + +prop = icalproperty_new_dtstamp(atime) ; + +icalcomponent_add_property(event, prop); + +prop = icalproperty_new_uid(''guid-1.host1.com''); + +icalcomponent_add_property(event,prop); + +prop=icalproperty_new_organizer(''mrbig@host.com''); + +param = icalparameter_new_role(ICAL_ROLE_CHAIR) + +icalproperty_add_parameter(prop, param); + +icalcomponent_add_property(event,prop); + +Notice that libical uses a semi-object-oriented style of interface. +Most things you work with are objects, that are instantiated with +a constructor that has "new" in the name. Also note that, other than +the object reference, most structure data is passed in to libical +routines by value. Libical has some complex but very regular memory +handling rules. These are detailed in section [sec:memory]. + +If any of the constructors fail, they will return 0. If you try to +insert 0 into a property or component, or use a zero-valued object +reference, libical will either silently ignore the error or will abort +with an error message. This behavior is controlled by a compile time +flag (ICAL_ERRORS_ARE_FATAL), and will abort by default. + +5.1.2 vaargs Constructors + +There is another way to create complex components, which is arguably +more elegant, if you are not horrified by varargs. The varargs constructor +interface allows you to create intricate components in a single block +of code. Here is the previous examples in the vaargs style. + + calendar = + + icalcomponent_vanew( + + ICAL_VCALENDAR_COMPONENT, + + icalproperty_new_version(''2.0''), + + icalproperty_new_prodid( + + ''-//RDU Software//NONSGML HandCal//EN''), + + icalcomponent_vanew( + + ICAL_VEVENT_COMPONENT, + + icalproperty_new_dtstamp(atime), + + icalproperty_new_uid(''guid-1.host1.com''), + + icalproperty_vanew_organizer( + + ''mrbig@host.com''), + + icalparameter_new_role(ICAL_ROLE_CHAIR), + + 0 + + ), + + icalproperty_vanew_attendee( + + ''employee-A@host.com'', + + icalparameter_new_role( + + ICAL_ROLE_REQPARTICIPANT), + + icalparameter_new_rsvp(1), + + icalparameter_new_cutype(ICAL_CUTYPE_GROUP), + + 0 + + ), + + icalproperty_new_location( + + "1CP Conference Room 4350"), + + 0 + + ), + + 0 + + ); + +This form is similar to the constructor form , except that the constructors +have "vanew" instead of "new" in the name. The arguments are similar +too, except that the component constructor can have a list of properties, +and the property constructor can have a list of parameters. Be sure +to terminate every list with a '0', or your code will crash, if you +are lucky. + +5.1.3 Parsing Text Files + +The final way to create components will probably be the most common; +you can create components from RFC2445 compliant text. If you have +the string in memory, use + +icalcomponent* icalparser_parse_string(char* str); + +If the string contains only one component, the parser will return the +component in libical form. If the string contains multiple components, +the multiple components will be returned as the children of an ICAL_XROOT_COMPONENT +component. + +Parsing a whole string may seem wasteful if you want to pull a large +component off of the network or from a file; you may prefer to parse +the component line by line. This is possible too by using: + +icalparser* icalparser_new(); + +void icalparser_free(icalparser* parser); + +icalparser_get_line(parser,read_stream); + +icalparser_add_line(parser,line); + +icalparser_set_gen_data(parser,stream) + +These routines will construct a parser object to which you can add +lines of input and retrieve any components that the parser creates +from the input. These routines work by specifing an adaptor routine +to get string data from a source. For an example: + +char* read_stream(char *s, size_t size, void *d) + +{ + + char *c = fgets(s,size, (FILE*)d); + + return c; + +} + +main() { + + char* line; + + icalcomponent *c; + + icalparser *parser = icalparser_new(); + + FILE* stream = fopen(argv[1],"r"); + + icalparser_set_gen_data(parser,stream); + + do{ + + line = icalparser_get_line(parser,read_stream); + + c = icalparser_add_line(parser,line); + + if (c != 0){ + + printf("%s",icalcomponent_as_ical_string(c)); + + icalparser_claim(parser); + + printf("\n---------------\n"); + + icalcomponent_free(c); + + } + + } while ( line != 0); + +} + +The parser object parameterizes the routine used to get input lines +with icalparser_set_gen_data() and icalparser_get_line(). In this +example, the routine read_stream() will fetch the next line from a +stream, with the stream passed in as the void* parameter d. The parser +calls read_stream() from icalparser_get_line(), but it also needs +to know what stream to use. This is set by the call to icalparser_set_gen_data(). +By using a different routine for read_stream or passing in different +data with icalparser_set_gen_data, you can connect to any data source. + +Using the same mechanism, other implementations could read from memory +buffers, sockets or other interfaces. + +Since the example code is a very common way to use the parser, there +is a convenience routine; + +icalcomponent* icalparser_parse(icalparser *parser, + + char* (*line_gen_func)(char *s, size_t size, void* +d)) + +To use this routine, you still must construct the parser object and +pass in a reference to a line reading routine. If the parser can create +a single component from the input, it will return a pointer to the +newly constructed component. If the parser can construct multiple +components from the input, it will return a reference to an XROOT +component ( of type ICAL_XROOT_COMPONENT.) This XROOT component will +hold all of the components constructed from the input as children. + +5.2 Accessing Components + +Given a reference to a component, you probably will want to access +the properties, parameters and values inside. Libical interfaces let +you find sub-component, add and remove sub-components, and do the +same three operations on properties. + +5.2.1 Finding Components + +To find a sub-component of a component, use: + +icalcomponent* icalcomponent_get_first_component( + + icalcomponent* component, + + icalcomponent_kind kind); + +This routine will return a reference to the first component of the +type 'kind.' The key kind values, listed in icalenums.h are: + +ICAL_ANY_COMPONENT + +ICAL_VEVENT_COMPONENT + +ICAL_VTODO_COMPONENT + +ICAL_VJOURNAL_COMPONENT + +ICAL_VCALENDAR_COMPONENT + +ICAL_VFREEBUSY_COMPONENT + +ICAL_VALARM_COMPONENT + +These are only the most common components; there are many more listed +in icalenums.h. + +As you might guess, if there is more than one subcomponent of the type +you have chosen, this routine will return only the first. to get at +the others, you need to iterate through the component. + +5.2.2 Iterating Through Components + +Iteration requires a second routine to get the next subcomponent after +the first: + +icalcomponent* icalcomponent_get_next_component( + + icalcomponent* component, + + icalcomponent_kind kind); + +With the 'first' and 'next' routines, you can create a for loop to +iterate through all of a components subcomponents + + for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT); + + c != 0; + + c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)) + +{ + + do_something(c); + +} + +This code bit wil iterate through all of the subcomponents in 'comp' +but you can select a specific type of component by changing ICAL_ANY_COMPONENT +to another component type. + +5.2.3 Using Component Iterators + +The iteration model in the previous section requires the component +to keep the state of the iteration. So, you could not use this model +to perform a sorting operations, since you'd need two iterators and +there is only space for one. If you ever call icalcomponent_get_first_component() +when an iteration is in progress, the pointer will be reset to the +beginning. + +To solve this problem, there are also external iterators for components. +The routines associated with these external iterators are: + +icalcompiter icalcomponent_begin_component(icalcomponent* component, +icalcomponent_kind kind); + +icalcompiter icalcomponent_end_component(icalcomponent* component, +icalcomponent_kind kind); + +icalcomponent* icalcompiter_next(icalcompiter* i); + +icalcomponent* icalcompiter_prior(icalcompiter* i); + +icalcomponent* icalcompiter_deref(icalcompiter* i); + +The _begin_() and _end_() routines return a new iterator that points +to the beginning and ending of the list of subcomponent for the given +component, and the kind argument works like the kind argument for +internal iterators. + +After creating an iterators, use _next_() and _prior_() to step forward +and backward through the list and get the component that the iterator +points to, and use _deref() to return the component that the iterator +points to without moving the iterator. All routines will return 0 +when they move to point off the end of the list. + +Here is an example of a loop using these routines: + +for( + + i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT); + + icalcompiter_deref(&i)!= 0; + + icalcompiter_next(&i) + +) { + + icalcomponent *this = icalcompiter_deref(&i); + +} + +5.2.4 Removing Components + +Removing an element from a list while iterating through the list with +the internal iterators can cause problems, since you will probably +be removing the element that the internal iterator points to. The +_remove() routine will keep the iterator valid by moving it to the +next component, but in a normal loop, this will result in two advances +per iteration, and you will remove only every other component. To +avoid the problem, you will need to step the iterator ahead of the +element you are going to remove, like this: + +for(c = icalcomponent_get_first_component(parent_comp,ICAL_ANY_COMPONENT); + + c != 0; + + c = next + +{ + + next = icalcomponent_get_next_component(parent_comp,ICAL_ANY_COMPONENT); + + icalcomponent_remove_component(parent_comp,c); + +} + +Another way to remove components is to rely on the side effect of icalcomponent_remove_component: +if component iterator in the parent component is pointing to the child +that will be removed, it will move the iterator to the component after +the child. The following code will exploit this behavior: + +icalcomponent_get_first_component(parent_comp,ICAL_VEVENT_COMPONENT); + +while((c=icalcomponent_get_current_component(c)) != 0 ){ + + if(icalcomponent_isa(c) == ICAL_VEVENT_COMPONENT){ + + icalcomponent_remove_component(parent_comp,inner); + + } else { + + icalcomponent_get_next_component(parent_comp,ICAL_VEVENT_COMPONENT); + + } + +} + +5.2.5 Working with properties and parameters + +Finding, iterating and removing properties works the same as it does +for components, using the property-specific or parameter-specific +interfaces: + +icalproperty* icalcomponent_get_first_property( + + icalcomponent* component, + + icalproperty_kind kind); + +icalproperty* icalcomponent_get_next_property( + + icalcomponent* component, + + icalproperty_kind kind); + +void icalcomponent_add_property( + + icalcomponent* component, + + icalproperty* property); + +void icalcomponent_remove_property( + + icalcomponent* component, + + icalproperty* property); + +For parameters: + +icalparameter* icalproperty_get_first_parameter( + + icalproperty* prop, + + icalparameter_kind kind); + +icalparameter* icalproperty_get_next_parameter( + + icalproperty* prop, + + icalparameter_kind kind); + +void icalproperty_add_parameter( + + icalproperty* prop, + + icalparameter* parameter); + +void icalproperty_remove_parameter( + + icalproperty* prop, + + icalparameter_kind kind); + +Note that since there should be only one parameter of each type in +a property, you will rarely need to use icalparameter_get_nect_paameter. + +5.2.6 Working with values + +Values are typically part of a property, although they can exist on +their own. You can manipulate them either as part of the property +or independently. + +The most common way to work with values to is to manipulate them from +they properties that contain them. This involves fewer routine calls +and intermediate variables than working with them independently, and +it is type-safe. + +For each property, there are a _get_ and a _set_ routine that access +the internal value. For instanace, for the UID property, the routines +are: + +void icalproperty_set_uid(icalproperty* prop, const char* v) + +const char* icalproperty_get_uid(icalproperty* prop) + +For multi-valued properties, like ATTACH, the value type is usually +a struct or union that holds both possible types. + +If you want to work with the underlying value object, you can get and +set it with: + +icalvalue* icalproperty_get_value (icalproperty* prop) + +void icalproperty_set_value(icalproperty* prop, icalvalue* value); + +Icalproperty_get_value() will return a reference that you can manipulate +with other icalvalue routines. Most of the time, you will have to +know what the type of the value is. For instance, if you know that +the value is a DATETIME type, you can manipulate it with: + +struct icaltimetype icalvalue_get_datetime(icalvalue* value); + +void icalvalue_set_datetime(icalvalue* value, struct icaltimetype v); + +When working with an extension property or value (and X-PROPERTY or +a property that has the parameter VALUE=x-name ) the value type is +always a string. To get and set the value, use: + +void icalproperty_set_x(icalproperty* prop, char* v); + +char* icalproperty_get_x(icalproperty* prop); + +All X properties have the type of ICAL_X_PROPERTY, so you will need +these routines to get and set the name of the property: + +char* icalproperty_get_x_name(icalproperty* prop) + +void icalproperty_set_x_name(icalproperty* prop, char* name); + +5.2.7 Checking Component Validity + +RFC 2446 defines rules for what properties must exist in a component +to be used for transferring scheduling data. Most of these rules relate +to the existence of properties relative to the METHOD property, which +declares what operation a remote receiver should use to process a +component. For instance, if the METHOD is REQUEST and the component +is a VEVENT, the sender is probably asking the receiver to join in +a meeting. In this case, RFC2446 says that the component must specify +a start time (DTSTART) and list the receiver as an attendee (ATTENDEE). + +Libical can check these restrictions with the routine: + +int icalrestriction_check(icalcomponent* comp); + +This routine returns 0 if the component does not pass RFC2446 restrictions, +or if the component is malformed. The component you pass in must be +a VCALENDAR, with one or more children, like the examples in RFC2446. + +When this routine runs, it will insert new properties into the component +to indicate any errors it finds. See section 6.5.3, X-LIC-ERROR for +more information about these error properties. + +5.2.8 Converting Components to Text + +To create an RFC2445 compliant text representation of an object, use +one of the *_as_ical_string() routines: + +char* icalcomponent_as_ical_string (icalcomponent* component) + +char* icalproperty_as_ical_string (icalproperty* property) + +char* icalparameter_as_ical_string (icalparameter* parameter) + +char* icalvalue_as_ical_string (icalvalue* value) + +In most cases, you will only use icalcomponent_as_ical_string (), since +it will cascade and convert all of the parameters, properties and +values that are attached to the root component. + +Icalproperty_as_ical_string() will terminate each line with the RFC2445 +specified line terminator "\\n" However, if you compile with the symbol +ICAL_UNIX_NEWLINE undefined, ( it is defined by default) it will terminate +lines with "\\n\\r" + +Remember that the string returned by these routines is owned by the +library, and will eventually be re-written. You should copy it if +you want to preserve it. + +5.3 Time + +5.3.1 Time structure + +LIbical defines it's own time structure for storing all dates and times. +It would have been nice to re-use the C library's struct tm, but that +structure does not differentiate between dates and times, and between +local time and UTC. The libical structure is: + +struct icaltimetype { + + int year; + + int month; + + int day; + + int hour; + + int minute; + + int second; + + int is_utc; /* 1-> time is in UTC timezone */ + + int is_date; /* 1 -> interpret this as date. */ }; + +The year, month, day, hour, minute and second fields hold the broken-out +time values. The is_utc field distinguishes between times in UTC and +a local time zone. The is_date field indicates if the time should +be interpreted only as a date. If it is a date, the hour, minute and +second fields are assumed to be zero, regardless of their actual vaules. + +5.3.2 Creating time structures + +There are several ways to create a new icaltimetype structure: + +struct icaltimetype icaltime_from_string(const char* str); + +struct icaltimetype icaltime_from_timet(time_t v, int is_date); + +struct icaltimetype icaltime_from_int(int v, int is_date, int is_utc); + +Icaltime_from_string takes any RFC2445 compliant time string: + +struct icaltimetype tt = icaltime_from_string("19970101T103000"); + +Icaltime_from_timet takes a timet value, representing seconds past +the POSIX epoch, and a flag to indicate if the time is a date. Dates +have an identical structure to a time, but the time portion ( hours, +minuts and seconds ) is always 00:00:00. Dates act differently in +sorting an comparision, and they have a different string representation +in RFC2445. + +The icaltime_from_int is like icaltime_from_timet, but with an arbitrary +epoch. This routine was a mistake and is deprecated. + +5.3.3 Time manipulating routines + +The null time value is used to indicate that the data in the structure +is not a valid time. + +struct icaltimetype icaltime_null_time(void); + +int icaltime_is_null_time(struct icaltimetype t); + +It is sensible for the broken-out time fields to contain values that +are not permitted in an ISO compliant time string. For instance, the +seconds field can hold values greater than 59, and the hours field +can hold values larger than 24. The excessive values will be rolled +over into the next larger field when the structure is normalized. + +struct icaltimetype icaltime_normalize(struct icaltimetype t); + +Normalizing allows you to do arithmetic operations on time values. + +struct icaltimetype tt = icaltime_from_string("19970101T103000"); + +tt.days +=3 + +tt.second += 70; + +tt = icaltime_normalize(tt); + +There are several routines to get the day of the week or month, etc, +from a time structure. + +short icaltime_day_of_year(struct icaltimetype t); + +struct icaltimetype icaltime_from_day_of_year(short doy, short year); + +short icaltime_day_of_week(struct icaltimetype t); + +short icaltime_start_doy_of_week(struct icaltimetype t); + +short icaltime_week_number(short day_of_month, short month, short year); + +struct icaltimetype icaltime_from_week_number(short week_number, short +year); + +short icaltime_days_in_month(short month,short year); + +Two routines convert time structures to and from the number of seconds +since the POSIX epoch. The is_date field indicates whether or not +the hour, minute and second fields should be used in the conversion. + +struct icaltimetype icaltime_from_timet(time_t v, int is_date); + +time_t icaltime_as_timet(struct icaltimetype); + +The compare routine works exactly like strcmp, but on time structures. + +int icaltime_compare(struct icaltimetype a,struct icaltimetype b); + +The following routines convert between UTC and a named timezone. The +tzid field must be a timezone name from the Olsen database, such as +"America/Los_Angeles." + +The utc_offset routine returns the offset of the named time zone from +UTC, in seconds. + +The tt parameter in the following routines indicates the date on which +the conversion should be made. The tt parameter is necessary because +timezones have many different rules for when daylight savings time +is used, and these rules can change over time. So, for a single timezone +one year may have daylight savings time on March 15, but for other +years March 15 may be standard time, and some years may have standard +time all year. + +int icaltime_utc_offset(struct icaltimetype tt, char* tzid); + +int icaltime_local_utc_offset(); + +struct icaltimetype icaltime_as_utc(struct icaltimetype tt,char* tzid); + +struct icaltimetype icaltime_as_zone(struct icaltimetype tt,char* tzid); + +struct icaltimetype icaltime_as_local(struct icaltimetype tt); + +5.4 Storing Objects + +The libical distribution includes a separate library, libicalss, that +allows you to store iCal component data to disk in a variety of ways. + +The file storage routines are organized in an inheritance heirarchy +that is rooted in icalset, with the derived class icalfileset and +icaldirset. Icalfileset stores components to a file, while icaldirset +stores components to multiple files, one per month based on DTSTAMP. +Other storages classess, for storage to a heap or a mysql database +for example, could be added in the future. + +All of the icalset derived classes have the same interface: + +icaldirset* icaldirset_new(const char* path); + +void icaldirset_free(icaldirset* store); + +const char* icaldirset_path(icaldirset* store); + +void icaldirset_mark(icaldirset* store); + +icalerrorenum icaldirset_commit(icaldirset* store); + +icalerrorenum icaldirset_add_component(icaldirset* store, icalcomponent* +comp); + +icalerrorenum icaldirset_remove_component(icaldirset* store, icalcomponent* +comp); + +int icaldirset_count_components(icaldirset* store, icalcomponent_kind +kind); + +icalerrorenum icaldirset_select(icaldirset* store, icalcomponent* gauge); + +void icaldirset_clear(icaldirset* store); + +icalcomponent* icaldirset_fetch(icaldirset* store, const char* uid); + +int icaldirset_has_uid(icaldirset* store, const char* uid); + +icalcomponent* icaldirset_fetch_match(icaldirset* set, icalcomponent +*c); + +icalerrorenum icaldirset_modify(icaldirset* store, icalcomponent *oldc, +icalcomponent *newc); + +icalcomponent* icaldirset_get_current_component(icaldirset* store); + +icalcomponent* icaldirset_get_first_component(icaldirset* store); + +icalcomponent* icaldirset_get_next_component(icaldirset* store); + +5.4.1 Creating a new set + +You can create a new set from either the base class or the direved +class. From the base class use one of: + +icalset* icalset_new_file(const char* path); + +icalset* icalset_new_dir(const char* path); + +icalset* icalset_new_heap(void); + +icalset* icalset_new_mysql(const char* path); + +You can also create a new set based on the derived class, For instance, +with icalfileset: + +icalfileset* icalfileset_new(const char* path); + +icalfileset* icalfileset_new_open(const char* path, int flags, mode_t +mode); + +icalset_new_file is identical to icalfileset_new. Both routines will +open an existing file for readinga and writing, or create a new file +if it does not exist. Icalfilset_new_open takes the same arguments +as the open() system routine and behaves in the same way. + +The icalset and icalfilset objects are somewhat interchangable -- you +can use an icalfileset* as an argument to any of the icalset routines. + +The following examples will all use icalfileset routines; using the +other icalset derived classess will be similar. + +5.4.2 Adding, Finding and Removing Components + +To add components to a set, use: + +icalerrorenum icalfileset_add_component(icalfileset* cluster, icalcomponent* +child); + +The fileset keeps an inmemory copy of the components, and this set +must be written back to the file ocassionally. There are two routines +to manage this: + +void icalfileset_mark(icalfileset* cluster); + +icalerrorenum icalfileset_commit(icalfileset* cluster); + +icalfileset_mark indicates that the in-memory components have changed. +Calling the _add_component routine will call _mark automatically, +but you may need to call it yourself if you have made a change to +an existing component. The _commit routine writes the data base to +disk, but only if it is marked. The _commit routine is called automatically +when the icalfileset is freed. + +To iterate through the components in a set, use: + +icalcomponent* icalfileset_get_first_component(icalfileset* cluster); + +icalcomponent* icalfileset_get_next_component(icalfileset* cluster); + +icalcomponent* icalfileset_get_current_component (icalfileset* cluster); + +These routines work like the corresponding routines from icalcomponent, +except that their output is filtered through a gauge. A gauge is a +test for the properties within a components; only components that +pass the test are returned. A gauge can be constructed from a MINSQL +string with: + +icalgauge* icalgauge_new_from_sql(char* sql); + +Then, you can add the gauge to the set with : + +icalerrorenum icalfileset_select(icalfileset* store, icalgauge* gauge); + +Here is an example that puts all of these routines together: + +void test_fileset() + +{ + + icalfileset *fs; + + icalcomponent *c; + + int i; + + char *path = "test_fileset.ics"; + + icalgauge *g = icalgauge_new_from_sql( + + "SELECT * FROM VEVENT WHERE DTSTART > '20000103T120000Z' AND +DTSTART <= '20000106T120000Z'"); + + + + fs = icalfileset_new(path); + + + + for (i = 0; i!= 10; i++){ + + c = make_component(i); /* Make a new component where DTSTART +has month of i */ + + icalfileset_add_component(fs,c); + + } + + icalfileset_commit(fs); /* Write to disk */ + + icalfileset_select(fs,g); /* Set the gauge to filter components +*/ + + + + for (c = icalfileset_get_first_component(fs); + + c != 0; + + c = icalfileset_get_next_component(fs)){ + + struct icaltimetype t = icalcomponent_get_dtstart(c); + + + + printf("%s\n",icaltime_as_ctime(t)); + + } + + icalfileset_free(fs); + +} + +5.4.3 Other routines + +There are several other routines in the icalset interface, but they +not fully implemented yet. + +5.5 Memory Management + +Libical relies heavily on dynamic allocation for both the core objects +and for the strings used to hold values. Some of this memory the library +caller owns and must free, and some of the memory is managed by the +library. Here is a summary of the memory rules. + +1) If the function name has "new" in it, the caller gets control + of the memory. ( such as icalcomponent_new(), or icalproperty_new_clone() + ) + +2) If you got the memory from a routine with new in it, you must + call the corresponding *_free routine to free the memory. ( Use + icalcomponent_free() to free objects created with icalcomponent_new()) + +3) If the function name has "add" in it, the caller is transferring + control of the memory to the routine. ( icalproperty_add_parameter() ) + +4) If the function name has "remove" in it, the caller passes in + a pointer to an object and after the call returns, the caller owns + the object. So, before you call icalcomponent_remove_property(comp,foo), + you do not own "foo" and after the call returns, you do. + +5) If the routine returns a string and its name does NOT end in "_r", + libical owns the memory and will put it on a ring buffer to reclaim + later. For example, icalcomponent_as_ical_string(). You'd better + strdup() it if you want to keep it, and you don't have to delete it. + +6) If the routine returns a string and its name *does* end in "_r", the + caller gets control of the memory and is responsible for freeing it. + For example, icalcomponent_as_ical_string_r() does the same thing as + icalcomponent_as_ical_string(), except you now have control of the + string buffer it returns. + +5.6 Error Handling + +Libical has several error handling mechanisms for the various types +of programming, semantic and syntactic errors you may encounter. + +5.6.1 Return values + +Many library routines signal errors through their return values. All +routines that return a pointer, such as icalcomponent_new(), will +return 0 ( zero ) on a fatal error. Some routines will return a value +of enum icalerrorenum. + +5.6.2 icalerrno + +Most routines will set the global error value icalerrno on errors. +This variable is an enumeration; permissible values can be found in +libical/icalerror.h. If the routine returns an enum icalerrorenum, +then the return value will be the same as icalerrno. You can use icalerror_strerror() +to get a string that describes the error. The enumerations are: + +* ICAL_BADARG_ERROR -- One of the argument to a routine was bad. Typically + for a null pointer. + +* ICAL_NEWFAILED_ERROR -- A new() or malloc() failed + +* ICAL_MALFORMEDDATA_ERROR -- An input string was not in the correct + format + +* ICAL_PARSE_ERROR -- The parser failed to parse an incomming component + +* ICAL_INTERNAL_ERROR -- Largely equivalent to an assert + +* ICAL_FILE_ERROR -- A file operation failed. Check errno for more + detail. + +* ICAL_ALLOCATION_ERROR -- ? + +* ICAL_USAGE_ERROR -- ? + +* ICAL_NO_ERROR -- No error + +* ICAL_MULTIPLEINCLUSION_ERROR -- ? + +* ICAL_TIMEDOUT_ERROR -- For CSTP and acquiring locks + +* ICAL_UNKNOWN_ERROR -- ? + +5.6.3 X-LIC-ERROR and X-LIC-INVALID-COMPONENT + +The library handles semantic and syntactic errors in components by +inserting errors properties into the components. If the parser cannot +parse incoming text ( a syntactic error ) or if the icalrestriction_check() +routine indicates that the component does not meet the requirements +of RFC2446 ( a semantic error) the library will insert properties +of the type X-LIC-ERROR to describe the error. Here is an example +of the error property: + +X-LIC-ERROR;X-LIC-ERRORTYPE=INVALID_ITIP :Failed iTIP restrictions +for property DTSTART. + +Expected 1 instances of the property and got 0 + +This error resulted from a call to icalrestriction_check(), which discovered +that the component does not have a DTSTART property, as required by +RFC2445. + +There are a few routines to manipulate error properties: + +[ The following data is supposed to be in a table. It looks OK in LyX, +but does not format propertly in output. ] + ++-------------------------------------+---------------------------------------------------------+ +| Routine | Purpose | ++-------------------------------------+---------------------------------------------------------+ +| void icalrestriction_check() | Check a component against RFC2446 and insert | ++-------------------------------------+---------------------------------------------------------+ +| | error properties to indicate non compliance | ++-------------------------------------+---------------------------------------------------------+ +| int icalcomponent_count_errors() | Return the number of error properties | ++-------------------------------------+---------------------------------------------------------+ +| | in a component | ++-------------------------------------+---------------------------------------------------------+ +| void icalcomponent_strip_errors() | Remove all error properties in as | ++-------------------------------------+---------------------------------------------------------+ +| | component | ++-------------------------------------+---------------------------------------------------------+ +| void icalcomponent_convert_errors() | Convert some error properties into | ++-------------------------------------+---------------------------------------------------------+ +| | REQUESTS-STATUS proprties to indicate the inability to | ++-------------------------------------+---------------------------------------------------------+ +| | process the component as an iTIP request. | ++-------------------------------------+---------------------------------------------------------+ + + +The types of errors are listed in icalerror.h. They are: + +ICAL_XLICERRORTYPE_COMPONENTPARSEERROR + +ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR + +ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR + +ICAL_XLICERRORTYPE_PROPERTYPARSEERROR + +ICAL_XLICERRORTYPE_VALUEPARSEERROR + +ICAL_XLICERRORTYPE_UNKVCALPROP + +ICAL_XLICERRORTYPE_INVALIDITIP + +The libical parser will generate the error that end in PARSEERROR when +it encounters garbage in the input steam. ICAL_XLICERRORTYPE_INVALIDITIP +is inserted by icalrestriction_check(), and ICAL_XLICERRORTYPE_UNKVCALPROP +is generated by icalvcal_convert() when it encounters a vCal property +that it cannot convert or does not know about. + +Icalcomponent_convert_errors() converts some of the error properties +in a component into REQUEST-STATUS properties that indicate a failure. +As of libical version0.18, this routine only convert *PARSEERROR errors +and it always generates a 3.x ( failure ) code. This makes it more +of a good idea than a really useful bit of code. + +5.6.4 ICAL_ERRORS_ARE_FATAL and icalerror_errors_are_fatal + +If the global variable icalerror_errors_are_fatal is set to 1, then +any error condition will cause the program to abort. The abort occurs +in icalerror_set_errno(), and is done with an assert(0) if NDEBUG +is undefined, and with icalerror_crash_here if NDEBUG is defined. +The default value of icalerror_errors_are_fatal is 1 when ICAL_ERRORS_ARE_FATAL +is defined, and 0 otherwise. Since ICAL_ERRORS_ARE_FATAL is defined +by default, icalerror_errors_are_fatal is also defined by default. + +5.7 Naming Standard + +Structures that you access with the "struct" keyword, such as "struct +icaltimetype" are things that you are allowed to see inside and poke +at. + +Structures that you access though a typedef, such as "icalcomponent" +are things where all of the data is hidden. + +Component names that start with "V" are part of RFC 2445 or another +iCal standard. Component names that start with "X" are also part of +the spec, but they are not actually components in the spec. However, +they look and act like components, so they are components in libical. +Names that start with "XLIC" or "X-LIC" are not part of any iCal spec. +They are used internally by libical. + +Enums that identify a component, property, value or parameter end with +"_COMPONENT," "_PROPERTY," "_VALUE," or "_PARAMETER"s + +Enums that identify a parameter value have the name of the parameter +as the second word. For instance: ICAL_ROLE_REQPARTICIPANT or ICAL_PARTSTAT_ACCEPTED. + +The enums for the parts of a recurarance rule and request statuses +are irregular. + +6 Hacks and Bugs + +There are a lot of hacks in the library -- bits of code that I am not +proud of and should probably be changed. These are marked with the +comment string "HACK." + +7 Library Reference + +7.1 Manipulating struct icaltimetype + +7.1.1 Struct icaltimetype + +struct icaltimetype + +{ + + int year; + + int month; + + int day; + + int hour; + + int minute; + + int second; + + int is_utc; + + int is_date; + + const char* zone; + +}; |