зеркало из https://github.com/mozilla/gecko-dev.git
2579 строки
58 KiB
Plaintext
2579 строки
58 KiB
Plaintext
#LyX 1.1 created this file. For more info see http://www.lyx.org/
|
|
\lyxformat 2.16
|
|
\textclass article
|
|
\language default
|
|
\inputencoding latin1
|
|
\fontscheme default
|
|
\graphics default
|
|
\paperfontsize default
|
|
\spacing single
|
|
\papersize Default
|
|
\paperpackage a4
|
|
\use_geometry 0
|
|
\use_amsmath 0
|
|
\paperorientation portrait
|
|
\secnumdepth 3
|
|
\tocdepth 3
|
|
\paragraph_separation indent
|
|
\defskip medskip
|
|
\quotes_language english
|
|
\quotes_times 2
|
|
\papercolumns 1
|
|
\papersides 1
|
|
\paperpagestyle default
|
|
|
|
\layout Title
|
|
|
|
Using Libical
|
|
\layout Author
|
|
|
|
Eric Busboom (eric@softwarestudio.org)
|
|
\layout Date
|
|
|
|
January 2001
|
|
\layout Standard
|
|
|
|
|
|
\begin_inset LatexCommand \tableofcontents{}
|
|
|
|
\end_inset
|
|
|
|
|
|
\layout Section
|
|
|
|
Introduction
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
Libical implements RFC2445, RFC2446 and some of RFC2447 and the CAP draft.
|
|
|
|
\layout Standard
|
|
|
|
This documentation assumes that you are familiar with the iCalendar standards
|
|
RFC2445 and RFC2446.
|
|
these specifications are online on the CALSCH webpage at:
|
|
\layout LyX-Code
|
|
|
|
http://www.imc.org/ietf-calendar/
|
|
\layout Subsection
|
|
|
|
The libical project
|
|
\layout Standard
|
|
|
|
This code is under active development.
|
|
If you would like to contribute to the project, you can contact me, Eric
|
|
Busboom, at eric@softwarestudio.org.
|
|
The project has a webpage at
|
|
\layout LyX-Code
|
|
|
|
http://softwarestudio.org/libical/index.html
|
|
\layout Standard
|
|
|
|
and a mailing list that you can join by sending the following mail:
|
|
\layout LyX-Code
|
|
|
|
To: minimalist@softwarestudio.org
|
|
\layout LyX-Code
|
|
|
|
Subject: subscribe libical
|
|
\layout Subsection
|
|
|
|
License
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Subsection
|
|
|
|
Example Code
|
|
\layout Standard
|
|
|
|
A lot of the documentation for this library is in the form of example code.
|
|
These examples are in the
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
examples
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
directory of the distribution.
|
|
Also look in
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
src/test
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
for additional annotated examples.
|
|
|
|
\layout Section
|
|
|
|
Building and Installing the Library
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
For a more complete guide to building the library, see the README file in
|
|
the distribution.
|
|
|
|
\layout Standard
|
|
|
|
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
make install
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
will install the libraries and header files for three modules: libical,
|
|
libicalss.
|
|
and libicalvcal.
|
|
If you build shared objects, then these files will be installed:
|
|
\layout Itemize
|
|
|
|
ical.h
|
|
\layout Itemize
|
|
|
|
libical.a
|
|
\layout Itemize
|
|
|
|
libical.so
|
|
\layout Itemize
|
|
|
|
icalss.h
|
|
\layout Itemize
|
|
|
|
libicalss.a
|
|
\layout Itemize
|
|
|
|
libicalss.so
|
|
\layout Itemize
|
|
|
|
icalvcal.h
|
|
\layout Itemize
|
|
|
|
libicalvcal.a
|
|
\layout Itemize
|
|
|
|
libicalvcal.so
|
|
\layout Standard
|
|
|
|
The header files ical.h and icalss.h are combined header files, generated
|
|
by concatenating together all of the header files in src/libical and src/libica
|
|
lss respectively.
|
|
|
|
\layout Section
|
|
|
|
Structure
|
|
\layout Standard
|
|
|
|
The iCal calendar model is based on four types of objects: components, propertie
|
|
s, values and parameters.
|
|
|
|
\layout Standard
|
|
|
|
Properties are the fundamental unit of information in iCal, 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
|
|
\layout LyX-Code
|
|
|
|
ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com
|
|
\layout Standard
|
|
|
|
The property name is
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
ORGANIZER,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
the value of the property is
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
mrbig@host.com
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
and the
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
ROLE
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
parameter specifies that Mr Big is the chair of the meetings associated
|
|
with this property.
|
|
|
|
\layout Standard
|
|
|
|
Components are groups of properties that represent the core objects of a
|
|
calendar system, such as events or timezones.
|
|
Components are delimited by
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
BEGIN
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
and
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
END
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
tags.
|
|
|
|
\layout Standard
|
|
\added_space_bottom 0.3cm
|
|
When a component is sent across a network, if it is un-encrypted, it will
|
|
look something like:
|
|
\layout LyX-Code
|
|
|
|
BEGIN:VCALENDAR
|
|
\layout LyX-Code
|
|
|
|
METHOD:REQUEST
|
|
\layout LyX-Code
|
|
|
|
PRODID: -//hacksw/handcal//NONSGML v1.0//EN
|
|
\layout LyX-Code
|
|
|
|
BEGIN:VEVENT
|
|
\layout LyX-Code
|
|
|
|
DTSTAMP:19980309T231000Z
|
|
\layout LyX-Code
|
|
|
|
UID:guid-1.host1.com
|
|
\layout LyX-Code
|
|
|
|
ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com
|
|
\layout LyX-Code
|
|
|
|
ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:
|
|
\layout LyX-Code
|
|
|
|
MAILTO:employee-A@host.com
|
|
\layout LyX-Code
|
|
|
|
DESCRIPTION:Project XYZ Review Meeting
|
|
\layout LyX-Code
|
|
|
|
CATEGORIES:MEETING
|
|
\layout LyX-Code
|
|
|
|
CLASS:PUBLIC
|
|
\layout LyX-Code
|
|
|
|
CREATED:19980309T130000Z
|
|
\layout LyX-Code
|
|
|
|
SUMMARY:XYZ Project Review
|
|
\layout LyX-Code
|
|
|
|
DTSTART;TZID=US-Eastern:19980312T083000
|
|
\layout LyX-Code
|
|
|
|
DTEND;TZID=US-Eastern:19980312T093000
|
|
\layout LyX-Code
|
|
|
|
LOCATION:1CP Conference Room 4350
|
|
\layout LyX-Code
|
|
|
|
END:VEVENT
|
|
\layout LyX-Code
|
|
|
|
END:VCALENDAR
|
|
\layout Standard
|
|
|
|
Note that components can be nested; this example has both a VCALENDAR and
|
|
a VEVENT component, one nested inside the other.
|
|
|
|
\layout Standard
|
|
|
|
The main goal of Libical is to offer a structured, type-safe to create,
|
|
access and manipulate components and their properties, values and parameters.
|
|
|
|
\layout Subsection
|
|
|
|
Core iCal classes
|
|
\layout Standard
|
|
|
|
Libical is an object-based, data-oriented library.
|
|
There are no real-objects, but the way the routines are named and organized
|
|
results in the same sort of encapsulations and abstraction that are major
|
|
features of Object-Orieted languages.
|
|
Nearly all of the routines in the library are associated with an opaque
|
|
data types and perform some operation on that data type.
|
|
For instnace, a Property is declared as:
|
|
\layout LyX-Code
|
|
|
|
icalproperty *prop;
|
|
\layout Standard
|
|
|
|
Icalproperty is typedef'd to void, so the only way to manipulate it is through
|
|
the accessor routines, all of which have a form similar to:
|
|
\layout LyX-Code
|
|
|
|
char* icalproperty_as_ical_string(icalproperty* prop);
|
|
\layout Standard
|
|
|
|
That is, the name of the 'class' is the first word in the routine name,
|
|
and the first parameter is a pointer to the 'object.'
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Properties
|
|
\layout LyX-Code
|
|
|
|
icalproperty *prop;
|
|
\layout Standard
|
|
|
|
Properties are represented with the icalproperty class and its many
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
derived
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
classes with on
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
derived
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Components
|
|
\layout LyX-Code
|
|
|
|
icalcomponent *comp;
|
|
\layout Standard
|
|
|
|
In libical, components are represented with the icalcomponent class.
|
|
Icalcomponent is a container for a set of other components and properties.
|
|
\layout Subsubsection
|
|
|
|
Values
|
|
\layout LyX-Code
|
|
|
|
icalvalue *value;
|
|
\layout Standard
|
|
|
|
Values are represented in a similar way to properties; a base class and
|
|
many
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
derived
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
classes.
|
|
A value is essentially a abstract handle on a single fundamental type,
|
|
a structure or a union.
|
|
You probably will never use a value directly, since for most operations
|
|
you can get to its data through the property that holds it.
|
|
|
|
\layout Subsubsection
|
|
|
|
Parameters
|
|
\layout LyX-Code
|
|
|
|
icalparameter *param;
|
|
\layout Standard
|
|
|
|
Parameters are represetned in a similar way to properties, except that they
|
|
contain only one value
|
|
\layout Subsection
|
|
|
|
Other elements of libical
|
|
\layout Standard
|
|
|
|
In addition to the core iCal classes, libical has many other types, structures,
|
|
classes that aid in creating and using iCal components.
|
|
|
|
\layout Subsubsection
|
|
|
|
Enumerations and types
|
|
\layout Standard
|
|
|
|
Libical is strongly typed, so every component, property, parameter, and
|
|
value type has an enumeration, and some have an associated structure or
|
|
union.
|
|
|
|
\layout Subsubsection
|
|
|
|
The parser
|
|
\layout Standard
|
|
|
|
The libical parser offers a variety of ways to convert RFC2445 text into
|
|
a libical iinsteral component structure.
|
|
the parser can parse blocks of text as a string, or it can parse lin-by-line.
|
|
\layout Subsubsection
|
|
|
|
Error objects
|
|
\layout Standard
|
|
|
|
Libical has a substantial error reporting system for both programming errors
|
|
and component usage errors.
|
|
|
|
\layout Subsubsection
|
|
|
|
Memory Management
|
|
\layout Standard
|
|
|
|
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 libraru.
|
|
|
|
\layout Subsubsection
|
|
|
|
Storage classes
|
|
\layout Standard
|
|
|
|
The library also offers several classes to store components to flies, memory
|
|
or databases.
|
|
|
|
\layout Section
|
|
|
|
Differences From RFCs
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsection
|
|
|
|
Pseudo Components
|
|
\layout Standard
|
|
|
|
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_inset Quotes eld
|
|
\end_inset
|
|
|
|
BEGIN:DAYLIGHT
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
and ends with
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
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
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
V,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
while pseudo components start with
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
X.
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
For instance, if a VALARM component has an ACTION property with the value
|
|
of
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
AUDIO,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
the component must also have an
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
ATTACH
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
property.
|
|
However, if the ACTION value is
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
DISPLAY,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
the component must have a DESCRIPTION property.
|
|
|
|
\layout Standard
|
|
|
|
To handle these various, complex restrictions, libical has pseudo components
|
|
for each type of alarm: XAUDIOALARM, XDISPLAYALARM, XEMAILALARM and XPROCEDUREA
|
|
LARM.
|
|
|
|
\layout Subsection
|
|
|
|
Combined Values
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsection
|
|
|
|
Multi-Valued Properties
|
|
\layout Standard
|
|
|
|
Some properties, such as CATEGORIES have only one value type, but each CATEGORIE
|
|
S 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,
|
|
\layout LyX-Code
|
|
|
|
CATEGORIES: work, home
|
|
\layout Standard
|
|
|
|
becomes in libical's internal representation
|
|
\layout LyX-Code
|
|
|
|
CATEGORIES: work
|
|
\layout LyX-Code
|
|
|
|
CATEGORIES: home
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Section
|
|
|
|
Using libical
|
|
\layout Subsection
|
|
|
|
Creating Components
|
|
\layout Standard
|
|
|
|
There are three ways to create components in Libical:
|
|
\layout Itemize
|
|
|
|
Create individual components, properties and parameters and assemble them
|
|
into structures
|
|
\layout Itemize
|
|
|
|
Build complete components with nested vaargs calls
|
|
\layout Itemize
|
|
|
|
Parse bits of text
|
|
\layout Itemize
|
|
|
|
Parse entire files
|
|
\layout Subsubsection
|
|
|
|
Constructor Interfaces
|
|
\layout Standard
|
|
|
|
Using constructor interfaces, you create each of the objects separately
|
|
and then assemble them in to components:
|
|
\layout LyX-Code
|
|
|
|
icalcomponent *event;
|
|
\layout LyX-Code
|
|
|
|
icalproperty *prop;
|
|
\layout LyX-Code
|
|
|
|
icalparameter *param;
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype atime;
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
event = icalcomponent_new(ICAL_VEVENT_COMPONENT);
|
|
\layout LyX-Code
|
|
|
|
prop = icalproperty_new_dtstamp(atime);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_add_property(event, prop);
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
prop = icalproperty_new_uid(''guid-1.host1.com'') );
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_add_property(event,prop);
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
prop=icalproperty_new_organizer(''mrbig@host.com'');
|
|
\layout LyX-Code
|
|
|
|
param = icalparameter_new_role(ICAL_ROLE_CHAIR)
|
|
\layout LyX-Code
|
|
|
|
icalproperty_add_parameter(prop, param);
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_add_property(event,prop);
|
|
\layout Standard
|
|
|
|
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
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
new
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
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
|
|
\begin_inset LatexCommand \ref{sec:memory}
|
|
|
|
\end_inset
|
|
|
|
.
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
vaargs Constructors
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout LyX-Code
|
|
|
|
calendar =
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_vanew(
|
|
\layout LyX-Code
|
|
|
|
ICAL_VCALENDAR_COMPONENT,
|
|
\layout LyX-Code
|
|
|
|
icalproperty_new_version(''2.0''),
|
|
\layout LyX-Code
|
|
|
|
icalproperty_new_prodid(
|
|
\layout LyX-Code
|
|
|
|
''-//RDU Software//NONSGML HandCal//EN''),
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_vanew(
|
|
\layout LyX-Code
|
|
|
|
ICAL_VEVENT_COMPONENT,
|
|
\layout LyX-Code
|
|
|
|
icalproperty_new_dtstamp(atime),
|
|
\layout LyX-Code
|
|
|
|
icalproperty_new_uid(''guid-1.host1.com''),
|
|
\layout LyX-Code
|
|
|
|
icalproperty_vanew_organizer(
|
|
\layout LyX-Code
|
|
|
|
''mrbig@host.com''),
|
|
\layout LyX-Code
|
|
|
|
icalparameter_new_role(ICAL_ROLE_CHAIR),
|
|
\layout LyX-Code
|
|
|
|
0
|
|
\layout LyX-Code
|
|
|
|
),
|
|
\layout LyX-Code
|
|
|
|
icalproperty_vanew_attendee(
|
|
\layout LyX-Code
|
|
|
|
''employee-A@host.com'',
|
|
\layout LyX-Code
|
|
|
|
icalparameter_new_role(
|
|
\layout LyX-Code
|
|
|
|
ICAL_ROLE_REQPARTICIPANT),
|
|
\layout LyX-Code
|
|
|
|
icalparameter_new_rsvp(1),
|
|
\layout LyX-Code
|
|
|
|
icalparameter_new_cutype(ICAL_CUTYPE_GROUP),
|
|
\layout LyX-Code
|
|
|
|
0
|
|
\layout LyX-Code
|
|
|
|
),
|
|
\layout LyX-Code
|
|
|
|
icalproperty_new_location(
|
|
\layout LyX-Code
|
|
|
|
"1CP Conference Room 4350"),
|
|
\layout LyX-Code
|
|
|
|
0
|
|
\layout LyX-Code
|
|
|
|
),
|
|
\layout LyX-Code
|
|
|
|
0
|
|
\layout LyX-Code
|
|
|
|
);
|
|
\layout Standard
|
|
|
|
This form is similar to the constructor form , except that the constructors
|
|
have
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
vanew
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
instead of
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
new
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Parsing Text
|
|
\layout Standard
|
|
|
|
Several routines are available for generating objects from text.
|
|
For properties, use:
|
|
\layout LyX-Code
|
|
|
|
icalproperty* p;
|
|
\layout LyX-Code
|
|
|
|
p = icalproperty_new_from_string("DTSTART:19970101T120000Z
|
|
\backslash
|
|
n");
|
|
\layout Standard
|
|
|
|
For parameters, use:
|
|
\layout LyX-Code
|
|
|
|
icalparameter *param
|
|
\layout LyX-Code
|
|
|
|
param = icalparameter_new_from_string("PARTSTAT=ACCEPTED");
|
|
\layout Standard
|
|
|
|
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
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcomponent_new_from_string(char* str);
|
|
\layout Standard
|
|
|
|
If the string contains only one component, the routine 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.
|
|
This routine is identical to ( and actually uses ) icalparser_parse_string(char
|
|
* str).
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
icalparser* icalparser_new();
|
|
\layout LyX-Code
|
|
|
|
void icalparser_free(icalparser* parser);
|
|
\layout LyX-Code
|
|
|
|
icalparser_get_line(parser,read_stream);
|
|
\layout LyX-Code
|
|
|
|
icalparser_add_line(parser,line);
|
|
\layout LyX-Code
|
|
|
|
icalparser_set_gen_data(parser,stream)
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
char* read_stream(char *s, size_t size, void *d)
|
|
\layout LyX-Code
|
|
|
|
{
|
|
\layout LyX-Code
|
|
|
|
char *c = fgets(s,size, (FILE*)d);
|
|
\layout LyX-Code
|
|
|
|
return c;
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout LyX-Code
|
|
|
|
main() {
|
|
\layout LyX-Code
|
|
|
|
char* line;
|
|
\layout LyX-Code
|
|
|
|
icalcomponent *c;
|
|
\layout LyX-Code
|
|
|
|
icalparser *parser = icalparser_new();
|
|
\layout LyX-Code
|
|
|
|
FILE* stream = fopen(argv[1],"r");
|
|
\layout LyX-Code
|
|
|
|
icalparser_set_gen_data(parser,stream);
|
|
\layout LyX-Code
|
|
|
|
do{
|
|
\layout LyX-Code
|
|
|
|
line = icalparser_get_line(parser,read_stream);
|
|
\layout LyX-Code
|
|
|
|
c = icalparser_add_line(parser,line);
|
|
\layout LyX-Code
|
|
|
|
if (c != 0){
|
|
\layout LyX-Code
|
|
|
|
printf("%s",icalcomponent_as_ical_string(c));
|
|
\layout LyX-Code
|
|
|
|
icalparser_claim(parser);
|
|
\layout LyX-Code
|
|
|
|
printf("
|
|
\backslash
|
|
n---------------
|
|
\backslash
|
|
n");
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_free(c);
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout LyX-Code
|
|
|
|
} while ( line != 0);
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout Standard
|
|
|
|
The parser object parameterizes the routine used to get input lines with
|
|
icalparser_set_gen_data() and
|
|
\emph on
|
|
|
|
\emph default
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
Using the same mechanism, other implementations could read from memory buffers,
|
|
sockets or other interfaces.
|
|
|
|
\layout Standard
|
|
|
|
Since the example code is a very common way to use the parser, there is
|
|
a convenience routine;
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalparser_parse(icalparser *parser,
|
|
\layout LyX-Code
|
|
|
|
char* (*line_gen_func)(char *s, size_t size, void* d))
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsection
|
|
|
|
Accessing Components
|
|
\layout Standard
|
|
|
|
Given a reference to a component, you probably will want to access the propertie
|
|
s, parameters and values inside.
|
|
Libical interfaces let you find sub-components, add and remove sub-components,
|
|
and do the same three operations on properties.
|
|
|
|
\layout Subsubsection
|
|
|
|
Finding Components
|
|
\layout Standard
|
|
|
|
To find a sub-component of a component, use:
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcomponent_get_first_component(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_kind kind);
|
|
\layout Standard
|
|
|
|
This routine will return a reference to the first component of the type
|
|
'kind.' The key kind values, listed in icalenums.h are:
|
|
\layout LyX-Code
|
|
|
|
ICAL_ANY_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VEVENT_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VTODO_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VJOURNAL_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VCALENDAR_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VFREEBUSY_COMPONENT
|
|
\layout LyX-Code
|
|
|
|
ICAL_VALARM_COMPONENT
|
|
\layout Standard
|
|
|
|
These are only the most common components; there are many more listed in
|
|
icalenums.h.
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Iterating Through Components
|
|
\layout Standard
|
|
|
|
Iteration requires a second routine to get the next subcomponent after the
|
|
first:
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcomponent_get_next_component(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_kind kind);
|
|
\layout Standard
|
|
|
|
With the 'first' and 'next' routines, you can create a for loop to iterate
|
|
through all of a components subcomponents
|
|
\layout LyX-Code
|
|
|
|
for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
|
|
\layout LyX-Code
|
|
|
|
c != 0;
|
|
\layout LyX-Code
|
|
|
|
c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT))
|
|
\layout LyX-Code
|
|
|
|
{
|
|
\layout LyX-Code
|
|
|
|
do_something(c);
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Subsubsection
|
|
|
|
Using Component Iterators
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
To solve this problem, there are also external iterators for components.
|
|
The routines associated with these external iterators are:
|
|
\layout LyX-Code
|
|
|
|
icalcompiter icalcomponent_begin_component(icalcomponent* component, icalcompone
|
|
nt_kind kind);
|
|
\layout LyX-Code
|
|
|
|
icalcompiter icalcomponent_end_component(icalcomponent* component, icalcomponent
|
|
_kind kind);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcompiter_next(icalcompiter* i);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcompiter_prior(icalcompiter* i);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalcompiter_deref(icalcompiter* i);
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
Here is an example of a loop using these routines:
|
|
\layout LyX-Code
|
|
|
|
for(
|
|
\layout LyX-Code
|
|
|
|
i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT);
|
|
|
|
\layout LyX-Code
|
|
|
|
icalcompiter_deref(&i)!= 0;
|
|
\layout LyX-Code
|
|
|
|
icalcompiter_next(&i)
|
|
\layout LyX-Code
|
|
|
|
) {
|
|
\layout LyX-Code
|
|
|
|
icalcomponent *this = icalcompiter_deref(&i);
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout Subsubsection
|
|
|
|
Removing Components
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
for(c = icalcomponent_get_first_component(parent_comp,ICAL_ANY_COMPONENT);
|
|
|
|
\layout LyX-Code
|
|
|
|
c != 0;
|
|
\layout LyX-Code
|
|
|
|
c = next
|
|
\layout LyX-Code
|
|
|
|
{
|
|
\layout LyX-Code
|
|
|
|
next = icalcomponent_get_next_component(parent_comp,ICAL_ANY_COMPONENT);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_remove_component(parent_comp,c);
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_get_first_component(parent_comp,ICAL_VEVENT_COMPONENT);
|
|
\layout LyX-Code
|
|
|
|
while((c=icalcomponent_get_current_component(c)) != 0 ){
|
|
\layout LyX-Code
|
|
|
|
if(icalcomponent_isa(c) == ICAL_VEVENT_COMPONENT){
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_remove_component(parent_comp,inner);
|
|
\layout LyX-Code
|
|
|
|
} else {
|
|
\layout LyX-Code
|
|
|
|
icalcomponent_get_next_component(parent_comp,ICAL_VEVENT_COMPONENT);
|
|
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout LyX-Code
|
|
|
|
}
|
|
\layout Subsubsection
|
|
|
|
Working with properties and parameters
|
|
\layout Standard
|
|
|
|
Finding, iterating and removing properties works the same as it does for
|
|
components, using the property-specific or parameter-specific interfaces:
|
|
|
|
\layout LyX-Code
|
|
|
|
icalproperty* icalcomponent_get_first_property(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalproperty_kind kind);
|
|
\layout LyX-Code
|
|
|
|
icalproperty* icalcomponent_get_next_property(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalproperty_kind kind);
|
|
\layout LyX-Code
|
|
|
|
void icalcomponent_add_property(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalproperty* property);
|
|
\layout LyX-Code
|
|
|
|
void icalcomponent_remove_property(
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* component,
|
|
\layout LyX-Code
|
|
|
|
icalproperty* property);
|
|
\layout Standard
|
|
|
|
For parameters:
|
|
\layout LyX-Code
|
|
|
|
icalparameter* icalproperty_get_first_parameter(
|
|
\layout LyX-Code
|
|
|
|
icalproperty* prop,
|
|
\layout LyX-Code
|
|
|
|
icalparameter_kind kind);
|
|
\layout LyX-Code
|
|
|
|
icalparameter* icalproperty_get_next_parameter(
|
|
\layout LyX-Code
|
|
|
|
icalproperty* prop,
|
|
\layout LyX-Code
|
|
|
|
icalparameter_kind kind);
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_add_parameter(
|
|
\layout LyX-Code
|
|
|
|
icalproperty* prop,
|
|
\layout LyX-Code
|
|
|
|
icalparameter* parameter);
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_remove_parameter(
|
|
\layout LyX-Code
|
|
|
|
icalproperty* prop,
|
|
\layout LyX-Code
|
|
|
|
icalparameter_kind kind);
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Subsubsection
|
|
|
|
Working with values
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_set_uid(icalproperty* prop, const char* v)
|
|
\layout LyX-Code
|
|
|
|
const char* icalproperty_get_uid(icalproperty* prop)
|
|
\layout Standard
|
|
|
|
For multi-valued properties, like ATTACH, the value type is usually a struct
|
|
or union that holds both possible types.
|
|
|
|
\layout Standard
|
|
|
|
If you want to work with the underlying value object, you can get and set
|
|
it with:
|
|
\layout LyX-Code
|
|
|
|
icalvalue* icalproperty_get_value (icalproperty* prop)
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_set_value(icalproperty* prop, icalvalue* value);
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icalvalue_get_datetime(icalvalue* value);
|
|
\layout LyX-Code
|
|
|
|
void icalvalue_set_datetime(icalvalue* value, struct icaltimetype v);
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_set_x(icalproperty* prop, char* v);
|
|
\layout LyX-Code
|
|
|
|
char* icalproperty_get_x(icalproperty* prop);
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
char* icalproperty_get_x_name(icalproperty* prop)
|
|
\layout LyX-Code
|
|
|
|
void icalproperty_set_x_name(icalproperty* prop, char* name);
|
|
\layout Subsubsection
|
|
|
|
Checking Component Validity
|
|
\layout Standard
|
|
|
|
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).
|
|
|
|
\layout Standard
|
|
|
|
Libical can check these restrictions with the routine:
|
|
\layout LyX-Code
|
|
|
|
int icalrestriction_check(icalcomponent* comp);
|
|
\layout Standard
|
|
|
|
This routine returns 0 if the component does not pass RFC2446 restrictions,
|
|
or if the component is malformed.
|
|
The component you pass in
|
|
\emph on
|
|
must
|
|
\emph default
|
|
be a VCALENDAR, with one or more children, like the examples in RFC2446.
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Converting Components to Text
|
|
\layout Standard
|
|
|
|
To create an RFC2445 compliant text representation of an object, use one
|
|
of the *_as_ical_string() routines:
|
|
\layout LyX-Code
|
|
|
|
char* icalcomponent_as_ical_string (icalcomponent* component)
|
|
\layout LyX-Code
|
|
|
|
char* icalproperty_as_ical_string (icalproperty* property)
|
|
\layout LyX-Code
|
|
|
|
char* icalparameter_as_ical_string (icalparameter* parameter)
|
|
\layout LyX-Code
|
|
|
|
char* icalvalue_as_ical_string (icalvalue* value)
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Standard
|
|
|
|
Icalproperty_as_ical_string() will terminate each line with the RFC2445
|
|
specified line terminator
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
|
|
\backslash
|
|
|
|
\backslash
|
|
n
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
However, if you compile with the symbol ICAL_UNIX_NEWLINE undefined, (
|
|
it is defined by default) it will terminate lines with
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
|
|
\backslash
|
|
|
|
\backslash
|
|
n
|
|
\backslash
|
|
|
|
\backslash
|
|
r
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsection
|
|
|
|
Time
|
|
\layout Subsubsection
|
|
|
|
Time structure
|
|
\layout Standard
|
|
|
|
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
|
|
\emph on
|
|
struct tm,
|
|
\emph default
|
|
but that structure does not differentiate between dates and times, and between
|
|
local time and UTC.
|
|
The libical structure is:
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype {
|
|
\layout LyX-Code
|
|
|
|
int year;
|
|
\layout LyX-Code
|
|
|
|
int month;
|
|
\layout LyX-Code
|
|
|
|
int day;
|
|
\layout LyX-Code
|
|
|
|
int hour;
|
|
\layout LyX-Code
|
|
|
|
int minute;
|
|
\layout LyX-Code
|
|
|
|
int second;
|
|
\layout LyX-Code
|
|
|
|
int is_utc; /* 1-> time is in UTC timezone */
|
|
\layout LyX-Code
|
|
|
|
int is_date; /* 1 -> interpret this as date.
|
|
*/ };
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Creating time structures
|
|
\layout Standard
|
|
|
|
There are several ways to create a new icaltimetype structure:
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_from_string(const char* str);
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_from_timet(time_t v, int is_date);
|
|
\layout LyX-Code
|
|
|
|
\layout Standard
|
|
|
|
Icaltime_from_string takes any RFC2445 compliant time string:
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype tt = icaltime_from_string("19970101T103000");
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
Time manipulating routines
|
|
\layout Standard
|
|
|
|
The null time value is used to indicate that the data in the structure is
|
|
not a valid time.
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_null_time(void);
|
|
\layout LyX-Code
|
|
|
|
int icaltime_is_null_time(struct icaltimetype t);
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_normalize(struct icaltimetype t);
|
|
\layout Standard
|
|
|
|
Normalizing allows you to do arithmetic operations on time values.
|
|
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype tt = icaltime_from_string(
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
19970101T103000
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
);
|
|
\layout LyX-Code
|
|
|
|
tt.days +=3
|
|
\layout LyX-Code
|
|
|
|
tt.second += 70;
|
|
\layout LyX-Code
|
|
|
|
tt = icaltime_normalize(tt);
|
|
\layout Standard
|
|
|
|
There are several routines to get the day of the week or month, etc, from
|
|
a time structure.
|
|
\layout LyX-Code
|
|
|
|
short icaltime_day_of_year(struct icaltimetype t);
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_from_day_of_year(short doy, short year);
|
|
\layout LyX-Code
|
|
|
|
short icaltime_day_of_week(struct icaltimetype t);
|
|
\layout LyX-Code
|
|
|
|
short icaltime_start_doy_of_week(struct icaltimetype t);
|
|
\layout LyX-Code
|
|
|
|
short icaltime_week_number(short day_of_month, short month, short year);
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_from_week_number(short week_number, short year);
|
|
\layout LyX-Code
|
|
|
|
short icaltime_days_in_month(short month,short year);
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_from_timet(time_t v, int is_date);
|
|
\layout LyX-Code
|
|
|
|
time_t icaltime_as_timet(struct icaltimetype);
|
|
\layout Standard
|
|
|
|
The compare routine works exactly like strcmp, but on time structures.
|
|
|
|
\layout LyX-Code
|
|
|
|
int icaltime_compare(struct icaltimetype a,struct icaltimetype b);
|
|
\layout Standard
|
|
|
|
The following routines convert between UTC and a named timezone.
|
|
The tzid field must be a timezone name from the Olsen database, such as
|
|
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
America/Los_Angeles.
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\layout Standard
|
|
|
|
The utc_offset routine returns the offset of the named time zone from UTC,
|
|
in seconds.
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout LyX-Code
|
|
|
|
int icaltime_utc_offset(struct icaltimetype tt, char* tzid);
|
|
\layout LyX-Code
|
|
|
|
int icaltime_local_utc_offset();
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_as_utc(struct icaltimetype tt,char* tzid);
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_as_zone(struct icaltimetype tt,char* tzid);
|
|
\layout LyX-Code
|
|
|
|
struct icaltimetype icaltime_as_local(struct icaltimetype tt);
|
|
\layout Subsection
|
|
|
|
Storing Objects
|
|
\layout Standard
|
|
|
|
The libical distribution includes a separate library, libicalss, that allows
|
|
you to store iCal component data to disk in a variety of ways.
|
|
This library also includes code to implement the CSTP protocol of CAP and
|
|
has some routines for deciphering incomming messages.
|
|
|
|
\layout Standard
|
|
|
|
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 are
|
|
planned for the future.
|
|
|
|
\layout Standard
|
|
|
|
All of the icalset derived classes have the same interface:
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
icaldirset* icaldirset_new(const char* path);
|
|
\layout LyX-Code
|
|
|
|
void icaldirset_free(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
const char* icaldirset_path(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
void icaldirset_mark(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icaldirset_commit(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icaldirset_add_component(icaldirset* store, icalcomponent*
|
|
comp);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icaldirset_remove_component(icaldirset* store, icalcomponent*
|
|
comp);
|
|
\layout LyX-Code
|
|
|
|
int icaldirset_count_components(icaldirset* store, icalcomponent_kind kind);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icaldirset_select(icaldirset* store, icalcomponent* gauge);
|
|
\layout LyX-Code
|
|
|
|
void icaldirset_clear(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icaldirset_fetch(icaldirset* store, const char* uid);
|
|
\layout LyX-Code
|
|
|
|
int icaldirset_has_uid(icaldirset* store, const char* uid);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icaldirset_fetch_match(icaldirset* set, icalcomponent *c);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icaldirset_modify(icaldirset* store, icalcomponent *oldc,
|
|
icalcomponent *newc);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icaldirset_get_current_component(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icaldirset_get_first_component(icaldirset* store);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icaldirset_get_next_component(icaldirset* store);
|
|
\layout Subsubsection
|
|
|
|
Creating a new set
|
|
\layout Standard
|
|
|
|
You can create a new set from either the base class or the direved class.
|
|
From the base class use one of:
|
|
\layout LyX-Code
|
|
|
|
icalset* icalset_new_file(const char* path);
|
|
\layout LyX-Code
|
|
|
|
icalset* icalset_new_dir(const char* path);
|
|
\layout LyX-Code
|
|
|
|
icalset* icalset_new_heap(void);
|
|
\layout LyX-Code
|
|
|
|
icalset* icalset_new_mysql(const char* path);
|
|
\layout Standard
|
|
|
|
You can also create a new set based on the derived class, For instance,
|
|
with icalfileset:
|
|
\layout LyX-Code
|
|
|
|
icalfileset* icalfileset_new(const char* path);
|
|
\layout LyX-Code
|
|
|
|
icalfileset* icalfileset_new_open(const char* path, int flags, mode_t mode);
|
|
\layout Standard
|
|
|
|
Icaset_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.
|
|
|
|
\layout Standard
|
|
|
|
The icalset and icalfilset objects are somewhat interchangable -- you can
|
|
use an icalfileset* as an argument to any of the icalset routines.
|
|
\layout Standard
|
|
|
|
The following examples will all use icalfileset routines; using the other
|
|
icalset derived classess will be similar.
|
|
|
|
\layout Subsubsection
|
|
|
|
Adding, Finding and Removing Components
|
|
\layout Standard
|
|
|
|
To add components to a set, use:
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icalfileset_add_component(icalfileset* cluster, icalcomponent*
|
|
child);
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
void icalfileset_mark(icalfileset* cluster);
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icalfileset_commit(icalfileset* cluster);
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
To iterate through the components in a set, use:
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalfileset_get_first_component(icalfileset* cluster);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalfileset_get_next_component(icalfileset* cluster);
|
|
\layout LyX-Code
|
|
|
|
icalcomponent* icalfileset_get_current_component (icalfileset* cluster);
|
|
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
icalgauge* icalgauge_new_from_sql(char* sql);
|
|
\layout Standard
|
|
|
|
Then, you can add the gauge to the set with :
|
|
\layout LyX-Code
|
|
|
|
icalerrorenum icalfileset_select(icalfileset* store, icalgauge* gauge);
|
|
\layout Standard
|
|
|
|
Here is an example that puts all of these routines together:
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
void test_fileset()
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
{
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalfileset *fs;
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalcomponent *c;
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
int i;
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
char *path = "test_fileset.ics";
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalgauge *g = icalgauge_new_from_sql(
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
"SELECT * FROM VEVENT WHERE DTSTART > '20000103T120000Z' AND DTSTART
|
|
<= '20000106T120000Z'");
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
fs = icalfileset_new(path);
|
|
\layout LyX-Code
|
|
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
for (i = 0; i!= 10; i++){
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
c = make_component(i);
|
|
\latex default
|
|
/* Make a new component where DTSTART has month of i */
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalfileset_add_component(fs,c);
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
}
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalfileset_commit(fs);
|
|
\latex default
|
|
/* Write to disk */
|
|
\layout LyX-Code
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalfileset_select(fs,g);
|
|
\latex default
|
|
/* Set the gauge to filter components */
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
for (c = icalfileset_get_first_component(fs);
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
c != 0;
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
c = icalfileset_get_next_component(fs)){
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
struct icaltimetype t = icalcomponent_get_dtstart(c);
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
printf("%s
|
|
\backslash
|
|
n",icaltime_as_ctime(t));
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
}
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
icalfileset_free(fs);
|
|
\layout LyX-Code
|
|
|
|
|
|
\latex no_latex
|
|
}
|
|
\layout Subsubsection
|
|
|
|
Other routines
|
|
\layout Standard
|
|
|
|
There are several other routines in the icalset interface, but they not
|
|
fully implemented yet.
|
|
|
|
\layout Subsection
|
|
|
|
|
|
\begin_inset LatexCommand \label{sec:memory}
|
|
|
|
\end_inset
|
|
|
|
Memory Management
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Description
|
|
|
|
1) If the function name has "new" in it, the caller gets control of the
|
|
memory.
|
|
( such as icalcomponent_new(), or icalproperty_new_clone() )
|
|
\layout Description
|
|
|
|
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())
|
|
|
|
\layout Description
|
|
|
|
3) If the function name has "add" in it, the caller is transferring control
|
|
of the memory to the routine.
|
|
( icalproperty_add_parameter() )
|
|
\layout Description
|
|
|
|
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.
|
|
|
|
\layout Description
|
|
|
|
5) If the routine returns a string, 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.
|
|
|
|
\layout Subsection
|
|
|
|
Error Handling
|
|
\layout Standard
|
|
|
|
Libical has several error handling mechanisms for the various types of programmi
|
|
ng, semantic and syntactic errors you may encounter.
|
|
\layout Subsubsection
|
|
|
|
Return values
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
icalerrno
|
|
\layout Standard
|
|
|
|
Most routines will set the global error value icalerrno on errors.
|
|
This variable is an enumeration; permissible values can be found in libical/ica
|
|
lerror.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:
|
|
\layout Standard
|
|
\added_space_top 0.3cm \added_space_bottom 0.3cm \align center \LyXTable
|
|
multicol5
|
|
12 2 0 0 -1 -1 -1 -1
|
|
1 1 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 0 0 0
|
|
1 1 0 0
|
|
2 1 0 "" ""
|
|
2 1 1 "" ""
|
|
0 8 1 0 0 0 0 "" ""
|
|
0 8 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
|
|
|
|
\newline
|
|
|
|
\newline
|
|
ICAL_BADARG_ERROR
|
|
\newline
|
|
One of the argument to a routine was bad.
|
|
Typically for a null pointer.
|
|
\newline
|
|
ICAL_NEWFAILED_ERROR
|
|
\newline
|
|
A new() or malloc() failed
|
|
\newline
|
|
ICAL_MALFORMEDDATA_ERROR
|
|
\newline
|
|
An input string was not in the correct format
|
|
\newline
|
|
ICAL_PARSE_ERROR
|
|
\newline
|
|
the parser failed to parse an incomming component
|
|
\newline
|
|
ICAL_INTERNAL_ERROR
|
|
\newline
|
|
Largely equivalent to an assert; it indicates a bug in the libical code
|
|
\newline
|
|
ICAL_FILE_ERROR
|
|
\newline
|
|
A file operation failed.
|
|
Check errno for more detai
|
|
\newline
|
|
ICAL_ALLOCATION_ERROR
|
|
\newline
|
|
|
|
\newline
|
|
ICAL_NO_ERROR
|
|
\newline
|
|
No error has occured
|
|
\newline
|
|
ICAL_TIMEDOUT_ERROR
|
|
\newline
|
|
Failed to acquire a lock on a file, or the CSTP protocol timed out.
|
|
|
|
\newline
|
|
ICAL_MULTIPLEINCLUSION_ERROR
|
|
\newline
|
|
|
|
\newline
|
|
ICAL_UNKNOWN_ERROR
|
|
\newline
|
|
|
|
\layout Subsubsection
|
|
|
|
X-LIC-ERROR and X-LIC-INVALID-COMPONENT
|
|
\layout Standard
|
|
|
|
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:
|
|
\layout LyX-Code
|
|
|
|
X-LIC-ERROR;X-LIC-ERRORTYPE=INVALID_ITIP :Failed iTIP restrictions for property
|
|
DTSTART.
|
|
|
|
\layout LyX-Code
|
|
|
|
Expected 1 instances of the property and got 0
|
|
\layout Standard
|
|
|
|
This error resulted from a call to icalrestriction_check(), which discovered
|
|
that the component does not have a DTSTART property, as required by RFC2445.
|
|
|
|
\layout Standard
|
|
|
|
There are a few routines to manipulate error properties:
|
|
\layout Standard
|
|
\LyXTable
|
|
multicol5
|
|
10 2 0 0 -1 -1 -1 -1
|
|
1 1 0 0
|
|
0 0 0 0
|
|
0 1 1 0
|
|
0 0 0 0
|
|
0 1 1 0
|
|
0 1 0 0
|
|
0 1 1 0
|
|
0 1 0 0
|
|
0 1 1 0
|
|
0 1 1 0
|
|
2 1 1 "" ""
|
|
2 1 1 "3in" ""
|
|
0 2 1 1 0 0 0 "" ""
|
|
0 8 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 1 0 1 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 1 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 1 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 1 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 1 1 0 1 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 1 1 0 1 "" ""
|
|
0 2 1 0 0 0 0 "" ""
|
|
0 2 1 1 0 0 1 "" ""
|
|
|
|
Routine
|
|
\newline
|
|
Purpose
|
|
\newline
|
|
void icalrestriction_check()
|
|
\newline
|
|
Check a component against RFC2446 and insert
|
|
\newline
|
|
|
|
\newline
|
|
error properties to indicate non compliance
|
|
\newline
|
|
int icalcomponent_count_errors()
|
|
\newline
|
|
Return the number of error properties
|
|
\newline
|
|
|
|
\newline
|
|
in a component
|
|
\newline
|
|
void icalcomponent_strip_errors()
|
|
\newline
|
|
Remove all error properties in as
|
|
\newline
|
|
|
|
\newline
|
|
component
|
|
\newline
|
|
void icalcomponent_convert_errors()
|
|
\newline
|
|
Convert some error properties into
|
|
\newline
|
|
|
|
\newline
|
|
REQUESTS-STATUS proprties to indicate the inability to
|
|
\newline
|
|
|
|
\newline
|
|
process the component as an iTIP request.
|
|
|
|
\layout Standard
|
|
|
|
The types of errors are listed in icalerror.h.
|
|
They are:
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_COMPONENTPARSEERROR
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_PROPERTYPARSEERROR
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_VALUEPARSEERROR
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_UNKVCALPROP
|
|
\layout LyX-Code
|
|
|
|
ICAL_XLICERRORTYPE_INVALIDITIP
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsubsection
|
|
|
|
ICAL_ERRORS_ARE_FATAL and icalerror_errors_are_fatal
|
|
\layout Standard
|
|
|
|
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.
|
|
|
|
\layout Subsection
|
|
|
|
Naming Standard
|
|
\layout Standard
|
|
|
|
Structures that you access with the
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
struct
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
keyword, such as
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
struct icaltimetype
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
are things that you are allowed to see inside and poke at.
|
|
|
|
\layout Standard
|
|
|
|
Structures that you access though a typedef, such as
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
icalcomponent
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
are things where all of the data is hidden.
|
|
|
|
\layout Standard
|
|
|
|
Component names that start with
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
V
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
are part of RFC 2445 or another iCal standard.
|
|
Component names that start with
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
X
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
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
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
XLIC
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
or
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
X-LIC
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
are not part of any iCal spec.
|
|
They are used internally by libical.
|
|
|
|
\layout Standard
|
|
|
|
Enums that identify a component, property, value or parameter end with
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
_COMPONENT,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
_PROPERTY,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
_VALUE,
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
or
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
_PARAMETER
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
s
|
|
\layout Standard
|
|
|
|
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.
|
|
\layout Standard
|
|
|
|
The enums for the parts of a recurarance rule and request statuses are irregular.
|
|
|
|
\layout Section
|
|
|
|
Hacks and Bugs
|
|
\layout Standard
|
|
|
|
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
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
HACK.
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
|
|
\the_end
|