aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/libicalss
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/libicalss')
-rw-r--r--libical/src/libicalss/.cvsignore6
-rw-r--r--libical/src/libicalss/Makefile.am23
-rw-r--r--libical/src/libicalss/icalcalendar.c268
-rw-r--r--libical/src/libicalss/icalcalendar.h68
-rw-r--r--libical/src/libicalss/icalcluster.c423
-rw-r--r--libical/src/libicalss/icalcluster.h73
-rw-r--r--libical/src/libicalss/icalcomponent.h115
-rw-r--r--libical/src/libicalss/icalstore.c858
-rw-r--r--libical/src/libicalss/icalstore.h78
9 files changed, 1912 insertions, 0 deletions
diff --git a/libical/src/libicalss/.cvsignore b/libical/src/libicalss/.cvsignore
new file mode 100644
index 0000000000..732c1577b6
--- /dev/null
+++ b/libical/src/libicalss/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+.deps
+Makefile.in
+*.lo
+*.la
+.libs \ No newline at end of file
diff --git a/libical/src/libicalss/Makefile.am b/libical/src/libicalss/Makefile.am
new file mode 100644
index 0000000000..ea37380688
--- /dev/null
+++ b/libical/src/libicalss/Makefile.am
@@ -0,0 +1,23 @@
+
+
+#noinst_LTLIBRARIES = libicalss.la
+lib_LTLIBRARIES = libicalss.la
+
+libicalss_la_SOURCES =\
+ icalcalendar.c \
+ icalcalendar.h \
+ icalcluster.c \
+ icalcluster.h \
+ icalstore.c \
+ icalstore.h
+
+include_HEADERS =\
+ icalcalendar.h \
+ icalcluster.h \
+ icalstore.h
+
+
+INCLUDES = \
+ -I $(srcdir)/../libical/ \
+ -I ../libical
+
diff --git a/libical/src/libicalss/icalcalendar.c b/libical/src/libicalss/icalcalendar.c
new file mode 100644
index 0000000000..0f2231b1d7
--- /dev/null
+++ b/libical/src/libicalss/icalcalendar.c
@@ -0,0 +1,268 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcalendar.c
+ CREATOR: eric 23 December 1999
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "icalcalendar.h"
+#include "icalcluster.h"
+#include <limits.h>
+#include <sys/stat.h> /* For mkdir, stat */
+#include <sys/types.h> /* For mkdir */
+#include <fcntl.h> /* For mkdir */
+#include <unistd.h> /* For mkdir, stat */
+#include <stdlib.h> /* for malloc */
+#include <string.h> /* for strcat */
+#include <errno.h>
+
+#define BOOKED_DIR "booked"
+#define INCOMING_FILE "incoming.ics"
+#define PROP_FILE "properties.ics"
+#define FBLIST_FILE "freebusy.ics"
+
+struct icalcalendar_impl
+{
+ char* dir;
+ icalcomponent* freebusy;
+ icalcomponent* properties;
+ icalstore* booked;
+ icalstore* incoming;
+};
+
+struct icalcalendar_impl* icalcalendar_new_impl()
+{
+ struct icalcalendar_impl* impl;
+
+ if ( ( impl = (struct icalcalendar_impl*)
+ malloc(sizeof(struct icalcalendar_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ return impl;
+}
+
+
+icalerrorenum icalcalendar_create(struct icalcalendar_impl* impl)
+{
+ char path[PATH_MAX];
+ struct stat sbuf;
+ int r;
+
+ icalerror_check_arg_re((impl != 0),"impl",ICAL_BADARG_ERROR);
+
+ path[0] = '\0';
+ strcpy(path,impl->dir);
+ strcat(path,"/");
+ strcat(path,BOOKED_DIR);
+
+ r = stat(path,&sbuf);
+
+ if( r != 0 && errno == ENOENT){
+
+ if(mkdir(path,0777)!=0){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+ }
+
+ return ICAL_NO_ERROR;
+}
+
+icalcalendar* icalcalendar_new(char* dir)
+{
+ struct icalcalendar_impl* impl;
+
+ icalerror_check_arg_rz((dir != 0),"dir");
+
+ impl = icalcalendar_new_impl();
+
+ if (impl == 0){
+ return 0;
+ }
+
+ impl->dir = (char*)strdup(dir);
+ impl->freebusy = 0;
+ impl->properties = 0;
+ impl->booked = 0;
+ impl->incoming = 0;
+
+ if (icalcalendar_create(impl) != ICAL_NO_ERROR){
+ free(impl);
+ return 0;
+ }
+
+ return impl;
+}
+
+void icalcalendar_free(icalcalendar* calendar)
+{
+
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+
+ if (impl->dir !=0){
+ free(impl->dir);
+ }
+
+ if (impl->freebusy !=0){
+ icalcluster_free(impl->freebusy);
+ }
+
+ if (impl->properties !=0){
+ icalcluster_free(impl->properties);
+ }
+
+ if (impl->booked !=0){
+ icalstore_free(impl->booked);
+ }
+
+ if (impl->incoming !=0){
+ icalstore_free(impl->incoming);
+ }
+
+ impl->dir = 0;
+ impl->freebusy = 0;
+ impl->properties = 0;
+ impl->booked = 0;
+ impl->incoming = 0;
+
+
+ free(impl);
+}
+
+
+int icalcalendar_lock(icalcalendar* calendar)
+{
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_unlock(icalcalendar* calendar)
+{
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_islocked(icalcalendar* calendar)
+{
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_ownlock(icalcalendar* calendar)
+{
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+icalstore* icalcalendar_get_booked(icalcalendar* calendar)
+{
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ char dir[PATH_MAX];
+
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ dir[0] = '\0';
+ strcpy(dir,impl->dir);
+ strcat(dir,"/");
+ strcat(dir,BOOKED_DIR);
+
+ if (impl->booked == 0){
+ icalerror_clear_errno();
+ impl->booked = icalstore_new(dir);
+ assert(icalerrno == ICAL_NO_ERROR);
+ }
+
+ return impl->booked;
+
+}
+
+icalcluster* icalcalendar_get_incoming(icalcalendar* calendar)
+{
+ char path[PATH_MAX];
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strcpy(path,impl->dir);
+ strcat(path,"/");
+ strcat(path,INCOMING_FILE);
+
+ if (impl->properties == 0){
+ impl->properties = icalcluster_new(path);
+ }
+
+ return impl->properties;
+}
+
+icalcluster* icalcalendar_get_properties(icalcalendar* calendar)
+{
+ char path[PATH_MAX];
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strcpy(path,impl->dir);
+ strcat(path,"/");
+ strcat(path,PROP_FILE);
+
+ if (impl->properties == 0){
+ impl->properties = icalcluster_new(path);
+ }
+
+ return impl->properties;
+}
+
+icalcluster* icalcalendar_get_freebusy(icalcalendar* calendar)
+{
+ char path[PATH_MAX];
+ struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar;
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strcpy(path,impl->dir);
+ strcat(path,"/");
+ strcat(path,FBLIST_FILE);
+
+
+ if (impl->freebusy == 0){
+ impl->freebusy = icalcluster_new(path);
+ }
+
+ return impl->freebusy;
+}
+
+
+
+
diff --git a/libical/src/libicalss/icalcalendar.h b/libical/src/libicalss/icalcalendar.h
new file mode 100644
index 0000000000..90e7b33c22
--- /dev/null
+++ b/libical/src/libicalss/icalcalendar.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcalendar.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALCALENDAR_H
+#define ICALCALENDAR_H
+
+#include "ical.h"
+#include "icalstore.h"
+#include "icalcluster.h"
+
+/* icalcalendar
+ * Routines for storing calendar data in a file system. The calendar
+ * has two icalstores, one for incoming components and one for booked
+ * components. It also has interfaces to access the free/busy list
+ * and a list of calendar properties */
+
+typedef void icalcalendar;
+
+icalcalendar* icalcalendar_new(char* dir);
+
+void icalcalendar_free(icalcalendar* calendar);
+
+int icalcalendar_lock(icalcalendar* calendar);
+
+int icalcalendar_unlock(icalcalendar* calendar);
+
+int icalcalendar_islocked(icalcalendar* calendar);
+
+int icalcalendar_ownlock(icalcalendar* calendar);
+
+icalstore* icalcalendar_get_booked(icalcalendar* calendar);
+
+icalcluster* icalcalendar_get_incoming(icalcalendar* calendar);
+
+icalcluster* icalcalendar_get_properties(icalcalendar* calendar);
+
+icalcluster* icalcalendar_get_freebusy(icalcalendar* calendar);
+
+
+#endif /* !ICALCALENDAR_H */
+
+
+
diff --git a/libical/src/libicalss/icalcluster.c b/libical/src/libicalss/icalcluster.c
new file mode 100644
index 0000000000..36bdccc743
--- /dev/null
+++ b/libical/src/libicalss/icalcluster.c
@@ -0,0 +1,423 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcluster.c
+ CREATOR: eric 23 December 1999
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "icalcluster.h"
+#include <errno.h>
+#include <limits.h> /* For PATH_MAX */
+#include <sys/stat.h> /* for stat */
+#include <unistd.h> /* for stat, getpid */
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h> /* for fcntl */
+#include <unistd.h> /* for fcntl */
+
+icalerrorenum icalcluster_create_cluster(char *path);
+
+struct icalcluster_impl {
+ char *path;
+ icalcomponent* cluster;
+ int changed;
+ FILE* stream;
+};
+
+icalcluster* icalcluster_new_impl()
+{
+ struct icalcluster_impl* comp;
+
+ if ( ( comp = (struct icalcluster_impl*)
+ malloc(sizeof(struct icalcluster_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ errno = ENOMEM;
+ return 0;
+ }
+
+ return comp;
+}
+
+char* read_from_file(char *s, size_t size, void *d)
+{
+ char *c = fgets(s,size, (FILE*)d);
+ return c;
+}
+
+icalcluster* icalcluster_new(char* path)
+{
+ struct icalcluster_impl *impl = icalcluster_new_impl();
+ struct stat sbuf;
+ int createclusterfile = 0;
+ icalerrorenum error = ICAL_NO_ERROR;
+ icalparser *parser;
+ struct icaltimetype tt;
+ off_t cluster_file_size;
+
+ memset(&tt,0,sizeof(struct icaltimetype));
+
+ icalerror_clear_errno();
+ icalerror_check_arg_rz( (path!=0), "path");
+
+ if (impl == 0){
+ return 0;
+ }
+
+ /*impl->path = strdup(path); icalcluster_load does this */
+ impl->changed = 0;
+
+ impl->cluster = 0;
+
+ impl->path = 0;
+ impl->stream = 0;
+
+ /* Check if the path already exists and if it is a regular file*/
+ if (stat(path,&sbuf) != 0){
+
+ /* A file by the given name does not exist, or there was
+ another error */
+ cluster_file_size = 0;
+ if (errno == ENOENT) {
+ /* It was because the file does not exist */
+ createclusterfile = 1;
+ } else {
+ /* It was because of another error */
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return 0;
+ }
+ } else {
+ /* A file by the given name exists, but is it a regular file */
+
+ if (!S_ISREG(sbuf.st_mode)){
+ /* Nope, not a directory */
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return 0;
+ } else {
+ /* Lets assume that it is a file of the right type */
+ cluster_file_size = sbuf.st_size;
+ createclusterfile = 0;
+ }
+ }
+
+ /* if cluster does not already exist, create it */
+
+ if (createclusterfile == 1) {
+ error = icalcluster_create_cluster(path);
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return 0;
+ }
+ }
+
+ impl->path = (char*)strdup(path);
+
+ errno = 0;
+ impl->stream = fopen(impl->path,"r");
+
+ if (impl->stream ==0 || errno != 0){
+ impl->cluster = 0;
+ icalerror_set_errno(ICAL_FILE_ERROR); /* Redundant, actually */
+ return 0;
+ }
+
+ icalcluster_lock(impl);
+
+ if(cluster_file_size > 0){
+ parser = icalparser_new();
+ icalparser_set_gen_data(parser,impl->stream);
+ impl->cluster = icalparser_parse(parser,read_from_file);
+ icalparser_free(parser);
+
+ if (icalcomponent_isa(impl->cluster) != ICAL_XROOT_COMPONENT){
+ /* The parser got a single component, so it did not put it in
+ an XROOT. */
+ icalcomponent *cl = impl->cluster;
+ impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ icalcomponent_add_component(impl->cluster,cl);
+ }
+
+ } else {
+
+ impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ }
+
+ if (impl->cluster == 0){
+ icalerror_set_errno(ICAL_PARSE_ERROR);
+ return 0;
+ }
+
+ if (error != ICAL_NO_ERROR){
+ return 0;
+ }
+
+ return impl;
+}
+
+void icalcluster_free(icalcluster* cluster)
+{
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rv((cluster!=0),"cluster");
+
+ if (impl->cluster != 0){
+ icalcluster_commit(cluster);
+ icalcomponent_free(impl->cluster);
+ impl->cluster=0;
+ }
+
+ if(impl->path != 0){
+ free(impl->path);
+ impl->path = 0;
+ }
+
+ if(impl->stream != 0){
+ icalcluster_unlock(impl);
+ fclose(impl->stream);
+ impl->stream = 0;
+ }
+
+ free(impl);
+}
+
+char* icalcluster_path(icalcluster* cluster)
+{
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+ icalerror_check_arg_rz((cluster!=0),"cluster");
+
+ return impl->path;
+}
+
+
+int icalcluster_lock(icalcluster *cluster)
+{
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+ struct flock lock;
+ int fd;
+
+ icalerror_check_arg_rz((impl->stream!=0),"impl->stream");
+
+ fd = fileno(impl->stream);
+
+ lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
+ lock.l_start = 0; /* byte offset relative to l_whence */
+ lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
+ lock.l_len = 0; /* #bytes (0 means to EOF) */
+
+ return (fcntl(fd, F_SETLKW, &lock));
+}
+
+int icalcluster_unlock(icalcluster *cluster)
+{
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+ int fd;
+ struct flock lock;
+ icalerror_check_arg_rz((impl->stream!=0),"impl->stream");
+
+ fd = fileno(impl->stream);
+
+ lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
+ lock.l_start = 0; /* byte offset relative to l_whence */
+ lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
+ lock.l_len = 0; /* #bytes (0 means to EOF) */
+
+ return (fcntl(fd, F_UNLCK, &lock));
+
+}
+
+icalerrorenum icalcluster_create_cluster(char *path)
+{
+
+ FILE* f;
+ int r;
+ icalcomponent *c;
+
+ icalerror_clear_errno();
+
+ f = fopen(path,"w");
+
+ if (f == 0){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+
+
+ /* This used to write data to the file... */
+
+
+ fclose(f);
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcluster_commit(icalcluster* cluster)
+{
+ FILE *f;
+ char tmp[PATH_MAX]; /* HACK Buffer overflow potential */
+ char *str;
+ icalparser *parser;
+ icalcomponent *c;
+
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR);
+
+ if (impl->changed == 0 ){
+ return ICAL_NO_ERROR;
+ }
+
+#ifdef ICAL_SAFESAVES
+ snprintf(tmp,PATH_MAX,"%s-tmp",impl->path);
+#else
+ strcpy(tmp,impl->path);
+#endif
+
+ if ( (f = fopen(tmp,"w")) < 0 ){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+
+ for(c = icalcomponent_get_first_component(impl->cluster,ICAL_ANY_COMPONENT);
+ c != 0;
+ c = icalcomponent_get_next_component(impl->cluster,ICAL_ANY_COMPONENT)){
+
+ str = icalcomponent_as_ical_string(c);
+
+ if ( fwrite(str,sizeof(char),strlen(str),f) < strlen(str)){
+ fclose(f);
+ return ICAL_FILE_ERROR;
+ }
+ }
+
+ fclose(f);
+ impl->changed = 0;
+
+#ifdef ICAL_SAFESAVES
+ rename(tmp,impl->path); /* HACK, should check for error here */
+#endif
+
+ return ICAL_NO_ERROR;
+
+}
+
+void icalcluster_mark(icalcluster* cluster){
+
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rv((impl!=0),"cluster");
+
+ impl->changed = 1;
+
+}
+
+icalcomponent* icalcluster_get_component(icalcluster* cluster){
+ struct icalcluster_impl *impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR);
+
+ return impl->cluster;
+}
+
+
+/* manipulate the components in the cluster */
+
+icalerrorenum icalcluster_add_component(icalcluster *cluster,
+ icalcomponent* child)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rv((cluster!=0),"cluster");
+ icalerror_check_arg_rv((child!=0),"child");
+
+ icalcomponent_add_component(impl->cluster,child);
+
+ icalcluster_mark(cluster);
+
+ return ICAL_NO_ERROR;
+
+}
+
+icalerrorenum icalcluster_remove_component(icalcluster *cluster,
+ icalcomponent* child)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rv((cluster!=0),"cluster");
+ icalerror_check_arg_rv((child!=0),"child");
+
+ icalcomponent_remove_component(impl->cluster,child);
+
+ icalcluster_mark(cluster);
+
+ return ICAL_NO_ERROR;
+}
+
+int icalcluster_count_components(icalcluster *cluster,
+ icalcomponent_kind kind)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ if(cluster == 0){
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return -1;
+ }
+
+ return icalcomponent_count_components(impl->cluster,kind);
+}
+
+/* Iterate through components */
+icalcomponent* icalcluster_get_current_component (icalcluster* cluster)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rz((cluster!=0),"cluster");
+
+ return icalcomponent_get_current_component(impl->cluster);
+}
+
+icalcomponent* icalcluster_get_first_component(icalcluster* cluster,
+ icalcomponent_kind kind)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rz((cluster!=0),"cluster");
+
+ return icalcomponent_get_first_component(impl->cluster,kind);
+}
+
+icalcomponent* icalcluster_get_next_component(icalcluster* cluster,
+ icalcomponent_kind kind)
+{
+ struct icalcluster_impl* impl = (struct icalcluster_impl*)cluster;
+
+ icalerror_check_arg_rz((cluster!=0),"cluster");
+
+ return icalcomponent_get_next_component(impl->cluster,kind);
+}
+
diff --git a/libical/src/libicalss/icalcluster.h b/libical/src/libicalss/icalcluster.h
new file mode 100644
index 0000000000..39fe542027
--- /dev/null
+++ b/libical/src/libicalss/icalcluster.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcluster.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALCLUSTER_H
+#define ICALCLUSTER_H
+
+#include "ical.h"
+
+typedef void icalcluster;
+
+
+icalcluster* icalcluster_new(char* path);
+void icalcluster_free(icalcluster* cluster);
+
+char* icalcluster_path(icalcluster* cluster);
+
+/* Return a reference to the internal component. */
+icalcomponent* icalcluster_get_component(icalcluster* cluster);
+
+/* Mark the cluster as changed, so it will be written to disk when it
+ is freed*/
+void icalcluster_mark(icalcluster* cluster);
+
+/* Write the cluster data back to disk */
+icalerrorenum icalcluster_commit(icalcluster* cluster);
+
+/* manipulate the components in the cluster */
+icalerrorenum icalcluster_add_component(icalcomponent* parent,
+ icalcomponent* child);
+
+icalerrorenum icalcluster_remove_component(icalcomponent* parent,
+ icalcomponent* child);
+
+int icalcluster_count_components(icalcomponent* component,
+ icalcomponent_kind kind);
+
+/* Iterate through components */
+icalcomponent* icalcluster_get_current_component (icalcomponent* component);
+
+icalcomponent* icalcluster_get_first_component(icalcomponent* component,
+ icalcomponent_kind kind);
+icalcomponent* icalcluster_get_next_component(icalcomponent* component,
+ icalcomponent_kind kind);
+
+#endif /* !ICALCLUSTER_H */
+
+
+
diff --git a/libical/src/libicalss/icalcomponent.h b/libical/src/libicalss/icalcomponent.h
new file mode 100644
index 0000000000..9e0e9f5a9f
--- /dev/null
+++ b/libical/src/libicalss/icalcomponent.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcomponent.h
+ CREATOR: eric 20 March 1999
+
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The original author is Eric Busboom
+ The original code is icalcomponent.h
+
+======================================================================*/
+
+#ifndef ICALCOMPONENT_H
+#define ICALCOMPONENT_H
+
+#include "icalproperty.h"
+#include "icalvalue.h"
+#include "icalenums.h" /* defines icalcomponent_kind */
+
+typedef void icalcomponent;
+
+icalcomponent* icalcomponent_new(icalcomponent_kind kind);
+icalcomponent* icalcomponent_new_clone(icalcomponent* component);
+icalcomponent* icalcomponent_new_from_string(char* str);
+icalcomponent* icalcomponent_vanew(icalcomponent_kind kind, ...);
+void icalcomponent_free(icalcomponent* component);
+
+char* icalcomponent_as_ical_string(icalcomponent* component);
+
+int icalcomponent_is_valid(icalcomponent* component);
+
+icalcomponent_kind icalcomponent_isa(icalcomponent* component);
+
+int icalcomponent_isa_component (void* component);
+
+/*
+ * Working with properties
+ */
+
+void icalcomponent_add_property(icalcomponent* component,
+ icalproperty* property);
+
+void icalcomponent_remove_property(icalcomponent* component,
+ icalproperty* property);
+
+int icalcomponent_count_properties(icalcomponent* component,
+ icalproperty_kind kind);
+
+/* Iterate through the properties */
+icalproperty* icalcomponent_get_current_property(icalcomponent* component);
+
+icalproperty* icalcomponent_get_first_property(icalcomponent* component,
+ icalproperty_kind kind);
+icalproperty* icalcomponent_get_next_property(icalcomponent* component,
+ icalproperty_kind kind);
+
+/* Return a null-terminated array of icalproperties*/
+
+icalproperty** icalcomponent_get_properties(icalcomponent* component,
+ icalproperty_kind kind);
+
+
+/*
+ * Working with components
+ */
+
+
+void icalcomponent_add_component(icalcomponent* parent,
+ icalcomponent* child);
+
+void icalcomponent_remove_component(icalcomponent* parent,
+ icalcomponent* child);
+
+int icalcomponent_count_components(icalcomponent* component,
+ icalcomponent_kind kind);
+
+/* Iterate through components */
+icalcomponent* icalcomponent_get_current_component (icalcomponent* component);
+
+icalcomponent* icalcomponent_get_first_component(icalcomponent* component,
+ icalcomponent_kind kind);
+icalcomponent* icalcomponent_get_next_component(icalcomponent* component,
+ icalcomponent_kind kind);
+
+/* Return a null-terminated array of icalproperties*/
+icalproperty** icalcomponent_get_component(icalcomponent* component,
+ icalproperty_kind kind);
+
+/* Working with embedded error properties */
+
+int icalcomponent_count_errors(icalcomponent* component);
+void icalcomponent_strip_errors(icalcomponent* component);
+
+
+/* Internal operations. You don't see these... */
+icalcomponent* icalcomponent_get_parent(icalcomponent* component);
+void icalcomponent_set_parent(icalcomponent* component,
+ icalcomponent* parent);
+
+#endif /* !ICALCOMPONENT_H */
+
+
+
diff --git a/libical/src/libicalss/icalstore.c b/libical/src/libicalss/icalstore.c
new file mode 100644
index 0000000000..382464e476
--- /dev/null
+++ b/libical/src/libicalss/icalstore.c
@@ -0,0 +1,858 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalstore.c
+ CREATOR: eric 28 November 1999
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+/*
+
+ icalstore manages a database of ical components and offers
+ interfaces for reading, writting and searching for components.
+
+ icalstore groups components in to clusters based on their DTSTART
+ time -- all components that start in the same month are grouped
+ together in a single file. All files in a sotre are kept in a single
+ directory. ( If a component does not have DTSTART, the store uses
+ DTSTAMP or CREATE )
+
+ The primary interfaces are icalstore_first and icalstore_next. These
+ routine iterate through all of the components in the store, subject
+ to the current gauge. A gauge is an icalcomponent that is tested
+ against other componets for a match. If a gauge has been set with
+ icalstore_select, icalstore_first and icalstore_next will only
+ return componentes that match the gauge.
+
+ The Store generated UIDs for all objects that are stored if they do
+ not already have a UID. The UID is the name of the cluster (month &
+ year as MMYYYY) plus a unique serial number. The serial number is
+ stored as a property of the cluster.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "ical.h"
+#include "icalstore.h"
+#include "pvl.h"
+#include "icalerror.h"
+#include "icalparser.h"
+#include "icalcluster.h"
+
+#include <limits.h>
+#include <dirent.h> /* for opendir() */
+#include <errno.h>
+#include <sys/types.h> /* for opendir() */
+#include <sys/stat.h> /* for stat */
+#include <unistd.h> /* for stat, getpid */
+#include <time.h> /* for clock() */
+#include <stdlib.h> /* for rand(), srand() */
+#include <sys/utsname.h> /* for uname */
+#include <string.h> /* for strdup */
+
+
+struct icalstore_impl
+{
+ char* dir;
+ icalcomponent* gauge;
+ icalcluster* cluster;
+ int first_component;
+ pvl_list directory;
+ pvl_elem directory_iterator;
+};
+
+struct icalstore_impl* icalstore_new_impl()
+{
+ struct icalstore_impl* comp;
+
+ if ( ( comp = (struct icalstore_impl*)
+ malloc(sizeof(struct icalstore_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ return comp;
+}
+
+void icalstore_lock(char* dir)
+{
+}
+
+
+void icalstore_unlock(char* dir)
+{
+}
+
+/* Load the contents of the store directory into the store's internal directory list*/
+icalerrorenum icalstore_read_directory(struct icalstore_impl* impl)
+{
+ struct dirent *de;
+ DIR* dp;
+ char *str;
+
+ dp = opendir(impl->dir);
+
+ if ( dp == 0) {
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+
+ /* clear contents of directory list */
+ while((str = pvl_pop(impl->directory))){
+ free(str);
+ }
+
+ /* load all of the cluster names in the directory list */
+ for(de = readdir(dp);
+ de != 0;
+ de = readdir(dp)){
+
+ /* Remove known directory names '.' and '..'*/
+ if (strcmp(de->d_name,".") == 0 ||
+ strcmp(de->d_name,"..") == 0 ){
+ continue;
+ }
+
+ pvl_push(impl->directory, (void*)strdup(de->d_name));
+ }
+
+ closedir(dp);
+
+ return ICAL_NO_ERROR;
+}
+
+icalstore* icalstore_new(char* dir)
+{
+ struct icalstore_impl *impl = icalstore_new_impl();
+ struct stat sbuf;
+
+ if (impl == 0){
+ return 0;
+ }
+
+ icalerror_check_arg_rz( (dir!=0), "dir");
+
+ if (stat(dir,&sbuf) != 0){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return 0;
+ }
+
+ /* dir is not the name of a direectory*/
+ if (!S_ISDIR(sbuf.st_mode)){
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return 0;
+ }
+
+ icalstore_lock(dir);
+
+ impl = icalstore_new_impl();
+
+ if (impl ==0){
+ icalerror_set_errno(ICAL_ALLOCATION_ERROR);
+ return 0;
+ }
+
+ impl->directory = pvl_newlist();
+ impl->directory_iterator = 0;
+ impl->dir = (char*)strdup(dir);
+ impl->gauge = 0;
+ impl->first_component = 0;
+ impl->cluster = 0;
+
+ icalstore_read_directory(impl);
+
+ return (icalstore*) impl;
+}
+
+void icalstore_free(icalstore* s)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)s;
+ char* str;
+
+ icalstore_unlock(impl->dir);
+
+ if(impl->dir !=0){
+ free(impl->dir);
+ }
+
+ if(impl->gauge !=0){
+ icalcomponent_free(impl->gauge);
+ }
+
+ if(impl->cluster !=0){
+ icalcluster_free(impl->cluster);
+ }
+
+ while(impl->directory !=0 && (str=pvl_pop(impl->directory)) != 0){
+ free(str);
+ }
+
+ if(impl->directory != 0){
+ pvl_free(impl->directory);
+ }
+
+ impl->directory = 0;
+ impl->directory_iterator = 0;
+ impl->dir = 0;
+ impl->gauge = 0;
+ impl->first_component = 0;
+
+ free(impl);
+
+}
+
+/* icalstore_next_uid_number updates a serial number in the Store
+ directory in a file called SEQUENCE */
+
+int icalstore_next_uid_number(icalstore* store)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+ char sequence = 0;
+ char temp[128];
+ char filename[PATH_MAX];
+ char *r;
+ FILE *f;
+ struct stat sbuf;
+
+ icalerror_check_arg_rz( (store!=0), "store");
+
+ sprintf(filename,"%s/%s",impl->dir,"SEQUENCE");
+
+ /* Create the file if it does not exist.*/
+ if (stat(filename,&sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
+
+ f = fopen(filename,"w");
+ if (f != 0){
+ fprintf(f,"0");
+ fclose(f);
+ } else {
+ icalerror_warn("Can't create SEQUENCE file in icalstore_next_uid_number");
+ return 0;
+ }
+
+ }
+
+ if ( (f = fopen(filename,"r+")) != 0){
+
+ rewind(f);
+ r = fgets(temp,128,f);
+
+ if (r == 0){
+ sequence = 1;
+ } else {
+ sequence = atoi(temp)+1;
+ }
+
+ rewind(f);
+
+ fprintf(f,"%d",sequence);
+
+ fclose(f);
+
+ return sequence;
+
+ } else {
+ icalerror_warn("Can't create SEQUENCE file in icalstore_next_uid_number");
+ return 0;
+ }
+
+}
+
+icalerrorenum icalstore_next_cluster(icalstore* store)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+ char path[PATH_MAX];
+
+ if (impl->directory_iterator == 0){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return ICAL_INTERNAL_ERROR;
+ }
+ impl->directory_iterator = pvl_next(impl->directory_iterator);
+
+ if (impl->directory_iterator == 0){
+ /* There are no more clusters */
+ impl->cluster = 0;
+ return ICAL_NO_ERROR;
+ }
+
+ sprintf(path,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator));
+
+ icalcluster_free(impl->cluster);
+
+ impl->cluster = icalcluster_new(path);
+
+ return icalerrno;
+}
+
+void icalstore_add_uid(icalstore* store, icalstore* comp)
+{
+ char uidstring[PATH_MAX];
+ icalproperty *uid;
+ struct utsname unamebuf;
+
+ icalerror_check_arg_rv( (store!=0), "store");
+ icalerror_check_arg_rv( (comp!=0), "comp");
+
+ uid = icalcomponent_get_first_property(comp,ICAL_UID_PROPERTY);
+
+ if (uid == 0) {
+
+ uname(&unamebuf);
+
+ sprintf(uidstring,"%d-%s",(int)getpid(),unamebuf.nodename);
+
+ uid = icalproperty_new_uid(uidstring);
+ icalcomponent_add_property(comp,uid);
+ } else {
+
+ strcpy(uidstring,icalproperty_get_uid(uid));
+ }
+}
+
+
+/* This assumes that the top level component is a VCALENDAR, and there
+ is an inner component of type VEVENT, VTODO or VJOURNAL. The inner
+ component must have a DTSTART property */
+
+icalerrorenum icalstore_add_component(icalstore* store, icalstore* comp)
+{
+ struct icalstore_impl *impl;
+ char clustername[PATH_MAX];
+ icalproperty *dt, *count;
+ icalvalue *v;
+ struct icaltimetype tm;
+ icalerrorenum error = ICAL_NO_ERROR;
+ icalcomponent *inner;
+
+ impl = (struct icalstore_impl*)store;
+ icalerror_check_arg_rz( (store!=0), "store");
+ icalerror_check_arg_rz( (comp!=0), "comp");
+
+ errno = 0;
+
+ icalstore_add_uid(store,comp);
+
+ /* Determine which cluster this object belongs in. This is a HACK */
+
+ for(inner = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
+ inner != 0;
+ inner = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
+
+ dt = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY);
+
+ if (dt != 0){
+ break;
+ }
+ }
+
+ if (dt == 0){
+ icalerror_warn("The component does not have a DTSTART property, so it cannot be added to the store");
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return ICAL_BADARG_ERROR;
+ }
+
+ v = icalproperty_get_value(dt);
+
+ tm = icalvalue_get_datetime(v);
+
+ snprintf(clustername,PATH_MAX,"%s/%04d%02d",impl->dir,tm.year,tm.month);
+
+ /* Load the cluster and insert the object */
+
+ if(impl->cluster != 0 &&
+ strcmp(clustername,icalcluster_path(impl->cluster)) != 0 ){
+ icalcluster_free(impl->cluster);
+ impl->cluster = 0;
+ }
+
+ if (impl->cluster == 0){
+ impl->cluster = icalcluster_new(clustername);
+
+ if (impl->cluster == 0){
+ error = icalerrno;
+ }
+ }
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return error;
+ }
+
+ /* Add the component to the cluster */
+
+ icalcluster_add_component(impl->cluster,comp);
+
+
+ /* Increment the clusters count value */
+ count = icalcomponent_get_first_property(
+ icalcluster_get_component(impl->cluster),
+ ICAL_XLICCLUSTERCOUNT_PROPERTY);
+
+ if (count == 0){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return ICAL_INTERNAL_ERROR;
+ }
+
+ icalproperty_set_xlicclustercount(count,
+ icalproperty_get_xlicclustercount(count)+1);
+
+
+ icalcluster_mark(impl->cluster);
+
+ return ICAL_NO_ERROR;
+}
+
+/* Remove a component in the current cluster */
+icalerrorenum icalstore_remove_component(icalstore* store, icalstore* comp)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+ icalproperty *count;
+
+ icalerror_check_arg_re((store!=0),"store",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((comp!=0),"comp",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((impl->cluster!=0),"Cluster pointer",ICAL_USAGE_ERROR);
+
+/* HACK The following code should be used to ensure that the component
+ the caller is trying to remove is actually in the cluster, but it
+ resets the internal iterators, which immediately ends any loops over
+ the cluster the caller may have in progress
+
+ for(c = icalcluster_get_first_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT);
+ c != 0;
+ c = icalcluster_get_next_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT)){
+
+ if (c == comp){
+ found = 1;
+ }
+
+ }
+
+ if (found != 1){
+ icalerror_warn("icalstore_remove_component: component is not part of current cluster");
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return ICAL_USAGE_ERROR;
+ }
+
+*/
+
+ icalcluster_remove_component(impl->cluster,
+ comp);
+
+ icalcluster_mark(impl->cluster);
+
+ /* Decrement the clusters count value */
+ count = icalcomponent_get_first_property(
+ icalcluster_get_component(impl->cluster),
+ ICAL_XLICCLUSTERCOUNT_PROPERTY);
+
+ if (count == 0){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return ICAL_INTERNAL_ERROR;
+ }
+
+ icalproperty_set_xlicclustercount(count,
+ icalproperty_get_xlicclustercount(count)-1);
+
+ return ICAL_NO_ERROR;
+}
+
+/* Convert a VQUERY component into a gauge */
+icalcomponent* icalstore_make_gauge(icalcomponent* query);
+
+/* icalstore_test compares a component against a gauge, and returns
+ true if the component passes the test
+
+ The gauge is a VCALENDAR component that specifies how to test the
+ target components. The guage holds a collection of VEVENT, VTODO or
+ VJOURNAL sub-components. Each of the sub-components has a
+ collection of properties that are compared to corresponding
+ properties in the target component, according to the
+ X-LIC-COMPARETYPE parameters to the gauge's properties.
+
+ When a gauge has several sub-components, the results of testing the
+ target against each of them is ORed together - the target
+ component will pass if it matches any of the sub-components in the
+ gauge. However, the results of matching the proeprties in a
+ sub-component are ANDed -- the target must match every property in
+ a gauge sub-component to match the sub-component.
+
+ Here is an example:
+
+ BEGIN:XROOT
+ BEGIN:VCOMPONENT
+ BEGIN:VEVENT
+ DTSTART;X-LIC-COMPARETYPE=LESS:19981025T020000
+ ORGANIZER;X-LIC-COMPARETYPE=EQUAL:mrbig@host.com
+ END:VEVENT
+ BEGIN:VEVENT
+ LOCATION;X-LIC-COMPARETYPE=EQUAL:McNary's Pub
+ END:VEVENT
+ END:VCALENDAR
+ END:XROOT
+
+ This gauge has two sub-components; one which will match a VEVENT
+ based on start time, and organizer, and another that matches based
+ on LOCATION. A target component will pass the test if it matched
+ either of the sub-components.
+
+ */
+
+
+int icalstore_test_recurse(icalcomponent* comp, icalcomponent* gauge)
+{
+ int pass = 1,localpass = 0;
+ icalproperty *p;
+ icalcomponent *child,*subgauge;
+ icalcomponent_kind gaugekind, compkind;
+
+ icalerror_check_arg_rz( (comp!=0), "comp");
+ icalerror_check_arg_rz( (gauge!=0), "gauge");
+
+ gaugekind = icalcomponent_isa(gauge);
+ compkind = icalcomponent_isa(comp);
+
+ if( ! (gaugekind == compkind || gaugekind == ICAL_ANY_COMPONENT) ){
+ return 0;
+ }
+
+ /* Test properties. For each property in the gauge, search through
+ the component for a similar property. If one is found, compare
+ the two properties value with the comparison specified in the
+ gauge with the X-LIC-COMPARETYPE parameter */
+
+ for(p = icalcomponent_get_first_property(gauge,ICAL_ANY_PROPERTY);
+ p != 0;
+ p = icalcomponent_get_next_property(gauge,ICAL_ANY_PROPERTY)){
+
+ icalproperty* targetprop;
+ icalparameter* compareparam;
+ icalparameter_xliccomparetype compare;
+ int rel; /* The relationship between the gauge and target values.*/
+
+ /* Extract the comparison type from the gauge. If there is no
+ comparison type, assume that it is "EQUAL" */
+
+ compareparam = icalproperty_get_first_parameter(
+ p,
+ ICAL_XLICCOMPARETYPE_PARAMETER);
+
+ if (compareparam!=0){
+ compare = icalparameter_get_xliccomparetype(compareparam);
+ } else {
+ compare = ICAL_XLICCOMPARETYPE_EQUAL;
+ }
+
+ /* Find a property in the component that has the same type
+ as the gauge property. HACK -- multiples of a single
+ property type in the gauge will match only the first
+ instance in the component */
+
+ targetprop = icalcomponent_get_first_property(comp,
+ icalproperty_isa(p));
+
+ if(targetprop != 0){
+
+ /* Compare the values of the gauge property and the target
+ property */
+
+ rel = icalvalue_compare(icalproperty_get_value(p),
+ icalproperty_get_value(targetprop));
+
+ /* Now see if the comparison is equavalent to the comparison
+ specified in the gauge */
+
+ if (rel == compare){
+ localpass++;
+ } else if (compare == ICAL_XLICCOMPARETYPE_LESSEQUAL &&
+ ( rel == ICAL_XLICCOMPARETYPE_LESS ||
+ rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
+ localpass++;
+ } else if (compare == ICAL_XLICCOMPARETYPE_GREATEREQUAL &&
+ ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
+ rel == ICAL_XLICCOMPARETYPE_EQUAL)) {
+ localpass++;
+ } else if (compare == ICAL_XLICCOMPARETYPE_NOTEQUAL &&
+ ( rel == ICAL_XLICCOMPARETYPE_GREATER ||
+ rel == ICAL_XLICCOMPARETYPE_LESS)) {
+ localpass++;
+ } else {
+ localpass = 0;
+ }
+
+ pass = pass && (localpass>0);
+ }
+ }
+
+ /* Test subcomponents. Look for a child component that has a
+ counterpart in the gauge. If one is found, recursively call
+ icalstore_test */
+
+ for(subgauge = icalcomponent_get_first_component(gauge,ICAL_ANY_COMPONENT);
+ subgauge != 0;
+ subgauge = icalcomponent_get_next_component(gauge,ICAL_ANY_COMPONENT)){
+
+ gaugekind = icalcomponent_isa(subgauge);
+
+ if (gaugekind == ICAL_ANY_COMPONENT){
+ child = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
+ } else {
+ child = icalcomponent_get_first_component(comp,gaugekind);
+ }
+
+ if(child !=0){
+ localpass = icalstore_test_recurse(child,subgauge);
+ pass = pass && localpass;
+ } else {
+ pass = 0;
+ }
+ }
+
+ return pass;
+}
+
+/* guagecontainer is an XROOT component that holds several gauges. The
+ results of comparing against these gauges are ORed together in this
+ routine */
+int icalstore_test(icalcomponent* comp, icalcomponent* gaugecontainer)
+{
+ int pass = 0;
+ icalcomponent *gauge;
+
+ icalerror_check_arg_rz( (comp!=0), "comp");
+ icalerror_check_arg_rz( (gauge!=0), "gauge");
+
+ for(gauge = icalcomponent_get_first_component(gaugecontainer,ICAL_ANY_COMPONENT);
+ gauge != 0;
+ gauge = icalcomponent_get_next_component(gaugecontainer,ICAL_ANY_COMPONENT)){
+
+ pass += icalstore_test_recurse(comp, gauge);
+ }
+
+ return pass>0;
+
+}
+
+icalcomponent* icalstore_query(icalstore* store, icalstore* query);
+
+
+icalcomponent* icalstore_fetch(icalstore* store, char* uid)
+{
+ icalcomponent *gauge;
+ icalcomponent *old_gauge;
+ icalcomponent *c;
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+
+ icalerror_check_arg_rz( (store!=0), "store");
+ icalerror_check_arg_rz( (uid!=0), "uid");
+
+ gauge =
+ icalcomponent_vanew(
+ ICAL_VCALENDAR_COMPONENT,
+ icalcomponent_vanew(
+ ICAL_VEVENT_COMPONENT,
+ icalproperty_vanew_uid(
+ uid,
+ icalparameter_new_xliccomparetype(
+ ICAL_XLICCOMPARETYPE_EQUAL),
+ 0),
+ 0),
+ 0);
+
+ old_gauge = impl->gauge;
+ impl->gauge = gauge;
+
+ c= icalstore_get_first_component(store);
+
+ impl->gauge = old_gauge;
+
+ icalcomponent_free(gauge);
+
+ return c;
+}
+
+
+int icalstore_has_uid(icalstore* store, char* uid)
+{
+ icalcomponent *c;
+
+ icalerror_check_arg_rz( (store!=0), "store");
+ icalerror_check_arg_rz( (uid!=0), "uid");
+
+ /* HACK. This is a temporary implementation. _has_uid should use a
+ database, and _fetch should use _has_uid, not the other way
+ around */
+ c = icalstore_fetch(store,uid);
+
+ return c!=0;
+
+}
+
+
+icalerrorenum icalstore_select(icalstore* store, icalcomponent* gauge)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+
+ icalerror_check_arg_re( (store!=0), "store",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re( (gauge!=0), "gauge",ICAL_BADARG_ERROR);
+
+ if (!icalcomponent_is_valid(gauge)){
+ return ICAL_BADARG_ERROR;
+ }
+
+ impl->gauge = gauge;
+
+ return ICAL_NO_ERROR;
+}
+
+
+
+icalcomponent* icalstore_get_first_component(icalstore* store)
+{
+ struct icalstore_impl *impl = (struct icalstore_impl*)store;
+ icalerrorenum error;
+ char path[PATH_MAX];
+
+ error = icalstore_read_directory(impl);
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ impl->directory_iterator = pvl_head(impl->directory);
+
+ if (impl->directory_iterator == 0){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ sprintf(path,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator));
+
+ /* If the next cluster we need is different than the current cluster,
+ delete the current one and get a new one */
+
+ if(impl->cluster != 0 && strcmp(path,icalcluster_path(impl->cluster)) != 0 ){
+ icalcluster_free(impl->cluster);
+ impl->cluster = 0;
+ }
+
+ if (impl->cluster == 0){
+ impl->cluster = icalcluster_new(path);
+
+ if (impl->cluster == 0){
+ error = icalerrno;
+ }
+ }
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ impl->first_component = 1;
+
+ return icalstore_get_next_component(store);
+}
+
+icalcomponent* icalstore_get_next_component(icalstore* store)
+{
+ struct icalstore_impl *impl;
+ icalcomponent *c;
+ icalerrorenum error;
+
+ icalerror_check_arg_rz( (store!=0), "store");
+
+ impl = (struct icalstore_impl*)store;
+
+ if(impl->cluster == 0){
+
+ icalerror_warn("icalstore_get_next_component called with a NULL cluster (Caller must call icalstore_get_first_component first");
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return 0;
+
+ }
+
+ /* Set the component iterator for the following for loop */
+ if (impl->first_component == 1){
+ icalcluster_get_first_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT);
+ impl->first_component = 0;
+ } else {
+ icalcluster_get_next_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT);
+ }
+
+
+ while(1){
+ /* Iterate through all of the objects in the cluster*/
+ for( c = icalcluster_get_current_component(
+ impl->cluster);
+ c != 0;
+ c = icalcluster_get_next_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT)){
+
+ /* If there is a gauge defined and the component does not
+ pass the gauge, skip the rest of the loop */
+ if (impl->gauge != 0 && icalstore_test(c,impl->gauge) == 0){
+ continue;
+ }
+
+ /* Either there is no gauge, or the component passed the
+ gauge, so return it*/
+
+ return c;
+ }
+
+ /* Fell through the loop, so the component we want is not
+ in this cluster. Load a new cluster and try again.*/
+
+ error = icalstore_next_cluster(store);
+
+ if(impl->cluster == 0 || error != ICAL_NO_ERROR){
+ /* No more clusters */
+ return 0;
+ } else {
+ c = icalcluster_get_first_component(
+ impl->cluster,
+ ICAL_ANY_COMPONENT);
+ }
+ }
+}
+
+
+
+
+
+
+
diff --git a/libical/src/libicalss/icalstore.h b/libical/src/libicalss/icalstore.h
new file mode 100644
index 0000000000..13e0a182b5
--- /dev/null
+++ b/libical/src/libicalss/icalstore.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalstore.h
+ CREATOR: eric 28 November 1999
+
+
+ $Id$
+ $Locker$
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALSTORE_H
+#define ICALSTORE_H
+
+#include "ical.h"
+#include "icalerror.h"
+typedef void icalstore;
+
+/* icalstore Routines for storing, fetching, and searching for ical
+ * objects in a database */
+
+icalstore* icalstore_new(char* dir);
+
+void icalstore_free(icalstore* store);
+
+/* Add a new component to the store */
+icalerrorenum icalstore_add_component(icalstore* store, icalstore* comp);
+
+/* Remove a component from the store */
+icalerrorenum icalstore_remove_component(icalstore* store, icalstore* comp);
+
+/* Restrict the component returned by icalstore_first, _next to those
+ that pass the gauge */
+icalerrorenum icalstore_select(icalstore* store, icalcomponent* gauge);
+
+/* Return true if a component passes the gauge */
+int icalstore_test(icalcomponent* comp, icalcomponent* gauge);
+
+/* Clear the restrictions set by icalstore_select */
+void icalstore_clear(icalstore* store);
+
+/* Get a single component by uid */
+icalcomponent* icalstore_fetch(icalstore* store, char* uid);
+
+/* Return true of the store has an object with the given UID */
+int icalstore_has_uid(icalstore* store, char* uid);
+
+/* Return the first component in the store, or first that passes the gauge.*/
+icalcomponent* icalstore_get_first_component(icalstore* store);
+
+/* Return the next component in the store, or next that passes the gauge.*/
+icalcomponent* icalstore_get_next_component(icalstore* store);
+
+
+int icalstore_next_uid_number(icalstore* store);
+
+
+#endif /* !ICALSTORE_H */
+
+
+