summaryrefslogtreecommitdiff
path: root/src/libicalss
diff options
context:
space:
mode:
authorAllen Winter <allen.winter@kdab.com>2014-05-31 17:22:41 -0400
committerAllen Winter <allen.winter@kdab.com>2014-05-31 17:22:41 -0400
commitbc831ea040913b1069e8eaf99496dc12704b94a9 (patch)
tree1502b86977c42dd5e5d202a2ff3807b08309f9ff /src/libicalss
parentc1d3761c08651f469a3bd3a8130e6005b8e26136 (diff)
downloadlibical-git-bc831ea040913b1069e8eaf99496dc12704b94a9.tar.gz
Re-arrange after svn to git conversion
Diffstat (limited to 'src/libicalss')
-rw-r--r--src/libicalss/.svnignore8
-rw-r--r--src/libicalss/CMakeLists.txt113
-rw-r--r--src/libicalss/icalbdbset.c1599
-rw-r--r--src/libicalss/icalbdbset.h147
-rw-r--r--src/libicalss/icalbdbset_cxx.h61
-rw-r--r--src/libicalss/icalbdbsetimpl.h41
-rw-r--r--src/libicalss/icalcalendar.c272
-rw-r--r--src/libicalss/icalcalendar.h67
-rw-r--r--src/libicalss/icalcaputil.h58
-rw-r--r--src/libicalss/icalclassify.c823
-rw-r--r--src/libicalss/icalclassify.h47
-rw-r--r--src/libicalss/icalcluster.c248
-rw-r--r--src/libicalss/icalcluster.h61
-rw-r--r--src/libicalss/icalclusterimpl.h45
-rw-r--r--src/libicalss/icalcomponent.h117
-rw-r--r--src/libicalss/icalcsdb.h67
-rw-r--r--src/libicalss/icalcstp.c118
-rw-r--r--src/libicalss/icalcstp.h79
-rw-r--r--src/libicalss/icalcstpclient.c353
-rw-r--r--src/libicalss/icalcstpclient.h101
-rw-r--r--src/libicalss/icalcstpserver.c280
-rw-r--r--src/libicalss/icalcstpserver.h101
-rw-r--r--src/libicalss/icaldirset.c804
-rw-r--r--src/libicalss/icaldirset.h98
-rw-r--r--src/libicalss/icaldirsetimpl.h48
-rw-r--r--src/libicalss/icalfileset.c990
-rw-r--r--src/libicalss/icalfileset.h132
-rw-r--r--src/libicalss/icalfilesetimpl.h53
-rw-r--r--src/libicalss/icalgauge.c524
-rw-r--r--src/libicalss/icalgauge.h63
-rw-r--r--src/libicalss/icalgaugeimpl.h63
-rw-r--r--src/libicalss/icalmessage.c387
-rw-r--r--src/libicalss/icalmessage.h71
-rw-r--r--src/libicalss/icalset.c493
-rw-r--r--src/libicalss/icalset.h184
-rw-r--r--src/libicalss/icalspanlist.c571
-rw-r--r--src/libicalss/icalspanlist.h77
-rw-r--r--src/libicalss/icalspanlist_cxx.cpp92
-rw-r--r--src/libicalss/icalspanlist_cxx.h54
-rw-r--r--src/libicalss/icalss_file.cmake32
-rw-r--r--src/libicalss/icalsslexer.c1972
-rw-r--r--src/libicalss/icalsslexer.l139
-rw-r--r--src/libicalss/icalssutil.c29
-rw-r--r--src/libicalss/icalssutil.h27
-rw-r--r--src/libicalss/icalssyacc.c1863
-rw-r--r--src/libicalss/icalssyacc.h100
-rw-r--r--src/libicalss/icalssyacc.y258
-rw-r--r--src/libicalss/libicalss.dsp212
48 files changed, 14142 insertions, 0 deletions
diff --git a/src/libicalss/.svnignore b/src/libicalss/.svnignore
new file mode 100644
index 00000000..f141c061
--- /dev/null
+++ b/src/libicalss/.svnignore
@@ -0,0 +1,8 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.lo
+*.la
+icalssyacc.output
+y.output
diff --git a/src/libicalss/CMakeLists.txt b/src/libicalss/CMakeLists.txt
new file mode 100644
index 00000000..a0162166
--- /dev/null
+++ b/src/libicalss/CMakeLists.txt
@@ -0,0 +1,113 @@
+include_directories(
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src
+ ${CMAKE_SOURCE_DIR}/src/libicalss ${CMAKE_BINARY_DIR}/src/libicalss
+ ${CMAKE_SOURCE_DIR}/src/libical ${CMAKE_BINARY_DIR}/src/libical
+)
+
+if(WIN32)
+ set(TOPS "\"${CMAKE_SOURCE_DIR}\"")
+ set(TOPB "\"${CMAKE_BINARY_DIR}\"")
+else(WIN32)
+ set(TOPS "${CMAKE_SOURCE_DIR}")
+ set(TOPB "${CMAKE_BINARY_DIR}")
+endif(WIN32)
+
+add_custom_command(
+ OUTPUT
+ ${CMAKE_BINARY_DIR}/src/libicalss/icalss.h
+ COMMAND
+ ${CMAKE_COMMAND}
+ -DTOPS:FILEPATH=${TOPS}
+ -DTOPB:FILEPATH=${TOPB}
+ -DICAL_FILE_H_FILE:FILEPATH=${CMAKE_BINARY_DIR}/src/libicalss/icalss.h
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/icalss_file.cmake
+ DEPENDS
+ ical-header
+)
+
+add_custom_target(icalss-header
+ DEPENDS
+ ical-header
+ ${CMAKE_BINARY_DIR}/src/libicalss/icalss.h
+)
+
+########### next target ###############
+
+#these are generated sources, but we keep them in the repo
+set(icalss_LIB_DEVSRCS icalsslexer.c icalssyacc.c)
+
+set(icalss_LIB_SRCS
+ icalcalendar.c
+ icalcalendar.h
+ icalclassify.c
+ icalclassify.h
+ icalcluster.c
+ icalcluster.h
+ icalclusterimpl.h
+ icalgauge.c
+ icalgauge.h
+ icalgaugeimpl.h
+ icaldirset.c
+ icaldirset.h
+ icaldirsetimpl.h
+ icalfileset.c
+ icalfileset.h
+ icalfilesetimpl.h
+ icalset.c
+ icalset.h
+ icalssyacc.h
+ icalspanlist.c
+ icalspanlist.h
+ icalmessage.c
+ icalmessage.h
+ ${icalss_LIB_DEVSRCS}
+)
+
+if(MSVC)
+ list(APPEND icalss_LIB_SRCS ../icalss.def)
+endif(MSVC)
+
+add_library(icalss ${LIBRARY_TYPE} ${icalss_LIB_SRCS})
+add_library(icalss-static STATIC ${icalss_LIB_SRCS})
+
+add_dependencies(icalss icalss-header)
+add_dependencies(icalss-static icalss-header)
+
+target_link_libraries(icalss ical)
+
+if(MSVC)
+ set_target_properties(icalss PROPERTIES OUTPUT_NAME "libicalss")
+ set_target_properties(icalss-static PROPERTIES OUTPUT_NAME "libicalss-static")
+else(MSVC)
+ set_target_properties(icalss-static PROPERTIES OUTPUT_NAME "icalss")
+endif(MSVC)
+set_target_properties(icalss PROPERTIES
+ VERSION ${LIBICAL_LIB_VERSION_STRING}
+ SOVERSION ${LIBICAL_LIB_MAJOR_VERSION}
+)
+set_target_properties(icalss PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+set_target_properties(icalss-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+
+install(TARGETS icalss icalss-static ${INSTALL_TARGETS_DEFAULT_ARGS})
+
+########### install files ###############
+
+install(FILES
+ ${CMAKE_BINARY_DIR}/src/libicalss/icalss.h
+ icalcalendar.h
+ icalclassify.h
+ icalcluster.h
+ icaldirset.h
+ icaldirsetimpl.h
+ icalfileset.h
+ icalfilesetimpl.h
+ icalgauge.h
+ icalgaugeimpl.h
+ icalmessage.h
+ icalset.h
+ icalspanlist.h
+ icalssyacc.h
+ DESTINATION
+ ${INCLUDE_INSTALL_DIR}/libical
+)
diff --git a/src/libicalss/icalbdbset.c b/src/libicalss/icalbdbset.c
new file mode 100644
index 00000000..f8cee039
--- /dev/null
+++ b/src/libicalss/icalbdbset.c
@@ -0,0 +1,1599 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalbdbset.c
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "icalbdbset.h"
+#include "icalgauge.h"
+#include <errno.h>
+#include <sys/stat.h> /* for stat */
+#include <stdio.h>
+
+#ifndef WIN32
+#include <unistd.h> /* for stat, getpid, unlink */
+#include <fcntl.h> /* for fcntl */
+#else
+#define S_IRUSR S_IREAD /* R for owner */
+#define S_IWUSR S_IWRITE /* W for owner */
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "icalbdbsetimpl.h"
+
+#define STRBUF_LEN 255
+#define MAX_RETRY 5
+
+extern int errno;
+
+
+
+/* these are just stub functions */
+icalerrorenum icalbdbset_read_database(icalbdbset* bset, char *(*pfunc)(const DBT *dbt));
+icalerrorenum icalbdbset_create_cluster(const char *path);
+int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, int access_method);
+
+static int _compare_keys(DB *dbp, const DBT *a, const DBT *b);
+
+
+/** Default options used when NULL is passed to icalset_new() **/
+icalbdbset_options icalbdbset_options_default = {ICALBDB_EVENTS, DB_BTREE, 0644, 0, NULL, NULL};
+
+
+static DB_ENV *ICAL_DB_ENV = 0;
+
+/** Initialize the db environment */
+
+int icalbdbset_init_dbenv(char *db_env_dir, void (*logDbFunc)(const char*, char*)) {
+ int ret;
+ int flags;
+
+ if (db_env_dir) {
+ struct stat env_dir_sb;
+
+ if (stat(db_env_dir, &env_dir_sb)) {
+ fprintf(stderr, "The directory '%s' is missing, please create it.\n", db_env_dir);
+ return EINVAL;
+ }
+ }
+
+ ret = db_env_create(&ICAL_DB_ENV, 0);
+
+ if (ret) {
+ /* some kind of error... */
+ return ret;
+ }
+
+ /* Do deadlock detection internally */
+ if ((ret = ICAL_DB_ENV->set_lk_detect(ICAL_DB_ENV, DB_LOCK_DEFAULT)) != 0) {
+ char * foo = db_strerror(ret);
+ fprintf(stderr, "Could not initialize the database locking environment\n");
+ return ret;
+ }
+
+ flags = DB_INIT_LOCK | DB_INIT_TXN | DB_CREATE | DB_THREAD | \
+ DB_RECOVER | DB_INIT_LOG | DB_INIT_MPOOL;
+ ret = ICAL_DB_ENV->open(ICAL_DB_ENV, db_env_dir, flags, S_IRUSR|S_IWUSR);
+
+ if (ret) {
+ char * foo = db_strerror(ret);
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "dbenv->open");
+ return ret;
+ }
+
+ /* display additional error messages */
+ if (logDbFunc != NULL) {
+ ICAL_DB_ENV->set_errcall(ICAL_DB_ENV, logDbFunc);
+ }
+
+ return ret;
+}
+
+void icalbdbset_checkpoint(void)
+{
+ int ret;
+ char *err;
+
+ switch (ret = ICAL_DB_ENV->txn_checkpoint(ICAL_DB_ENV, 0,0,0)) {
+ case 0:
+ case DB_INCOMPLETE:
+ break;
+ default:
+ err = db_strerror(ret);
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "checkpoint failed");
+ abort();
+ }
+}
+
+void icalbdbset_rmdbLog(void)
+{
+ int ret = 0;
+ char** listp;
+
+ /* remove log files that are archivable (ie. no longer needed) */
+ if (ICAL_DB_ENV->log_archive(ICAL_DB_ENV, &listp, DB_ARCH_ABS) == 0) {
+ if (listp != NULL) {
+ int ii = 0;
+ while (listp[ii] != NULL) {
+ ret = unlink(listp[ii]);
+ ii++;
+ }
+ free(listp);
+ }
+ }
+}
+
+int icalbdbset_cleanup(void)
+{
+ int ret = 0;
+
+ /* one last checkpoint.. */
+ icalbdbset_checkpoint();
+
+ /* remove logs that are not needed anymore */
+ icalbdbset_rmdbLog();
+
+ if (ICAL_DB_ENV)
+ ret = ICAL_DB_ENV->close(ICAL_DB_ENV, 0);
+
+ return ret;
+}
+
+DB_ENV *icalbdbset_get_env(void) {
+ return ICAL_DB_ENV;
+}
+
+
+/** Initialize an icalbdbset. Also attempts to populate from the
+ * database (primary if only dbp is given, secondary if sdbp is
+ * given) and creates an empty object if retrieval is unsuccessful.
+ * pfunc is used to unpack data from the database. If not given, we
+ * assume data is a string.
+ */
+
+icalset* icalbdbset_init(icalset* set, const char* dsn, void* options_in)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalbdbset_options *options = options_in;
+ int ret;
+ DB *cal_db;
+ char *subdb_name;
+
+ if (options == NULL)
+ *options = icalbdbset_options_default;
+
+ switch (options->subdb) {
+ case ICALBDB_CALENDARS:
+ subdb_name = "calendars";
+ break;
+ case ICALBDB_EVENTS:
+ subdb_name = "events";
+ break;
+ case ICALBDB_TODOS:
+ subdb_name = "todos";
+ break;
+ case ICALBDB_REMINDERS:
+ subdb_name = "reminders";
+ break;
+ }
+
+ cal_db = icalbdbset_bdb_open(set->dsn,
+ subdb_name,
+ options->dbtype,
+ options->mode,
+ options->flag);
+ if (cal_db == NULL)
+ return NULL;
+
+ bset->dbp = cal_db;
+ bset->sdbp = NULL;
+ bset->gauge = 0;
+ bset->cluster = 0;
+
+ if ((ret = icalbdbset_read_database(bset, options->pfunc)) != ICAL_NO_ERROR) {
+ return NULL;
+ }
+
+ return (icalset *)bset;
+}
+
+
+/** open a database and return a reference to it. Used only for
+ opening the primary index.
+ flag = set_flag() DUP | DUP_SORT
+ */
+
+icalset* icalbdbset_new(const char* database_filename,
+ icalbdbset_subdb_type subdb_type,
+ int dbtype, int flag)
+{
+ icalbdbset_options options = icalbdbset_options_default;
+
+ options.subdb = subdb_type;
+ options.dbtype = dbtype;
+ options.flag = flag;
+
+ /* this will in turn call icalbdbset_init */
+ return icalset_new(ICAL_BDB_SET, database_filename, &options);
+}
+
+/**
+ * Open a secondary database, used for accessing secondary indices.
+ * The callback function tells icalbdbset how to associate secondary
+ * key information with primary data. See the BerkeleyDB reference
+ * guide for more information.
+ */
+
+DB * icalbdbset_bdb_open_secondary(DB *dbp,
+ const char *database,
+ const char *sub_database,
+ int (*callback) (DB *db,
+ const DBT *dbt1,
+ const DBT *dbt2,
+ DBT *dbt3),
+ int type)
+{
+ int ret;
+ int flags;
+ DB *sdbp = NULL;
+
+ if (!sub_database)
+ return NULL;
+
+ if (!ICAL_DB_ENV)
+ icalbdbset_init_dbenv(NULL, NULL);
+
+ /* Open/create secondary */
+ if((ret = db_create(&sdbp, ICAL_DB_ENV, 0)) != 0) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "secondary index: %s", sub_database);
+ return NULL;
+ }
+
+ if ((ret = sdbp->set_flags(sdbp, DB_DUP | DB_DUPSORT)) != 0) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "set_flags error for secondary index: %s", sub_database);
+ return NULL;
+ }
+
+ flags = DB_CREATE | DB_THREAD;
+ if ((ret = sdbp->open(sdbp, database, sub_database, type, (u_int32_t) flags, 0644)) != 0) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to open secondary index: %s", sub_database);
+ if (ret == DB_RUNRECOVERY)
+ abort();
+ else
+ return NULL;
+ }
+
+ /* Associate the primary index with a secondary */
+ if((ret = dbp->associate(dbp, sdbp, callback, 0)) != 0) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to associate secondary index: %s", sub_database);
+ return NULL;
+ }
+
+ return sdbp;
+}
+
+DB* icalbdbset_bdb_open(const char* path,
+ const char *subdb,
+ int dbtype,
+ mode_t mode,
+ int flag)
+{
+ DB *dbp = NULL;
+ int ret;
+ int flags;
+
+ /* Initialize the correct set of db subsystems (see capdb.c) */
+ flags = DB_CREATE | DB_THREAD;
+
+ /* should just abort here instead of opening an env in the current dir.. */
+ if (!ICAL_DB_ENV)
+ icalbdbset_init_dbenv(NULL, NULL);
+
+ /* Create and initialize database object, open the database. */
+ if ((ret = db_create(&dbp, ICAL_DB_ENV, 0)) != 0) {
+ return (NULL);
+ }
+
+ /* set comparison function, if BTREE */
+ if (dbtype == DB_BTREE)
+ dbp->set_bt_compare(dbp, _compare_keys);
+
+ /* set DUP, DUPSORT */
+ if (flag != 0)
+ dbp->set_flags(dbp, flag);
+
+ if ((ret = dbp->open(dbp, path, subdb, dbtype, flags, mode)) != 0) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "%s (database: %s): open failed.", path, subdb);
+ if (ret == DB_RUNRECOVERY)
+ abort();
+ else
+ return NULL;
+ }
+
+ return (dbp);
+}
+
+
+/* icalbdbset_parse_data -- parses using pfunc to unpack data. */
+char *icalbdbset_parse_data(DBT *dbt, char *(*pfunc)(const DBT *dbt))
+{
+ char *ret;
+
+ if(pfunc) {
+ ret = (char *)pfunc(dbt);
+ } else {
+ ret = (char *) dbt->data;
+ }
+
+ return (ret);
+}
+
+/* This populates a cluster with the entire contents of a database */
+icalerrorenum icalbdbset_read_database(icalbdbset* bset, char *(*pfunc)(const DBT *dbt))
+{
+
+ DB *dbp;
+ DBC *dbcp;
+ DBT key, data;
+ char *str, *szpstr;
+ int ret;
+ char keystore[256];
+ char datastore[1024];
+ char *more_mem = NULL;
+ DB_TXN *tid;
+
+ memset(&key, 0, sizeof(DBT));
+ memset(&data, 0, sizeof(DBT));
+
+ if (bset->sdbp) { dbp = bset->sdbp; }
+ else { dbp = bset->dbp; }
+
+ if(!dbp) { goto err1; }
+
+ bset->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
+
+ if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
+ char *foo = db_strerror(ret);
+ abort();
+ }
+
+ /* acquire a cursor for the database */
+ if ((ret = dbp->cursor(dbp, tid, &dbcp, 0)) != 0) {
+ dbp->err(dbp, ret, "primary index");
+ goto err1;
+ }
+
+ key.flags = DB_DBT_USERMEM;
+ key.data = keystore;
+ key.ulen = sizeof(keystore);
+
+ data.flags= DB_DBT_USERMEM;
+ data.data = datastore;
+ data.ulen = sizeof(datastore);
+
+
+ /* fetch the key/data pair */
+ while (1) {
+ ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
+ if (ret == DB_NOTFOUND) {
+ break;
+ } else if (ret == ENOMEM) {
+ if (more_mem) free (more_mem);
+ more_mem = malloc(data.ulen+1024);
+ data.data = more_mem;
+ data.ulen = data.ulen+1024;
+ } else if (ret == DB_LOCK_DEADLOCK) {
+ char *foo = db_strerror(ret);
+ abort(); /* should retry in case of DB_LOCK_DEADLOCK */
+ } else if (ret) {
+ char *foo = db_strerror(ret);
+ /* some other weird-ass error */
+ dbp->err(dbp, ret, "cursor");
+ abort();
+ } else {
+ icalcomponent *cl;
+
+ /* this prevents an array read bounds error */
+ if((str = (char *)calloc(data.size + 1, sizeof(char)))==NULL)
+ goto err2;
+ memcpy(str, (char *)data.data, data.size);
+
+ cl = icalparser_parse_string(str);
+
+ icalcomponent_add_component(bset->cluster, cl);
+ free(str);
+ }
+ }
+ if(ret != DB_NOTFOUND) {
+ goto err2;
+ }
+
+
+ if (more_mem) {
+ free(more_mem);
+ more_mem = NULL;
+ }
+
+ if ((ret = dbcp->c_close(dbcp)) != 0) {
+ char * foo = db_strerror(ret);
+ abort(); /* should retry in case of DB_LOCK_DEADLOCK */
+ }
+
+ if ((ret = tid->commit(tid, 0)) != 0) {
+ char * foo = db_strerror(ret);
+ abort();
+ }
+
+ return ICAL_NO_ERROR;
+
+ err2:
+ if (more_mem) free(more_mem);
+ dbcp->c_close(dbcp);
+ abort(); /* should retry in case of DB_LOCK_DEADLOCK */
+ return ICAL_INTERNAL_ERROR;
+
+ err1:
+ dbp->err(dbp, ret, "cursor index");
+ abort();
+ return (ICAL_FILE_ERROR);
+}
+
+
+/* XXX add more to this */
+void icalbdbset_free(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ int ret;
+
+ icalerror_check_arg_rv((bset!=0),"bset");
+
+ if (bset->cluster != 0){
+ icalbdbset_commit(set);
+ icalcomponent_free(bset->cluster);
+ bset->cluster=0;
+ }
+
+ if(bset->gauge !=0){
+ icalgauge_free(bset->gauge);
+ }
+
+ if(bset->path != 0){
+ free((char *)bset->path);
+ bset->path = 0;
+ }
+
+ if(bset->sindex != 0) {
+ free((char *)bset->sindex);
+ bset->sindex = 0;
+ }
+
+ if (bset->dbp &&
+ ((ret = bset->dbp->close(bset->dbp, 0)) != 0)) {
+ }
+ bset->dbp = NULL;
+}
+
+/* return cursor is in rdbcp */
+int icalbdbset_acquire_cursor(DB *dbp, DB_TXN *tid, DBC **rdbcp) {
+ int ret=0;
+
+ if((ret = dbp->cursor(dbp, tid, rdbcp, 0)) != 0) {
+ dbp->err(dbp, ret, "couldn't open cursor");
+ goto err1;
+ }
+
+ return ICAL_NO_ERROR;
+
+ err1:
+ return ICAL_FILE_ERROR;
+
+}
+
+/* returns key/data in arguments */
+int icalbdbset_get_first(DBC *dbcp, DBT *key, DBT *data) {
+ return icalbdbset_cget(dbcp, key, data, DB_FIRST);
+}
+
+int icalbdbset_get_next(DBC *dbcp, DBT *key, DBT *data) {
+ return icalbdbset_cget(dbcp, key, data, DB_NEXT);
+}
+
+int icalbdbset_get_last(DBC *dbcp, DBT *key, DBT *data) {
+ return icalbdbset_cget(dbcp, key, data, DB_LAST);
+}
+
+int icalbdbset_get_key(DBC *dbcp, DBT *key, DBT *data) {
+ return icalbdbset_cget(dbcp, key, data, DB_SET);
+}
+
+int icalbdbset_delete(DB *dbp, DBT *key) {
+ DB_TXN *tid;
+ int ret;
+ int done = 0;
+ int retry = 0;
+
+ while ((retry < MAX_RETRY) && !done) {
+
+ if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else {
+ char *foo = db_strerror(ret);
+ abort();
+ }
+ }
+
+ if ((ret = dbp->del(dbp, tid, key, 0)) != 0) {
+ if (ret == DB_NOTFOUND) {
+ /* do nothing - not an error condition */
+ }
+ else if (ret == DB_LOCK_DEADLOCK) {
+ tid->abort(tid);
+ retry++;
+ continue;
+ }
+ else {
+ char *strError = db_strerror(ret);
+ icalerror_warn("icalbdbset_delete faild: ");
+ icalerror_warn(strError);
+ tid->abort(tid);
+ return ICAL_FILE_ERROR;
+ }
+ }
+
+ if ((ret = tid->commit(tid, 0)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ tid->abort(tid);
+ retry++;
+ continue;
+ }
+ else {
+ char * foo = db_strerror(ret);
+ abort();
+ }
+ }
+
+ done = 1; /* all is well */
+ }
+
+ if (!done) {
+ if (tid != NULL) tid->abort(tid);
+ }
+
+ return ret;
+}
+
+int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, int access_method) {
+ int ret=0;
+
+ key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
+ data->flags |= DB_DBT_MALLOC;
+
+ /* fetch the key/data pair */
+ if((ret = dbcp->c_get(dbcp, key, data, access_method)) != 0) {
+ goto err1;
+ }
+
+ return ICAL_NO_ERROR;
+
+ err1:
+ return ICAL_FILE_ERROR;
+}
+
+
+int icalbdbset_cput(DBC *dbcp, DBT *key, DBT *data, int access_method) {
+ int ret=0;
+
+ key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
+ data->flags |= DB_DBT_MALLOC;
+
+ /* fetch the key/data pair */
+ if((ret = dbcp->c_put(dbcp, key, data, 0)) != 0) {
+ goto err1;
+ }
+
+ return ICAL_NO_ERROR;
+
+ err1:
+ return ICAL_FILE_ERROR;
+}
+
+
+int icalbdbset_put(DB *dbp, DBT *key, DBT *data, int access_method)
+{
+ int ret = 0;
+ DB_TXN *tid = NULL;
+ int retry = 0;
+ int done = 0;
+
+ while ((retry < MAX_RETRY) && !done) {
+
+ if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else {
+ char *foo = db_strerror(ret);
+ abort();
+ }
+ }
+
+ if ((ret = dbp->put(dbp, tid, key, data, access_method)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ tid->abort(tid);
+ retry++;
+ continue;
+ }
+ else {
+ char *strError = db_strerror(ret);
+ icalerror_warn("icalbdbset_put faild: ");
+ icalerror_warn(strError);
+ tid->abort(tid);
+ return ICAL_FILE_ERROR;
+ }
+ }
+
+ if ((ret = tid->commit(tid, 0)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ tid->abort(tid);
+ retry++;
+ continue;
+ }
+ else {
+ char * foo = db_strerror(ret);
+ abort();
+ }
+ }
+
+ done = 1; /* all is well */
+ }
+
+ if (!done) {
+ if (tid != NULL) tid->abort(tid);
+ return ICAL_FILE_ERROR;
+ }
+ else
+ return ICAL_NO_ERROR;
+}
+
+int icalbdbset_get(DB *dbp, DB_TXN *tid, DBT *key, DBT *data, int flags)
+{
+ return (dbp->get(dbp, tid, key, data, flags));
+}
+
+/** Return the path of the database file **/
+
+const char* icalbdbset_path(icalset* set)
+{
+ icalerror_check_arg_rz((set!=0),"set");
+
+ return set->dsn;
+}
+
+const char* icalbdbset_subdb(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ return bset->subdb;
+}
+
+
+/** Write changes out to the database file.
+ */
+
+icalerrorenum icalbdbset_commit(icalset *set) {
+ DB *dbp;
+ DBC *dbcp;
+ DBT key, data;
+ icalcomponent *c;
+ char *str;
+ int ret=0;
+ int reterr = ICAL_NO_ERROR;
+ char keystore[256];
+ char uidbuf[256];
+ char datastore[1024];
+ char *more_mem = NULL;
+ DB_TXN *tid = NULL;
+ icalbdbset *bset = (icalbdbset*)set;
+ int bad_uid_counter = 0;
+ int retry = 0, done = 0, completed = 0, deadlocked = 0;
+
+ icalerror_check_arg_re((bset!=0),"bset",ICAL_BADARG_ERROR);
+
+ dbp = bset->dbp;
+ icalerror_check_arg_re((dbp!=0),"dbp is invalid",ICAL_BADARG_ERROR);
+
+ if (bset->changed == 0)
+ return ICAL_NO_ERROR;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.flags = DB_DBT_USERMEM;
+ key.data = keystore;
+ key.ulen = sizeof(keystore);
+
+ data.flags = DB_DBT_USERMEM;
+ data.data = datastore;
+ data.ulen = sizeof(datastore);
+
+ if (!ICAL_DB_ENV)
+ icalbdbset_init_dbenv(NULL, NULL);
+
+ while ((retry < MAX_RETRY) && !done) {
+
+ if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else if (ret == DB_RUNRECOVERY) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit: txn_begin failed");
+ abort();
+ }
+ else {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit");
+ return ICAL_INTERNAL_ERROR;
+ }
+ }
+
+ /* first delete everything in the database, because there could be removed components */
+ if ((ret = dbp->cursor(dbp, tid, &dbcp, DB_DIRTY_READ)) != 0) {
+ tid->abort(tid);
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else if (ret == DB_RUNRECOVERY) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
+ abort();
+ }
+ else {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
+ /* leave bset->changed set to true */
+ return ICAL_INTERNAL_ERROR;
+ }
+ }
+
+ /* fetch the key/data pair, then delete it */
+ completed = 0;
+ while (!completed && !deadlocked) {
+ ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
+ if (ret == DB_NOTFOUND) {
+ completed = 1;
+ } else if (ret == ENOMEM) {
+ if (more_mem) free(more_mem);
+ more_mem = malloc(data.ulen+1024);
+ data.data = more_mem;
+ data.ulen = data.ulen+1024;
+ } else if (ret == DB_LOCK_DEADLOCK) {
+ deadlocked = 1;
+ } else if (ret == DB_RUNRECOVERY) {
+ tid->abort(tid);
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_get failed.");
+ abort();
+ } else if (ret == 0) {
+ if ((ret = dbcp->c_del(dbcp,0))!=0) {
+ dbp->err(dbp, ret, "cursor");
+ if (ret == DB_KEYEMPTY) {
+ /* never actually created, continue onward.. */
+ /* do nothing - break; */
+ } else if (ret == DB_LOCK_DEADLOCK) {
+ deadlocked = 1;
+ } else {
+ char *foo = db_strerror(ret);
+ abort();
+ }
+ }
+ } else { /* some other non-fatal error */
+ dbcp->c_close(dbcp);
+ tid->abort(tid);
+ if (more_mem) {
+ free(more_mem);
+ more_mem = NULL;
+ }
+ return ICAL_INTERNAL_ERROR;
+ }
+ }
+
+ if (more_mem) {
+ free(more_mem);
+ more_mem = NULL;
+ }
+
+ if (deadlocked) {
+ dbcp->c_close(dbcp);
+ tid->abort(tid);
+ retry++;
+ continue; /* next retry */
+ }
+
+ deadlocked = 0;
+ for (c = icalcomponent_get_first_component(bset->cluster,ICAL_ANY_COMPONENT);
+ c != 0 && !deadlocked;
+ c = icalcomponent_get_next_component(bset->cluster,ICAL_ANY_COMPONENT)) {
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ /* Note that we're always inserting into a primary index. */
+ if (icalcomponent_isa(c) != ICAL_VAGENDA_COMPONENT) {
+ char *uidstr = (char *)icalcomponent_get_uid(c);
+ if (!uidstr) { /* this shouldn't happen */
+ /* no uid string, we need to add one */
+ snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
+ key.data = uidbuf;
+ } else {
+ key.data = uidstr;
+ }
+ } else {
+ char *relcalid = NULL;
+ relcalid = (char*)icalcomponent_get_relcalid(c);
+ if (relcalid == NULL) {
+ snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
+ key.data = uidbuf;
+ } else {
+ key.data = relcalid;
+ }
+ }
+ key.size = strlen(key.data);
+
+ str = icalcomponent_as_ical_string_r(c);
+ data.data = str;
+ data.size = strlen(str);
+
+ if ((ret = dbcp->c_put(dbcp, &key, &data, DB_KEYLAST)) != 0) {
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlocked = 1;
+ }
+ else if (ret == DB_RUNRECOVERY) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed.");
+ abort();
+ }
+ else {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed %s.", str);
+ /* continue to try to put as many icalcomponent as possible */
+ reterr = ICAL_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ free(str);
+
+ if (deadlocked) {
+ dbcp->c_close(dbcp);
+ tid->abort(tid);
+ retry++;
+ continue;
+ }
+
+ if ((ret = dbcp->c_close(dbcp)) != 0) {
+ tid->abort(tid);
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else if (ret == DB_RUNRECOVERY) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
+ abort();
+ }
+ else {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
+ reterr = ICAL_INTERNAL_ERROR;
+ }
+ }
+
+ if ((ret = tid->commit(tid, 0)) != 0) {
+ tid->abort(tid);
+ if (ret == DB_LOCK_DEADLOCK) {
+ retry++;
+ continue;
+ }
+ else if (ret == DB_RUNRECOVERY) {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
+ abort();
+ }
+ else {
+ ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
+ reterr = ICAL_INTERNAL_ERROR;
+ }
+ }
+
+ done = 1;
+ }
+
+ bset->changed = 0;
+ return reterr;
+}
+
+
+void icalbdbset_mark(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rv((bset!=0),"bset");
+
+ bset->changed = 1;
+}
+
+
+icalcomponent* icalbdbset_get_component(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ return bset->cluster;
+}
+
+
+/* manipulate the components in the cluster */
+
+icalerrorenum icalbdbset_add_component(icalset *set,
+ icalcomponent* child)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_add_component(bset->cluster,child);
+
+ icalbdbset_mark(set);
+
+ return ICAL_NO_ERROR;
+}
+
+
+icalerrorenum icalbdbset_remove_component(icalset *set,
+ icalcomponent* child)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_remove_component(bset->cluster,child);
+
+ icalbdbset_mark(set);
+
+ return ICAL_NO_ERROR;
+}
+
+
+int icalbdbset_count_components(icalset *set,
+ icalcomponent_kind kind)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+
+ if(set == 0){
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return -1;
+ }
+
+ return icalcomponent_count_components(bset->cluster,kind);
+}
+
+
+/** Set the gauge **/
+
+icalerrorenum icalbdbset_select(icalset* set, icalgauge* gauge)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
+ icalerror_check_arg_re(gauge!=0,"gauge",ICAL_BADARG_ERROR);
+
+ bset->gauge = gauge;
+
+ return ICAL_NO_ERROR;
+}
+
+
+/** Clear the gauge **/
+
+void icalbdbset_clear(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rv((bset!=0),"bset");
+
+ bset->gauge = 0;
+}
+
+
+icalcomponent* icalbdbset_fetch(icalset* set, icalcomponent_kind kind, const char* uid)
+{
+ icalcompiter i;
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ for(i = icalcomponent_begin_component(bset->cluster, kind);
+ icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
+
+ icalcomponent *this = icalcompiter_deref(&i);
+ icalproperty *p = NULL;
+ const char *this_uid = NULL;
+
+ if (this != 0){
+ if (kind == ICAL_VAGENDA_COMPONENT) {
+ p = icalcomponent_get_first_property(this,ICAL_RELCALID_PROPERTY);
+ if (p != NULL) this_uid = icalproperty_get_relcalid(p);
+ } else {
+ p = icalcomponent_get_first_property(this,ICAL_UID_PROPERTY);
+ if (p != NULL) this_uid = icalproperty_get_uid(p);
+ }
+
+ if(this_uid==NULL){
+ icalerror_warn("icalbdbset_fetch found a component with no UID");
+ continue;
+ }
+
+ if (strcmp(uid,this_uid)==0){
+ return this;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int icalbdbset_has_uid(icalset* store,const char* uid)
+{
+ assert(0); /* HACK, not implemented */
+ return 0;
+}
+
+
+/******* support routines for icalbdbset_fetch_match *********/
+
+struct icalbdbset_id {
+ char* uid;
+ char* recurrence_id;
+ int sequence;
+};
+
+void icalbdbset_id_free(struct icalbdbset_id *id)
+{
+ if(id->recurrence_id != 0){
+ free(id->recurrence_id);
+ }
+
+ if(id->uid != 0){
+ free(id->uid);
+ }
+
+}
+
+struct icalbdbset_id icalbdbset_get_id(icalcomponent* comp)
+{
+
+ icalcomponent *inner;
+ struct icalbdbset_id id;
+ icalproperty *p;
+
+ inner = icalcomponent_get_first_real_component(comp);
+
+ p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
+
+ assert(p!= 0);
+
+ id.uid = strdup(icalproperty_get_uid(p));
+
+ p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
+
+ if(p == 0) {
+ id.sequence = 0;
+ } else {
+ id.sequence = icalproperty_get_sequence(p);
+ }
+
+ p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
+
+ if (p == 0){
+ id.recurrence_id = 0;
+ } else {
+ icalvalue *v;
+ v = icalproperty_get_value(p);
+ id.recurrence_id = icalvalue_as_ical_string_r(v);
+
+ assert(id.recurrence_id != 0);
+ }
+
+ return id;
+}
+
+/* Find the component that is related to the given
+ component. Currently, it just matches based on UID and
+ RECURRENCE-ID */
+
+icalcomponent* icalbdbset_fetch_match(icalset* set, icalcomponent *comp)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalcompiter i;
+ struct icalbdbset_id comp_id, match_id;
+
+ icalerror_check_arg_rz((bset!=0),"bset");
+ comp_id = icalbdbset_get_id(comp);
+
+ for(i = icalcomponent_begin_component(bset->cluster,ICAL_ANY_COMPONENT);
+ icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
+
+ icalcomponent *match = icalcompiter_deref(&i);
+
+ match_id = icalbdbset_get_id(match);
+
+ if(strcmp(comp_id.uid, match_id.uid) == 0 &&
+ ( comp_id.recurrence_id ==0 ||
+ strcmp(comp_id.recurrence_id, match_id.recurrence_id) ==0 )){
+
+ /* HACK. What to do with SEQUENCE? */
+
+ icalbdbset_id_free(&match_id);
+ icalbdbset_id_free(&comp_id);
+ return match;
+
+ }
+
+ icalbdbset_id_free(&match_id);
+ }
+
+ icalbdbset_id_free(&comp_id);
+ return 0;
+
+}
+
+
+icalerrorenum icalbdbset_modify(icalset* set, icalcomponent *old,
+ icalcomponent *newc)
+{
+ assert(0); /* HACK, not implemented */
+ return ICAL_NO_ERROR;
+}
+
+/* caller is responsible to cal icalbdbset_free_cluster first */
+icalerrorenum icalbdbset_set_cluster(icalset* set, icalcomponent* cluster)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ bset->cluster = cluster;
+}
+
+icalerrorenum icalbdbset_free_cluster(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ if (bset->cluster != NULL) icalcomponent_free(bset->cluster);
+}
+
+icalcomponent* icalbdbset_get_cluster(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ return (bset->cluster);
+}
+
+
+/** Iterate through components. */
+icalcomponent* icalbdbset_get_current_component (icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ return icalcomponent_get_current_component(bset->cluster);
+}
+
+
+icalcomponent* icalbdbset_get_first_component(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalcomponent *c=0;
+
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ do {
+ if (c == 0)
+ c = icalcomponent_get_first_component(bset->cluster,
+ ICAL_ANY_COMPONENT);
+ else
+ c = icalcomponent_get_next_component(bset->cluster,
+ ICAL_ANY_COMPONENT);
+
+ if(c != 0 && (bset->gauge == 0 ||
+ icalgauge_compare(bset->gauge,c) == 1)){
+ return c;
+ }
+
+ } while (c!=0);
+
+ return 0;
+}
+
+
+icalsetiter icalbdbset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge, const char* tzid)
+{
+ icalsetiter itr = icalsetiter_null;
+ icalcomponent* comp = NULL;
+ icalcompiter citr;
+ icalbdbset *bset = (icalbdbset*) set;
+ struct icaltimetype start, next, end;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ icaltimezone *u_zone;
+ int g = 0;
+ int orig_time_was_utc = 0;
+
+ icalerror_check_arg_re((set!=0), "set", icalsetiter_null);
+
+ itr.gauge = gauge;
+ itr.tzid = tzid;
+
+ citr = icalcomponent_begin_component(bset->cluster, kind);
+ comp = icalcompiter_deref(&citr);
+
+ if (gauge == 0) {
+ itr.iter = citr;
+ return itr;
+ }
+
+ /* if there is a gauge, the first matched component is returned */
+ while (comp != 0) {
+
+ /* check if it is a recurring component and with guage expand, if so
+ * we need to add recurrence-id property to the given component */
+ rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
+ g = icalgauge_get_expand(gauge);
+
+ if (rrule != 0
+ && g == 1) {
+
+ /* it is a recurring event */
+
+ u_zone = icaltimezone_get_builtin_timezone(itr.tzid);
+
+ /* use UTC, if that's all we have. */
+ if (!u_zone)
+ u_zone = icaltimezone_get_utc_timezone();
+
+
+ recur = icalproperty_get_rrule(rrule);
+
+ if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ /* Convert to the user's timezone in order to be able to compare
+ * the results from the rrule iterator. */
+ if (icaltime_is_utc(start)) {
+ start = icaltime_convert_to_zone(start, u_zone);
+ orig_time_was_utc = 1;
+ }
+
+ if (itr.last_component == NULL) {
+ itr.ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(itr.ritr);
+ itr.last_component = comp;
+ }
+ else {
+ next = icalrecur_iterator_next(itr.ritr);
+ if (icaltime_is_null_time(next)){
+ itr.last_component = NULL;
+ icalrecur_iterator_free(itr.ritr);
+ itr.ritr = NULL;
+ /* no matched occurence */
+ goto getNextComp;
+ } else {
+ itr.last_component = comp;
+ }
+ }
+
+ /* if it is excluded, do next one */
+ if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
+ icalrecur_iterator_decrement_count(itr.ritr);
+ continue;
+ }
+
+ /* add recurrence-id value to the property if the property already exist;
+ * add the recurrence id property and the value if the property does not exist */
+ prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
+ if (prop == 0)
+ icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
+ else
+ icalproperty_set_recurrenceid(prop, next);
+
+ /* convert the next recurrence time into the user's timezone */
+ if (orig_time_was_utc)
+ next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
+
+ } /* end of a recurring event */
+
+ if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
+ /* find a matched and return it */
+ itr.iter = citr;
+ return itr;
+ }
+
+ /* if it is a recurring but no matched occurrence has been found OR
+ * it is not a recurring and no matched component has been found,
+ * read the next component to find out */
+getNextComp:
+ if ((rrule != NULL && itr.last_component == NULL) ||
+ (rrule == NULL)) {
+ comp = icalcompiter_next(&citr);
+ comp = icalcompiter_deref(&citr);
+ }
+ } /* while */
+
+ /* no matched component has found */
+ return icalsetiter_null;
+}
+
+icalcomponent* icalbdbset_form_a_matched_recurrence_component(icalsetiter* itr)
+{
+ icalcomponent* comp = NULL;
+ struct icaltimetype start, next, end;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ icaltimezone *u_zone;
+ int g = 0;
+ int orig_time_was_utc = 0;
+
+ comp = itr->last_component;
+
+ if (comp == NULL || itr->gauge == NULL) {
+ return NULL;
+ }
+
+
+ rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
+ /* if there is no RRULE, simply return to the caller */
+ if (rrule == NULL)
+ return NULL;
+
+ u_zone = icaltimezone_get_builtin_timezone(itr->tzid);
+
+ /* use UTC, if that's all we have. */
+ if (!u_zone)
+ u_zone = icaltimezone_get_utc_timezone();
+
+ recur = icalproperty_get_rrule(rrule);
+
+ if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ /* Convert to the user's timezone in order to be able to compare the results
+ * from the rrule iterator. */
+ if (icaltime_is_utc(start)) {
+ start = icaltime_convert_to_zone(start, u_zone);
+ orig_time_was_utc = 1;
+ }
+
+ if (itr->ritr == NULL) {
+ itr->ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(itr->ritr);
+ itr->last_component = comp;
+ } else {
+ next = icalrecur_iterator_next(itr->ritr);
+ if (icaltime_is_null_time(next)){
+ /* no more recurrence, returns */
+ itr->last_component = NULL;
+ icalrecur_iterator_free(itr->ritr);
+ itr->ritr = NULL;
+ /* no more pending matched occurence,
+ * all the pending matched occurences have been returned */
+ return NULL;
+ } else {
+ itr->last_component = comp;
+ }
+ }
+
+ /* if it is excluded, return NULL to the caller */
+ if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
+ icalrecur_iterator_decrement_count(itr->ritr);
+ return NULL;
+ }
+
+ /* set recurrence-id value to the property if the property already exist;
+ * add the recurrence id property and the value if the property does not exist */
+ prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
+ if (prop == 0)
+ icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
+ else
+ icalproperty_set_recurrenceid(prop, next);
+
+ if (orig_time_was_utc) {
+ next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
+ }
+
+
+ if (itr->gauge == 0 || icalgauge_compare(itr->gauge, comp) == 1) {
+ /* find a matched and return it */
+ return comp;
+ }
+
+ /* not matched */
+ return NULL;
+
+}
+
+icalcomponent* icalbdbsetiter_to_next(icalset *set, icalsetiter* i)
+{
+
+ icalcomponent* comp = NULL;
+ icalbdbset *bset = (icalbdbset*) set;
+ struct icaltimetype start, next, end;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ icaltimezone *u_zone;
+ int g = 0;
+ int orig_time_was_utc = 0;
+
+ do {
+
+ /* no pending occurence, read the next component */
+ if (i->last_component == NULL) {
+ comp = icalcompiter_next(&(i->iter));
+ }
+ else {
+ comp = i->last_component;
+ }
+
+ /* no next component, simply return */
+ if (comp == 0) return NULL;
+ if (i->gauge == 0) return comp;
+
+ /* finding the next matched component and return it to the caller */
+
+ rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
+ g = icalgauge_get_expand(i->gauge);
+
+ /* a recurring component with expand query */
+ if (rrule != 0
+ && g == 1) {
+
+ u_zone = icaltimezone_get_builtin_timezone(i->tzid);
+
+ /* use UTC, if that's all we have. */
+ if (!u_zone)
+ u_zone = icaltimezone_get_utc_timezone();
+
+ recur = icalproperty_get_rrule(rrule);
+
+ if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ /* Convert to the user's timezone in order to be able to compare
+ * the results from the rrule iterator. */
+ if (icaltime_is_utc(start)) {
+ start = icaltime_convert_to_zone(start, u_zone);
+ orig_time_was_utc = 1;
+ }
+
+ if (i->ritr == NULL) {
+ i->ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(i->ritr);
+ i->last_component = comp;
+ } else {
+ next = icalrecur_iterator_next(i->ritr);
+ if (icaltime_is_null_time(next)) {
+ i->last_component = NULL;
+ icalrecur_iterator_free(i->ritr);
+ i->ritr = NULL;
+ /* no more occurence, should go to get next component */
+ continue;
+ } else {
+ i->last_component = comp;
+ }
+ }
+
+ /* if it is excluded, do next one */
+ if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
+ icalrecur_iterator_decrement_count(i->ritr);
+ continue;
+ }
+
+ /* set recurrence-id value to the property if the property already exist;
+ * add the recurrence id property and the value if the property does not exist */
+ prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
+ if (prop == 0)
+ icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
+ else
+ icalproperty_set_recurrenceid(prop, next);
+
+ if (orig_time_was_utc) {
+ next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
+ }
+
+ } /* end of recurring event with expand query */
+
+ if(comp != 0 && (i->gauge == 0 ||
+ icalgauge_compare(i->gauge, comp) == 1)){
+ /* found a matched, return it */
+ return comp;
+ }
+ } while (comp != 0);
+
+ return 0;
+
+}
+
+icalcomponent* icalbdbset_get_next_component(icalset* set)
+{
+ icalbdbset *bset = (icalbdbset*)set;
+ icalcomponent *c=0;
+
+ struct icaltimetype start, next;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ int g = 0;
+
+ icalerror_check_arg_rz((bset!=0),"bset");
+
+ do {
+ c = icalcomponent_get_next_component(bset->cluster,
+ ICAL_ANY_COMPONENT);
+ if(c != 0 && (bset->gauge == 0 ||
+ icalgauge_compare(bset->gauge,c) == 1)){
+ return c;
+ }
+
+ } while(c != 0);
+
+ return 0;
+}
+
+int icalbdbset_begin_transaction(DB_TXN* parent_tid, DB_TXN** tid)
+{
+ return (ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, parent_tid, tid, 0));
+}
+
+int icalbdbset_commit_transaction(DB_TXN* txnid)
+{
+ return (txnid->commit(txnid, 0));
+}
+
+
+static int _compare_keys(DB *dbp, const DBT *a, const DBT *b)
+{
+/*
+ * Returns:
+ * < 0 if a < b
+ * = 0 if a = b
+ * > 0 if a > b
+ */
+
+ char* ac = (char*)a->data;
+ char* bc = (char*)b->data;
+ return (strncmp(ac, bc, a->size));
+}
+
+
+
diff --git a/src/libicalss/icalbdbset.h b/src/libicalss/icalbdbset.h
new file mode 100644
index 00000000..90f0aca8
--- /dev/null
+++ b/src/libicalss/icalbdbset.h
@@ -0,0 +1,147 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalbdbset.h
+ CREATOR: dml 12 December 2001
+ (C) COPYRIGHT 2001, Critical Path
+
+ $Id: icalbdbset.h,v 1.5 2008-01-02 20:07:39 dothebart Exp $
+ $Locker: $
+======================================================================*/
+
+#ifndef ICALBDBSET_H
+#define ICALBDBSET_H
+
+#include <libical/ical.h>
+#include <libicalss/icalset.h>
+#include <libicalss/icalgauge.h>
+#include <db.h>
+
+typedef struct icalbdbset_impl icalbdbset;
+
+enum icalbdbset_subdb_type {ICALBDB_CALENDARS, ICALBDB_EVENTS, ICALBDB_TODOS, ICALBDB_REMINDERS};
+typedef enum icalbdbset_subdb_type icalbdbset_subdb_type;
+
+/** sets up the db environment, should be done in parent thread.. */
+int icalbdbset_init_dbenv(char *db_env_dir, void (*logDbFunc)(const char*, char*));
+
+icalset* icalbdbset_init(icalset* set, const char *dsn, void *options);
+int icalbdbset_cleanup(void);
+void icalbdbset_checkpoint(void);
+void icalbdbset_rmdbLog(void);
+
+/** Creates a component handle. flags allows caller to
+ specify if database is internally a BTREE or HASH */
+icalset * icalbdbset_new(const char* database_filename,
+ icalbdbset_subdb_type subdb_type,
+ int dbtype, int flag);
+
+DB * icalbdbset_bdb_open_secondary(DB *dbp,
+ const char *subdb,
+ const char *sindex,
+ int (*callback) (DB *db,
+ const DBT *dbt1,
+ const DBT *dbt2,
+ DBT *dbt3),
+ int type);
+
+char *icalbdbset_parse_data(DBT *dbt, char *(*pfunc)(const DBT *dbt)) ;
+
+void icalbdbset_free(icalset* set);
+
+/* cursor operations */
+int icalbdbset_acquire_cursor(DB *dbp, DB_TXN* tid, DBC **rdbcp);
+int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, int access_method);
+int icalbdbset_cput(DBC *dbcp, DBT *key, DBT *data, int access_method);
+
+int icalbdbset_get_first(DBC *dbcp, DBT *key, DBT *data);
+int icalbdbset_get_next(DBC *dbcp, DBT *key, DBT *data);
+int icalbdbset_get_last(DBC *dbcp, DBT *key, DBT *data);
+int icalbdbset_get_key(DBC *dbcp, DBT *key, DBT *data);
+int icalbdbset_delete(DB *dbp, DBT *key);
+int icalbdbset_put(DB *dbp, DBT *key, DBT *data, int access_method);
+int icalbdbset_get(DB *dbp, DB_TXN *tid, DBT *key, DBT *data, int flags);
+
+const char* icalbdbset_path(icalset* set);
+const char* icalbdbset_subdb(icalset* set);
+
+/* Mark the set as changed, so it will be written to disk when it
+ is freed. Commit writes to disk immediately. */
+void icalbdbset_mark(icalset* set);
+icalerrorenum icalbdbset_commit(icalset *set);
+
+icalerrorenum icalbdbset_add_component(icalset* set,
+ icalcomponent* child);
+
+icalerrorenum icalbdbset_remove_component(icalset* set,
+ icalcomponent* child);
+
+int icalbdbset_count_components(icalset* set,
+ icalcomponent_kind kind);
+
+/* Restrict the component returned by icalbdbset_first, _next to those
+ that pass the gauge. _clear removes the gauge */
+icalerrorenum icalbdbset_select(icalset* store, icalgauge* gauge);
+void icalbdbset_clear(icalset* store);
+
+/* Get and search for a component by uid */
+icalcomponent* icalbdbset_fetch(icalset* set, icalcomponent_kind kind, const char* uid);
+int icalbdbset_has_uid(icalset* set, const char* uid);
+icalcomponent* icalbdbset_fetch_match(icalset* set, icalcomponent *c);
+
+
+icalerrorenum icalbdbset_modify(icalset* set, icalcomponent *old,
+ icalcomponent *newc);
+
+/* cluster management functions */
+icalerrorenum icalbdbset_set_cluster(icalset* set, icalcomponent* cluster);
+icalerrorenum icalbdbset_free_cluster(icalset* set);
+icalcomponent* icalbdbset_get_cluster(icalset* set);
+
+/* Iterate through components. If a gauge has been defined, these
+ will skip over components that do not pass the gauge */
+
+icalcomponent* icalbdbset_get_current_component (icalset* set);
+icalcomponent* icalbdbset_get_first_component(icalset* set);
+icalcomponent* icalbdbset_get_next_component(icalset* set);
+
+/* External iterator for thread safety */
+icalsetiter icalbdbset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge, const char* tzid);
+
+icalcomponent* icalbdbset_form_a_matched_recurrence_component(icalsetiter* itr);
+
+icalcomponent* icalbdbsetiter_to_next(icalset* set, icalsetiter* i);
+icalcomponent* icalbdbsetiter_to_prior(icalset* set, icalsetiter* i);
+
+/* Return a reference to the internal component. You probably should
+ not be using this. */
+
+icalcomponent* icalbdbset_get_component(icalset* set);
+
+DB_ENV *icalbdbset_get_env(void);
+
+
+int icalbdbset_begin_transaction(DB_TXN* parent_id, DB_TXN** txnid);
+int icalbdbset_commit_transaction(DB_TXN* txnid);
+
+DB* icalbdbset_bdb_open(const char* path,
+ const char *subdb,
+ int type,
+ mode_t mode, int flag);
+
+
+typedef struct icalbdbset_options {
+ icalbdbset_subdb_type subdb; /**< the subdatabase to open */
+ int dbtype; /**< db_open type: DB_HASH | DB_BTREE */
+ mode_t mode; /**< file mode */
+ u_int32_t flag; /**< DB->set_flags(): DB_DUP | DB_DUPSORT */
+ char *(*pfunc)(const DBT *dbt); /**< parsing function */
+ int (*callback) (DB *db, /**< callback for secondary db open */
+ const DBT *dbt1,
+ const DBT *dbt2,
+ DBT *dbt3);
+} icalbdbset_options;
+
+#endif /* !ICALBDBSET_H */
+
+
+
diff --git a/src/libicalss/icalbdbset_cxx.h b/src/libicalss/icalbdbset_cxx.h
new file mode 100644
index 00000000..a80e1951
--- /dev/null
+++ b/src/libicalss/icalbdbset_cxx.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalbdbset_cxx.h
+ CREATOR: dml 12/12/01
+ (C) COPYRIGHT 2001, Critical Path
+======================================================================*/
+
+#ifndef ICALBDBSET_CXX_H
+#define ICALBDBSET_CXX_H
+
+
+extern "C" {
+#include <libical/ical.h>
+#include <libicalss/icalgauge.h>
+}
+
+#include "vcomponent.h"
+#include <db_cxx.h>
+
+typedef char* string; // Will use the string library from STL
+
+class ICalBDBSet {
+public:
+
+ ICalBDBSet();
+ ICalBDBSet(const ICalBDBSet&);
+ ICalBDBSet operator=(const ICalBDBSet &);
+ ~ICalBDBSet();
+
+ ICalBDBSet(const string& path, int flags);
+
+public:
+
+ void free();
+ string path();
+
+ icalerrorenum add_component(VComponent* child);
+ icalerrorenum remove_component(VComponent* child);
+ int count_components(icalcomponent_kind kind);
+
+ // Restrict the component returned by icalbdbset_first, _next to those
+ // that pass the gauge. _clear removes the gauge
+ icalerrorenum select(icalgauge *gauge);
+ void clear();
+
+ // Get and search for a component by uid
+ VComponent* fetch(string &uid);
+ VComponent* fetch_match(icalcomponent *c);
+ int has_uid(string &uid);
+
+ // Iterate through components. If a guage has been defined, these
+ // will skip over components that do not pass the gauge
+ VComponent* get_current_component();
+ VComponent* get_first_component();
+ VComponent* get_next_component();
+
+ VComponent* get_component();
+
+};
+
+#endif
diff --git a/src/libicalss/icalbdbsetimpl.h b/src/libicalss/icalbdbsetimpl.h
new file mode 100644
index 00000000..84d19ace
--- /dev/null
+++ b/src/libicalss/icalbdbsetimpl.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalbdbsetimpl.h
+ CREATOR: dml 12 December 2001
+ (C) COPYRIGHT 2001, Critical Path
+
+ $Id: icalbdbsetimpl.h,v 1.4 2008-01-02 20:07:39 dothebart Exp $
+ $Locker: $
+ ======================================================================*/
+
+#ifndef ICALBDBSETIMPL_H
+#define ICALBDBSETIMPL_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libicalss/icalgauge.h>
+#include <db.h>
+
+/* This definition is in its own file so it can be kept out of the
+ main header file, but used by "friend classes" like icaldirset*/
+
+struct icalbdbset_impl {
+ icalset super; /**< parent class */
+ const char *path;
+ const char *subdb;
+ const char *sindex;
+ const char *key;
+ void *data;
+ int datasize;
+ int changed;
+ icalcomponent* cluster;
+ icalgauge* gauge;
+ DB_ENV *dbenv;
+ DB *dbp;
+ DB *sdbp;
+ DBC *dbcp;
+};
+
+#endif
diff --git a/src/libicalss/icalcalendar.c b/src/libicalss/icalcalendar.c
new file mode 100644
index 00000000..c4a81524
--- /dev/null
+++ b/src/libicalss/icalcalendar.c
@@ -0,0 +1,272 @@
+/*======================================================================
+ FILE: icalcalendar.c
+ CREATOR: eric 23 December 1999
+
+ $Id: icalcalendar.c,v 1.8 2008-01-02 20:07:39 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "icalcalendar.h"
+#include "icalset.h"
+#include "icalfileset.h"
+#include "icaldirset.h"
+#include <limits.h>
+#include <sys/stat.h> /* For mkdir, stat */
+#include <sys/types.h> /* For mkdir */
+#include <fcntl.h> /* For mkdir */
+
+#ifndef WIN32
+#include <unistd.h> /* For mkdir, stat */
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif
+
+
+#include <stdlib.h> /* for malloc */
+#include <string.h> /* for strcat */
+#include <errno.h>
+
+#ifdef WIN32
+#include <direct.h>
+#define mkdir(path, mode) _mkdir(path)
+#endif
+
+#define BOOKED_DIR "booked"
+#define INCOMING_FILE "incoming.ics"
+#define PROP_FILE "properties.ics"
+#define FBLIST_FILE "freebusy.ics"
+
+struct icalcalendar_impl
+{
+ char* dir;
+ icalset* freebusy;
+ icalset* properties;
+ icalset* booked;
+ icalset* incoming;
+};
+
+struct icalcalendar_impl* icalcalendar_new_impl(void)
+{
+ 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';
+ strncpy(path,impl->dir,PATH_MAX-1);
+ strncat(path,"/",PATH_MAX-strlen(path)-1);
+ strncat(path,BOOKED_DIR,PATH_MAX-strlen(path)-1);
+ path[PATH_MAX-1] = '\0';
+
+ 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* impl)
+{
+ if (impl->dir !=0){
+ free(impl->dir);
+ }
+
+ if (impl->freebusy !=0){
+ icalset_free(impl->freebusy);
+ }
+
+ if (impl->properties !=0){
+ icalset_free(impl->properties);
+ }
+
+ if (impl->booked !=0){
+ icalset_free(impl->booked);
+ }
+
+ if (impl->incoming !=0){
+ icalset_free(impl->incoming);
+ }
+
+ impl->dir = 0;
+ impl->freebusy = 0;
+ impl->properties = 0;
+ impl->booked = 0;
+ impl->incoming = 0;
+
+
+ free(impl);
+}
+
+
+int icalcalendar_lock(icalcalendar* impl)
+{
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_unlock(icalcalendar* impl)
+{
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_islocked(icalcalendar* impl)
+{
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+int icalcalendar_ownlock(icalcalendar* impl)
+{
+ icalerror_check_arg_rz((impl != 0),"impl");
+ return 0;
+}
+
+icalset* icalcalendar_get_booked(icalcalendar* impl)
+{
+ char dir[PATH_MAX];
+
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ dir[0] = '\0';
+ strncpy(dir,impl->dir,PATH_MAX-1);
+ strncat(dir,"/",PATH_MAX-strlen(dir)-1);
+ strncat(dir,BOOKED_DIR,PATH_MAX-strlen(dir)-1);
+ dir[PATH_MAX-1] = '\0';
+
+ if (impl->booked == 0){
+ icalerror_clear_errno();
+ impl->booked = icaldirset_new(dir);
+ assert(icalerrno == ICAL_NO_ERROR);
+ }
+
+ return impl->booked;
+
+}
+
+icalset* icalcalendar_get_incoming(icalcalendar* impl)
+{
+ char path[PATH_MAX];
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strncpy(path,impl->dir,PATH_MAX-1);
+ strncat(path,"/",PATH_MAX-strlen(path)-1);
+ strncat(path,INCOMING_FILE,PATH_MAX-strlen(path)-1);
+ path[PATH_MAX-1] = '\0';
+
+ if (impl->properties == 0){
+ impl->properties = icalfileset_new(path);
+ }
+
+ return impl->properties;
+}
+
+icalset* icalcalendar_get_properties(icalcalendar* impl)
+{
+ char path[PATH_MAX];
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strncpy(path,impl->dir,PATH_MAX-1);
+ strncat(path,"/",PATH_MAX-strlen(path)-1);
+ strncat(path,PROP_FILE,PATH_MAX-strlen(path)-1);
+ path[PATH_MAX-1] = '\0';
+
+ if (impl->properties == 0){
+ impl->properties = icalfileset_new(path);
+ }
+
+ return impl->properties;
+}
+
+icalset* icalcalendar_get_freebusy(icalcalendar* impl)
+{
+ char path[PATH_MAX];
+ icalerror_check_arg_rz((impl != 0),"impl");
+
+ path[0] = '\0';
+ strncpy(path,impl->dir,PATH_MAX-1);
+ strncat(path,"/",PATH_MAX-strlen(path)-1);
+ strncat(path,FBLIST_FILE,PATH_MAX-strlen(path)-1);
+ path[PATH_MAX-1] = '\0';
+
+ if (impl->freebusy == 0){
+ impl->freebusy = icalfileset_new(path);
+ }
+
+ return impl->freebusy;
+}
+
+
+
+
diff --git a/src/libicalss/icalcalendar.h b/src/libicalss/icalcalendar.h
new file mode 100644
index 00000000..3dcd1fb4
--- /dev/null
+++ b/src/libicalss/icalcalendar.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcalendar.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalcalendar.h,v 1.4 2008-01-02 20:07:39 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALCALENDAR_H
+#define ICALCALENDAR_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+
+/* icalcalendar
+ * Routines for storing calendar data in a file system. The calendar
+ * has two icaldirsets, 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 struct icalcalendar_impl 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);
+
+icalset* icalcalendar_get_booked(icalcalendar* calendar);
+
+icalset* icalcalendar_get_incoming(icalcalendar* calendar);
+
+icalset* icalcalendar_get_properties(icalcalendar* calendar);
+
+icalset* icalcalendar_get_freebusy(icalcalendar* calendar);
+
+
+#endif /* !ICALCALENDAR_H */
+
+
+
diff --git a/src/libicalss/icalcaputil.h b/src/libicalss/icalcaputil.h
new file mode 100644
index 00000000..5e7fddc8
--- /dev/null
+++ b/src/libicalss/icalcaputil.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalutil.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalcaputil.h,v 1.1.1.1 2001-01-02 07:33:03 ebusboom Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ =========================================================================*/
+
+
+/* Create new components that have a form suitable for the various
+ iTIP trasactions */
+
+/* Scheduling commands */
+icalcomponent* icalcaputil_new_accept_reply(icalcomponent* comp, char* calid);
+icalcomponent* icalcaputil_new_decline_reply(icalcomponent* comp, char* calid);
+icalcomponent* icalcaputil_new_refresh(icalcomponent* comp, char* calid);
+icalcomponent* icalcaputil_new_cancel(icalcomponent* comp);
+icalcomponent* icalcaputil_new_counter(icalcomponent* comp);
+icalcomponent* icalcaputil_new_declinecounter(icalcomponent* comp);
+
+/* Calendaring commands */
+icalcomponent* icalcaputil_new_create();
+icalcomponent* icalcaputil_new_delete();
+icalcomponent* icalcaputil_new_modify();
+icalerrorenum* icalcaputil_modify_add_old_prop(icalcomponent* c,
+ icalproperty *p);
+icalerrorenum* icalcaputil_modify_add_new_prop(icalcomponent* c,
+ icalproperty *p);
+icalerrorenum* icalcaputil_add_query(icalcomponent* c, char* str);
+
+
+icalcomponent* icalcaputil_new_move();
+icalcomponent* icalcaputil_new_read();
+
+icalerrorenum icalcaputil_add_target(icalcomponent* comp,char* target);
+icalerrorenum icalcaputil_add_to_vcar(icalcomponent* comp,char* target);
+
+
+
+
+
diff --git a/src/libicalss/icalclassify.c b/src/libicalss/icalclassify.c
new file mode 100644
index 00000000..50dc1b5d
--- /dev/null
+++ b/src/libicalss/icalclassify.c
@@ -0,0 +1,823 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalclassify.c
+ CREATOR: ebusboom 23 aug 2000
+
+ $Id: icalclassify.c,v 1.19 2008-01-15 23:17:43 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
+ http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalclassify.h"
+#include <libical/icalmemory.h>
+#include "icalerror.h"
+
+#include <ctype.h> /* For tolower() */
+#include <string.h> /* for index() */
+#include <stdlib.h> /* for malloc and free */
+
+
+
+struct icalclassify_parts {
+ icalcomponent *c;
+ icalcomponent_kind inner_kind;
+ icalproperty_method method;
+ char* organizer;
+ icalparameter_partstat reply_partstat;
+ char* reply_attendee;
+ char* uid;
+ int sequence;
+ struct icaltimetype dtstamp;
+ struct icaltimetype recurrence_id;
+};
+
+
+char* icalclassify_lowercase(const char* str)
+{
+ char* p = 0;
+ char *xnew;
+
+ if(str ==0){
+ return 0;
+ }
+
+ xnew = icalmemory_strdup(str);
+ for(p = xnew; *p!=0; p++){
+ *p = tolower(*p);
+ }
+
+ return xnew;
+}
+
+/* Return a set of components that intersect in time with comp. For
+component X and Y to intersect:
+ X.DTSTART < Y.DTEND && X.DTEND > Y.DTSTART
+*/
+
+
+icalcomponent* icalclassify_find_overlaps(icalset* set, icalcomponent* comp)
+{
+ icalcomponent *return_set;
+ icalcomponent *c;
+ struct icaltime_span span,compspan;
+
+ icalerror_clear_errno();
+ compspan = icalcomponent_get_span(comp);
+
+ if(icalerrno != ICAL_NO_ERROR){
+ return 0;
+ }
+
+
+ return_set = icalcomponent_new(ICAL_XROOT_COMPONENT);
+
+ for(c = icalset_get_first_component(set);
+ c != 0;
+ c = icalset_get_next_component(set)){
+
+ icalerror_clear_errno();
+
+ span = icalcomponent_get_span(c);
+
+ if(icalerrno != ICAL_NO_ERROR){
+ continue;
+ }
+
+ if (compspan.start < span.end &&
+ compspan.end > span.start){
+
+ icalcomponent *clone = icalcomponent_new_clone(c);
+
+ icalcomponent_add_component(return_set,clone);
+ }
+ }
+
+ if(icalcomponent_count_components(return_set,ICAL_ANY_COMPONENT) !=0){
+ return return_set;
+ } else {
+ icalcomponent_free(return_set);
+ return 0;
+ }
+}
+
+
+
+icalproperty* icalclassify_find_attendee(icalcomponent *c,
+ const char* attendee)
+{
+ icalproperty *p;
+ icalcomponent* inner;
+ char* lattendee;
+ char* upn;
+
+ if(attendee == 0){
+ return 0;
+ }
+
+ lattendee = icalclassify_lowercase(attendee);
+ upn = strchr(lattendee,':');
+
+ if (upn== 0){
+ upn = lattendee;
+ } else {
+ upn++; /* skip the ";"*/
+ }
+
+ inner = icalcomponent_get_first_real_component(c);
+
+ for(p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY);
+ p != 0;
+ p = icalcomponent_get_next_property(inner,ICAL_ATTENDEE_PROPERTY))
+ {
+ char* this_upn;
+ char* this_attendee
+ = icalclassify_lowercase(icalproperty_get_attendee(p));
+ if ( !this_attendee ) continue;
+ this_upn = strchr(this_attendee,':');
+
+ if(this_upn == 0){
+ free(this_attendee);
+ continue;
+ } else {
+ this_upn++;
+ }
+
+ if(strcmp(this_upn,upn)==0){
+ free(lattendee);
+ free(this_attendee);
+ return p;
+ }
+
+ free(this_attendee);
+ }
+ free(lattendee);
+
+ return 0;
+
+}
+
+void icalssutil_free_parts(struct icalclassify_parts *parts)
+{
+ if(parts == 0){
+ return;
+ }
+
+ if(parts->organizer != 0){
+ free(parts->organizer);
+ }
+
+ if(parts->uid != 0){
+ free(parts->uid);
+ }
+
+ if(parts->reply_attendee){
+ free(parts->reply_attendee);
+ }
+}
+
+void icalssutil_get_parts(icalcomponent* c,
+ struct icalclassify_parts* parts)
+{
+ icalproperty *p;
+ icalcomponent *inner;
+
+ memset(parts,0,sizeof(struct icalclassify_parts));
+
+ parts->method = ICAL_METHOD_NONE;
+ parts->sequence = 0;
+ parts->reply_partstat = ICAL_PARTSTAT_NONE;
+
+ if(c == 0){
+ return;
+ }
+
+ parts->c = c;
+
+ p = icalcomponent_get_first_property(c,ICAL_METHOD_PROPERTY);
+ if(p!=0){
+ parts->method = icalproperty_get_method(p);
+ }
+
+ inner = icalcomponent_get_first_real_component(c);
+
+ parts->inner_kind = icalcomponent_isa(inner);
+
+ p = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
+ if(p!=0){
+ const char *p_organizer = icalproperty_get_organizer(p);
+ if (p_organizer!=0) {
+ parts->organizer = strdup(p_organizer);
+ }
+ }
+
+ p = icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY);
+ if(p!=0){
+ parts->sequence = icalproperty_get_sequence(p);
+ }
+
+ p = icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY);
+ if(p!=0){
+ const char *p_uid = icalproperty_get_uid(p);
+ if (p_uid!=0) {
+ parts->uid = strdup(p_uid);
+ }
+ }
+
+ p = icalcomponent_get_first_property(inner,ICAL_RECURRENCEID_PROPERTY);
+ if(p!=0){
+ parts->recurrence_id = icalproperty_get_recurrenceid(p);
+ }
+
+ p = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY);
+ if(p!=0){
+ parts->dtstamp = icalproperty_get_dtstamp(p);
+ }
+
+ if(parts->method==ICAL_METHOD_REPLY){
+ icalparameter *param;
+ p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY);
+
+ if(p!=0){
+ const char *attendee = 0;
+ param = icalproperty_get_first_parameter(p,ICAL_PARTSTAT_PARAMETER);
+
+ if(param != 0){
+ parts->reply_partstat =
+ icalparameter_get_partstat(param);
+ }
+ attendee = icalproperty_get_attendee(p);
+ if ( attendee )
+ parts->reply_attendee = strdup( attendee );
+ }
+
+ }
+
+
+}
+
+
+int icalssutil_is_rescheduled(icalcomponent* a,icalcomponent* b)
+{
+ icalproperty *p1,*p2;
+ icalcomponent *i1,*i2;
+ char *temp1, *temp2;
+ int i;
+
+ icalproperty_kind kind_array[] = {
+ ICAL_DTSTART_PROPERTY,
+ ICAL_DTEND_PROPERTY,
+ ICAL_DURATION_PROPERTY,
+ ICAL_DUE_PROPERTY,
+ ICAL_RRULE_PROPERTY,
+ ICAL_RDATE_PROPERTY,
+ ICAL_EXRULE_PROPERTY,
+ ICAL_EXDATE_PROPERTY,
+ ICAL_NO_PROPERTY
+ };
+
+ i1 = icalcomponent_get_first_real_component(a);
+ i2 = icalcomponent_get_first_real_component(b);
+
+ for(i =0; kind_array[i] != ICAL_NO_PROPERTY; i++){
+ int cmp;
+ p1 = icalcomponent_get_first_property(i1,kind_array[i]);
+ p2 = icalcomponent_get_first_property(i2,kind_array[i]);
+
+ if( (p1!=0)^(p2!=0) ){
+ /* Return true if the property exists in one component and not
+ the other */
+ return 1;
+ }
+ else if (!p1 && !p2)
+ continue;
+
+ temp1 = icalproperty_as_ical_string_r(p1);
+ temp2 = icalproperty_as_ical_string_r(p2);
+ cmp = strcmp(temp1, temp2);
+ free(temp1);
+ free(temp2);
+
+ if (p1 && cmp != 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+
+}
+
+#define icalclassify_pre \
+ int rtrn =0;
+
+#define icalclassify_post \
+ return rtrn;
+
+
+int icalclassify_publish_new(struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre;
+ (void)user;
+
+ if(comp->method == ICAL_METHOD_PUBLISH &&
+ match == 0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){
+ rtrn = 1;
+ }
+
+ icalclassify_post;
+
+}
+
+int icalclassify_publish_update(struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre;
+ (void)user;
+
+ if(comp->method == ICAL_METHOD_PUBLISH &&
+ match !=0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){
+ rtrn = 1;
+ }
+
+ icalclassify_post;
+
+}
+
+int icalclassify_publish_freebusy(struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre;
+
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_PUBLISH &&
+ comp->inner_kind == ICAL_VFREEBUSY_COMPONENT){
+ rtrn = 1;
+ }
+
+ icalclassify_post;
+
+}
+
+
+int icalclassify_request_new(struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ /* Method is REQUEST, and there is no match */
+
+ icalclassify_pre
+ (void)user;
+
+ if(match->c==0 && comp->method == ICAL_METHOD_REQUEST){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+
+}
+
+int icalclassify_request_update(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ /* REQUEST method, Higher SEQUENCE than match, and all
+ time-related properties are unchanged */
+
+ icalclassify_pre
+ (void)user;
+
+ if (match != 0 &&
+ comp->sequence >= match->sequence &&
+ !icalssutil_is_rescheduled(comp->c,match->c)){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+
+}
+
+int icalclassify_request_reschedule(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ /* REQUEST method, Higher SEQUENCE than match, and one or more
+ time-related properties are changed */
+ icalclassify_pre
+ (void)user;
+
+ if (match->c != 0 &&
+ comp->sequence > match->sequence &&
+ icalssutil_is_rescheduled(comp->c,match->c)){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+
+}
+
+int icalclassify_request_delegate(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalparameter* param;
+ icalclassify_pre;
+ (void)match;
+
+ attendee = icalclassify_find_attendee(comp->c,user);
+
+ if(attendee == 0){
+ return 0;
+ }
+
+ param = icalproperty_get_first_parameter(attendee,ICAL_DELEGATEDFROM_PARAMETER);
+
+ if (param != 0){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+
+}
+
+int icalclassify_request_new_organizer(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ /* Organizer has changed between match and component */
+ icalclassify_pre
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ icalclassify_post
+/* already done before.
+ (void)comp;
+ (void)match;
+ (void)user;
+*/
+}
+
+int icalclassify_request_status(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ icalclassify_post
+/*
+ (void)comp;
+ (void)match;
+ (void)user;
+*/
+}
+
+int icalclassify_request_forward(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ icalclassify_post
+/*
+ (void)comp;
+ (void)match;
+ (void)user;
+*/
+}
+
+int icalclassify_request_freebusy(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ icalclassify_post
+/*
+ (void)comp;
+ (void)match;
+ (void)user;
+*/
+}
+
+int icalclassify_reply_accept(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalclassify_pre;
+ (void)user;
+
+ attendee = icalclassify_find_attendee(match->c,comp->reply_attendee);
+
+ if(attendee != 0&&
+ comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+}
+int icalclassify_reply_decline(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalclassify_pre;
+ (void)user;
+
+ attendee = icalclassify_find_attendee(match->c,comp->reply_attendee);
+
+
+ if( attendee != 0 &&
+ comp->reply_partstat == ICAL_PARTSTAT_DECLINED){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_reply_delegate(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalclassify_pre;
+ (void)user;
+
+ attendee = icalclassify_find_attendee(match->c,comp->reply_attendee);
+
+ if( attendee != 0 &&
+ comp->reply_partstat == ICAL_PARTSTAT_DELEGATED){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_reply_crasher_accept(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalclassify_pre;
+ (void)user;
+
+ attendee= icalclassify_find_attendee(match->c,comp->reply_attendee);
+
+ if(attendee == 0 &&
+ comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_reply_crasher_decline(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalproperty* attendee;
+ icalclassify_pre;
+ (void)user;
+
+
+ attendee = icalclassify_find_attendee(match->c,comp->reply_attendee);
+
+ if(attendee == 0 &&
+ comp->reply_partstat == ICAL_PARTSTAT_DECLINED){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_add_instance(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+
+ if(comp->method == ICAL_METHOD_ADD){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_cancel_event(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_CANCEL){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_cancel_instance(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_CANCEL){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_cancel_all(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_CANCEL){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_refesh(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_REFRESH){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_counter(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+ if(comp->method == ICAL_METHOD_COUNTER){
+ rtrn = 1;
+ }
+ icalclassify_post
+}
+int icalclassify_delinecounter(
+ struct icalclassify_parts *comp,
+ struct icalclassify_parts *match,
+ const char* user)
+{
+ icalclassify_pre
+ (void)match;
+ (void)user;
+
+ if(comp->method == ICAL_METHOD_DECLINECOUNTER){
+ rtrn = 1;
+ }
+
+ icalclassify_post
+}
+
+static const struct icalclassify_map {
+ icalproperty_method method;
+ int (*fn)(struct icalclassify_parts *comp,struct icalclassify_parts *match, const char* user);
+ icalproperty_xlicclass class;
+} icalclassify_map[] =
+{ {ICAL_METHOD_PUBLISH,icalclassify_publish_new,ICAL_XLICCLASS_PUBLISHNEW},
+ {ICAL_METHOD_PUBLISH,icalclassify_publish_update,ICAL_XLICCLASS_PUBLISHUPDATE},
+ {ICAL_METHOD_PUBLISH,icalclassify_publish_freebusy,ICAL_XLICCLASS_PUBLISHFREEBUSY},
+ {ICAL_METHOD_REQUEST,icalclassify_request_delegate,ICAL_XLICCLASS_REQUESTDELEGATE},
+ {ICAL_METHOD_REQUEST,icalclassify_request_new,ICAL_XLICCLASS_REQUESTNEW},
+ {ICAL_METHOD_REQUEST,icalclassify_request_update,ICAL_XLICCLASS_REQUESTUPDATE},
+ {ICAL_METHOD_REQUEST,icalclassify_request_reschedule,ICAL_XLICCLASS_REQUESTRESCHEDULE},
+
+ {ICAL_METHOD_REQUEST,icalclassify_request_new_organizer,ICAL_XLICCLASS_REQUESTNEWORGANIZER},
+ {ICAL_METHOD_REQUEST,icalclassify_request_forward,ICAL_XLICCLASS_REQUESTFORWARD},
+ {ICAL_METHOD_REQUEST,icalclassify_request_status,ICAL_XLICCLASS_REQUESTSTATUS},
+ {ICAL_METHOD_REQUEST,icalclassify_request_freebusy,ICAL_XLICCLASS_REQUESTFREEBUSY},
+
+ {ICAL_METHOD_REPLY,icalclassify_reply_accept,ICAL_XLICCLASS_REPLYACCEPT},
+ {ICAL_METHOD_REPLY,icalclassify_reply_decline,ICAL_XLICCLASS_REPLYDECLINE},
+ {ICAL_METHOD_REPLY,icalclassify_reply_delegate,ICAL_XLICCLASS_REPLYDELEGATE},
+ {ICAL_METHOD_REPLY,icalclassify_reply_crasher_accept,ICAL_XLICCLASS_REPLYCRASHERACCEPT},
+ {ICAL_METHOD_REPLY,icalclassify_reply_crasher_decline,ICAL_XLICCLASS_REPLYCRASHERDECLINE},
+
+ {ICAL_METHOD_ADD,icalclassify_add_instance,ICAL_XLICCLASS_ADDINSTANCE},
+
+ {ICAL_METHOD_CANCEL,icalclassify_cancel_event,ICAL_XLICCLASS_CANCELEVENT},
+ {ICAL_METHOD_CANCEL,icalclassify_cancel_instance,ICAL_XLICCLASS_CANCELINSTANCE},
+ {ICAL_METHOD_CANCEL,icalclassify_cancel_all,ICAL_XLICCLASS_CANCELALL},
+
+ {ICAL_METHOD_REFRESH,icalclassify_refesh,ICAL_XLICCLASS_REFRESH},
+ {ICAL_METHOD_COUNTER,icalclassify_counter,ICAL_XLICCLASS_COUNTER},
+ {ICAL_METHOD_DECLINECOUNTER,icalclassify_delinecounter,ICAL_XLICCLASS_DECLINECOUNTER},
+ {ICAL_METHOD_NONE,0,ICAL_XLICCLASS_NONE}
+};
+
+
+icalproperty_xlicclass icalclassify(icalcomponent* c,icalcomponent* match,
+ const char* user)
+{
+ icalcomponent *inner;
+ icalproperty *p;
+ icalproperty_method method;
+ icalproperty_xlicclass class = ICAL_XLICCLASS_UNKNOWN;
+
+ int i;
+
+ struct icalclassify_parts comp_parts;
+ struct icalclassify_parts match_parts;
+
+ inner = icalcomponent_get_first_real_component(c);
+
+ if (inner == 0) {
+ return ICAL_XLICCLASS_NONE;
+ }
+
+ icalssutil_get_parts(c,&comp_parts);
+ icalssutil_get_parts(match,&match_parts);
+
+ /* Determine if the incoming component is obsoleted by the match */
+ if(match != 0 && (
+ comp_parts.method == ICAL_METHOD_REQUEST
+ )){
+ assert ( ! ((comp_parts.dtstamp.is_utc==1)^
+ (match_parts.dtstamp.is_utc==1)));
+
+ if( comp_parts.sequence<match_parts.sequence &&
+ icaltime_compare(comp_parts.dtstamp,match_parts.dtstamp)>0)
+ {
+ /* comp has a smaller sequence and a later DTSTAMP */
+ class = ICAL_XLICCLASS_MISSEQUENCED;
+ goto CLEANUP;
+ }
+
+ if( (comp_parts.sequence<match_parts.sequence )
+ /*&&icaltime_compare(comp_parts.dtstamp,match_parts.dtstamp)<=0*/
+ ||
+ ( comp_parts.sequence == match_parts.sequence &&
+ icaltime_compare(comp_parts.dtstamp,match_parts.dtstamp)<=0)){
+
+ class = ICAL_XLICCLASS_OBSOLETE;
+ goto CLEANUP;
+ }
+
+ }
+
+ p = icalcomponent_get_first_property(c,ICAL_METHOD_PROPERTY);
+ if (p == 0) {
+ class = ICAL_XLICCLASS_UNKNOWN;
+ goto CLEANUP;
+ }
+ method = icalproperty_get_method(p);
+
+ for (i =0; icalclassify_map[i].method != ICAL_METHOD_NONE; i++){
+ if(icalclassify_map[i].method == method){
+ if( (*(icalclassify_map[i].fn))(&comp_parts,&match_parts,user)==1){
+ class = icalclassify_map[i].class;
+ break;
+ }
+ }
+ }
+
+CLEANUP:
+ icalssutil_free_parts(&comp_parts);
+ icalssutil_free_parts(&match_parts);
+
+ return class;
+
+}
+
diff --git a/src/libicalss/icalclassify.h b/src/libicalss/icalclassify.h
new file mode 100644
index 00000000..b692e745
--- /dev/null
+++ b/src/libicalss/icalclassify.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalclassify.h
+ CREATOR: eric 21 Aug 2000
+
+
+ $Id: icalclassify.h,v 1.7 2008-01-15 23:17:43 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
+ http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ =========================================================================*/
+
+#ifndef ICALCLASSIFY_H
+#define ICALCLASSIFY_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+#include "icalcomponent.h"
+
+icalproperty_xlicclass icalclassify(icalcomponent* c,icalcomponent* match,
+ const char* user);
+
+icalcomponent* icalclassify_find_overlaps(icalset* set, icalcomponent* comp);
+
+char* icalclassify_class_to_string(icalproperty_xlicclass c);
+
+
+#endif /* ICALCLASSIFY_H*/
+
+
+
+
+
diff --git a/src/libicalss/icalcluster.c b/src/libicalss/icalcluster.c
new file mode 100644
index 00000000..d1ab253a
--- /dev/null
+++ b/src/libicalss/icalcluster.c
@@ -0,0 +1,248 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcluster.c
+ CREATOR: acampi 13 March 2002
+
+ $Id: icalcluster.c,v 1.4 2007-04-30 13:57:48 artcancro Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2002, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+/**
+ *
+ * icalcluster is an utility class design to manage clusters of
+ * icalcomponents on behalf of an implementation of icalset. This is
+ * done in order to split out common behavior different classes might
+ * need.
+ * The definition of what exactly a cluster will contain depends on the
+ * icalset subclass. At the basic level, an icluster is just a tuple,
+ * with anything as key and an icalcomponent as value.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+#include <errno.h>
+#include <sys/stat.h> /* for stat */
+#ifndef WIN32
+#include <unistd.h> /* for stat, getpid */
+#else
+#include <io.h>
+#include <share.h>
+#endif
+#include <fcntl.h> /* for fcntl */
+#endif
+
+#include "icalcluster.h"
+#include "icalclusterimpl.h"
+#include "icalgauge.h"
+
+#if defined(_MSC_VER)
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#endif
+
+
+icalcluster * icalcluster_new_impl(void) {
+
+ struct icalcluster_impl* impl;
+
+ if ((impl = (struct icalcluster_impl*)malloc(
+ sizeof(struct icalcluster_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ memset(impl, 0, sizeof(struct icalcluster_impl));
+ strcpy(impl->id,ICALCLUSTER_ID);
+
+ return impl;
+}
+
+/**
+ * Create a cluster with a key/value pair.
+ *
+ * @todo Always do a deep copy.
+ */
+
+icalcluster * icalcluster_new(const char* key, icalcomponent *data) {
+ struct icalcluster_impl *impl = icalcluster_new_impl();
+ assert(impl->data == 0);
+
+ impl->key = strdup(key);
+ impl->changed = 0;
+ impl->data = 0;
+
+ if (data != NULL) {
+ if (icalcomponent_isa(data) != ICAL_XROOT_COMPONENT) {
+ impl->data = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ icalcomponent_add_component(impl->data, data);
+ } else {
+ impl->data = icalcomponent_new_clone(data);
+ }
+ } else {
+ impl->data = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ }
+
+ return impl;
+}
+
+/**
+ * Deep clone an icalcluster to a new one
+ */
+
+icalcluster *icalcluster_new_clone(const icalcluster *data) {
+ struct icalcluster_impl *old = (struct icalcluster_impl *)data;
+ struct icalcluster_impl *impl = icalcluster_new_impl();
+
+ impl->key = strdup(old->key);
+ impl->data = icalcomponent_new_clone(old->data);
+ impl->changed = 0;
+
+ return impl;
+}
+
+
+void icalcluster_free(icalcluster *impl) {
+ icalerror_check_arg_rv((impl!=0),"cluster");
+
+ if (impl->key != 0){
+ free(impl->key);
+ impl->key = 0;
+ }
+
+ if (impl->data != 0){
+ icalcomponent_free(impl->data);
+ impl->data = 0;
+ }
+
+ free(impl);
+}
+
+
+const char *icalcluster_key(icalcluster *impl) {
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ return impl->key;
+}
+
+
+int icalcluster_is_changed(icalcluster *impl) {
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ return impl->changed;
+}
+
+
+void icalcluster_mark(icalcluster *impl) {
+ icalerror_check_arg_rv((impl!=0),"cluster");
+
+ impl->changed = 1;
+}
+
+
+void icalcluster_commit(icalcluster *impl) {
+ icalerror_check_arg_rv((impl!=0),"cluster");
+
+ impl->changed = 0;
+}
+
+
+icalcomponent *icalcluster_get_component(icalcluster *impl) {
+
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ if (icalcomponent_isa(impl->data) != ICAL_XROOT_COMPONENT) {
+ char *obj;
+ icalerror_warn("The top component is not an XROOT");
+ obj = icalcomponent_as_ical_string_r(impl->data);
+ fprintf(stderr, "%s\n", obj);
+ free(obj);
+ abort();
+ }
+
+ return impl->data;
+}
+
+
+icalerrorenum icalcluster_add_component(icalcluster *impl, icalcomponent* child) {
+
+ icalerror_check_arg_re((impl!=0),"cluster", ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_add_component(impl->data, child);
+ icalcluster_mark(impl);
+
+ return ICAL_NO_ERROR;
+}
+
+
+icalerrorenum icalcluster_remove_component(icalcluster *impl, icalcomponent* child) {
+
+ icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_remove_component(impl->data,child);
+ icalcluster_mark(impl);
+
+ return ICAL_NO_ERROR;
+}
+
+
+int icalcluster_count_components(icalcluster *impl, icalcomponent_kind kind) {
+
+ icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR);
+
+ return icalcomponent_count_components(impl->data, kind);
+}
+
+
+/** Iterate through components **/
+icalcomponent *icalcluster_get_current_component(icalcluster* impl) {
+
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ return icalcomponent_get_current_component(impl->data);
+}
+
+
+icalcomponent *icalcluster_get_first_component(icalcluster* impl) {
+
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ return icalcomponent_get_first_component(impl->data,
+ ICAL_ANY_COMPONENT);
+}
+
+
+icalcomponent *icalcluster_get_next_component(icalcluster* impl) {
+
+ icalerror_check_arg_rz((impl!=0),"cluster");
+
+ return icalcomponent_get_next_component(impl->data,
+ ICAL_ANY_COMPONENT);
+}
diff --git a/src/libicalss/icalcluster.h b/src/libicalss/icalcluster.h
new file mode 100644
index 00000000..6ce13c7d
--- /dev/null
+++ b/src/libicalss/icalcluster.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcluster.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalcluster.h,v 1.4 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALCLUSTER_H
+#define ICALCLUSTER_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+
+typedef struct icalcluster_impl icalcluster;
+
+icalcluster* icalcluster_new(const char *key, icalcomponent *data);
+icalcluster* icalcluster_new_clone(const icalcluster *cluster);
+
+void icalcluster_free(icalcluster *cluster);
+
+const char* icalcluster_key(icalcluster *cluster);
+int icalcluster_is_changed(icalcluster *cluster);
+void icalcluster_mark(icalcluster *cluster);
+void icalcluster_commit(icalcluster *cluster);
+
+icalcomponent* icalcluster_get_component(icalcluster* cluster);
+int icalcluster_count_components(icalcluster *cluster, icalcomponent_kind kind);
+icalerrorenum icalcluster_add_component(icalcluster* cluster,
+ icalcomponent* child);
+icalerrorenum icalcluster_remove_component(icalcluster* cluster,
+ icalcomponent* child);
+
+icalcomponent* icalcluster_get_current_component(icalcluster* cluster);
+icalcomponent* icalcluster_get_first_component(icalcluster* cluster);
+icalcomponent* icalcluster_get_next_component(icalcluster* cluster);
+
+#endif /* !ICALCLUSTER_H */
+
+
+
diff --git a/src/libicalss/icalclusterimpl.h b/src/libicalss/icalclusterimpl.h
new file mode 100644
index 00000000..edb9a163
--- /dev/null
+++ b/src/libicalss/icalclusterimpl.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalfilesetimpl.h
+ CREATOR: eric 23 December 1999
+
+ $Id: icalclusterimpl.h,v 1.2 2007-04-30 13:57:48 artcancro Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* This definition is in its own file so it can be kept out of the
+ main header file, but used by "friend classes" like icaldirset*/
+
+#define ICALCLUSTER_ID "clus"
+
+struct icalcluster_impl {
+
+ char id[5]; /* clus */
+
+ char *key;
+ icalcomponent *data;
+ int changed;
+};
diff --git a/src/libicalss/icalcomponent.h b/src/libicalss/icalcomponent.h
new file mode 100644
index 00000000..c097ab39
--- /dev/null
+++ b/src/libicalss/icalcomponent.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcomponent.h
+ CREATOR: eric 20 March 1999
+
+
+ (C) COPYRIGHT 1999 Eric Busboom
+ http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+ The original code is icalcomponent.h
+
+======================================================================*/
+
+#ifndef ICALCOMPONENT_H
+#define ICALCOMPONENT_H
+
+#include <libicalss/icalproperty.h>
+#include <libicalss/icalvalue.h>
+#include <libicalss/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/src/libicalss/icalcsdb.h b/src/libicalss/icalcsdb.h
new file mode 100644
index 00000000..c6c7a180
--- /dev/null
+++ b/src/libicalss/icalcsdb.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcsdb.h Calendar Server Database
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalcsdb.h,v 1.2 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+======================================================================*/
+
+#ifndef ICALCSDB_H
+#define ICALCSDB_H
+
+#include <libical/ical.h>
+
+typedef void icalcsdb;
+
+icalcsdb* icalcsdb_new(char* path);
+
+void icalcsdb_free(icalcsdb* csdb);
+
+icalerrorenum icalcsdb_create(icalcsdb* db, char* calid);
+
+icalerrorenum icalcsdb_delete(icalcsdb* db, char* calid);
+
+icalerrorenum icalcsdb_move(icalcsdb* db, char* oldcalid, char* newcalid);
+
+icalerrorenum icalcsdb_noop(icalcsdb* db);
+
+char* icalcsdb_generateuid(icalcsdb* db);
+
+icalcomponent* icalcsdb_expand_upn(icalcsdb* db, char* upn);
+icalcomponent* icalcsdb_expand_calid(icalcsdb* db, char* calid);
+
+icalerrorenum icalcsbd_senddata(icalcsdb* db, icalcomponent* comp);
+
+icalset* icalcsdb_get_calendar(icalcsdb* db, char* calid,
+ icalcomponent *gauge);
+
+icalset* icalcsdb_get_vcars(icalcsdb* db);
+
+icalset* icalcsdb_get_properties(icalcsdb* db);
+
+icalset* icalcsdb_get_capabilities(icalcsdb* db);
+
+icalset* icalcsdb_get_timezones(icalcsdb* db);
+
+
+#endif /* !ICALCSDB_H */
+
+
+
diff --git a/src/libicalss/icalcstp.c b/src/libicalss/icalcstp.c
new file mode 100644
index 00000000..5ae6a02b
--- /dev/null
+++ b/src/libicalss/icalcstp.c
@@ -0,0 +1,118 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcstps.c
+ CREATOR: ebusboom 23 Jun 2000
+
+ $Id: icalcstp.c,v 1.10 2008-01-02 20:15:44 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalcstp.h"
+#include "pvl.h"
+
+#include <sys/types.h> /* For send(), others */
+#include <sys/socket.h> /* For send(), others. */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h> /* For alarm */
+#endif
+#include <errno.h>
+#include <stdlib.h> /* for malloc */
+#include <string.h>
+
+
+struct command_map {
+ enum icalcstp_command command;
+ char *str;
+} command_map[] =
+{
+ {ICAL_ABORT_COMMAND,"ABORT"},
+ {ICAL_AUTHENTICATE_COMMAND,"AUTHENTICATE"},
+ {ICAL_CAPABILITY_COMMAND,"CAPABILITY"},
+ {ICAL_CONTINUE_COMMAND,"CONTINUE"},
+ {ICAL_CALIDEXPAND_COMMAND,"CALIDEXPAND"},
+ {ICAL_IDENTIFY_COMMAND,"IDENTIFY"},
+ {ICAL_DISCONNECT_COMMAND,"DISCONNECT"},
+ {ICAL_SENDDATA_COMMAND,"SENDDATA"},
+ {ICAL_STARTTLS_COMMAND,"STARTTLS"},
+ {ICAL_UPNEXPAND_COMMAND,"UPNEXPAND"},
+ {ICAL_UNKNOWN_COMMAND,"UNKNOWN"}
+};
+
+
+icalcstp_command icalcstp_line_command(char* line)
+{
+ int i;
+
+ for(i = 0; command_map[i].command != ICAL_UNKNOWN_COMMAND; i++){
+ size_t l = strlen(command_map[i].str);
+
+ if(strncmp(line, command_map[i].str, l) == 0){
+ return command_map[i].command;
+ }
+
+ }
+
+ return ICAL_UNKNOWN_COMMAND;
+}
+
+icalrequeststatus icalcstp_line_response_code(char* line)
+{
+ struct icalreqstattype rs;
+
+ rs = icalreqstattype_from_string(line);
+
+ return rs.code;
+}
+
+int icalcstp_line_is_endofdata(char* line)
+{
+ if(line[0] == '.' && line[1] == '\n'){
+ return 1;
+ }
+
+ return 0;
+
+}
+
+int icalcstp_line_is_mime(char* line)
+{
+}
+
+
+const char* icalcstp_command_to_string(icalcstp_command command){
+
+ int i;
+
+ for(i = 0; command_map[i].command != ICAL_UNKNOWN_COMMAND; i++){
+ size_t l = strlen(command_map[i].str);
+
+ if(command_map[i].command == command){
+ return command_map[i].str;
+ }
+
+ }
+
+ return command_map[i].str;
+
+}
+
diff --git a/src/libicalss/icalcstp.h b/src/libicalss/icalcstp.h
new file mode 100644
index 00000000..e3b273d1
--- /dev/null
+++ b/src/libicalss/icalcstp.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcstp.h
+ CREATOR: eric 20 April 1999
+
+ $Id: icalcstp.h,v 1.8 2008-01-02 20:15:44 dothebart Exp $
+
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The original code is icalcstp.h
+
+======================================================================*/
+
+
+#ifndef ICALCSTP_H
+#define ICALCSTP_H
+
+#include <libical/ical.h>
+
+
+/* Connection state, from the state machine in RFC2445 */
+enum cstps_state {
+ NO_STATE,
+ CONNECTED,
+ AUTHENTICATED,
+ IDENTIFIED,
+ DISCONNECTED,
+ RECEIVE
+};
+
+/* CSTP Commands that a client can issue to a server */
+typedef enum icalcstp_command {
+ ICAL_ABORT_COMMAND,
+ ICAL_AUTHENTICATE_COMMAND,
+ ICAL_CAPABILITY_COMMAND,
+ ICAL_CONTINUE_COMMAND,
+ ICAL_CALIDEXPAND_COMMAND,
+ ICAL_IDENTIFY_COMMAND,
+ ICAL_DISCONNECT_COMMAND,
+ ICAL_SENDDATA_COMMAND,
+ ICAL_STARTTLS_COMMAND,
+ ICAL_UPNEXPAND_COMMAND,
+ ICAL_COMPLETE_COMMAND,
+ ICAL_UNKNOWN_COMMAND
+} icalcstp_command;
+
+
+
+/* A statement is a combination of command or response code and a
+ component that the server and client exchage with each other. */
+struct icalcstp_statement {
+ icalcstp_command command;
+ char* str_data; /* If non-NUll use as arguments to command */
+ int int_data; /* If non-NULL use as arguments to command */
+
+ icalrequeststatus code;
+
+ icalcomponent* data;
+};
+
+const char* icalcstp_command_to_string(icalcstp_command command);
+icalcstp_command icalcstp_string_to_command(const char* str);
+
+#endif /* !ICALCSTP_H */
+
+
+
diff --git a/src/libicalss/icalcstpclient.c b/src/libicalss/icalcstpclient.c
new file mode 100644
index 00000000..67334964
--- /dev/null
+++ b/src/libicalss/icalcstpclient.c
@@ -0,0 +1,353 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcstps.c
+ CREATOR: ebusboom 23 Jun 2000
+
+ $Id: icalcstpclient.c,v 1.9 2008-01-02 20:15:44 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalcstp.h"
+#include "icalcstpclient.h"
+#include "pvl.h"
+
+#include <sys/types.h> /* For send(), others */
+#include <sys/socket.h> /* For send(), others. */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h> /* For alarm */
+#endif
+#include <errno.h>
+#include <stdlib.h> /* for malloc */
+#include <string.h>
+
+#define EOL "\n"
+
+
+/* Client state machine */
+
+typedef enum icalcstpc_line_type {
+ ICALCSTPC_RESPONSE_CODE_LINE,
+ ICALCSTPC_TERMINATOR_LINE,
+ ICALCSTPC_APPLICATION_DATA_LINE
+} icalcstpc_line_type;
+
+typedef enum icalcstpc_state {
+ ICALCSTPC_SEND_STATE,
+ ICALCSTPC_RESPONSE_CODE_STATE,
+ ICALCSTPC_RESPONSE_DATA_STATE
+} icalcstpc_state;
+
+
+
+struct icalcstpc_impl {
+ int timeout;
+ icalparser *parser;
+ icalcstp_command command;
+ icalcstpc_state state;
+ char* next_output;
+ char* next_input;
+};
+
+icalcstpc* icalcstpc_new()
+{
+ struct icalcstpc_impl *impl;
+
+ impl = malloc(sizeof(struct icalcstpc_impl));
+
+ if(impl == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ memset(impl,0,sizeof(struct icalcstpc_impl));
+
+ return impl;
+}
+
+void icalcstpc_free(icalcstpc* cstpc)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstpc;
+
+ if(impl->next_output != 0){
+ free(impl->next_output);
+ }
+
+ if(impl->next_input != 0){
+ free(impl->next_input);
+ }
+
+
+ if(impl->parser != 0){
+ icalparser_free(impl->parser);
+ }
+}
+
+/* Get the next string to send to the server */
+char* icalcstpc_next_output_r(icalcstpc* cstp, char * line)
+{
+ char* out;
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ if(impl->next_output == 0){
+ return 0;
+ }
+
+ out = impl->next_output;
+
+ impl->next_output = 0;
+
+ return out;
+}
+
+
+char* icalcstpc_next_output(icalcstpc* cstp, char * line)
+{
+ char *buf;
+ buf = icalcstpc_next_output_r(cstp, line);
+ icalmemory_add_tmp_buffer(buf);
+ return buf;
+}
+
+
+/* process the next string sent by the server */
+int icalcstpc_next_input(icalcstpc* cstp, char* line)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+ icalcstpc_line_type line_type;
+
+ if(icalcstp_line_is_endofdata(line) || line == 0){
+ return 0;
+ }
+
+ switch (impl->command){
+ case ICAL_ABORT_COMMAND:{
+ break;
+ }
+ case ICAL_AUTHENTICATE_COMMAND:{
+ break;
+ }
+ case ICAL_CAPABILITY_COMMAND:{
+ break;
+ }
+ case ICAL_CONTINUE_COMMAND:{
+ break;
+ }
+ case ICAL_CALIDEXPAND_COMMAND:{
+ break;
+ }
+ case ICAL_IDENTIFY_COMMAND:{
+ break;
+ }
+ case ICAL_DISCONNECT_COMMAND:{
+ break;
+ }
+ case ICAL_SENDDATA_COMMAND:{
+ break;
+ }
+ case ICAL_STARTTLS_COMMAND:{
+ break;
+ }
+ case ICAL_UPNEXPAND_COMMAND:{
+ break;
+ }
+ case ICAL_COMPLETE_COMMAND:{
+ break;
+ }
+ case ICAL_UNKNOWN_COMMAND:{
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/* After icalcstpc_next_input returns a 0, there are responses
+ ready. use these to get them */
+icalcstpc_response icalcstpc_first_response(icalcstpc* cstp)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+}
+
+
+icalcstpc_response icalcstpc_next_response(icalcstpc* cstp)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+}
+
+
+int icalcstpc_set_timeout(icalcstpc* cstp, int sec)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+}
+
+icalerrorenum icalcstpc_abort(icalcstpc* cstp)
+{
+ struct icalcstpc_impl* impl = (struct icalcstpc_impl*)cstp;
+
+ icalerror_check_arg_re(cstp!=0,"cstp",ICAL_BADARG_ERROR);
+
+ impl->next_output = "ABORT\n";
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpclient_setup_output(icalcstpc* cstp, size_t sz)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ if(impl->next_output != 0){
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return ICAL_USAGE_ERROR;
+ }
+
+ impl->next_output = malloc(sz);
+
+ if(impl->next_output == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return ICAL_NEWFAILED_ERROR;
+ }
+
+ return ICAL_NO_ERROR;
+
+}
+
+icalerrorenum icalcstpc_authenticate(icalcstpc* cstp, char* mechanism,
+ char* data, char* f(char*))
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+ char* command_str;
+ icalerrorenum error;
+ size_t sz;
+
+ icalerror_check_arg_re(cstp!=0,"cstp",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re(mechanism!=0,"mechanism",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re(data!=0,"data",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re(f!=0,"f",ICAL_BADARG_ERROR);
+
+ impl->command = ICAL_AUTHENTICATE_COMMAND;
+
+ command_str = icalcstp_command_to_string(impl->command);
+
+ sz = strlen(command_str) + strlen(mechanism) + strlen(data) + 4;
+
+ if((error=icalcstpclient_setup_output(cstp,sz)) != ICAL_NO_ERROR){
+ return error;
+ }
+
+ sprintf(impl->next_output,"%s %s %s%s",command_str,mechanism,data,EOL);
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_capability(icalcstpc* cstp)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+ char* command_str;
+ icalerrorenum error;
+ size_t sz;
+
+ icalerror_check_arg_re(cstp!=0,"cstp",ICAL_BADARG_ERROR);
+
+ impl->command = ICAL_CAPABILITY_COMMAND;
+
+ command_str = icalcstp_command_to_string(impl->command);
+
+ sz = strlen(command_str);
+
+ if((error=icalcstpclient_setup_output(cstp,sz)) != ICAL_NO_ERROR){
+ return error;
+ }
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_calidexpand(icalcstpc* cstp,char* calid)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ impl->command = ICAL_CALIDEXPAND_COMMAND;
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_continue(icalcstpc* cstp, unsigned int time)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ impl->command = ICAL_CONTINUE_COMMAND;
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_disconnect(icalcstpc* cstp)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+
+ impl->command = ICAL_DISCONNECT_COMMAND;
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_identify(icalcstpc* cstp, char* id)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+
+ impl->command = ICAL_IDENTIFY_COMMAND;
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_starttls(icalcstpc* cstp, char* command,
+ char* data, char * f(char*))
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ impl->command = ICAL_STARTTLS_COMMAND;
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_upnexpand(icalcstpc* cstp,char* calid)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+
+ impl->command = ICAL_UPNEXPAND_COMMAND;
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalcstpc_sendata(icalcstpc* cstp, unsigned int time,
+ icalcomponent *comp)
+{
+ struct icalcstpc_impl *impl = (struct icalcstpc_impl *)cstp;
+
+ impl->command = ICAL_SENDDATA_COMMAND;
+
+ return ICAL_NO_ERROR;
+}
+
+
+
+
diff --git a/src/libicalss/icalcstpclient.h b/src/libicalss/icalcstpclient.h
new file mode 100644
index 00000000..ae176b33
--- /dev/null
+++ b/src/libicalss/icalcstpclient.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcstpclient.h
+ CREATOR: eric 4 Feb 01
+
+ $Id: icalcstpclient.h,v 1.3 2008-01-02 20:15:44 dothebart Exp $
+
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The original code is icalcstp.h
+
+======================================================================*/
+
+
+#ifndef ICALCSTPC_H
+#define ICALCSTPC_H
+
+#include <libical/ical.h>
+#include <libicalss/icalcstp.h>
+
+/********************** Client (Sender) Interfaces **************************/
+
+/* How to use:
+
+ 1) Construct a new icalcstpc
+ 2) Issue a command by calling one of the command routines.
+ 3) Repeat until both call icalcstpc_next_output and
+ icalcstpc_next_input return 0:
+ 3a) Call icalcstpc_next_output. Send string to server.
+ 3b) Get string from server, & give to icalcstp_next_input()
+ 4) Iterate with icalcstpc_first_response & icalcstp_next_response to
+ get the servers responses
+ 5) Repeat at #2
+*/
+
+
+typedef void icalcstpc;
+
+/* Response code sent by the server. */
+typedef struct icalcstpc_response {
+ icalrequeststatus code;
+ char *arg; /* These strings are owned by libical */
+ char *debug_text;
+ char *more_text;
+ void* result;
+} icalcstpc_response;
+
+
+icalcstpc* icalcstpc_new();
+
+void icalcstpc_free(icalcstpc* cstpc);
+
+int icalcstpc_set_timeout(icalcstpc* cstp, int sec);
+
+
+/* Get the next string to send to the server */
+char* icalcstpc_next_output(icalcstpc* cstp, char* line);
+char* icalcstpc_next_output_r(icalcstpc* cstp, char* line);
+
+/* process the next string from the server */
+int icalcstpc_next_input(icalcstpc* cstp, char * line);
+
+/* After icalcstpc_next_input returns a 0, there are responses
+ ready. use these to get them */
+icalcstpc_response icalcstpc_first_response(icalcstpc* cstp);
+icalcstpc_response icalcstpc_next_response(icalcstpc* cstp);
+
+/* Issue a command */
+icalerrorenum icalcstpc_abort(icalcstpc* cstp);
+icalerrorenum icalcstpc_authenticate(icalcstpc* cstp, char* mechanism,
+ char* init_data, char* f(char*) );
+icalerrorenum icalcstpc_capability(icalcstpc* cstp);
+icalerrorenum icalcstpc_calidexpand(icalcstpc* cstp,char* calid);
+icalerrorenum icalcstpc_continue(icalcstpc* cstp, unsigned int time);
+icalerrorenum icalcstpc_disconnect(icalcstpc* cstp);
+icalerrorenum icalcstpc_identify(icalcstpc* cstp, char* id);
+icalerrorenum icalcstpc_starttls(icalcstpc* cstp, char* command,
+ char* init_data, char* f(char*));
+icalerrorenum icalcstpc_senddata(icalcstpc* cstp, unsigned int time,
+ icalcomponent *comp);
+icalerrorenum icalcstpc_upnexpand(icalcstpc* cstp,char* calid);
+icalerrorenum icalcstpc_sendata(icalcstpc* cstp, unsigned int time,
+ icalcomponent *comp);
+
+
+#endif /* !ICALCSTPC_H */
+
+
+
diff --git a/src/libicalss/icalcstpserver.c b/src/libicalss/icalcstpserver.c
new file mode 100644
index 00000000..5728a8d1
--- /dev/null
+++ b/src/libicalss/icalcstpserver.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalcstpserver.c
+ CREATOR: ebusboom 13 Feb 01
+
+ $Id: icalcstpserver.c,v 1.5 2008-01-02 20:15:45 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalcstp.h"
+#include "icalcstpserver.h"
+#include "pvl.h"
+
+#include <sys/types.h> /* For send(), others */
+#include <sys/socket.h> /* For send(), others. */
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h> /* For alarm */
+#endif
+#include <errno.h>
+#include <stdlib.h> /* for malloc */
+#include <string.h>
+
+
+
+struct icalcstps_impl {
+ int timeout;
+ icalparser *parser;
+ enum cstps_state major_state;
+ struct icalcstps_commandfp commandfp;
+};
+
+
+
+
+/* This state machine is a Mealy-type: actions occur on the
+ transitions, not in the states.
+
+ Here is the state machine diagram from the CAP draft:
+
+
+ STARTTLS /
+ CAPABILITY
+ +-------+
+ | | +---------------+
+ | +-----------+ AUTHENTICATE | |
+ +-->| Connected |-------------->| Authenticated |
+ +-----------+ | |
+ | +---------------+
+ | |
+ | |
+ | |
+ | | +-----+ STARTTLS /
+ | V | | CAPABILITY /
+ | +---------------+ | IDENTIFY
+ | | |<-+
+ | | Identified |<----+
+ | +--------| | |
+ | | +---------------+ | command
+ | | | | completes
+ V |DISCONNECT | |
+ +--------------+ | |SENDDATA |
+ | Disconnected |<--+ | |
+ +--------------+ | | ABORT
+ A | |
+ | V |
+ | DISCONNECT +---------------+ |
+ +--------------------| Receive |--+
+ | |<--+
+ +---------------+ |
+ | | CONTINUTE
+ +----+
+
+ In this implmenetation, the transition from CONNECTED to IDENTIFIED
+ is non-standard. The spec specifies that on the ATHENTICATE
+ command, the machine transitions from CONNECTED to AUTHENTICATED,
+ and then immediately goes to IDENTIFIED. This makes AUTHENTICATED a
+ useless state, so I removed it */
+
+struct state_table {
+ enum cstps_state major_state;
+ enum icalcstp_command command;
+ void (*action)();
+ enum cstps_state next_state;
+
+} server_state_table[] =
+{
+ { CONNECTED, ICAL_CAPABILITY_COMMAND , 0, CONNECTED},
+ { CONNECTED, ICAL_AUTHENTICATE_COMMAND , 0, IDENTIFIED}, /* Non-standard */
+ { IDENTIFIED, ICAL_STARTTLS_COMMAND, 0, IDENTIFIED},
+ { IDENTIFIED, ICAL_IDENTIFY_COMMAND, 0, IDENTIFIED},
+ { IDENTIFIED, ICAL_CAPABILITY_COMMAND, 0, IDENTIFIED},
+ { IDENTIFIED, ICAL_SENDDATA_COMMAND, 0, RECEIVE},
+ { IDENTIFIED, ICAL_DISCONNECT_COMMAND, 0, DISCONNECTED},
+ { DISCONNECTED, 0, 0, 0},
+ { RECEIVE, ICAL_DISCONNECT_COMMAND, 0, DISCONNECTED},
+ { RECEIVE, ICAL_CONTINUE_COMMAND, 0, RECEIVE},
+ { RECEIVE, ICAL_ABORT_COMMAND , 0, IDENTIFIED},
+ { RECEIVE, ICAL_COMPLETE_COMMAND , 0, IDENTIFIED}
+};
+
+
+/**********************************************************************/
+
+
+
+icalcstps* icalcstps_new(struct icalcstps_commandfp cfp)
+{
+ struct icalcstps_impl* impl;
+
+ if ( ( impl = (struct icalcstps_impl*)
+ malloc(sizeof(struct icalcstps_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ impl->commandfp = cfp;
+ impl->timeout = 10;
+
+ return (icalcstps*)impl;
+
+}
+
+void icalcstps_free(icalcstps* cstp);
+
+int icalcstps_set_timeout(icalcstps* cstp, int sec)
+{
+ struct icalcstps_impl *impl = (struct icalcstps_impl *) cstp;
+
+ icalerror_check_arg_rz( (cstp!=0), "cstp");
+
+ impl->timeout = sec;
+
+ return sec;
+}
+
+typedef struct icalcstps_response {
+ icalrequeststatus code;
+ char caluid[1024];
+ void* result;
+} icalcstps_response;
+
+
+icalerrorenum prep_abort(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_authenticate(struct icalcstps_impl* impl, char* data)
+{ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_capability(struct icalcstps_impl* impl, char* data)
+{ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_calidexpand(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_continue(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_disconnect(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_identify(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_starttls(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_upnexpand(struct icalcstps_impl* impl, char* data)
+{
+ return ICAL_NO_ERROR;
+}
+icalerrorenum prep_sendata(struct icalcstps_impl* impl, char* data)
+{ return ICAL_NO_ERROR;
+}
+
+char* icalcstps_process_incoming(icalcstps* cstp, char* input)
+{
+ struct icalcstps_impl *impl = (struct icalcstps_impl *) cstp;
+ char *i;
+ char *cmd_or_resp;
+ char *data;
+ char *input_cpy;
+ icalerrorenum error;
+
+ icalerror_check_arg_rz(cstp !=0,"cstp");
+ icalerror_check_arg_rz(input !=0,"input");
+
+ if ((input_cpy = (char*)strdup(input)) == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ i = (char*)strstr(" ",input_cpy);
+
+ cmd_or_resp = input_cpy;
+
+ if (i != 0){
+ *i = '\0';
+ data = ++i;
+ } else {
+ data = 0;
+ }
+
+ printf("cmd: %s\n",cmd_or_resp);
+ printf("data: %s\n",data);
+
+ /* extract the command, look up in the state table, and dispatch
+ to the proper handler */
+
+ if(strcmp(cmd_or_resp,"ABORT") == 0){
+ error = prep_abort(impl,data);
+ } else if(strcmp(cmd_or_resp,"AUTHENTICATE") == 0){
+ error = prep_authenticate(impl,data);
+ } else if(strcmp(cmd_or_resp,"CAPABILITY") == 0){
+ error = prep_capability(impl,data);
+ } else if(strcmp(cmd_or_resp,"CALIDEXPAND") == 0){
+ error = prep_calidexpand(impl,data);
+ } else if(strcmp(cmd_or_resp,"CONTINUE") == 0){
+ error = prep_continue(impl,data);
+ } else if(strcmp(cmd_or_resp,"DISCONNECT") == 0){
+ error = prep_disconnect(impl,data);
+ } else if(strcmp(cmd_or_resp,"IDENTIFY") == 0){
+ error = prep_identify(impl,data);
+ } else if(strcmp(cmd_or_resp,"STARTTLS") == 0){
+ error = prep_starttls(impl,data);
+ } else if(strcmp(cmd_or_resp,"UPNEXPAND") == 0){
+ error = prep_upnexpand(impl,data);
+ } else if(strcmp(cmd_or_resp,"SENDDATA") == 0){
+ error = prep_sendata(impl,data);
+ }
+
+ return 0;
+}
+
+ /* Read data until we get a end of data marker */
+
+
+
+struct icalcstps_server_stubs {
+ icalerrorenum (*abort)(icalcstps* cstp);
+ icalerrorenum (*authenticate)(icalcstps* cstp, char* mechanism,
+ char* data);
+ icalerrorenum (*calidexpand)(icalcstps* cstp, char* calid);
+ icalerrorenum (*capability)(icalcstps* cstp);
+ icalerrorenum (*cont)(icalcstps* cstp, unsigned int time);
+ icalerrorenum (*identify)(icalcstps* cstp, char* id);
+ icalerrorenum (*disconnect)(icalcstps* cstp);
+ icalerrorenum (*sendata)(icalcstps* cstp, unsigned int time,
+ icalcomponent *comp);
+ icalerrorenum (*starttls)(icalcstps* cstp, char* command,
+ char* data);
+ icalerrorenum (*upnexpand)(icalcstps* cstp, char* upn);
+ icalerrorenum (*unknown)(icalcstps* cstp, char* command, char* data);
+};
+
diff --git a/src/libicalss/icalcstpserver.h b/src/libicalss/icalcstpserver.h
new file mode 100644
index 00000000..52390209
--- /dev/null
+++ b/src/libicalss/icalcstpserver.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalcstpserver.h
+ CREATOR: eric 13 Feb 01
+
+ $Id: icalcstpserver.h,v 1.3 2008-01-02 20:15:45 dothebart Exp $
+
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The original code is icalcstp.h
+
+======================================================================*/
+
+
+#ifndef ICALCSTPS_H
+#define ICALCSTPS_H
+
+#include <libical/ical.h>
+
+
+/********************** Server (Reciever) Interfaces *************************/
+
+/* On the server side, the caller will recieve data from the incoming
+ socket and pass it to icalcstps_next_input. The caller then takes
+ the return from icalcstps_next_outpu and sends it out through the
+ socket. This gives the caller a point of control. If the cstp code
+ connected to the socket itself, it would be hard for the caller to
+ do anything else after the cstp code was started.
+
+ All of the server and client command routines will generate
+ response codes. On the server side, these responses will be turned
+ into text and sent to the client. On the client side, the reponse
+ is the one sent from the server.
+
+ Since each command can return multiple responses, the responses are
+ stored in the icalcstps object and are accesses by
+ icalcstps_first_response() and icalcstps_next_response()
+
+ How to use:
+
+ 1) Construct a new icalcstps, bound to your code via stubs
+ 2) Repeat forever:
+ 2a) Get string from client & give to icalcstps_next_input()
+ 2b) Repeat until icalcstp_next_output returns 0:
+ 2b1) Call icalcstps_next_output.
+ 2b2) Send string to client.
+*/
+
+
+
+typedef void icalcstps;
+
+/* Pointers to the rountines that
+ icalcstps_process_incoming will call when it recognizes a CSTP
+ command in the data. BTW, the CONTINUE command is named 'cont'
+ because 'continue' is a C keyword */
+
+struct icalcstps_commandfp {
+ icalerrorenum (*abort)(icalcstps* cstp);
+ icalerrorenum (*authenticate)(icalcstps* cstp, char* mechanism,
+ char* data);
+ icalerrorenum (*calidexpand)(icalcstps* cstp, char* calid);
+ icalerrorenum (*capability)(icalcstps* cstp);
+ icalerrorenum (*cont)(icalcstps* cstp, unsigned int time);
+ icalerrorenum (*identify)(icalcstps* cstp, char* id);
+ icalerrorenum (*disconnect)(icalcstps* cstp);
+ icalerrorenum (*sendata)(icalcstps* cstp, unsigned int time,
+ icalcomponent *comp);
+ icalerrorenum (*starttls)(icalcstps* cstp, char* command,
+ char* data);
+ icalerrorenum (*upnexpand)(icalcstps* cstp, char* upn);
+ icalerrorenum (*unknown)(icalcstps* cstp, char* command, char* data);
+};
+
+
+
+icalcstps* icalcstps_new(struct icalcstps_commandfp stubs);
+
+void icalcstps_free(icalcstps* cstp);
+
+int icalcstps_set_timeout(icalcstps* cstp, int sec);
+
+/* Get the next string to send to the client */
+char* icalcstps_next_output(icalcstps* cstp);
+
+/* process the next string from the client */
+int icalcstps_next_input(icalcstps* cstp);
+
+#endif /* ICALCSTPS */
diff --git a/src/libicalss/icaldirset.c b/src/libicalss/icaldirset.c
new file mode 100644
index 00000000..852206f1
--- /dev/null
+++ b/src/libicalss/icaldirset.c
@@ -0,0 +1,804 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icaldirset.c
+ CREATOR: eric 28 November 1999
+
+ $Id: icaldirset.c,v 1.24 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+/**
+ @file icaldirset.c
+
+ @brief icaldirset manages a database of ical components and offers
+ interfaces for reading, writing and searching for components.
+
+ icaldirset groups components in to clusters based on their DTSTAMP
+ 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.
+
+ The primary interfaces are icaldirset__get_first_component and
+ icaldirset_get_next_component. 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 icaldirset_select,
+ icaldirset_first and icaldirset_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 <libical/ical.h>
+#include "icaldirset.h"
+#include "icaldirset.h"
+#include "icalfileset.h"
+#include "icalfilesetimpl.h"
+#include "icalcluster.h"
+#include "icalgauge.h"
+
+#ifndef WIN32
+#include <dirent.h> /* for opendir() */
+#include <unistd.h> /* for stat, getpid */
+#include <sys/utsname.h> /* for uname */
+#else
+#include <io.h>
+#include <process.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h> /* for opendir() */
+#include <sys/stat.h> /* for stat */
+#include <limits.h> /* For PATH_MAX */
+#include <time.h> /* for clock() */
+#include <stdlib.h> /* for rand(), srand() */
+#include <string.h> /* for strdup */
+#include "icaldirsetimpl.h"
+
+#if defined(_MSC_VER)
+#define _S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
+#define S_ISDIR(mode) _S_ISTYPE((mode), _S_IFDIR)
+#define S_ISREG(mode) _S_ISTYPE((mode), _S_IFREG)
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#endif
+
+/** Default options used when NULL is passed to icalset_new() **/
+icaldirset_options icaldirset_options_default = {O_RDWR|O_CREAT};
+
+
+const char* icaldirset_path(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+
+ return dset->dir;
+}
+
+
+void icaldirset_mark(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+
+ icalcluster_mark(dset->cluster);
+}
+
+
+icalerrorenum icaldirset_commit(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+ icalset *fileset;
+ icalfileset_options options = icalfileset_options_default;
+
+ options.cluster = dset->cluster;
+
+ fileset = icalset_new(ICAL_FILE_SET, icalcluster_key(dset->cluster), &options);
+
+ fileset->commit(fileset);
+ fileset->free(fileset);
+
+ return ICAL_NO_ERROR;
+}
+
+void icaldirset_lock(const char* dir)
+{
+}
+
+
+void icaldirset_unlock(const char* dir)
+{
+}
+
+/* Load the contents of the store directory into the store's internal directory list*/
+icalerrorenum icaldirset_read_directory(icaldirset *dset)
+{
+ char *str;
+#ifndef WIN32
+ struct dirent *de;
+ DIR* dp;
+
+ dp = opendir(dset->dir);
+
+ if (dp == 0) {
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+
+ /* clear contents of directory list */
+ while((str = pvl_pop(dset->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(dset->directory, (void*)strdup(de->d_name));
+ }
+
+ closedir(dp);
+#else
+ struct _finddata_t c_file;
+ intptr_t hFile;
+
+ /* Find first .c file in current directory */
+ if( (hFile = _findfirst( "*", &c_file )) == -1L ) {
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ } else {
+ while((str = pvl_pop(dset->directory))){
+ free(str);
+ }
+
+ /* load all of the cluster names in the directory list */
+ do {
+ /* Remove known directory names '.' and '..'*/
+ if (strcmp(c_file.name,".") == 0 ||
+ strcmp(c_file.name,"..") == 0 ){
+ continue;
+ }
+
+ pvl_push(dset->directory, (void*)strdup(c_file.name));
+ }
+ while ( _findnext( hFile, &c_file ) == 0 );
+
+ _findclose( hFile );
+ }
+
+#endif
+
+ return ICAL_NO_ERROR;
+}
+
+
+icalset* icaldirset_init(icalset* set, const char* dir, void* options_in)
+{
+ icaldirset *dset = (icaldirset*)set;
+ icaldirset_options *options = options_in;
+ struct stat sbuf;
+
+ icalerror_check_arg_rz( (dir!=0), "dir");
+ icalerror_check_arg_rz( (set!=0), "set");
+
+ 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;
+ }
+
+ icaldirset_lock(dir);
+
+ dset->dir = (char*)strdup(dir);
+ dset->options = *options;
+ dset->directory = pvl_newlist();
+ dset->directory_iterator = 0;
+ dset->gauge = 0;
+ dset->first_component = 0;
+ dset->cluster = 0;
+
+ return set;
+}
+
+icalset* icaldirset_new(const char* dir)
+{
+ return icalset_new(ICAL_DIR_SET, dir, &icaldirset_options_default);
+}
+
+
+icalset* icaldirset_new_reader(const char* dir)
+{
+ icaldirset_options reader_options = icaldirset_options_default;
+
+ reader_options.flags = O_RDONLY;
+
+ return icalset_new(ICAL_DIR_SET, dir, &reader_options);
+}
+
+
+icalset* icaldirset_new_writer(const char* dir)
+{
+ icaldirset_options writer_options = icaldirset_options_default;
+
+ writer_options.flags = O_RDWR|O_CREAT;
+
+ return icalset_new(ICAL_DIR_SET, dir, &writer_options);
+}
+
+
+void icaldirset_free(icalset* s)
+{
+ icaldirset *dset = (icaldirset*)s;
+ char* str;
+
+ icaldirset_unlock(dset->dir);
+
+ if(dset->dir !=0){
+ free(dset->dir);
+ dset->dir = 0;
+ }
+
+ if(dset->gauge !=0){
+ icalgauge_free(dset->gauge);
+ dset->gauge = 0;
+ }
+
+ if(dset->cluster !=0){
+ icalcluster_free(dset->cluster);
+ }
+
+ while(dset->directory !=0 && (str=pvl_pop(dset->directory)) != 0){
+ free(str);
+ }
+
+ if(dset->directory != 0){
+ pvl_free(dset->directory);
+ dset->directory = 0;
+ }
+
+ dset->directory_iterator = 0;
+ dset->first_component = 0;
+}
+
+
+/* icaldirset_next_uid_number updates a serial number in the Store
+ directory in a file called SEQUENCE */
+
+int icaldirset_next_uid_number(icaldirset* dset)
+{
+ char sequence = 0;
+ char temp[128];
+ char filename[ICAL_PATH_MAX];
+ char *r;
+ FILE *f;
+ struct stat sbuf;
+
+ icalerror_check_arg_rz( (dset!=0), "dset");
+
+ snprintf(filename,sizeof(filename),"%s/%s",dset->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 icaldirset_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 icaldirset_next_uid_number");
+ return 0;
+ }
+}
+
+icalerrorenum icaldirset_next_cluster(icaldirset* dset)
+{
+ char path[ICAL_PATH_MAX];
+
+ if (dset->directory_iterator == 0){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return ICAL_INTERNAL_ERROR;
+ }
+ dset->directory_iterator = pvl_next(dset->directory_iterator);
+
+ if (dset->directory_iterator == 0){
+ /* There are no more clusters */
+ if(dset->cluster != 0){
+ icalcluster_free(dset->cluster);
+ dset->cluster = 0;
+ }
+ return ICAL_NO_ERROR;
+ }
+
+ snprintf(path,sizeof(path),"%s/%s", dset->dir,(char*)pvl_data(dset->directory_iterator));
+
+ icalcluster_free(dset->cluster);
+ dset->cluster = icalfileset_produce_icalcluster(path);
+
+ return icalerrno;
+}
+
+static void icaldirset_add_uid(icalcomponent* comp)
+{
+ char uidstring[ICAL_PATH_MAX];
+ icalproperty *uid;
+#ifndef WIN32
+ struct utsname unamebuf;
+#endif
+
+ icalerror_check_arg_rv( (comp!=0), "comp");
+
+ uid = icalcomponent_get_first_property(comp,ICAL_UID_PROPERTY);
+
+ if (uid == 0) {
+
+#ifndef WIN32
+ uname(&unamebuf);
+
+ snprintf(uidstring,sizeof(uidstring),"%d-%s",(int)getpid(),unamebuf.nodename);
+#else
+ snprintf(uidstring,sizeof(uidstring),"%d-%s",(int)getpid(),"WINDOWS"); /* FIX: There must be an easy get the system name */
+#endif
+
+ uid = icalproperty_new_uid(uidstring);
+ icalcomponent_add_property(comp,uid);
+ } else {
+ strncpy(uidstring,icalproperty_get_uid(uid),ICAL_PATH_MAX-1);
+ uidstring[ICAL_PATH_MAX-1]='\0';
+ }
+}
+
+
+/**
+ 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 DSTAMP property
+*/
+
+icalerrorenum icaldirset_add_component(icalset* set, icalcomponent* comp)
+{
+ char clustername[ICAL_PATH_MAX];
+ icalproperty *dt = 0;
+ icalvalue *v;
+ struct icaltimetype tm;
+ icalerrorenum error = ICAL_NO_ERROR;
+ icalcomponent *inner;
+ icaldirset *dset = (icaldirset*) set;
+
+ icalerror_check_arg_rz( (dset!=0), "dset");
+ icalerror_check_arg_rz( (comp!=0), "comp");
+
+ icaldirset_add_uid(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_DTSTAMP_PROPERTY);
+
+ if (dt != 0)
+ break;
+ }
+
+ if (dt == 0) {
+ 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 DTSTAMP or 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,ICAL_PATH_MAX,"%s/%04d%02d",dset->dir, tm.year, tm.month);
+
+ /* Load the cluster and insert the object */
+ if(dset->cluster != 0 &&
+ strcmp(clustername,icalcluster_key(dset->cluster)) != 0 ){
+ icalcluster_free(dset->cluster);
+ dset->cluster = 0;
+ }
+
+ if (dset->cluster == 0){
+ dset->cluster = icalfileset_produce_icalcluster(clustername);
+
+ if (dset->cluster == 0){
+ error = icalerrno;
+ }
+ }
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return error;
+ }
+
+ /* Add the component to the cluster */
+ icalcluster_add_component(dset->cluster,comp);
+
+ /* icalcluster_mark(impl->cluster); */
+
+ return ICAL_NO_ERROR;
+}
+
+/**
+ Remove a component in the current cluster. HACK. This routine is a
+ "friend" of icalfileset, and breaks its encapsulation. It was
+ either do it this way, or add several layers of interfaces that had
+ no other use.
+ */
+
+icalerrorenum icaldirset_remove_component(icalset* set, icalcomponent* comp)
+{
+ icaldirset *dset = (icaldirset*)set;
+ icalcomponent *filecomp = icalcluster_get_component(dset->cluster);
+
+ icalcompiter i;
+ int found = 0;
+
+ icalerror_check_arg_re((set!=0),"set",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((comp!=0),"comp",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((dset->cluster!=0),"Cluster pointer",ICAL_USAGE_ERROR);
+
+ for(i = icalcomponent_begin_component(filecomp,ICAL_ANY_COMPONENT);
+ icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
+
+ icalcomponent *this = icalcompiter_deref(&i);
+
+ if (this == comp){
+ found = 1;
+ break;
+ }
+ }
+
+ if (found != 1){
+ icalerror_warn("icaldirset_remove_component: component is not part of current cluster");
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return ICAL_USAGE_ERROR;
+ }
+
+ icalcluster_remove_component(dset->cluster,comp);
+
+ /* icalcluster_mark(impl->cluster); */
+
+ /* If the removal emptied the fileset, get the next fileset */
+ if( icalcluster_count_components(dset->cluster,ICAL_ANY_COMPONENT)==0){
+ icalerrorenum error = icaldirset_next_cluster(dset);
+
+ if(dset->cluster != 0 && error == ICAL_NO_ERROR){
+ icalcluster_get_first_component(dset->cluster);
+ } else {
+ /* HACK. Not strictly correct for impl->cluster==0 */
+ return error;
+ }
+ } else {
+ /* Do nothing */
+ }
+
+ return ICAL_NO_ERROR;
+}
+
+
+
+int icaldirset_count_components(icalset* store,
+ icalcomponent_kind kind)
+{
+ /* HACK, not implemented */
+ assert(0);
+
+ return 0;
+}
+
+
+icalcomponent* icaldirset_fetch_match(icalset* set, icalcomponent *c)
+{
+ fprintf(stderr," icaldirset_fetch_match is not implemented\n");
+ assert(0);
+ return 0;
+}
+
+
+icalcomponent* icaldirset_fetch(icalset* set, const char* uid)
+{
+ icaldirset *dset = (icaldirset*)set;
+ icalgauge *gauge;
+ icalgauge *old_gauge;
+ icalcomponent *c;
+ char sql[256];
+
+ icalerror_check_arg_rz( (set!=0), "set");
+ icalerror_check_arg_rz( (uid!=0), "uid");
+
+ snprintf(sql, 256, "SELECT * FROM VEVENT WHERE UID = \"%s\"", uid);
+
+ gauge = icalgauge_new_from_sql(sql, 0);
+
+ old_gauge = dset->gauge;
+ dset->gauge = gauge;
+
+ c= icaldirset_get_first_component(set);
+
+ dset->gauge = old_gauge;
+
+ icalgauge_free(gauge);
+
+ return c;
+}
+
+
+int icaldirset_has_uid(icalset* set, const char* uid)
+{
+ icalcomponent *c;
+
+ icalerror_check_arg_rz( (set!=0), "set");
+ 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 = icaldirset_fetch(set,uid);
+
+ return c!=0;
+
+}
+
+
+icalerrorenum icaldirset_select(icalset* set, icalgauge* gauge)
+{
+ icaldirset *dset = (icaldirset*)set;
+
+ icalerror_check_arg_re( (set!=0), "set",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re( (gauge!=0), "gauge",ICAL_BADARG_ERROR);
+
+ dset->gauge = gauge;
+
+ return ICAL_NO_ERROR;
+}
+
+
+icalerrorenum icaldirset_modify(icalset* set,
+ icalcomponent *old,
+ icalcomponent *new)
+{
+ assert(0);
+ return ICAL_NO_ERROR; /* HACK, not implemented */
+
+}
+
+
+void icaldirset_clear(icalset* set)
+{
+
+ assert(0);
+ return;
+ /* HACK, not implemented */
+}
+
+icalcomponent* icaldirset_get_current_component(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+
+ if (dset->cluster == 0){
+ icaldirset_get_first_component(set);
+ }
+ if(dset->cluster == 0){
+ return 0;
+ }
+
+ return icalcluster_get_current_component(dset->cluster);
+}
+
+
+icalcomponent* icaldirset_get_first_component(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+
+ icalerrorenum error;
+ char path[ICAL_PATH_MAX];
+
+ error = icaldirset_read_directory(dset);
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ dset->directory_iterator = pvl_head(dset->directory);
+
+ if (dset->directory_iterator == 0){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ snprintf(path,ICAL_PATH_MAX,"%s/%s",
+ dset->dir,
+ (char*)pvl_data(dset->directory_iterator));
+
+ /* If the next cluster we need is different than the current cluster,
+ delete the current one and get a new one */
+
+ if(dset->cluster != 0 && strcmp(path,icalcluster_key(dset->cluster)) != 0 ){
+ icalcluster_free(dset->cluster);
+ dset->cluster = 0;
+ }
+
+ if (dset->cluster == 0){
+ dset->cluster = icalfileset_produce_icalcluster(path);
+
+ if (dset->cluster == 0){
+ error = icalerrno;
+ }
+ }
+
+ if (error != ICAL_NO_ERROR){
+ icalerror_set_errno(error);
+ return 0;
+ }
+
+ dset->first_component = 1;
+
+ return icaldirset_get_next_component(set);
+}
+
+
+icalcomponent* icaldirset_get_next_component(icalset* set)
+{
+ icaldirset *dset = (icaldirset*)set;
+ icalcomponent *c;
+ icalerrorenum error;
+
+ icalerror_check_arg_rz( (set!=0), "set");
+
+
+ if(dset->cluster == 0){
+ icalerror_warn("icaldirset_get_next_component called with a NULL cluster (Caller must call icaldirset_get_first_component first");
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return 0;
+
+ }
+
+ /* Set the component iterator for the following for loop */
+ if (dset->first_component == 1){
+ icalcluster_get_first_component(dset->cluster);
+ dset->first_component = 0;
+ } else {
+ icalcluster_get_next_component(dset->cluster);
+ }
+
+ while(1){
+ /* Iterate through all of the objects in the cluster*/
+ for( c = icalcluster_get_current_component(dset->cluster);
+ c != 0;
+ c = icalcluster_get_next_component(dset->cluster)){
+
+ /* If there is a gauge defined and the component does not
+ pass the gauge, skip the rest of the loop */
+
+ if (dset->gauge != 0 && icalgauge_compare(dset->gauge,c) == 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 = icaldirset_next_cluster(dset);
+
+ if(dset->cluster == 0 || error != ICAL_NO_ERROR){
+ /* No more clusters */
+ return 0;
+ } else {
+ c = icalcluster_get_first_component(dset->cluster);
+
+ return c;
+ }
+
+ }
+
+ return 0; /* Should never get here */
+}
+
+icalsetiter icaldirset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge)
+{
+ icalsetiter itr = icalsetiter_null;
+ icaldirset *fset = (icaldirset*) set;
+
+ icalerror_check_arg_re((fset!=0), "set", icalsetiter_null);
+
+ itr.iter.kind = kind;
+ itr.gauge = gauge;
+
+ /* TO BE IMPLEMENTED */
+ return icalsetiter_null;
+}
+
+icalcomponent* icaldirsetiter_to_next(icalset* set, icalsetiter* i)
+{
+ /* TO BE IMPLEMENTED */
+ return NULL;
+}
+
+icalcomponent* icaldirsetiter_to_prior(icalset* set, icalsetiter* i)
+{
+ /* TO BE IMPLEMENTED */
+ return NULL;
+}
diff --git a/src/libicalss/icaldirset.h b/src/libicalss/icaldirset.h
new file mode 100644
index 00000000..75d75141
--- /dev/null
+++ b/src/libicalss/icaldirset.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icaldirset.h
+ CREATOR: eric 28 November 1999
+
+
+ $Id: icaldirset.h,v 1.8 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALDIRSET_H
+#define ICALDIRSET_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+#include "icalcluster.h"
+#include "icalgauge.h"
+
+/* icaldirset Routines for storing, fetching, and searching for ical
+ * objects in a database */
+
+typedef struct icaldirset_impl icaldirset;
+
+icalset* icaldirset_new(const char* path);
+
+icalset* icaldirset_new_reader(const char* path);
+icalset* icaldirset_new_writer(const char* path);
+
+
+icalset* icaldirset_init(icalset* set, const char *dsn, void *options);
+void icaldirset_free(icalset* set);
+
+const char* icaldirset_path(icalset* set);
+
+/* Mark the cluster as changed, so it will be written to disk when it
+ is freed. Commit writes to disk immediately*/
+void icaldirset_mark(icalset* set);
+icalerrorenum icaldirset_commit(icalset* set);
+
+icalerrorenum icaldirset_add_component(icalset* store, icalcomponent* comp);
+icalerrorenum icaldirset_remove_component(icalset* store, icalcomponent* comp);
+
+int icaldirset_count_components(icalset* store,
+ icalcomponent_kind kind);
+
+/* Restrict the component returned by icaldirset_first, _next to those
+ that pass the gauge. _clear removes the gauge. */
+icalerrorenum icaldirset_select(icalset* store, icalgauge* gauge);
+void icaldirset_clear(icalset* store);
+
+/* Get a component by uid */
+icalcomponent* icaldirset_fetch(icalset* store, const char* uid);
+int icaldirset_has_uid(icalset* store, const char* uid);
+icalcomponent* icaldirset_fetch_match(icalset* set, icalcomponent *c);
+
+/* Modify components according to the MODIFY method of CAP. Works on
+ the currently selected components. */
+icalerrorenum icaldirset_modify(icalset* store, icalcomponent *oldc,
+ icalcomponent *newc);
+
+/* Iterate through the components. If a gauge has been defined, these
+ will skip over components that do not pass the gauge */
+
+icalcomponent* icaldirset_get_current_component(icalset* store);
+icalcomponent* icaldirset_get_first_component(icalset* store);
+icalcomponent* icaldirset_get_next_component(icalset* store);
+
+/* External iterator for thread safety */
+icalsetiter icaldirset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge);
+icalcomponent* icaldirsetiter_to_next(icalset* set, icalsetiter* i);
+icalcomponent* icaldirsetiter_to_prior(icalset* set, icalsetiter* i);
+
+typedef struct icaldirset_options {
+ int flags; /**< flags corresponding to the open() system call O_RDWR, etc. */
+} icaldirset_options;
+
+#endif /* !ICALDIRSET_H */
+
+
+
diff --git a/src/libicalss/icaldirsetimpl.h b/src/libicalss/icaldirsetimpl.h
new file mode 100644
index 00000000..d2aa4b00
--- /dev/null
+++ b/src/libicalss/icaldirsetimpl.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icaldirsetimpl.h
+ CREATOR: eric 21 Aug 2000
+
+ $Id: icaldirsetimpl.h,v 1.6 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libicalss/icalcluster.h>
+
+/* This definition is in its own file so it can be kept out of the
+ main header file, but used by "friend classes" like icalset*/
+
+struct icaldirset_impl
+{
+ icalset super; /**< parent class */
+ char* dir; /**< directory containing ics files */
+ icaldirset_options options; /**< copy of options passed to icalset_new() */
+ icalcluster* cluster; /**< cluster containing data */
+ icalgauge* gauge; /**< gauge for filtering out data */
+ int first_component; /**< ??? */
+ pvl_list directory; /**< ??? */
+ pvl_elem directory_iterator; /**< ??? */
+};
diff --git a/src/libicalss/icalfileset.c b/src/libicalss/icalfileset.c
new file mode 100644
index 00000000..9d739174
--- /dev/null
+++ b/src/libicalss/icalfileset.c
@@ -0,0 +1,990 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalfileset.c
+ CREATOR: eric 23 December 1999
+
+ $Id: icalfileset.c,v 1.36 2008-01-15 23:17:43 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "icalfileset.h"
+#include "icalgauge.h"
+#include <errno.h>
+#include <sys/stat.h> /* for stat */
+#ifndef WIN32
+#include <unistd.h> /* for stat, getpid */
+#else
+#include <io.h>
+#ifndef _WIN32_WCE
+#include <share.h>
+#endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h> /* for fcntl */
+#include "icalfilesetimpl.h"
+#include "icalclusterimpl.h"
+
+#if defined(_MSC_VER)
+#define _S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
+#define S_ISDIR(mode) _S_ISTYPE((mode), _S_IFDIR)
+#define S_ISREG(mode) _S_ISTYPE((mode), _S_IFREG)
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#endif
+
+#ifdef _WIN32_WCE
+#include <winbase.h>
+#endif
+
+/** Default options used when NULL is passed to icalset_new() **/
+icalfileset_options icalfileset_options_default = {O_RDWR|O_CREAT, 0644, 0};
+
+int icalfileset_lock(icalfileset *set);
+int icalfileset_unlock(icalfileset *set);
+icalerrorenum icalfileset_read_file(icalfileset* set, mode_t mode);
+int icalfileset_filesize(icalfileset* set);
+
+icalerrorenum icalfileset_create_cluster(const char *path);
+
+icalset* icalfileset_new(const char* path)
+{
+ return icalset_new(ICAL_FILE_SET, path, &icalfileset_options_default);
+}
+
+icalset* icalfileset_new_reader(const char* path)
+{
+ icalfileset_options reader_options = icalfileset_options_default;
+ reader_options.flags = O_RDONLY;
+
+ return icalset_new(ICAL_FILE_SET, path, &reader_options);
+}
+
+icalset* icalfileset_new_writer(const char* path)
+{
+ icalfileset_options writer_options = icalfileset_options_default;
+ writer_options.flags = O_RDONLY;
+
+ return icalset_new(ICAL_FILE_SET, path, &writer_options);
+}
+
+icalset* icalfileset_init(icalset *set, const char* path, void* options_in)
+{
+ icalfileset_options *options = (options_in) ? options_in : &icalfileset_options_default;
+ icalfileset *fset = (icalfileset*) set;
+ int flags;
+ mode_t mode;
+ off_t cluster_file_size;
+
+ icalerror_clear_errno();
+ icalerror_check_arg_rz( (path!=0), "path");
+ icalerror_check_arg_rz( (fset!=0), "fset");
+
+ fset->path = strdup(path);
+ fset->options = *options;
+
+ flags = options->flags;
+ mode = options->mode;
+
+ cluster_file_size = icalfileset_filesize(fset);
+
+ if(cluster_file_size < 0){
+ icalfileset_free(set);
+ return 0;
+ }
+
+#ifndef WIN32
+ fset->fd = open(fset->path, flags, mode);
+#else
+ fset->fd = open(fset->path, flags, mode);
+ /* fset->fd = sopen(fset->path,flags, _SH_DENYWR, _S_IREAD | _S_IWRITE); */
+#endif
+
+ if (fset->fd < 0){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ icalfileset_free(set);
+ return 0;
+ }
+
+#ifndef WIN32
+ icalfileset_lock(fset);
+#endif
+
+ if(cluster_file_size > 0 ){
+ icalerrorenum error;
+ if((error = icalfileset_read_file(fset,mode))!= ICAL_NO_ERROR){
+ icalfileset_free(set);
+ return 0;
+ }
+ }
+
+ if (options->cluster) {
+ fset->cluster = icalcomponent_new_clone(icalcluster_get_component(options->cluster));
+ fset->changed = 1;
+ }
+
+ if (fset->cluster == 0) {
+ fset->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ }
+
+ return set;
+}
+
+
+icalcluster* icalfileset_produce_icalcluster(const char *path) {
+ icalset *fileset;
+ icalcluster *ret;
+
+ int errstate = icalerror_errors_are_fatal;
+ icalerror_errors_are_fatal = 0;
+
+ fileset = icalfileset_new_reader(path);
+
+
+ if (fileset == 0 || icalerrno == ICAL_FILE_ERROR) {
+ /* file does not exist */
+ ret = icalcluster_new(path, NULL);
+ } else {
+ ret = icalcluster_new(path, ((icalfileset*)fileset)->cluster);
+ icalfileset_free(fileset);
+ }
+
+ icalerror_errors_are_fatal = errstate;
+ icalerror_set_errno(ICAL_NO_ERROR);
+ return ret;
+}
+
+
+
+char* icalfileset_read_from_file(char *s, size_t size, void *d)
+{
+ char* p = s;
+ icalfileset *set = d;
+
+ /* Simulate fgets -- read single characters and stop at '\n' */
+
+ for(p=s; p<s+size-1;p++){
+
+ if(read(set->fd,p,1) != 1 || *p=='\n'){
+ p++;
+ break;
+ }
+ }
+
+ *p = '\0';
+
+ if(*s == 0){
+ return 0;
+ } else {
+ return s;
+ }
+
+}
+
+
+icalerrorenum icalfileset_read_file(icalfileset* set,mode_t mode)
+{
+ icalparser *parser;
+
+ parser = icalparser_new();
+
+ icalparser_set_gen_data(parser, set);
+ set->cluster = icalparser_parse(parser,icalfileset_read_from_file);
+ icalparser_free(parser);
+
+ if (set->cluster == 0 || icalerrno != ICAL_NO_ERROR){
+ icalerror_set_errno(ICAL_PARSE_ERROR);
+ /*return ICAL_PARSE_ERROR;*/
+ }
+
+ if (icalcomponent_isa(set->cluster) != ICAL_XROOT_COMPONENT){
+ /* The parser got a single component, so it did not put it in
+ an XROOT. */
+ icalcomponent *cl = set->cluster;
+ set->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
+ icalcomponent_add_component(set->cluster,cl);
+ }
+
+ return ICAL_NO_ERROR;
+}
+
+int icalfileset_filesize(icalfileset* fset)
+{
+ int cluster_file_size;
+ struct stat sbuf;
+
+ if (stat(fset->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 */
+ return 0;
+ } else {
+ /* It was because of another error */
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return -1;
+ }
+ } else {
+ /* A file by the given name exists, but is it a regular file? */
+
+ if (!S_ISREG(sbuf.st_mode)){
+ /* Nope, not a regular file */
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return -1;
+ } else {
+ /* Lets assume that it is a file of the right type */
+ return sbuf.st_size;
+ }
+ }
+
+ /*return -1; not reached*/
+}
+
+void icalfileset_free(icalset* set)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_rv((set!=0),"set");
+
+ if (fset->cluster != 0){
+ icalfileset_commit(set);
+ icalcomponent_free(fset->cluster);
+ fset->cluster=0;
+ }
+
+ if (fset->gauge != 0){
+ icalgauge_free(fset->gauge);
+ fset->gauge=0;
+ }
+
+ if(fset->fd > 0){
+ icalfileset_unlock(fset);
+ close(fset->fd);
+ fset->fd = -1;
+ }
+
+ if(fset->path != 0){
+ free(fset->path);
+ fset->path = 0;
+ }
+}
+
+const char* icalfileset_path(icalset* set) {
+ icalerror_check_arg_rz((set!=0),"set");
+
+ return ((icalfileset*)set)->path;
+}
+
+
+int icalfileset_lock(icalfileset *set)
+{
+#ifndef WIN32
+ struct flock lock;
+ int rtrn;
+
+ icalerror_check_arg_rz((set->fd>0),"set->fd");
+ errno = 0;
+ 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) */
+
+ rtrn = fcntl(set->fd, F_SETLKW, &lock);
+
+ return rtrn;
+#else
+ return 0;
+#endif
+}
+
+int icalfileset_unlock(icalfileset *set)
+{
+#ifndef WIN32
+ struct flock lock;
+ icalerror_check_arg_rz((set->fd>0),"set->fd");
+
+ 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(set->fd, F_UNLCK, &lock));
+#else
+ return 0;
+#endif
+}
+
+static char * shell_quote(const char *s)
+{
+ char *result;
+ char *p;
+ p = result = malloc(strlen(s)*5+1);
+ while(*s)
+ {
+ if (*s == '\'')
+ {
+ *p++ = '\'';
+ *p++ = '"';
+ *p++ = *s++;
+ *p++ = '"';
+ *p++ = '\'';
+ }
+ else
+ {
+ *p++ = *s++;
+ }
+ }
+ *p = '\0';
+ return result;
+}
+
+icalerrorenum icalfileset_commit(icalset* set)
+{
+ char tmp[ICAL_PATH_MAX];
+ char *str;
+ icalcomponent *c;
+ off_t write_size=0;
+ icalfileset *fset = (icalfileset*) set;
+#ifdef _WIN32_WCE
+ wchar_t *wtmp=0;
+ PROCESS_INFORMATION pi;
+#endif
+
+ icalerror_check_arg_re((fset!=0),"set",ICAL_BADARG_ERROR);
+
+ icalerror_check_arg_re((fset->fd>0),"set->fd is invalid",
+ ICAL_INTERNAL_ERROR) ;
+
+ if (fset->changed == 0 ){
+ return ICAL_NO_ERROR;
+ }
+
+ if (fset->options.safe_saves == 1) {
+#ifndef WIN32
+ char *quoted_file = shell_quote(fset->path);
+ snprintf(tmp,ICAL_PATH_MAX,"cp '%s' '%s.bak'",fset->path, fset->path);
+ free(quoted_file);
+#else
+ snprintf(tmp,ICAL_PATH_MAX,"copy %s %s.bak", fset->path, fset->path);
+#endif
+
+#ifndef _WIN32_WCE
+ if(system(tmp) < 0){
+#else
+
+ wtmp = wce_mbtowc(tmp);
+
+ if (CreateProcess (wtmp, L"", NULL, NULL, FALSE, 0, NULL, NULL, NULL,&pi)){
+#endif
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+ }
+#ifdef _WIN32_WCE
+ free(wtmp);
+#endif
+
+ if(lseek(fset->fd, 0, SEEK_SET) < 0){
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ return ICAL_FILE_ERROR;
+ }
+
+ for(c = icalcomponent_get_first_component(fset->cluster,ICAL_ANY_COMPONENT);
+ c != 0;
+ c = icalcomponent_get_next_component(fset->cluster,ICAL_ANY_COMPONENT)){
+ int sz;
+
+ str = icalcomponent_as_ical_string_r(c);
+
+ sz=write(fset->fd,str,strlen(str));
+
+ if ( sz != strlen(str)){
+ perror("write");
+ icalerror_set_errno(ICAL_FILE_ERROR);
+ free(str);
+ return ICAL_FILE_ERROR;
+ }
+
+ free(str);
+ write_size += sz;
+ }
+
+ fset->changed = 0;
+
+#ifndef WIN32
+ if(ftruncate(fset->fd,write_size) < 0){
+ return ICAL_FILE_ERROR;
+ }
+#else
+#ifndef _WIN32_WCE
+ chsize( fset->fd, tell( fset->fd ) );
+#else
+ SetEndOfFile(fset->fd);
+#endif
+#endif
+
+ return ICAL_NO_ERROR;
+}
+
+void icalfileset_mark(icalset* set) {
+ icalerror_check_arg_rv((set!=0),"set");
+
+ ((icalfileset*)set)->changed = 1;
+}
+
+icalcomponent* icalfileset_get_component(icalset* set){
+ icalfileset *fset = (icalfileset*) set;
+ icalerror_check_arg_rz((set!=0),"set");
+
+ return fset->cluster;
+}
+
+
+/* manipulate the components in the set */
+
+icalerrorenum icalfileset_add_component(icalset *set,
+ icalcomponent* child)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_re((set!=0),"set", ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_add_component(fset->cluster,child);
+
+ icalfileset_mark(set);
+
+ return ICAL_NO_ERROR;
+}
+
+icalerrorenum icalfileset_remove_component(icalset *set,
+ icalcomponent* child)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_re((set!=0),"set",ICAL_BADARG_ERROR);
+ icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
+
+ icalcomponent_remove_component(fset->cluster,child);
+
+ icalfileset_mark(set);
+
+ return ICAL_NO_ERROR;
+}
+
+int icalfileset_count_components(icalset *set,
+ icalcomponent_kind kind)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ if (set == 0){
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return -1;
+ }
+
+ return icalcomponent_count_components(fset->cluster,kind);
+}
+
+icalerrorenum icalfileset_select(icalset* set, icalgauge* gauge)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_re(gauge!=0,"gauge",ICAL_BADARG_ERROR);
+
+ fset->gauge = gauge;
+
+ return ICAL_NO_ERROR;
+}
+
+void icalfileset_clear(icalset* set)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_rv(set!=0,"set");
+
+ fset->gauge = 0;
+}
+
+icalcomponent* icalfileset_fetch(icalset* set,const char* uid)
+{
+ icalfileset *fset = (icalfileset*) set;
+ icalcompiter i;
+
+ icalerror_check_arg_rz(set!=0,"set");
+
+ for(i = icalcomponent_begin_component(fset->cluster,ICAL_ANY_COMPONENT);
+ icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
+
+ icalcomponent *this = icalcompiter_deref(&i);
+ icalcomponent *inner;
+ icalproperty *p;
+ const char *this_uid;
+
+ for(inner = icalcomponent_get_first_component(this,ICAL_ANY_COMPONENT);
+ inner != 0;
+ inner = icalcomponent_get_next_component(this,ICAL_ANY_COMPONENT)){
+
+ p = icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY);
+ if ( p )
+ {
+ this_uid = icalproperty_get_uid(p);
+
+ if(this_uid==0){
+ icalerror_warn("icalfileset_fetch found a component with no UID");
+ continue;
+ }
+
+ if (strcmp(uid,this_uid)==0){
+ return this;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int icalfileset_has_uid(icalset* set,const char* uid)
+{
+ assert(0); /* HACK, not implemented */
+ return 0;
+}
+
+/******* support routines for icalfileset_fetch_match *********/
+
+struct icalfileset_id{
+ char* uid;
+ char* recurrence_id;
+ int sequence;
+};
+
+void icalfileset_id_free(struct icalfileset_id *id)
+{
+ if(id->recurrence_id != 0){
+ free(id->recurrence_id);
+ }
+
+ if(id->uid != 0){
+ free(id->uid);
+ }
+}
+
+
+struct icalfileset_id icalfileset_get_id(icalcomponent* comp)
+{
+ icalcomponent *inner;
+ struct icalfileset_id id;
+ icalproperty *p;
+
+ inner = icalcomponent_get_first_real_component(comp);
+
+ p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
+
+ assert(p!= 0);
+
+ id.uid = strdup(icalproperty_get_uid(p));
+
+ p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
+
+ if(p == 0) {
+ id.sequence = 0;
+ } else {
+ id.sequence = icalproperty_get_sequence(p);
+ }
+
+ p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
+
+ if (p == 0){
+ id.recurrence_id = 0;
+ } else {
+ icalvalue *v;
+ v = icalproperty_get_value(p);
+ id.recurrence_id = icalvalue_as_ical_string_r(v);
+
+ assert(id.recurrence_id != 0);
+ }
+
+ return id;
+}
+
+
+/* Find the component that is related to the given
+ component. Currently, it just matches based on UID and
+ RECURRENCE-ID */
+icalcomponent* icalfileset_fetch_match(icalset* set, icalcomponent *comp)
+{
+ icalfileset *fset = (icalfileset*) set;
+ icalcompiter i;
+
+ struct icalfileset_id comp_id, match_id;
+
+ comp_id = icalfileset_get_id(comp);
+
+ for(i = icalcomponent_begin_component(fset->cluster,ICAL_ANY_COMPONENT);
+ icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
+
+ icalcomponent *match = icalcompiter_deref(&i);
+
+ match_id = icalfileset_get_id(match);
+
+ if(strcmp(comp_id.uid, match_id.uid) == 0 &&
+ ( comp_id.recurrence_id ==0 ||
+ strcmp(comp_id.recurrence_id, match_id.recurrence_id) ==0 )){
+
+ /* HACK. What to do with SEQUENCE? */
+
+ icalfileset_id_free(&match_id);
+ icalfileset_id_free(&comp_id);
+ return match;
+
+ }
+
+ icalfileset_id_free(&match_id);
+ }
+
+ icalfileset_id_free(&comp_id);
+ return 0;
+
+}
+
+
+icalerrorenum icalfileset_modify(icalset* set, icalcomponent *old,
+ icalcomponent *new)
+{
+ /* icalfileset *fset = (icalfileset*) set; */
+
+ assert(0); /* HACK, not implemented */
+ return ICAL_NO_ERROR;
+}
+
+
+/* Iterate through components */
+icalcomponent* icalfileset_get_current_component (icalset* set)
+{
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_rz((set!=0),"set");
+
+ return icalcomponent_get_current_component(fset->cluster);
+}
+
+
+icalcomponent* icalfileset_get_first_component(icalset* set)
+{
+ icalcomponent *c=0;
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_rz((set!=0),"set");
+
+ do {
+ if (c == 0){
+ c = icalcomponent_get_first_component(fset->cluster,
+ ICAL_ANY_COMPONENT);
+ } else {
+ c = icalcomponent_get_next_component(fset->cluster,
+ ICAL_ANY_COMPONENT);
+ }
+
+ if(c != 0 && (fset->gauge == 0 ||
+ icalgauge_compare(fset->gauge, c) == 1)){
+ return c;
+ }
+
+ } while(c != 0);
+
+
+ return 0;
+}
+
+icalcomponent* icalfileset_get_next_component(icalset* set)
+{
+ icalfileset *fset = (icalfileset*) set;
+ icalcomponent *c;
+
+ icalerror_check_arg_rz((set!=0),"set");
+
+ do {
+ c = icalcomponent_get_next_component(fset->cluster,
+ ICAL_ANY_COMPONENT);
+
+ if(c != 0 && (fset->gauge == 0 ||
+ icalgauge_compare(fset->gauge,c) == 1)){
+ return c;
+ }
+
+ } while(c != 0);
+
+
+ return 0;
+}
+/*
+icalsetiter icalfileset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge)
+{
+ icalsetiter itr = icalsetiter_null;
+ icalcomponent* comp = NULL;
+ icalcompiter citr;
+ icalfileset *fset = (icalfileset*) set;
+
+ icalerror_check_arg_re((set!=0), "set", icalsetiter_null);
+
+ itr.gauge = gauge;
+
+ citr = icalcomponent_begin_component(fset->cluster, kind);
+ comp = icalcompiter_deref(&citr);
+
+ while (comp != 0) {
+ comp = icalcompiter_deref(&citr);
+ if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
+ itr.iter = citr;
+ return itr;
+ }
+ comp = icalcompiter_next(&citr);
+ }
+
+ return icalsetiter_null;
+}
+*/
+
+icalsetiter icalfileset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge)
+{
+ icalsetiter itr = icalsetiter_null;
+ icalcomponent* comp = NULL;
+ icalcompiter citr;
+ icalfileset *fset = (icalfileset*) set;
+ struct icaltimetype start, next;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ int g = 0;
+
+ icalerror_check_arg_re((set!=0), "set", icalsetiter_null);
+
+ start = icaltime_from_timet( time(0),0);
+ itr.gauge = gauge;
+
+ citr = icalcomponent_begin_component(fset->cluster, kind);
+ comp = icalcompiter_deref(&citr);
+
+ if (gauge == 0) {
+ itr.iter = citr;
+ return itr;
+ }
+
+ while (comp != 0) {
+
+ /* check if it is a recurring component and with guage expand, if so
+ we need to add recurrence-id property to the given component */
+ rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
+ g = icalgauge_get_expand(gauge);
+
+ if (rrule != 0
+ && g == 1) {
+
+ recur = icalproperty_get_rrule(rrule);
+ if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ if (itr.last_component == NULL) {
+ itr.ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(itr.ritr);
+ itr.last_component = comp;
+ }
+ else {
+ next = icalrecur_iterator_next(itr.ritr);
+ if (icaltime_is_null_time(next)){
+ itr.last_component = NULL;
+ icalrecur_iterator_free(itr.ritr);
+ itr.ritr = NULL;
+ return icalsetiter_null;
+ } else {
+ itr.last_component = comp;
+ }
+ }
+
+ /* add recurrence-id to the component
+ if there is a recurrence-id already, remove it, then add the new one */
+ prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
+ if (prop)
+ icalcomponent_remove_property(comp, prop);
+ icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
+
+ }
+
+ if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
+ /* matches and returns */
+ itr.iter = citr;
+ return itr;
+ }
+
+ /* if there is no previous component pending, then get the next component */
+ if (itr.last_component == NULL)
+ comp = icalcompiter_next(&citr);
+ }
+
+ return icalsetiter_null;
+}
+icalcomponent* icalfileset_form_a_matched_recurrence_component(icalsetiter* itr)
+{
+ icalcomponent* comp = NULL;
+ struct icaltimetype start, next;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+
+ start = icaltime_from_timet( time(0),0);
+ comp = itr->last_component;
+
+ if (comp == NULL || itr->gauge == NULL) {
+ return NULL;
+ }
+
+ rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
+
+ recur = icalproperty_get_rrule(rrule);
+
+ if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ if (itr->ritr == NULL) {
+ itr->ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(itr->ritr);
+ itr->last_component = comp;
+ } else {
+ next = icalrecur_iterator_next(itr->ritr);
+ if (icaltime_is_null_time(next)){
+ /* no more recurrence, returns */
+ itr->last_component = NULL;
+ icalrecur_iterator_free(itr->ritr);
+ itr->ritr = NULL;
+ return NULL;
+ } else {
+ itr->last_component = comp;
+ }
+ }
+
+ /* add recurrence-id to the component
+ * if there is a recurrence-id already, remove it, then add the new one */
+ prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
+ if (prop)
+ icalcomponent_remove_property(comp, prop);
+ icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
+
+ if (itr->gauge == 0 || icalgauge_compare(itr->gauge, comp) == 1) {
+ /* matches and returns */
+ return comp;
+ }
+ /* not matched */
+ return NULL;
+
+}
+icalcomponent* icalfilesetiter_to_next(icalset* set, icalsetiter* i)
+{
+
+ icalcomponent* c = NULL;
+ /* icalfileset *fset = (icalfileset*) set; */
+ struct icaltimetype start, next;
+ icalproperty *dtstart, *rrule, *prop, *due;
+ struct icalrecurrencetype recur;
+ int g = 0;
+
+ start = icaltime_from_timet( time(0),0);
+ next = icaltime_from_timet( time(0),0);
+
+ do {
+ c = icalcompiter_next(&(i->iter));
+
+ if (c == 0) continue;
+ if (i->gauge == 0) return c;
+
+
+ rrule = icalcomponent_get_first_property(c, ICAL_RRULE_PROPERTY);
+ g = icalgauge_get_expand(i->gauge);
+
+ /* a recurring component with expand query */
+ if (rrule != 0
+ && g == 1) {
+
+ recur = icalproperty_get_rrule(rrule);
+
+ if (icalcomponent_isa(c) == ICAL_VEVENT_COMPONENT) {
+ dtstart = icalcomponent_get_first_property(c, ICAL_DTSTART_PROPERTY);
+ if (dtstart)
+ start = icalproperty_get_dtstart(dtstart);
+ } else if (icalcomponent_isa(c) == ICAL_VTODO_COMPONENT) {
+ due = icalcomponent_get_first_property(c, ICAL_DUE_PROPERTY);
+ if (due)
+ start = icalproperty_get_due(due);
+ }
+
+ if (i->ritr == NULL) {
+ i->ritr = icalrecur_iterator_new(recur, start);
+ next = icalrecur_iterator_next(i->ritr);
+ i->last_component = c;
+ } else {
+ next = icalrecur_iterator_next(i->ritr);
+ if (icaltime_is_null_time(next)) {
+ /* no more recurrence, returns */
+ i->last_component = NULL;
+ icalrecur_iterator_free(i->ritr);
+ i->ritr = NULL;
+ return NULL;
+ } else {
+ i->last_component = c;
+ }
+ }
+ }
+
+ /* add recurrence-id to the component
+ * if there is a recurrence-id already, remove it, then add the new one */
+ prop = icalcomponent_get_first_property(c, ICAL_RECURRENCEID_PROPERTY);
+ if (prop)
+ icalcomponent_remove_property(c, prop);
+ icalcomponent_add_property(c, icalproperty_new_recurrenceid(next));
+
+ if(c != 0 && (i->gauge == 0 ||
+ icalgauge_compare(i->gauge, c) == 1)){
+ return c;
+ }
+ } while (c != 0);
+
+ return 0;
+
+}
diff --git a/src/libicalss/icalfileset.h b/src/libicalss/icalfileset.h
new file mode 100644
index 00000000..c95c70fa
--- /dev/null
+++ b/src/libicalss/icalfileset.h
@@ -0,0 +1,132 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalfileset.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalfileset.h,v 1.15 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALFILESET_H
+#define ICALFILESET_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+#include "icalcluster.h"
+#include "icalgauge.h"
+#include <sys/types.h> /* For open() flags and mode */
+#include <sys/stat.h> /* For open() flags and mode */
+#include <fcntl.h> /* For open() flags and mode */
+
+#ifdef WIN32
+#define mode_t int
+#endif
+
+typedef struct icalfileset_impl icalfileset;
+
+icalset* icalfileset_new(const char* path);
+icalset* icalfileset_new_reader(const char* path);
+icalset* icalfileset_new_writer(const char* path);
+
+icalset* icalfileset_init(icalset *set, const char *dsn, void* options);
+
+icalfileset* icalfileset_new_from_cluster(const char* path, icalcluster *cluster);
+
+icalcluster* icalfileset_produce_icalcluster(const char *path);
+
+void icalfileset_free(icalset* cluster);
+
+const char* icalfileset_path(icalset* cluster);
+
+/* Mark the cluster as changed, so it will be written to disk when it
+ is freed. Commit writes to disk immediately. */
+void icalfileset_mark(icalset* set);
+icalerrorenum icalfileset_commit(icalset* set);
+
+icalerrorenum icalfileset_add_component(icalset* set,
+ icalcomponent* child);
+
+icalerrorenum icalfileset_remove_component(icalset* set,
+ icalcomponent* child);
+
+int icalfileset_count_components(icalset* set,
+ icalcomponent_kind kind);
+
+/**
+ * Restrict the component returned by icalfileset_first, _next to those
+ * that pass the gauge. _clear removes the gauge
+ */
+icalerrorenum icalfileset_select(icalset* set, icalgauge* gauge);
+
+/** clear the gauge **/
+void icalfileset_clear(icalset* set);
+
+/** Get and search for a component by uid **/
+icalcomponent* icalfileset_fetch(icalset* set, const char* uid);
+int icalfileset_has_uid(icalset* set, const char* uid);
+icalcomponent* icalfileset_fetch_match(icalset* set, icalcomponent *c);
+
+
+/**
+ * Modify components according to the MODIFY method of CAP. Works on the
+ * currently selected components.
+ */
+icalerrorenum icalfileset_modify(icalset* set,
+ icalcomponent *oldcomp,
+ icalcomponent *newcomp);
+
+/* Iterate through components. If a gauge has been defined, these
+ will skip over components that do not pass the gauge */
+
+icalcomponent* icalfileset_get_current_component (icalset* cluster);
+icalcomponent* icalfileset_get_first_component(icalset* cluster);
+icalcomponent* icalfileset_get_next_component(icalset* cluster);
+
+/* External iterator for thread safety */
+icalsetiter icalfileset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge);
+icalcomponent * icalfilesetiter_to_next(icalset* set, icalsetiter *iter);
+icalcomponent* icalfileset_form_a_matched_recurrence_component(icalsetiter* itr);
+
+/** Return a reference to the internal component. You probably should
+ not be using this. */
+
+icalcomponent* icalfileset_get_component(icalset* cluster);
+
+/**
+ * @brief options for opening an icalfileset.
+ *
+ * These options should be passed to the icalset_new() function
+ */
+
+typedef struct icalfileset_options {
+ int flags; /**< flags for open() O_RDONLY, etc */
+ mode_t mode; /**< file mode */
+ int safe_saves; /**< to lock or not */
+ icalcluster *cluster; /**< use this cluster to initialize data */
+} icalfileset_options;
+
+extern icalfileset_options icalfileset_options_default;
+
+#endif /* !ICALFILESET_H */
+
+
+
diff --git a/src/libicalss/icalfilesetimpl.h b/src/libicalss/icalfilesetimpl.h
new file mode 100644
index 00000000..3eccf7cd
--- /dev/null
+++ b/src/libicalss/icalfilesetimpl.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalfilesetimpl.h
+ CREATOR: eric 23 December 1999
+
+ $Id: icalfilesetimpl.h,v 1.7 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+ ======================================================================*/
+
+#ifndef ICALFILESETIMPL_H
+#define ICALFILESETIMPL_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libicalss/icalgauge.h>
+
+/* This definition is in its own file so it can be kept out of the
+ main header file, but used by "friend classes" like icaldirset*/
+
+#define ICALFILESET_ID "fset"
+
+struct icalfileset_impl {
+ icalset super; /**< parent class */
+ char *path; /**< pathname of file */
+ icalfileset_options options; /**< copy of options passed to icalset_new() */
+
+ icalcomponent* cluster; /**< cluster containing data */
+ icalgauge* gauge; /**< gauge for filtering out data */
+ int changed; /**< boolean flag, 1 if data has changed */
+ int fd; /**< file descriptor */
+};
+
+#endif
diff --git a/src/libicalss/icalgauge.c b/src/libicalss/icalgauge.c
new file mode 100644
index 00000000..64ef1aea
--- /dev/null
+++ b/src/libicalss/icalgauge.c
@@ -0,0 +1,524 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalgauge.c
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalgauge.c,v 1.15 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#include <libical/ical.h>
+#include "icalgauge.h"
+#include "icalgaugeimpl.h"
+#include <stdlib.h>
+
+#include "icalssyacc.h"
+
+int ssparse(void);
+
+extern char *input_buffer;
+extern char *input_buffer_p;
+
+struct icalgauge_impl *icalss_yy_gauge;
+
+icalgauge* icalgauge_new_from_sql(char* sql, int expand)
+{
+ struct icalgauge_impl *impl;
+ int r;
+
+ if ( ( impl = (struct icalgauge_impl*)
+ malloc(sizeof(struct icalgauge_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ impl->select = pvl_newlist();
+ impl->from = pvl_newlist();
+ impl->where = pvl_newlist();
+ impl->expand = expand;
+
+ icalss_yy_gauge = impl;
+ input_buffer = input_buffer_p = sql;
+
+ r = ssparse();
+
+ if (r == 0) {
+ return impl;
+ }
+ else {
+ icalgauge_free(impl);
+ return NULL;
+ }
+}
+
+int icalgauge_get_expand(icalgauge* gauge)
+{
+return (gauge->expand);
+
+}
+
+void icalgauge_free(icalgauge* gauge)
+{
+ struct icalgauge_where *w;
+
+ assert(gauge->select != 0);
+ assert(gauge->where != 0);
+ assert(gauge->from != 0);
+
+ if(gauge->select){
+ while( (w=pvl_pop(gauge->select)) != 0){
+ if(w->value != 0){
+ free(w->value);
+ }
+ free(w);
+ }
+ pvl_free(gauge->select);
+ gauge->select = 0;
+ }
+
+ if(gauge->where){
+ while( (w=pvl_pop(gauge->where)) != 0){
+
+ if(w->value != 0){
+ free(w->value);
+ }
+ free(w);
+ }
+ pvl_free(gauge->where);
+ gauge->where = 0;
+ }
+
+ if(gauge->from){
+ pvl_free(gauge->from);
+ gauge->from = 0;
+ }
+
+ free(gauge);
+
+}
+
+
+/** Convert a VQUERY component into a gauge */
+icalcomponent* icalgauge_make_gauge(icalcomponent* query);
+
+/**
+ icaldirset_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 gauge 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 properties 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
+ DTSTART;X-LIC-COMPARETYPE=LESS:19981025T020000
+ ORGANIZER;X-LIC-COMPARETYPE=EQUAL:mrbig@host.com
+ END:XROOT
+ BEGIN:XROOT
+ LOCATION;X-LIC-COMPARETYPE=EQUAL:McNary's Pub
+ 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 icalgauge_compare_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
+ icaldirset_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 = icalgauge_compare_recurse(child,subgauge);
+ pass = pass && localpass;
+ } else {
+ pass = 0;
+ }
+ }
+
+ return pass;
+}
+
+
+int icalgauge_compare(icalgauge* gauge,icalcomponent* comp)
+{
+
+ icalcomponent *inner;
+ int local_pass = 0;
+ int last_clause = 1, this_clause = 1;
+ pvl_elem e;
+ icalcomponent_kind kind;
+ icalproperty *rrule;
+ int compare_recur = 0;
+
+
+ icalerror_check_arg_rz( (comp!=0), "comp");
+ icalerror_check_arg_rz( (gauge!=0), "gauge");
+
+ inner = icalcomponent_get_first_real_component(comp);
+
+ if(inner == 0){
+ /* Wally Yau: our component is not always wrapped with
+ * a <VCALENDAR>. It's not an error.
+ * icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+ * return 0; */
+ kind = icalcomponent_isa(comp);
+ if(kind == ICAL_VEVENT_COMPONENT ||
+ kind == ICAL_VTODO_COMPONENT ||
+ kind == ICAL_VJOURNAL_COMPONENT ||
+ kind == ICAL_VQUERY_COMPONENT ||
+ kind == ICAL_VAGENDA_COMPONENT){
+ inner = comp;
+ }
+ else {
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+ return 0;
+ }
+ inner = comp;
+ }
+
+ /* Check that this component is one of the FROM types */
+ local_pass = 0;
+ for(e = pvl_head(gauge->from);e!=0;e=pvl_next(e)){
+ icalcomponent_kind k = (icalcomponent_kind)pvl_data(e);
+
+ if(k == icalcomponent_isa(inner)){
+ local_pass=1;
+ }
+ }
+
+ if(local_pass == 0){
+ return 0;
+ }
+
+
+ /**** Check each where clause against the component ****/
+ for(e = pvl_head(gauge->where);e!=0;e=pvl_next(e)){
+ struct icalgauge_where *w = pvl_data(e);
+ icalcomponent *sub_comp;
+ icalvalue *v;
+ icalproperty *prop;
+ icalvalue_kind vk;
+
+ if(w->prop == ICAL_NO_PROPERTY || w->value == 0){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* First, create a value from the gauge */
+ vk = icalenum_property_kind_to_value_kind(w->prop);
+
+ if(vk == ICAL_NO_VALUE){
+ icalerror_set_errno(ICAL_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (w->compare == ICALGAUGECOMPARE_ISNULL || w->compare == ICALGAUGECOMPARE_ISNOTNULL)
+ v = icalvalue_new(vk);
+ else
+ v = icalvalue_new_from_string(vk,w->value);
+
+ if (v == 0){
+ /* Keep error set by icalvalue_from-string*/
+ return 0;
+ }
+
+ /* Now find the corresponding property in the component,
+ descending into a sub-component if necessary */
+
+ if(w->comp == ICAL_NO_COMPONENT){
+ sub_comp = inner;
+ } else {
+ sub_comp = icalcomponent_get_first_component(inner,w->comp);
+ if(sub_comp == 0){
+ icalvalue_free(v);
+ return 0;
+ }
+ }
+
+ /* check if it is a recurring */
+ rrule = icalcomponent_get_first_property(sub_comp,ICAL_RRULE_PROPERTY);
+
+ if (gauge->expand
+ && rrule) {
+
+ if (w->prop == ICAL_DTSTART_PROPERTY ||
+ w->prop == ICAL_DTEND_PROPERTY ||
+ w->prop == ICAL_DUE_PROPERTY){
+ /** needs to use recurrence-id to do comparison */
+ compare_recur = 1;
+ }
+
+ }
+
+
+ this_clause = 0;
+ local_pass = (w->compare == ICALGAUGECOMPARE_ISNULL) ? 1 : 0;
+
+ for(prop = icalcomponent_get_first_property(sub_comp,w->prop);
+ prop != 0;
+ prop = icalcomponent_get_next_property(sub_comp,w->prop)){
+ icalvalue* prop_value;
+ icalgaugecompare relation;
+
+ if (w->compare == ICALGAUGECOMPARE_ISNULL) {
+ local_pass = 0;
+ break;
+ }
+
+ if (w->compare == ICALGAUGECOMPARE_ISNOTNULL) {
+ local_pass = 1;
+ break;
+ }
+
+ if (compare_recur) {
+ icalproperty *p = icalcomponent_get_first_property(sub_comp, ICAL_RECURRENCEID_PROPERTY);
+ prop_value = icalproperty_get_value(p);
+ }
+ else /* prop value from this component */
+ prop_value = icalproperty_get_value(prop);
+
+ relation = (icalgaugecompare)icalvalue_compare(prop_value,v);
+
+ if (relation == w->compare){
+ local_pass++;
+ } else if (w->compare == ICALGAUGECOMPARE_LESSEQUAL &&
+ ( relation == ICALGAUGECOMPARE_LESS ||
+ relation == ICALGAUGECOMPARE_EQUAL)) {
+ local_pass++;
+ } else if (w->compare == ICALGAUGECOMPARE_GREATEREQUAL &&
+ ( relation == ICALGAUGECOMPARE_GREATER ||
+ relation == ICALGAUGECOMPARE_EQUAL)) {
+ local_pass++;
+ } else if (w->compare == ICALGAUGECOMPARE_NOTEQUAL &&
+ ( relation == ICALGAUGECOMPARE_GREATER ||
+ relation == ICALGAUGECOMPARE_LESS)) {
+ local_pass++;
+ } else {
+ local_pass = 0;
+ }
+ }
+
+
+ this_clause = local_pass > 0 ? 1 : 0;
+
+
+ /* Now look at the logic operator for this clause to see how
+ the value should be merge with the previous clause */
+
+ if(w->logic == ICALGAUGELOGIC_AND){
+ last_clause = this_clause && last_clause;
+ } else if(w->logic == ICALGAUGELOGIC_OR) {
+ last_clause = this_clause || last_clause;
+ } else {
+ last_clause = this_clause;
+ }
+
+ icalvalue_free(v);
+
+ }/**** check next one in where clause ****/
+
+ return last_clause;
+
+}
+
+/** @brief Debug
+ * Print gauge information to stdout.
+ */
+
+void icalgauge_dump(icalgauge* gauge)
+{
+
+ pvl_elem p;
+
+ printf("--- Select ---\n");
+ for(p = pvl_head(gauge->select);p!=0;p=pvl_next(p)){
+ struct icalgauge_where *w = pvl_data(p);
+
+ if(w->comp != ICAL_NO_COMPONENT){
+ printf("%s ",icalenum_component_kind_to_string(w->comp));
+ }
+
+ if(w->prop != ICAL_NO_PROPERTY){
+ printf("%s ",icalenum_property_kind_to_string(w->prop));
+ }
+
+ if (w->compare != ICALGAUGECOMPARE_NONE){
+ printf("%d ",w->compare);
+ }
+
+
+ if (w->value!=0){
+ printf("%s",w->value);
+ }
+
+
+ printf("\n");
+ }
+
+ printf("--- From ---\n");
+ for(p = pvl_head(gauge->from);p!=0;p=pvl_next(p)){
+ icalcomponent_kind k = (icalcomponent_kind)pvl_data(p);
+
+ printf("%s\n",icalenum_component_kind_to_string(k));
+ }
+
+ printf("--- Where ---\n");
+ for(p = pvl_head(gauge->where);p!=0;p=pvl_next(p)){
+ struct icalgauge_where *w = pvl_data(p);
+
+ if(w->logic != ICALGAUGELOGIC_NONE){
+ printf("%d ",w->logic);
+ }
+
+ if(w->comp != ICAL_NO_COMPONENT){
+ printf("%s ",icalenum_component_kind_to_string(w->comp));
+ }
+
+ if(w->prop != ICAL_NO_PROPERTY){
+ printf("%s ",icalenum_property_kind_to_string(w->prop));
+ }
+
+ if (w->compare != ICALGAUGECOMPARE_NONE){
+ printf("%d ",w->compare);
+ }
+
+
+ if (w->value!=0){
+ printf("%s",w->value);
+ }
+
+
+ printf("\n");
+ }
+}
+
diff --git a/src/libicalss/icalgauge.h b/src/libicalss/icalgauge.h
new file mode 100644
index 00000000..a2f5b7bb
--- /dev/null
+++ b/src/libicalss/icalgauge.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalgauge.h
+ CREATOR: eric 23 December 1999
+
+
+ $Id: icalgauge.h,v 1.6 2008-01-02 20:07:40 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALGAUGE_H
+#define ICALGAUGE_H
+
+#include "icalcomponent.h"
+
+/** @file icalgauge.h
+ * @brief Routines implementing a filter for ical components
+ */
+
+typedef struct icalgauge_impl icalgauge;
+
+icalgauge* icalgauge_new_from_sql(char* sql, int expand);
+
+int icalgauge_get_expand(icalgauge* gauge);
+
+void icalgauge_free(icalgauge* gauge);
+
+char* icalgauge_as_sql(icalcomponent* gauge);
+
+void icalgauge_dump(icalgauge* gauge);
+
+
+/** @brief Return true if comp matches the gauge.
+ *
+ * The component must be in
+ * cannonical form -- a VCALENDAR with one VEVENT, VTODO or VJOURNAL
+ * sub component
+ */
+int icalgauge_compare(icalgauge* g, icalcomponent* comp);
+
+/** Clone the component, but only return the properties
+ * specified in the gauge */
+icalcomponent* icalgauge_new_clone(icalgauge* g, icalcomponent* comp);
+
+#endif /* ICALGAUGE_H*/
diff --git a/src/libicalss/icalgaugeimpl.h b/src/libicalss/icalgaugeimpl.h
new file mode 100644
index 00000000..660a2032
--- /dev/null
+++ b/src/libicalss/icalgaugeimpl.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalgaugeimpl.h
+ CREATOR: eric 09 Aug 2000
+
+
+ $Id: icalgaugeimpl.h,v 1.8 2008-01-02 20:07:41 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+======================================================================*/
+
+#include <libical/ical.h>
+
+typedef enum icalgaugecompare {
+ ICALGAUGECOMPARE_EQUAL=ICAL_XLICCOMPARETYPE_EQUAL,
+ ICALGAUGECOMPARE_LESS=ICAL_XLICCOMPARETYPE_LESS,
+ ICALGAUGECOMPARE_LESSEQUAL=ICAL_XLICCOMPARETYPE_LESSEQUAL,
+ ICALGAUGECOMPARE_GREATER=ICAL_XLICCOMPARETYPE_GREATER,
+ ICALGAUGECOMPARE_GREATEREQUAL=ICAL_XLICCOMPARETYPE_GREATEREQUAL,
+ ICALGAUGECOMPARE_NOTEQUAL=ICAL_XLICCOMPARETYPE_NOTEQUAL,
+ ICALGAUGECOMPARE_REGEX=ICAL_XLICCOMPARETYPE_REGEX,
+ ICALGAUGECOMPARE_ISNULL=ICAL_XLICCOMPARETYPE_ISNULL,
+ ICALGAUGECOMPARE_ISNOTNULL=ICAL_XLICCOMPARETYPE_ISNOTNULL,
+ ICALGAUGECOMPARE_NONE=0
+} icalgaugecompare;
+
+typedef enum icalgaugelogic {
+ ICALGAUGELOGIC_NONE,
+ ICALGAUGELOGIC_AND,
+ ICALGAUGELOGIC_OR
+} icalgaugelogic;
+
+
+struct icalgauge_where {
+ icalgaugelogic logic;
+ icalcomponent_kind comp;
+ icalproperty_kind prop;
+ icalgaugecompare compare;
+ char* value;
+};
+
+struct icalgauge_impl
+{
+ pvl_list select; /**< Of icalgaugecompare, using only prop and comp fields*/
+ pvl_list from; /**< List of component_kinds, as integers */
+ pvl_list where; /**< List of icalgaugecompare */
+ int expand;
+};
+
+
diff --git a/src/libicalss/icalmessage.c b/src/libicalss/icalmessage.c
new file mode 100644
index 00000000..9c99452f
--- /dev/null
+++ b/src/libicalss/icalmessage.c
@@ -0,0 +1,387 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalmessage.c
+ CREATOR: ebusboom 07 Nov 2000
+
+ $Id: icalmessage.c,v 1.9 2008-01-02 20:07:41 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "icalmessage.h"
+#include <libical/icalenums.h>
+#include <ctype.h> /* for tolower()*/
+#include <string.h> /* for strstr */
+#include <stdlib.h> /* for free(), malloc() */
+
+#if defined(_MSC_VER)
+#define snprintf _snprintf
+#endif
+
+icalcomponent* icalmessage_get_inner(icalcomponent* comp)
+{
+ if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){
+ return icalcomponent_get_first_real_component(comp);
+ } else {
+ return comp;
+ }
+}
+
+static char* lowercase(const char* str)
+{
+ char* p = 0;
+ char* n = 0;
+
+ if(str ==0){
+ return 0;
+ }
+
+ n = icalmemory_strdup(str);
+
+ for(p = n; *p!=0; p++){
+ *p = tolower(*p);
+ }
+
+ return n;
+}
+
+icalproperty* icalmessage_find_attendee(icalcomponent* comp, const char* user)
+{
+ icalcomponent *inner = icalmessage_get_inner(comp);
+ icalproperty *p,*attendee = 0;
+ char* luser = lowercase(user);
+
+ for(p = icalcomponent_get_first_property(inner, ICAL_ATTENDEE_PROPERTY);
+ p != 0;
+ p = icalcomponent_get_next_property(inner, ICAL_ATTENDEE_PROPERTY)
+ ){
+
+ char* lattendee;
+
+ lattendee = lowercase(icalproperty_get_attendee(p));
+
+ if (strstr(lattendee,user) != 0){
+ free(lattendee);
+ attendee = p;
+ break;
+ }
+
+ free(lattendee);
+
+ }
+
+ free(luser);
+
+ return attendee;
+
+}
+
+void icalmessage_copy_properties(icalcomponent* to, icalcomponent* from,
+ icalproperty_kind kind)
+{
+ icalcomponent *to_inner = icalmessage_get_inner(to);
+ icalcomponent *from_inner = icalmessage_get_inner(from);
+
+ if (to_inner == 0 && from_inner == 0){
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+ return;
+ }
+
+ if(!icalcomponent_get_first_property(from_inner,kind)){
+ return;
+ }
+
+ icalcomponent_add_property(to_inner,
+ icalproperty_new_clone(
+ icalcomponent_get_first_property(
+ from_inner,
+ kind)
+ )
+ );
+}
+
+icalcomponent *icalmessage_new_reply_base(icalcomponent* c,
+ const char* user,
+ const char* msg)
+{
+ icalproperty *attendee;
+ char tmp[45];
+
+ icalcomponent *reply = icalcomponent_vanew(
+ ICAL_VCALENDAR_COMPONENT,
+ icalproperty_new_method(ICAL_METHOD_REPLY),
+ icalcomponent_vanew(
+ ICAL_VEVENT_COMPONENT,
+ icalproperty_new_dtstamp(icaltime_from_timet(time(0),0)),
+ 0),
+ 0);
+
+ icalcomponent *inner = icalmessage_get_inner(reply);
+
+ icalerror_check_arg_rz(c,"c");
+
+ icalmessage_copy_properties(reply,c,ICAL_UID_PROPERTY);
+ icalmessage_copy_properties(reply,c,ICAL_ORGANIZER_PROPERTY);
+ icalmessage_copy_properties(reply,c,ICAL_RECURRENCEID_PROPERTY);
+ icalmessage_copy_properties(reply,c,ICAL_SUMMARY_PROPERTY);
+ icalmessage_copy_properties(reply,c,ICAL_SEQUENCE_PROPERTY);
+
+ icalcomponent_set_dtstamp(reply,icaltime_from_timet(time(0),0));
+
+ if(msg != 0){
+ icalcomponent_add_property(inner,icalproperty_new_comment(msg));
+ }
+
+ /* Copy this user's attendee property */
+
+ attendee = icalmessage_find_attendee(c,user);
+
+ if (attendee == 0){
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+ icalcomponent_free(reply);
+ return 0;
+ }
+
+ icalcomponent_add_property(inner,icalproperty_new_clone(attendee));
+
+ /* Add PRODID and VERSION */
+
+ icalcomponent_add_property(reply,icalproperty_new_version("2.0"));
+
+#ifndef WIN32
+ snprintf(tmp,sizeof(tmp),
+ "-//SoftwareStudio//NONSGML %s %s //EN",PACKAGE,VERSION);
+#else
+ snprintf(tmp,sizeof(tmp),
+ "-//SoftwareStudio//NONSGML %s %s //EN",ICAL_PACKAGE,ICAL_VERSION);
+#endif
+ icalcomponent_add_property(reply,icalproperty_new_prodid(tmp));
+
+ return reply;
+
+}
+
+icalcomponent* icalmessage_new_accept_reply(icalcomponent* c,
+ const char* user,
+ const char* msg)
+{
+
+ icalcomponent *reply;
+ icalproperty *attendee;
+ icalcomponent *inner;
+
+ icalerror_check_arg_rz(c,"c");
+
+ reply = icalmessage_new_reply_base(c,user,msg);
+
+ if(reply == 0){
+ return 0;
+ }
+
+ inner = icalmessage_get_inner(reply);
+
+ attendee = icalcomponent_get_first_property(inner,
+ ICAL_ATTENDEE_PROPERTY);
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_partstat(ICAL_PARTSTAT_ACCEPTED));
+
+ return reply;
+}
+
+icalcomponent* icalmessage_new_decline_reply(icalcomponent* c,
+ const char* user,
+ const char* msg)
+{
+ icalcomponent *reply;
+ icalproperty *attendee;
+ icalcomponent *inner;
+
+ icalerror_check_arg_rz(c,"c");
+
+ reply = icalmessage_new_reply_base(c,user,msg);
+ inner = icalmessage_get_inner(reply);
+ if(reply == 0){
+ return 0;
+ }
+
+ attendee = icalcomponent_get_first_property(inner,
+ ICAL_ATTENDEE_PROPERTY);
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_partstat(ICAL_PARTSTAT_DECLINED));
+
+ return reply;
+}
+
+/* New is modified version of old */
+icalcomponent* icalmessage_new_counterpropose_reply(icalcomponent* oldc,
+ icalcomponent* newc,
+ const char* user,
+ const char* msg)
+{
+ icalcomponent *reply;
+
+ icalerror_check_arg_rz(oldc,"oldc");
+ icalerror_check_arg_rz(newc,"newc");
+
+ reply = icalmessage_new_reply_base(newc,user,msg);
+
+ icalcomponent_set_method(reply,ICAL_METHOD_COUNTER);
+
+ return reply;
+
+}
+
+
+icalcomponent* icalmessage_new_delegate_reply(icalcomponent* c,
+ const char* user,
+ const char* delegatee,
+ const char* msg)
+{
+
+ icalcomponent *reply;
+ icalproperty *attendee;
+ icalcomponent *inner;
+
+ icalerror_check_arg_rz(c,"c");
+
+ reply = icalmessage_new_reply_base(c,user,msg);
+ inner = icalmessage_get_inner(reply);
+ if(reply == 0){
+ return 0;
+ }
+
+ attendee = icalcomponent_get_first_property(inner,
+ ICAL_ATTENDEE_PROPERTY);
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_partstat(ICAL_PARTSTAT_DELEGATED));
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_delegatedto(delegatee));
+
+ return reply;
+
+}
+
+icalcomponent* icalmessage_new_delegate_request(icalcomponent* c,
+ const char* user,
+ const char* delegatee,
+ const char* msg)
+{
+
+ icalcomponent *reply;
+ icalproperty *attendee;
+ icalcomponent *inner;
+
+ icalerror_check_arg_rz(c,"c");
+
+ reply = icalmessage_new_reply_base(c,user,msg);
+ inner = icalmessage_get_inner(reply);
+
+ if(reply == 0){
+ return 0;
+ }
+
+ icalcomponent_set_method(reply,ICAL_METHOD_REQUEST);
+
+ attendee = icalcomponent_get_first_property(inner,
+ ICAL_ATTENDEE_PROPERTY);
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_partstat(ICAL_PARTSTAT_DELEGATED));
+
+ icalproperty_set_parameter(attendee,
+ icalparameter_new_delegatedto(delegatee));
+
+ icalcomponent_add_property(
+ inner,
+ icalproperty_vanew_attendee(
+ delegatee,
+ icalparameter_new_delegatedfrom(
+ icalproperty_get_attendee(attendee)
+ ),
+ 0
+ )
+ );
+
+
+ return reply;
+
+}
+
+
+icalcomponent* icalmessage_new_cancel_event(icalcomponent* c,
+ const char* user,
+ const char* msg);
+icalcomponent* icalmessage_new_cancel_instance(icalcomponent* c,
+ const char* user,
+ const char* msg);
+icalcomponent* icalmessage_new_cancel_all(icalcomponent* c,
+ const char* user,
+ const char* msg);
+
+
+
+icalcomponent* icalmessage_new_error_reply(icalcomponent* c,
+ const char* user,
+ const char* msg,
+ const char* debug,
+ icalrequeststatus code)
+{
+ icalcomponent *reply;
+ icalcomponent *inner, *cinner;
+ struct icalreqstattype rs;
+
+ icalerror_check_arg_rz(c,"c");
+
+ memset(&rs, 0, sizeof(struct icalreqstattype));
+ reply = icalmessage_new_reply_base(c,user,msg);
+ inner = icalmessage_get_inner(reply);
+ cinner = icalmessage_get_inner(c);
+ if(reply == 0){
+ return 0;
+ }
+
+ if( code != ICAL_UNKNOWN_STATUS){
+ rs.code = code;
+ rs.debug = debug;
+
+ icalcomponent_add_property(inner,
+ icalproperty_new_requeststatus(rs));
+ } else { /* code == ICAL_UNKNOWN_STATUS */
+
+ /* Copy all of the request status properties */
+ icalproperty *p;
+ for(p = icalcomponent_get_first_property(cinner,
+ ICAL_REQUESTSTATUS_PROPERTY);
+ p != 0;
+ p = icalcomponent_get_next_property(cinner,
+ ICAL_REQUESTSTATUS_PROPERTY)){
+
+
+ icalcomponent_add_property(inner,icalproperty_new_clone(p));
+ }
+ }
+
+ return reply;
+}
diff --git a/src/libicalss/icalmessage.h b/src/libicalss/icalmessage.h
new file mode 100644
index 00000000..5b541730
--- /dev/null
+++ b/src/libicalss/icalmessage.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalmessage.h
+ CREATOR: eric 07 Nov 2000
+
+
+ $Id: icalmessage.h,v 1.3 2008-01-02 20:07:41 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ =========================================================================*/
+
+#include <libical/ical.h>
+
+#ifndef ICALMESSAGE_H
+#define ICALMESSAGE_H
+
+
+icalcomponent* icalmessage_new_accept_reply(icalcomponent* c,
+ const char* user,
+ const char* msg);
+
+icalcomponent* icalmessage_new_decline_reply(icalcomponent* c,
+ const char* user,
+ const char* msg);
+
+/* New is modified version of old */
+icalcomponent* icalmessage_new_counterpropose_reply(icalcomponent* oldc,
+ icalcomponent* newc,
+ const char* user,
+ const char* msg);
+
+
+icalcomponent* icalmessage_new_delegate_reply(icalcomponent* c,
+ const char* user,
+ const char* delegatee,
+ const char* msg);
+
+
+icalcomponent* icalmessage_new_cancel_event(icalcomponent* c,
+ const char* user,
+ const char* msg);
+icalcomponent* icalmessage_new_cancel_instance(icalcomponent* c,
+ const char* user,
+ const char* msg);
+icalcomponent* icalmessage_new_cancel_all(icalcomponent* c,
+ const char* user,
+ const char* msg);
+
+
+icalcomponent* icalmessage_new_error_reply(icalcomponent* c,
+ const char* user,
+ const char* msg,
+ const char* debug,
+ icalrequeststatus rs);
+
+
+#endif /* ICALMESSAGE_H*/
diff --git a/src/libicalss/icalset.c b/src/libicalss/icalset.c
new file mode 100644
index 00000000..cd38033b
--- /dev/null
+++ b/src/libicalss/icalset.c
@@ -0,0 +1,493 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalset.c
+ CREATOR: eric 17 Jul 2000
+
+
+ Icalset is the "base class" for representations of a collection of
+ iCal components. Derived classes (actually delegates) include:
+
+ icalfileset Store components in a single file
+ icaldirset Store components in multiple files in a directory
+ icalheapset Store components on the heap
+ icalmysqlset Store components in a mysql database.
+
+ $Id: icalset.c,v 1.18 2008-01-02 20:07:41 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalset.h"
+#include "icalfileset.h"
+#include "icalfilesetimpl.h"
+#include "icaldirset.h"
+#include "icaldirsetimpl.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef WITH_BDB4
+#include "icalbdbset.h"
+#include "icalbdbsetimpl.h"
+#endif
+
+/* #define _DLOPEN_TEST */
+#ifdef _DLOPEN_TEST
+#include <sys/types.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#endif
+
+static icalset icalset_dirset_init = {
+ ICAL_DIR_SET,
+ sizeof(icaldirset),
+ NULL,
+ icaldirset_init,
+ icaldirset_free,
+ icaldirset_path,
+ icaldirset_mark,
+ icaldirset_commit,
+ icaldirset_add_component,
+ icaldirset_remove_component,
+ icaldirset_count_components,
+ icaldirset_select,
+ icaldirset_clear,
+ icaldirset_fetch,
+ icaldirset_fetch_match,
+ icaldirset_has_uid,
+ icaldirset_modify,
+ icaldirset_get_current_component,
+ icaldirset_get_first_component,
+ icaldirset_get_next_component,
+ icaldirset_begin_component,
+ icaldirsetiter_to_next,
+ icaldirsetiter_to_prior
+};
+
+
+static icalset icalset_fileset_init = {
+ ICAL_FILE_SET,
+ sizeof(icalfileset),
+ NULL,
+ icalfileset_init,
+ icalfileset_free,
+ icalfileset_path,
+ icalfileset_mark,
+ icalfileset_commit,
+ icalfileset_add_component,
+ icalfileset_remove_component,
+ icalfileset_count_components,
+ icalfileset_select,
+ icalfileset_clear,
+ icalfileset_fetch,
+ icalfileset_fetch_match,
+ icalfileset_has_uid,
+ icalfileset_modify,
+ icalfileset_get_current_component,
+ icalfileset_get_first_component,
+ icalfileset_get_next_component,
+ icalfileset_begin_component,
+ icalfilesetiter_to_next,
+ NULL
+};
+
+#ifdef WITH_BDB4
+static icalset icalset_bdbset_init = {
+ ICAL_BDB_SET,
+ sizeof(icalbdbset),
+ NULL,
+ icalbdbset_init,
+ icalbdbset_free,
+ icalbdbset_path,
+ icalbdbset_mark,
+ icalbdbset_commit,
+ icalbdbset_add_component,
+ icalbdbset_remove_component,
+ icalbdbset_count_components,
+ icalbdbset_select,
+ icalbdbset_clear,
+ icalbdbset_fetch,
+ icalbdbset_fetch_match,
+ icalbdbset_has_uid,
+ icalbdbset_modify,
+ icalbdbset_get_current_component,
+ icalbdbset_get_first_component,
+ icalbdbset_get_next_component,
+ icalbdbset_begin_component,
+ icalbdbsetiter_to_next,
+ NULL
+};
+#endif
+
+#ifdef _DLOPEN_TEST
+static int icalset_init_done = 0;
+static pvl_list icalset_kinds = 0;
+
+typedef icalset *(*fptr)(void);
+
+/**
+ * Try to load the file and register any icalset found within.
+ */
+static int load(const char *file) {
+
+ void *modh;
+ fptr inith;
+ icalset *icalset_init_ptr;
+
+ if ((modh = dlopen(file, RTLD_NOW)) == 0) {
+ perror("dlopen");
+ return 0;
+ }
+
+ if ((inith = (fptr)dlsym(modh, "InitModule")) == 0) {
+ perror("dlsym");
+ return 0;
+ }
+
+ while ((icalset_init_ptr = ((inith)())) != 0) {
+ pvl_push(icalset_kinds, &icalset_init_ptr);
+ }
+
+ return 1;
+}
+
+/**
+ * Look in the given directory for files called mod_*.o and try to
+ * load them.
+ */
+int icalset_loaddir(const char *path) {
+ DIR *d;
+ struct dirent *dp;
+ char buf[PATH_MAX],
+ *bufptr;
+ int tot = 0;
+
+ strcpy(buf, path);
+ bufptr = buf + strlen(buf);
+
+ if (*(bufptr-1) != '/')
+ *bufptr++ = '/';
+
+ if ((d = opendir(path)) == 0) {
+ perror("opendir");
+ return 0;
+ }
+
+ while ((dp = readdir(d)) != 0) {
+ if (strncmp(dp->d_name, "mod_", 4)) continue;
+
+ strcpy(bufptr, dp->d_name);
+
+ load(buf);
+ tot++;
+ }
+ (void)closedir(d);
+
+ return 1;
+}
+
+int icalset_register_class(icalset *set);
+
+static void icalset_init(void) {
+ assert(icalset_kinds == 0);
+ icalset_kinds = pvl_newlist();
+
+ pvl_push(icalset_kinds, &icalset_fileset_init);
+ pvl_push(icalset_kinds, &icalset_dirset_init);
+#ifdef WITH_BDB4
+ pvl_push(icalset_kinds, &icalset_bdb4set_init);
+#endif
+
+#ifdef EXT_PATH
+ icalset_loaddir(EXT_PATH);
+#endif
+
+ icalset_init_done++;
+}
+
+int icalset_register_class(icalset *set) {
+
+ if (!icalset_init_done)
+ icalset_init();
+
+ pvl_push(icalset_kinds, set);
+ return 1;
+}
+
+#endif
+
+icalset* icalset_new(icalset_kind kind, const char* dsn, void* options) {
+ icalset *data = NULL;
+ icalset *ret = NULL;
+
+#ifdef _DLOPEN_TEST
+ pvl_elem e;
+ icalset *impl;
+
+ if (!icalset_init_done)
+ icalset_init();
+
+ for(e = pvl_head(icalset_kinds); e!=0; e = pvl_next(e)) {
+ impl = (icalset*)pvl_data(e);
+ if (impl->kind == kind)
+ break;
+ }
+ if (e == 0) {
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ return(NULL);
+ }
+
+ data = (icalset*)malloc(impl->size);
+ if (data == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ errno = ENOMEM;
+ return 0;
+ }
+
+ /* The first member of the derived class must be an icalset. */
+ memset(data,0,impl->size);
+ /* *data = *impl; */
+ memcpy(data, impl, sizeof(icalset));
+
+ data->dsn = strdup(dsn);
+#else
+ switch(kind) {
+ case ICAL_FILE_SET:
+ data = (icalset*) malloc(sizeof(icalfileset));
+ if (data == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ errno = ENOMEM;
+ return 0;
+ }
+ memset(data,0,sizeof(icalfileset));
+ *data = icalset_fileset_init;
+ break;
+ case ICAL_DIR_SET:
+ data = (icalset*) malloc(sizeof(icaldirset));
+ if (data == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ errno = ENOMEM;
+ return 0;
+ }
+ memset(data,0,sizeof(icaldirset));
+ *data = icalset_dirset_init;
+ break;
+#ifdef WITH_BDB4
+ case ICAL_BDB_SET:
+ data = (icalset*) malloc(sizeof(icalbdbset));
+ if (data == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ errno = ENOMEM;
+ return 0;
+ }
+ memset(data,0,sizeof(icalbdbset));
+ *data = icalset_bdbset_init;
+ break;
+#endif
+
+ default:
+ icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
+ /** unimplemented **/
+ return(NULL);
+ }
+
+ data->kind = kind;
+ data->dsn = strdup(dsn);
+#endif
+
+ /** call the implementation specific initializer **/
+ if ((ret = data->init(data, dsn, options)) == NULL)
+ icalset_free(data);
+
+ return ret;
+}
+
+icalset* icalset_new_file(const char* path)
+{
+ return icalset_new(ICAL_FILE_SET, path, NULL);
+}
+
+icalset* icalset_new_file_writer(const char* path)
+{
+ return icalfileset_new_writer(path);
+}
+
+icalset* icalset_new_file_reader(const char* path)
+{
+ return icalfileset_new_reader(path);
+}
+
+
+icalset* icalset_new_dir(const char* path)
+{
+ return icalset_new(ICAL_DIR_SET, path, NULL);
+}
+
+icalset* icalset_new_dir_writer(const char* path)
+{
+ return icaldirset_new_writer(path);
+}
+
+icalset* icalset_new_dir_reader(const char* path)
+{
+ return icaldirset_new_reader(path);
+}
+
+
+
+/* Functions for built-in methods */
+
+/**
+ * free memory associated with this icalset
+ * automatically calls the implementation specific free routine
+ */
+
+void icalset_free(icalset* set)
+{
+ if (set->free)
+ set->free(set);
+
+ if (set->dsn)
+ free(set->dsn);
+
+ free(set);
+}
+
+
+const char* icalset_path(icalset* set) {
+ return set->path(set);
+}
+
+void icalset_mark(icalset* set) {
+ set->mark(set);
+}
+
+icalerrorenum icalset_commit(icalset* set) {
+ return set->commit(set);
+}
+
+icalerrorenum icalset_add_component(icalset* set, icalcomponent* comp) {
+ return set->add_component(set,comp);
+}
+
+icalerrorenum icalset_remove_component(icalset* set, icalcomponent* comp) {
+ return set->remove_component(set,comp);
+}
+
+int icalset_count_components(icalset* set,icalcomponent_kind kind) {
+ return set->count_components(set,kind);
+}
+
+icalerrorenum icalset_select(icalset* set, icalgauge* gauge) {
+ return set->select(set, gauge);
+}
+
+void icalset_clear(icalset* set) {
+ set->clear(set);
+}
+
+icalcomponent* icalset_fetch(icalset* set, const char* uid) {
+ return set->fetch(set, uid);
+}
+
+icalcomponent* icalset_fetch_match(icalset* set, icalcomponent *comp) {
+ return set->fetch_match(set, comp);
+}
+
+int icalset_has_uid(icalset* set, const char* uid) {
+ return set->has_uid(set, uid);
+}
+
+icalerrorenum icalset_modify(icalset* set, icalcomponent *old,
+ icalcomponent *new) {
+ return set->modify(set, old, new);
+}
+
+icalcomponent* icalset_get_current_component(icalset* set) {
+ return set->get_current_component(set);
+}
+
+icalcomponent* icalset_get_first_component(icalset* set) {
+ return set->get_first_component(set);
+}
+
+icalcomponent* icalset_get_next_component(icalset* set) {
+ return set->get_next_component(set);
+}
+
+icalsetiter icalsetiter_null = {{ICAL_NO_COMPONENT, 0}, 0};
+
+icalsetiter icalset_begin_component(icalset* set,
+ icalcomponent_kind kind, icalgauge* gauge) {
+ return set->icalset_begin_component(set, kind, gauge);
+}
+
+icalcomponent* icalsetiter_next(icalsetiter* itr) {
+
+ icalcomponent* c = 0;
+ icalerror_check_arg_rz( (itr != NULL), "i");
+
+ do {
+ c = icalcompiter_next(&(itr->iter));
+ if(c != 0 && (itr->gauge == 0 ||
+ icalgauge_compare(itr->gauge, c) == 1)){
+ return c;
+ }
+ } while (c != 0);
+
+ return 0;
+}
+
+icalcomponent* icalsetiter_prior(icalsetiter* i) {
+
+ icalcomponent* c = 0;
+ icalerror_check_arg_rz( (i != NULL), "i" );
+
+ do {
+ c = icalcompiter_prior(&(i->iter));
+ if(c != 0 && (i->gauge == 0 ||
+ icalgauge_compare(i->gauge, c) == 1)){
+ return c;
+ }
+ } while (c != 0);
+
+ return 0;
+}
+
+icalcomponent* icalsetiter_deref(icalsetiter* i) {
+ icalerror_check_arg_rz( (i != NULL), "i" );
+ return (icalcompiter_deref(&(i->iter)));
+}
+
+/* for subclasses that use multiple clusters that require specialized cluster traversal */
+icalcomponent* icalsetiter_to_next(icalset* set, icalsetiter* i)
+{
+ return set->icalsetiter_to_next(set, i);
+}
+
+icalcomponent* icalsetiter_to_prior(icalset* set, icalsetiter* i)
+{
+ return set->icalsetiter_to_prior(set, i);
+}
diff --git a/src/libicalss/icalset.h b/src/libicalss/icalset.h
new file mode 100644
index 00000000..b6929f0b
--- /dev/null
+++ b/src/libicalss/icalset.h
@@ -0,0 +1,184 @@
+/* -*- Mode: C -*- */
+/**
+ @file icalset.h
+ @author eric 28 November 1999
+
+ Icalset is the "base class" for representations of a collection of
+ iCal components. Derived classes (actually delegatees) include:
+
+ icalfileset Store components in a single file
+ icaldirset Store components in multiple files in a directory
+ icalbdbset Store components in a Berkeley DB File
+ icalheapset Store components on the heap
+ icalmysqlset Store components in a mysql database.
+**/
+
+/*
+ $Id: icalset.h,v 1.15 2008-01-02 20:07:42 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+
+======================================================================*/
+
+#ifndef ICALSET_H
+#define ICALSET_H
+
+#include <limits.h> /* For PATH_MAX */
+#include <libical/ical.h>
+#include "icalgauge.h"
+
+#ifdef PATH_MAX
+#define ICAL_PATH_MAX PATH_MAX
+#else
+#define ICAL_PATH_MAX 1024
+#endif
+
+
+typedef struct icalset_impl icalset;
+
+typedef enum icalset_kind {
+ ICAL_FILE_SET,
+ ICAL_DIR_SET,
+ ICAL_BDB_SET
+} icalset_kind;
+
+typedef struct icalsetiter
+{
+ icalcompiter iter; /* icalcomponent_kind, pvl_elem iter */
+ icalgauge* gauge;
+ icalrecur_iterator* ritr; /*the last iterator*/
+ icalcomponent* last_component; /*the pending recurring component to be processed */
+ const char* tzid; /* the calendar's timezone id */
+} icalsetiter;
+
+struct icalset_impl {
+ icalset_kind kind;
+ int size;
+ char *dsn;
+ icalset* (*init)(icalset* set, const char *dsn, void *options);
+ void (*free)(icalset* set);
+ const char* (*path)(icalset* set);
+ void (*mark)(icalset* set);
+ icalerrorenum (*commit)(icalset* set);
+ icalerrorenum (*add_component)(icalset* set, icalcomponent* comp);
+ icalerrorenum (*remove_component)(icalset* set, icalcomponent* comp);
+ int (*count_components)(icalset* set,
+ icalcomponent_kind kind);
+ icalerrorenum (*select)(icalset* set, icalgauge* gauge);
+ void (*clear)(icalset* set);
+ icalcomponent* (*fetch)(icalset* set, const char* uid);
+ icalcomponent* (*fetch_match)(icalset* set, icalcomponent *comp);
+ int (*has_uid)(icalset* set, const char* uid);
+ icalerrorenum (*modify)(icalset* set, icalcomponent *old,
+ icalcomponent *newc);
+ icalcomponent* (*get_current_component)(icalset* set);
+ icalcomponent* (*get_first_component)(icalset* set);
+ icalcomponent* (*get_next_component)(icalset* set);
+ icalsetiter (*icalset_begin_component)(icalset* set,
+ icalcomponent_kind kind, icalgauge* gauge);
+ icalcomponent* (*icalsetiter_to_next)(icalset* set, icalsetiter* i);
+ icalcomponent* (*icalsetiter_to_prior)(icalset* set, icalsetiter* i);
+};
+
+/** @brief Register a new derived class */
+int icalset_register_class(icalset *set);
+
+
+/** @brief Generic icalset constructor
+ *
+ * @param kind The type of icalset to create
+ * @param dsn Data Source Name - usually a pathname or DB handle
+ * @param options Any implementation specific options
+ *
+ * @return A valid icalset reference or NULL if error.
+ *
+ * This creates any of the icalset types available.
+ */
+
+icalset* icalset_new(icalset_kind kind, const char* dsn, void* options);
+
+icalset* icalset_new_file(const char* path);
+icalset* icalset_new_file_reader(const char* path);
+icalset* icalset_new_file_writer(const char* path);
+
+icalset* icalset_new_dir(const char* path);
+icalset* icalset_new_file_reader(const char* path);
+icalset* icalset_new_file_writer(const char* path);
+
+void icalset_free(icalset* set);
+
+const char* icalset_path(icalset* set);
+
+/** Mark the cluster as changed, so it will be written to disk when it
+ is freed. **/
+void icalset_mark(icalset* set);
+
+/** Write changes to disk immediately */
+icalerrorenum icalset_commit(icalset* set);
+
+icalerrorenum icalset_add_component(icalset* set, icalcomponent* comp);
+icalerrorenum icalset_remove_component(icalset* set, icalcomponent* comp);
+
+int icalset_count_components(icalset* set,
+ icalcomponent_kind kind);
+
+/** Restrict the component returned by icalset_first, _next to those
+ that pass the gauge. */
+icalerrorenum icalset_select(icalset* set, icalgauge* gauge);
+
+/** Clears the gauge defined by icalset_select() */
+void icalset_clear_select(icalset* set);
+
+/** Get a component by uid */
+icalcomponent* icalset_fetch(icalset* set, const char* uid);
+
+int icalset_has_uid(icalset* set, const char* uid);
+icalcomponent* icalset_fetch_match(icalset* set, icalcomponent *c);
+
+/** Modify components according to the MODIFY method of CAP. Works on
+ the currently selected components. */
+icalerrorenum icalset_modify(icalset* set, icalcomponent *oldc,
+ icalcomponent *newc);
+
+/** Iterate through the components. If a guage has been defined, these
+ will skip over components that do not pass the gauge */
+
+icalcomponent* icalset_get_current_component(icalset* set);
+icalcomponent* icalset_get_first_component(icalset* set);
+icalcomponent* icalset_get_next_component(icalset* set);
+
+/** External Iterator with gauge - for thread safety */
+extern icalsetiter icalsetiter_null;
+
+icalsetiter icalset_begin_component(icalset* set,
+ icalcomponent_kind kind, icalgauge* gauge);
+
+/** Default _next, _prior, _deref for subclasses that use single cluster */
+icalcomponent* icalsetiter_next(icalsetiter* i);
+icalcomponent* icalsetiter_prior(icalsetiter* i);
+icalcomponent* icalsetiter_deref(icalsetiter* i);
+
+/** for subclasses that use multiple clusters that require specialized cluster traversal */
+icalcomponent* icalsetiter_to_next(icalset* set, icalsetiter* i);
+icalcomponent* icalsetiter_to_prior(icalset* set, icalsetiter* i);
+
+#endif /* !ICALSET_H */
+
+
+
diff --git a/src/libicalss/icalspanlist.c b/src/libicalss/icalspanlist.c
new file mode 100644
index 00000000..456abb15
--- /dev/null
+++ b/src/libicalss/icalspanlist.c
@@ -0,0 +1,571 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalspanlist.c
+ CREATOR: ebusboom 23 aug 2000
+
+ $Id: icalspanlist.c,v 1.15 2008-01-02 20:07:42 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include "icalspanlist.h"
+
+#include <stdlib.h> /* for free and malloc */
+#include <string.h>
+
+struct icalspanlist_impl {
+ pvl_list spans; /**< list of icaltime_span data **/
+ struct icaltimetype start; /**< start time of span **/
+ struct icaltimetype end; /**< end time of span **/
+};
+
+/** @brief Internal comparison function for two spans
+ *
+ * @param a a spanlist.
+ * @param b another spanlist.
+ *
+ * @return -1, 0, 1 depending on the comparison of the start times.
+ *
+ * Used to insert spans into the tree in sorted order.
+ */
+
+static int compare_span(void* a, void* b)
+{
+ struct icaltime_span *span_a = (struct icaltime_span *)a ;
+ struct icaltime_span *span_b = (struct icaltime_span *)b ;
+
+ if(span_a->start == span_b->start){
+ return 0;
+ } else if(span_a->start < span_b->start){
+ return -1;
+ } else { /*if(span_a->start > span->b.start)*/
+ return 1;
+ }
+}
+
+
+/** @brief callback function for collecting spanlists of a
+ * series of events.
+ *
+ * @param comp A valid icalcomponent.
+ * @param span The span to insert into data.
+ * @param data The actual spanlist to insert into
+ *
+ * This callback is used by icalcomponent_foreach_recurrence()
+ * to build up a spanlist.
+ */
+
+static void icalspanlist_new_callback(icalcomponent *comp,
+ struct icaltime_span *span,
+ void *data)
+{
+ icaltime_span *s;
+ icalspanlist *sl = (icalspanlist*) data;
+
+ if (span->is_busy == 0)
+ return;
+
+ if ((s=(icaltime_span *) malloc(sizeof(icaltime_span))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return;
+ }
+
+ /** copy span data into allocated memory.. **/
+ *s = *span;
+ pvl_insert_ordered(sl->spans, compare_span, (void*)s);
+}
+
+
+
+/** @brief Make a free list from a set of VEVENT components.
+ *
+ * @param set A valid icalset containing VEVENTS
+ * @param start The free list starts at this date/time
+ * @param end The free list ends at this date/time
+ *
+ * @return A spanlist corresponding to the VEVENTS
+ *
+ * Given a set of components, a start time and an end time
+ * return a spanlist that contains the free/busy times.
+ */
+
+icalspanlist* icalspanlist_new(icalset *set,
+ struct icaltimetype start,
+ struct icaltimetype end)
+{
+ struct icaltime_span range;
+ pvl_elem itr;
+ icalcomponent *c,*inner;
+ icalcomponent_kind kind, inner_kind;
+ icalspanlist *sl;
+ struct icaltime_span *freetime;
+
+ if ( ( sl = (struct icalspanlist_impl*)
+ malloc(sizeof(struct icalspanlist_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ sl->spans = pvl_newlist();
+ sl->start = start;
+ sl->end = end;
+
+ range.start = icaltime_as_timet(start);
+ range.end = icaltime_as_timet(end);
+
+ /* Get a list of spans of busy time from the events in the set
+ and order the spans based on the start time */
+
+ for(c = icalset_get_first_component(set);
+ c != 0;
+ c = icalset_get_next_component(set)){
+
+ kind = icalcomponent_isa(c);
+ inner = icalcomponent_get_inner(c);
+
+ if(!inner){
+ continue;
+ }
+
+ inner_kind = icalcomponent_isa(inner);
+
+ if( kind != ICAL_VEVENT_COMPONENT &&
+ inner_kind != ICAL_VEVENT_COMPONENT){
+ continue;
+ }
+
+ icalerror_clear_errno();
+
+ icalcomponent_foreach_recurrence(c, start, end,
+ icalspanlist_new_callback,
+ (void*)sl);
+
+ }
+
+ /* Now Fill in the free time spans. loop through the spans. if the
+ start of the range is not within the span, create a free entry
+ that runs from the start of the range to the start of the
+ span. */
+
+ for( itr = pvl_head(sl->spans);
+ itr != 0;
+ itr = pvl_next(itr))
+ {
+ struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
+
+ if ((freetime=(struct icaltime_span *)
+ malloc(sizeof(struct icaltime_span))) == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ icalspanlist_free(sl);
+ return 0;
+ }
+
+ if(range.start < s->start){
+ freetime->start = range.start;
+ freetime->end = s->start;
+
+ freetime->is_busy = 0;
+
+
+ pvl_insert_ordered(sl->spans,compare_span,(void*)freetime);
+ } else {
+ free(freetime);
+ }
+
+ range.start = s->end;
+ }
+
+ /* If the end of the range is null, then assume that everything
+ after the last item in the calendar is open and add a span
+ that indicates this */
+
+ if( icaltime_is_null_time(end)){
+ struct icaltime_span* last_span;
+
+ last_span = (struct icaltime_span*)pvl_data(pvl_tail(sl->spans));
+
+ if (last_span != 0){
+
+ if ((freetime=(struct icaltime_span *)
+ malloc(sizeof(struct icaltime_span))) == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ icalspanlist_free(sl);
+ return 0;
+ }
+
+ freetime->is_busy = 0;
+ freetime->start = last_span->end;
+ freetime->end = freetime->start;
+ pvl_insert_ordered(sl->spans,compare_span,(void*)freetime);
+ }
+ }
+
+
+ return sl;
+}
+
+/** @brief Destructor.
+ * @param s A valid icalspanlist
+ *
+ * Free memory associated with the spanlist
+ */
+
+void icalspanlist_free(icalspanlist* s)
+{
+ struct icaltime_span *span;
+
+ if (s == NULL)
+ return;
+
+ while( (span=pvl_pop(s->spans)) != 0){
+ free(span);
+ }
+
+ pvl_free(s->spans);
+
+ s->spans = 0;
+
+ free(s);
+}
+
+
+/** @brief (Debug) print out spanlist to stdout.
+ * @param sl A valid icalspanlist.
+ */
+
+void icalspanlist_dump(icalspanlist* sl){
+ int i = 0;
+ pvl_elem itr;
+
+ for( itr = pvl_head(sl->spans);
+ itr != 0;
+ itr = pvl_next(itr))
+ {
+ struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
+
+ printf("#%02d %d start: %s",++i,s->is_busy,ctime(&s->start));
+ printf(" end : %s",ctime(&s->end));
+
+ }
+}
+
+icalcomponent* icalspanlist_make_free_list(icalspanlist* sl);
+icalcomponent* icalspanlist_make_busy_list(icalspanlist* sl);
+
+
+/** @brief Find next free time span in a spanlist.
+ *
+ * @param sl The spanlist to search.
+ * @param t The time to start looking.
+ *
+ * Given a spanlist and a time, find the next period of time
+ * that is free
+ */
+
+struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl,
+ struct icaltimetype t)
+{
+ pvl_elem itr;
+ struct icalperiodtype period;
+ struct icaltime_span *s;
+
+ time_t rangett= icaltime_as_timet(t);
+
+ period.start = icaltime_null_time();
+ period.end = icaltime_null_time();
+
+ itr = pvl_head(sl->spans);
+ s = (struct icaltime_span *)pvl_data(itr);
+
+ if (s == 0){
+ /* No elements in span */
+ return period;
+ }
+
+ /* Is the reference time before the first span? If so, assume
+ that the reference time is free */
+ if(rangett <s->start ){
+ /* End of period is start of first span if span is busy, end
+ of the span if it is free */
+ period.start = t;
+
+ if (s->is_busy == 1){
+ period.end = icaltime_from_timet(s->start,0);
+ } else {
+ period.end = icaltime_from_timet(s->end,0);
+ }
+
+ return period;
+ }
+
+ /* Otherwise, find the first free span that contains the
+ reference time. */
+ for( itr = pvl_head(sl->spans);
+ itr != 0;
+ itr = pvl_next(itr))
+ {
+ s = (struct icaltime_span *)pvl_data(itr);
+
+ if(s->is_busy == 0 && s->start >= rangett &&
+ ( rangett < s->end || s->end == s->start)){
+
+ if (rangett < s->start){
+ period.start = icaltime_from_timet(s->start,0);
+ } else {
+ period.start = icaltime_from_timet(rangett,0);
+ }
+
+ period.end = icaltime_from_timet(s->end,0);
+
+ return period;
+ }
+
+ }
+
+ period.start = icaltime_null_time();
+ period.end = icaltime_null_time();
+
+ return period;
+}
+
+struct icalperiodtype icalspanlist_next_busy_time(icalspanlist* sl,
+ struct icaltimetype t);
+
+
+/** @brief Returns an hour-by-hour array of free/busy times over a
+ * given period.
+ *
+ * @param sl A valid icalspanlist
+ * @param delta_t The time slice to divide by, in seconds. Default 3600.
+ *
+ * @return A pointer to an array of integers containing the number of
+ * busy events in each delta_t time period. The final entry
+ * contains the value -1.
+ *
+ * This calculation is somewhat tricky. This is due to the fact that
+ * the time range contains the start time, but does not contain the
+ * end time. To perform a proper calculation we subtract one second
+ * off the end times to get a true containing time.
+ *
+ * Also note that if you supplying a spanlist that does not start or
+ * end on a time boundary divisible by delta_t you may get results
+ * that are not quite what you expect.
+ */
+
+int* icalspanlist_as_freebusy_matrix(icalspanlist* sl, int delta_t) {
+ pvl_elem itr;
+ int spanduration_secs;
+ int *matrix;
+ int matrix_slots;
+ time_t sl_start, sl_end;
+
+ icalerror_check_arg_rz( (sl!=0), "spanlist");
+
+ if (!delta_t)
+ delta_t = 3600;
+
+ /** calculate the start and end time as time_t **/
+ sl_start = icaltime_as_timet_with_zone(sl->start, icaltimezone_get_utc_timezone());
+ sl_end = icaltime_as_timet_with_zone(sl->end, icaltimezone_get_utc_timezone());
+
+
+ /** insure that the time period falls on a time boundary divisable
+ by delta_t */
+
+ sl_start /= delta_t;
+ sl_start *= delta_t;
+
+ sl_end /= delta_t;
+ sl_end *= delta_t;
+
+
+ /** find the duration of this spanlist **/
+ spanduration_secs = sl_end - sl_start;
+
+
+ /** malloc our matrix, add one extra slot for a final -1 **/
+ matrix_slots = spanduration_secs/delta_t + 1;
+
+ matrix = (int*) malloc(sizeof(int) * matrix_slots);
+ if (matrix == NULL) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return NULL;
+ }
+ memset(matrix, 0, sizeof(int) * matrix_slots);
+ matrix[matrix_slots-1] = -1;
+
+ /* loop through each span and mark the slots in the array */
+
+ for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) {
+ struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
+
+ if (s->is_busy == 1) {
+ int offset_start = s->start/delta_t - sl_start/delta_t;
+ int offset_end = (s->end - 1) /delta_t - sl_start/delta_t + 1;
+ int i;
+
+ if (offset_end >= matrix_slots)
+ offset_end = matrix_slots - 1;
+
+ i = offset_start;
+ for (i=offset_start; i < offset_end; i++) {
+ matrix[i]++;
+ }
+ }
+ }
+ return matrix;
+}
+
+
+/** @brief Return a VFREEBUSY component for the corresponding spanlist
+ *
+ * @param sl A valid icalspanlist, from icalspanlist_new()
+ * @param organizer The organizer specified as MAILTO:user@domain
+ * @param attendee The attendee specified as MAILTO:user@domain
+ *
+ * @return A valid icalcomponent or NULL.
+ *
+ * This function returns a VFREEBUSY component for the given spanlist.
+ * The start time is mapped to DTSTART, the end time to DTEND.
+ * Each busy span is represented as a separate FREEBUSY entry.
+ * An attendee parameter is required, and organizer parameter is
+ * optional.
+ */
+
+icalcomponent *icalspanlist_as_vfreebusy(icalspanlist* sl,
+ const char* organizer,
+ const char* attendee) {
+ icalcomponent *comp;
+ icalproperty *p;
+ struct icaltimetype atime = icaltime_from_timet( time(0),0);
+ pvl_elem itr;
+ icaltimezone *utc_zone;
+ icalparameter *param;
+
+ if (!attendee) {
+ icalerror_set_errno(ICAL_USAGE_ERROR);
+ return 0;
+ }
+
+ utc_zone = icaltimezone_get_utc_timezone ();
+
+ comp = icalcomponent_new_vfreebusy();
+
+ icalcomponent_add_property(comp, icalproperty_new_dtstart(sl->start));
+ icalcomponent_add_property(comp, icalproperty_new_dtend(sl->end));
+ icalcomponent_add_property(comp, icalproperty_new_dtstamp(atime));
+
+ if (organizer) {
+ icalcomponent_add_property(comp, icalproperty_new_organizer(organizer));
+ }
+ icalcomponent_add_property(comp, icalproperty_new_attendee(attendee));
+
+ /* now add the freebusy sections.. */
+
+ for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) {
+ struct icalperiodtype period;
+ struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr);
+
+ if (s->is_busy == 1) {
+
+ period.start = icaltime_from_timet_with_zone (s->start, 0, utc_zone);
+ period.end = icaltime_from_timet_with_zone (s->end, 0, utc_zone);
+ period.duration = icaldurationtype_null_duration();
+
+
+ p = icalproperty_new_freebusy(period);
+ param = icalparameter_new_fbtype(ICAL_FBTYPE_BUSY);
+ icalproperty_add_parameter(p, param);
+
+ icalcomponent_add_property(comp, p);
+ }
+
+ }
+
+ return comp;
+}
+
+
+/** @brief Return a spanlist corresponding to the VFREEBUSY portion of
+ * an icalcomponent.
+ *
+ * @param c A valid icalcomponent.
+ *
+ * @return A valid icalspanlist or NULL if no VFREEBUSY section.
+ *
+ */
+
+
+icalspanlist *icalspanlist_from_vfreebusy(icalcomponent* comp)
+{
+ icalcomponent *inner;
+ icalproperty *prop;
+ icalspanlist *sl;
+
+ icalerror_check_arg_rz((comp != NULL), "comp");
+
+ inner = icalcomponent_get_inner(comp);
+ if (!inner) return NULL;
+
+ if ( ( sl = (icalspanlist*) malloc(sizeof(icalspanlist))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+ sl->spans = pvl_newlist();
+
+ /* cycle through each FREEBUSY property, adding to the spanlist */
+ for (prop = icalcomponent_get_first_property(inner, ICAL_FREEBUSY_PROPERTY);
+ prop != NULL;
+ prop = icalcomponent_get_next_property(inner, ICAL_FREEBUSY_PROPERTY)) {
+ icaltime_span *s = (icaltime_span *) malloc(sizeof(icaltime_span));
+ icalparameter *param;
+ struct icalperiodtype period;
+ icalparameter_fbtype fbtype;
+
+ if (s == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ icalspanlist_free(sl);
+ return 0;
+ }
+
+ param = icalproperty_get_first_parameter(prop, ICAL_FBTYPE_PARAMETER);
+ fbtype = (param) ? icalparameter_get_fbtype(param) : ICAL_FBTYPE_BUSY;
+
+ switch (fbtype) {
+ case ICAL_FBTYPE_FREE:
+ case ICAL_FBTYPE_NONE:
+ case ICAL_FBTYPE_X:
+ s->is_busy = 1;
+ break;
+ default:
+ s->is_busy = 0;
+ }
+
+ period = icalproperty_get_freebusy(prop);
+ s->start = icaltime_as_timet_with_zone(period.start, icaltimezone_get_utc_timezone());
+ s->end = icaltime_as_timet_with_zone(period.end, icaltimezone_get_utc_timezone());
+;
+ pvl_insert_ordered(sl->spans, compare_span, (void*)s);
+ }
+ /** @todo calculate start/end limits.. fill in holes? **/
+ return sl;
+}
diff --git a/src/libicalss/icalspanlist.h b/src/libicalss/icalspanlist.h
new file mode 100644
index 00000000..71056def
--- /dev/null
+++ b/src/libicalss/icalspanlist.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalspanlist.h
+ CREATOR: eric 21 Aug 2000
+
+
+ $Id: icalspanlist.h,v 1.8 2008-01-02 20:07:42 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ =========================================================================*/
+#ifndef ICALSPANLIST_H
+#define ICALSPANLIST_H
+
+#include <libical/ical.h>
+#include "icalset.h"
+
+/** @file icalspanlist.h
+ * @brief Code that supports collections of free/busy spans of time
+ */
+
+typedef struct icalspanlist_impl icalspanlist;
+
+
+/** @brief Constructor
+ * Make a free list from a set of component. Start and end should be in UTC
+ */
+
+icalspanlist* icalspanlist_new(icalset *set,
+ struct icaltimetype start,
+ struct icaltimetype end);
+
+/** @brief Destructor
+ */
+void icalspanlist_free(icalspanlist* spl);
+
+/* Unimplemented functions */
+icalcomponent* icalspanlist_make_free_list(icalspanlist* sl);
+icalcomponent* icalspanlist_make_busy_list(icalspanlist* sl);
+
+/** Get first next free time after time t. all times are in UTC. */
+struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl,
+ struct icaltimetype t);
+/** Get first next busy time after time t. all times are in UTC. */
+struct icalperiodtype icalspanlist_next_busy_time(icalspanlist* sl,
+ struct icaltimetype t);
+
+void icalspanlist_dump(icalspanlist* s);
+
+/** @brief Return a valid VFREEBUSY component for this span */
+icalcomponent *icalspanlist_as_vfreebusy(icalspanlist* s_in,
+ const char* organizer,
+ const char* attendee);
+
+/** @brief Return an integer matrix of total events per delta_t timespan */
+int *icalspanlist_as_freebusy_matrix(icalspanlist* span, int delta_t);
+
+/** @brief Construct an icalspanlist from a VFREEBUSY component */
+icalspanlist *icalspanlist_from_vfreebusy(icalcomponent* c);
+
+#endif
+
+
+
diff --git a/src/libicalss/icalspanlist_cxx.cpp b/src/libicalss/icalspanlist_cxx.cpp
new file mode 100644
index 00000000..38761af4
--- /dev/null
+++ b/src/libicalss/icalspanlist_cxx.cpp
@@ -0,0 +1,92 @@
+#include "icalspanlist_cxx.h"
+#include <exception>
+
+/** @brief Construct an ICalSpanList from an icalset
+ @param set The icalset containing the VEVENTS
+ @param start Designated start of the spanlist
+ @param end Designated end of the spanlist
+*/
+
+ICalSpanList::ICalSpanList(icalset *set, icaltimetype start, icaltimetype end) throw(icalerrorenum)
+{
+ data = icalspanlist_new(set, start, end);
+ if (!data) throw icalerrno;
+};
+
+
+/** @brief Constructor
+ @param comp A valid icalcomponent with a VFREEBUSY section
+*/
+
+ICalSpanList::ICalSpanList(icalcomponent *comp) throw(icalerrorenum)
+{
+ data = icalspanlist_from_vfreebusy(comp);
+ if (!data) throw icalerrno;
+}
+
+/** @brief Constructor
+ @param comp A valid VComponent with a VFREEBUSY section
+*/
+ICalSpanList::ICalSpanList(VComponent &comp) throw(icalerrorenum)
+{
+ data = icalspanlist_from_vfreebusy((icalcomponent*) comp);
+ if (!data) throw icalerrno;
+}
+
+/** Destructor */
+ICalSpanList::~ICalSpanList() {
+ if (data)
+ icalspanlist_free(data);
+}
+
+
+/**
+ * @brief Returns a VFREEBUSY component for the object.
+ *
+ * @see icalspanlist_as_vfreebusy()
+ */
+
+VComponent*
+ICalSpanList::get_vfreebusy(const char *organizer, const char *attendee) throw(icalerrorenum)
+{
+ icalcomponent *comp;
+ VComponent *vcomp;
+
+ comp = icalspanlist_as_vfreebusy(data, organizer, attendee);
+ if (comp == 0) throw icalerrno;
+
+ vcomp = new VComponent(comp);
+ if (vcomp == 0) throw icalerrno;
+
+ return vcomp;
+}
+
+
+/**
+ * @brief Returns a summary of events over delta_t
+ *
+ * @param delta_t Number of seconds to divide the spanlist time period
+ * into.
+ *
+ * This method calculates the total number of events in each time slot
+ * of delta_t seconds.
+ *
+ * @see icalspanlist_as_freebusy_matrix()
+ */
+
+std::vector<int> ICalSpanList::as_vector(int delta_t) throw(icalerrorenum)
+{
+ int *matrix;
+ int i = 0;
+ std::vector<int> event_vec;
+
+ matrix = icalspanlist_as_freebusy_matrix(data, delta_t);
+
+ if (!matrix) throw ICAL_USAGE_ERROR;
+
+ while (matrix[i] != -1) {
+ event_vec.push_back(matrix[i]); // Add item at end of vector
+ }
+
+ return(event_vec);
+}
diff --git a/src/libicalss/icalspanlist_cxx.h b/src/libicalss/icalspanlist_cxx.h
new file mode 100644
index 00000000..e230510d
--- /dev/null
+++ b/src/libicalss/icalspanlist_cxx.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++ -*- */
+
+/**
+ * @file icalspanlist_cxx.h
+ * @author Critical Path
+ * @brief C++ class wrapping the icalspanlist data structure
+ *
+ * This class wraps the icalspanlist routines in libicalss
+ *
+ * Errors within libicalss are propagated via exceptions of type
+ * icalerrorenum. See icalerror.h for the complete list of exceptions
+ * that might be thrown.
+ */
+
+#ifndef ICALSPANLIST_CXX_H
+#define ICALSPANLIST_CXX_H
+
+#include <libical/ical.h>
+#include <libicalss/icalset.h>
+#include <libicalss/icalspanlist.h>
+#include "vcomponent.h"
+#include <vector> /* For as_matrix.. */
+
+class ICalSpanList {
+ public:
+ /** Construct an ICalSpanList from an icalset */
+ ICalSpanList(icalset *set, icaltimetype start, icaltimetype end) throw(icalerrorenum);
+
+ /** Construct an ICalSpanList from the VFREEBUSY chunk of a icalcomponent */
+ ICalSpanList(icalcomponent *comp) throw(icalerrorenum);
+
+ /** Construct an ICalSpanList from the VFREEBUSY chunk of a vcomponent */
+ ICalSpanList(VComponent &comp) throw(icalerrorenum);
+
+ /** Destructor */
+ ~ICalSpanList();
+
+ /** Return a VFREEBUSY icalcomponent */
+ VComponent* get_vfreebusy(const char *organizer, const char *attendee) throw(icalerrorenum);
+
+ /** Return the base data when casting */
+ operator icalspanlist*() {return data;}
+
+ /** Return a vector of the number of events over delta t */
+ std::vector<int> as_vector(int delta_t) throw(icalerrorenum);
+
+ /** Dump the spanlist to stdout */
+ void dump() {icalspanlist_dump(data);}
+
+ private:
+ icalspanlist *data;
+};
+
+#endif
diff --git a/src/libicalss/icalss_file.cmake b/src/libicalss/icalss_file.cmake
new file mode 100644
index 00000000..6bf8627a
--- /dev/null
+++ b/src/libicalss/icalss_file.cmake
@@ -0,0 +1,32 @@
+# ORDERING OF HEADERS IS SIGNIFICANT. Don't change this ordering.
+# It is required to make the combined header icalss.h properly.
+set(COMBINEDHEADERSICALSS
+ ${TOPS}/src/libicalss/icalgauge.h
+ ${TOPS}/src/libicalss/icalset.h
+ ${TOPS}/src/libicalss/icalcluster.h
+ ${TOPS}/src/libicalss/icalfileset.h
+ ${TOPS}/src/libicalss/icaldirset.h
+ ${TOPS}/src/libicalss/icalcalendar.h
+ ${TOPS}/src/libicalss/icalclassify.h
+ ${TOPS}/src/libicalss/icalspanlist.h
+ ${TOPS}/src/libicalss/icalmessage.h
+)
+
+FILE(WRITE ${ICAL_FILE_H_FILE} "#ifndef LIBICAL_ICALSS_H\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#define LIBICAL_ICALSS_H\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#ifdef __cplusplus\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "extern \"C\" {\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#endif\n")
+
+foreach (_current_FILE ${COMBINEDHEADERSICALSS})
+ FILE(READ ${_current_FILE} _contents)
+ STRING(REGEX REPLACE "#include *\"ical.*\\.h\"" "" _contents "${_contents}" )
+ STRING(REGEX REPLACE "#include *\"pvl\\.h\"" "" _contents "${_contents}" )
+ FILE(APPEND ${ICAL_FILE_H_FILE} "${_contents}")
+endforeach (_current_FILE)
+
+FILE(APPEND ${ICAL_FILE_H_FILE} "\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#ifdef __cplusplus\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "}\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#endif\n")
+FILE(APPEND ${ICAL_FILE_H_FILE} "#endif\n")
diff --git a/src/libicalss/icalsslexer.c b/src/libicalss/icalsslexer.c
new file mode 100644
index 00000000..ae4a6569
--- /dev/null
+++ b/src/libicalss/icalsslexer.c
@@ -0,0 +1,1972 @@
+
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer ss_create_buffer
+#define yy_delete_buffer ss_delete_buffer
+#define yy_flex_debug ss_flex_debug
+#define yy_init_buffer ss_init_buffer
+#define yy_flush_buffer ss_flush_buffer
+#define yy_load_buffer_state ss_load_buffer_state
+#define yy_switch_to_buffer ss_switch_to_buffer
+#define yyin ssin
+#define yyleng ssleng
+#define yylex sslex
+#define yylineno sslineno
+#define yyout ssout
+#define yyrestart ssrestart
+#define yytext sstext
+#define yywrap sswrap
+#define yyalloc ssalloc
+#define yyrealloc ssrealloc
+#define yyfree ssfree
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef _WIN32_WCE
+#include <io.h>
+#endif
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE ssrestart(ssin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+extern int ssleng;
+
+extern FILE *ssin, *ssout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up sstext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up sstext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via ssrestart()), so that the user can continue scanning by
+ * just pointing ssin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when sstext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int ssleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow sswrap()'s to do buffer switches
+ * instead of setting up a fresh ssin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void ssrestart (FILE *input_file );
+void ss_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE ss_create_buffer (FILE *file,int size );
+void ss_delete_buffer (YY_BUFFER_STATE b );
+void ss_flush_buffer (YY_BUFFER_STATE b );
+void sspush_buffer_state (YY_BUFFER_STATE new_buffer );
+void sspop_buffer_state (void );
+
+static void ssensure_buffer_stack (void );
+static void ss_load_buffer_state (void );
+static void ss_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER ss_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE ss_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE ss_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE ss_scan_bytes (yyconst char *bytes,int len );
+
+void *ssalloc (yy_size_t );
+void *ssrealloc (void *,yy_size_t );
+void ssfree (void * );
+
+#define yy_new_buffer ss_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ ssensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ss_create_buffer(ssin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ ssensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ ss_create_buffer(ssin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *ssin = (FILE *) 0, *ssout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int sslineno;
+
+int sslineno = 1;
+
+extern char sstext[];
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up sstext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ ssleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ if ( ssleng >= YYLMAX ) \
+ YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \
+ yy_flex_strncpy( sstext, (yytext_ptr), ssleng + 1 ); \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 23
+#define YY_END_OF_BUFFER 24
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[56] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 24, 22, 18, 18,
+ 22, 17, 21, 4, 19, 8, 5, 9, 21, 21,
+ 21, 21, 21, 21, 21, 18, 7, 0, 21, 10,
+ 6, 11, 21, 21, 14, 21, 21, 13, 21, 21,
+ 20, 12, 21, 15, 21, 21, 21, 2, 16, 21,
+ 21, 21, 3, 1, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 5, 1, 1, 1, 1, 1, 6, 1,
+ 1, 7, 1, 8, 7, 7, 1, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 9, 10, 11,
+ 12, 13, 1, 7, 14, 7, 15, 16, 17, 18,
+ 7, 19, 20, 7, 7, 21, 22, 23, 24, 7,
+ 7, 25, 26, 27, 28, 7, 29, 7, 7, 7,
+ 1, 1, 1, 1, 1, 1, 30, 7, 31, 32,
+
+ 33, 34, 7, 35, 36, 7, 7, 37, 38, 39,
+ 40, 7, 7, 41, 42, 43, 44, 7, 45, 7,
+ 7, 7, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[46] =
+ { 0,
+ 1, 1, 1, 2, 1, 1, 3, 1, 2, 1,
+ 1, 1, 1, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3
+ } ;
+
+static yyconst flex_int16_t yy_base[58] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 98, 107, 44, 47,
+ 85, 0, 0, 107, 107, 84, 83, 79, 29, 28,
+ 28, 31, 31, 40, 39, 58, 107, 84, 0, 107,
+ 107, 107, 47, 40, 0, 38, 45, 0, 46, 59,
+ 107, 0, 55, 0, 57, 67, 60, 0, 0, 71,
+ 70, 61, 0, 0, 107, 103, 86
+ } ;
+
+static yyconst flex_int16_t yy_def[58] =
+ { 0,
+ 55, 1, 1, 1, 1, 1, 55, 55, 55, 55,
+ 55, 56, 57, 55, 55, 55, 55, 55, 57, 57,
+ 57, 57, 57, 57, 57, 55, 55, 56, 57, 55,
+ 55, 55, 57, 57, 57, 57, 57, 57, 57, 57,
+ 55, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 0, 55, 55
+ } ;
+
+static yyconst flex_int16_t yy_nxt[153] =
+ { 0,
+ 8, 9, 10, 9, 11, 12, 13, 14, 8, 15,
+ 16, 17, 18, 19, 13, 13, 13, 20, 13, 21,
+ 13, 13, 22, 23, 13, 24, 13, 13, 25, 19,
+ 13, 13, 13, 20, 13, 21, 13, 13, 22, 23,
+ 13, 24, 13, 13, 25, 26, 26, 26, 26, 26,
+ 26, 33, 34, 35, 36, 38, 39, 40, 37, 26,
+ 26, 26, 42, 43, 44, 45, 46, 33, 34, 35,
+ 36, 38, 39, 40, 37, 47, 48, 49, 42, 43,
+ 44, 45, 46, 50, 51, 52, 53, 54, 29, 41,
+ 32, 47, 48, 49, 31, 30, 27, 55, 55, 50,
+
+ 51, 52, 53, 54, 28, 28, 7, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55
+ } ;
+
+static yyconst flex_int16_t yy_chk[153] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 9, 9, 9, 10, 10,
+ 10, 19, 20, 21, 22, 23, 24, 25, 22, 26,
+ 26, 26, 33, 34, 36, 37, 39, 19, 20, 21,
+ 22, 23, 24, 25, 22, 40, 43, 45, 33, 34,
+ 36, 37, 39, 46, 47, 50, 51, 52, 57, 28,
+ 18, 40, 43, 45, 17, 16, 11, 7, 0, 46,
+
+ 47, 50, 51, 52, 56, 56, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int ss_flex_debug;
+int ss_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#ifndef YYLMAX
+#define YYLMAX 8192
+#endif
+
+char sstext[YYLMAX];
+char *yytext_ptr;
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalsslexer.l
+ CREATOR: eric 8 Aug 2000
+
+ DESCRIPTION:
+
+ $Id: icalsslexer.l,v 1.10 2008-01-02 20:07:42 dothebart Exp $
+ $Locker: $
+
+(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+ ======================================================================*/
+
+#include "icalssyacc.h"
+#include "icalgaugeimpl.h"
+#include "assert.h"
+
+#include <string.h> /* For strdup() */
+
+const char* input_buffer;
+const char* input_buffer_p;
+
+#define minInt(a,b) ((a) < (b) ? (a) : (b))
+
+int icalss_input(char* buf, int max_size)
+{
+ int n = minInt(max_size,strlen(input_buffer_p));
+
+ if (n > 0){
+ memcpy(buf, input_buffer_p, n);
+ input_buffer_p += n;
+ return n;
+ } else {
+ return 0;
+ }
+}
+
+#undef YY_INPUT
+#define YY_INPUT(b,r,ms) ( r= icalss_input(b,ms))
+
+#undef SS_FATAL_ERROR
+#define SS_FATAL_ERROR(msg) sserror(msg)
+
+
+
+#define INITIAL 0
+#define sql 1
+#define string_value 2
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int sslex_destroy (void );
+
+int ssget_debug (void );
+
+void ssset_debug (int debug_flag );
+
+YY_EXTRA_TYPE ssget_extra (void );
+
+void ssset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *ssget_in (void );
+
+void ssset_in (FILE * in_str );
+
+FILE *ssget_out (void );
+
+void ssset_out (FILE * out_str );
+
+int ssget_leng (void );
+
+char *ssget_text (void );
+
+int ssget_lineno (void );
+
+void ssset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int sswrap (void );
+#else
+extern int sswrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( sstext, ssleng, 1, ssout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( ssin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( ssin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, ssin))==0 && ferror(ssin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(ssin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int sslex (void);
+
+#define YY_DECL int sslex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after sstext and ssleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+
+
+
+
+
+
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! ssin )
+ ssin = stdin;
+
+ if ( ! ssout )
+ ssout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ ssensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ss_create_buffer(ssin,YY_BUF_SIZE );
+ }
+
+ ss_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of sstext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 56 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 107 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+{ return SELECT; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+{ return FROM; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+{ return WHERE; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{ return COMMA; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ return EQUALS; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return EQUALS; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return NOTEQUALS; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return LESS; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return GREATER; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return LESSEQUALS; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return GREATEREQUALS; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return AND; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return OR; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return IS; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return NOT; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return SQLNULL; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return QUOTE; }
+ YY_BREAK
+case 18:
+/* rule 18 can match eol */
+YY_RULE_SETUP
+;
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return EOL; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{
+ int c = input();
+ if(c != EOF){
+ unput(c);
+ }
+ if(c!='\''){
+ sslval.v_string= icalmemory_tmp_copy(sstext);
+ return STRING;
+ } else {
+ /*ssmore();*/
+ }
+}
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{
+ sslval.v_string= icalmemory_tmp_copy(sstext);
+ return STRING;
+}
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return sstext[0]; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(sql):
+case YY_STATE_EOF(string_value):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed ssin at a new source and called
+ * sslex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = ssin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( sswrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * sstext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of sslex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ ssrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ ssrestart(ssin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) ssrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 56 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 56 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 55);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up sstext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ ssrestart(ssin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( sswrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve sstext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void ssrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ ssensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ ss_create_buffer(ssin,YY_BUF_SIZE );
+ }
+
+ ss_init_buffer(YY_CURRENT_BUFFER,input_file );
+ ss_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void ss_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * sspop_buffer_state();
+ * sspush_buffer_state(new_buffer);
+ */
+ ssensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ ss_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (sswrap()) processing, but the only time this flag
+ * is looked at is after sswrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void ss_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ ssin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE ss_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) ssalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ss_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) ssalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ss_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ ss_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with ss_create_buffer()
+ *
+ */
+ void ss_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ ssfree((void *) b->yy_ch_buf );
+
+ ssfree((void *) b );
+}
+
+#ifndef __cplusplus
+extern int isatty (int );
+#endif /* __cplusplus */
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a ssrestart() or at EOF.
+ */
+ static void ss_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ ss_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then ss_init_buffer was _probably_
+ * called from ssrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void ss_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ ss_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void sspush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ ssensure_buffer_stack();
+
+ /* This block is copied from ss_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from ss_switch_to_buffer. */
+ ss_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void sspop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ ss_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ ss_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void ssensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)ssalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in ssensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)ssrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in ssensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ss_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) ssalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in ss_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ ss_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to sslex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * ss_scan_bytes() instead.
+ */
+YY_BUFFER_STATE ss_scan_string (yyconst char * yystr )
+{
+
+ return ss_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to sslex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE ss_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) ssalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in ss_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = ss_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in ss_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up sstext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ sstext[ssleng] = (yy_hold_char); \
+ (yy_c_buf_p) = sstext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ ssleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int ssget_lineno (void)
+{
+
+ return sslineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *ssget_in (void)
+{
+ return ssin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *ssget_out (void)
+{
+ return ssout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int ssget_leng (void)
+{
+ return ssleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *ssget_text (void)
+{
+ return sstext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void ssset_lineno (int line_number )
+{
+
+ sslineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see ss_switch_to_buffer
+ */
+void ssset_in (FILE * in_str )
+{
+ ssin = in_str ;
+}
+
+void ssset_out (FILE * out_str )
+{
+ ssout = out_str ;
+}
+
+int ssget_debug (void)
+{
+ return ss_flex_debug;
+}
+
+void ssset_debug (int bdebug )
+{
+ ss_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from sslex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ ssin = stdin;
+ ssout = stdout;
+#else
+ ssin = (FILE *) 0;
+ ssout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * sslex_init()
+ */
+ return 0;
+}
+
+/* sslex_destroy is for both reentrant and non-reentrant scanners. */
+int sslex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ ss_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ sspop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ ssfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * sslex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *ssalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *ssrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void ssfree (void * ptr )
+{
+ free( (char *) ptr ); /* see ssrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+
+
+
+int sswrap()
+{
+ return 1;
+}
+
+
diff --git a/src/libicalss/icalsslexer.l b/src/libicalss/icalsslexer.l
new file mode 100644
index 00000000..7003fc08
--- /dev/null
+++ b/src/libicalss/icalsslexer.l
@@ -0,0 +1,139 @@
+%{
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalsslexer.l
+ CREATOR: eric 8 Aug 2000
+
+ DESCRIPTION:
+
+ $Id: icalsslexer.l,v 1.10 2008-01-02 20:07:42 dothebart Exp $
+ $Locker: $
+
+(C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The Original Code is eric. The Initial Developer of the Original
+ Code is Eric Busboom
+
+ ======================================================================*/
+
+#include "icalssyacc.h"
+#include "icalgaugeimpl.h"
+#include "assert.h"
+
+#include <string.h> /* For strdup() */
+
+const char* input_buffer;
+const char* input_buffer_p;
+
+int icalss_input(char* buf, int max_size)
+{
+ int n;
+ int l;
+
+ l = strlen(input_buffer_p);
+ if (max_size<l) n = max_size;
+ else n = l;
+
+ if (n > 0){
+ memcpy(buf, input_buffer_p, n);
+ input_buffer_p += n;
+ return n;
+ } else {
+ return 0;
+ }
+}
+
+#undef YY_INPUT
+#define YY_INPUT(b,r,ms) ( r= icalss_input(b,ms))
+
+#undef SS_FATAL_ERROR
+#define SS_FATAL_ERROR(msg) sserror(msg)
+
+%}
+
+crlf \x0D?\x0A
+space [ ]
+qsafechar [^\x00-\x1F\"]
+safechar [^\x00-\x1F\"\:\;\,]
+tsafechar [\x20-\x21\x23-\x2B\x2D-\x39\x3C-\x5B\x5D-\x7E]
+valuechar [^\x00-\x08\x10-\x1F]
+xname X-[a-zA-Z0-9\-]+
+xname2 [a-zA-Z0-9\-\ ]
+paramtext {safechar}+
+value {valuechar}+
+quotedstring \"{qsafechar}+\"
+digit [0-9]
+
+%array /* Make yytext an array. Slow, but handy. HACK */
+
+%option caseless
+
+%s sql string_value
+
+
+
+%%
+
+%{
+%}
+
+
+SELECT { return SELECT; }
+FROM { return FROM; }
+WHERE { return WHERE; }
+, { return COMMA; }
+"=" { return EQUALS; }
+"==" { return EQUALS; }
+"!=" { return NOTEQUALS; }
+"<" { return LESS; }
+">" { return GREATER; }
+"<=" { return LESSEQUALS; }
+">=" { return GREATEREQUALS; }
+AND { return AND; }
+OR { return OR; }
+IS { return IS; }
+NOT { return NOT; }
+NULL { return SQLNULL; }
+\' { return QUOTE; }
+[ \t\n\r]+ ;
+; { return EOL; }
+
+\'[\@\*A-Za-z0-9\-\.\:\ ]+\' {
+ int c = input();
+ if(c != EOF){
+ unput(c);
+ }
+ if(c!='\''){
+ sslval.v_string= icalmemory_tmp_copy(yytext);
+ return STRING;
+ } else {
+ /*ssmore();*/
+ }
+}
+
+[\@\*A-Za-z0-9\-\.]+ {
+ sslval.v_string= icalmemory_tmp_copy(yytext);
+ return STRING;
+}
+
+
+. { return yytext[0]; }
+
+%%
+
+int yywrap()
+{
+ return 1;
+}
+
diff --git a/src/libicalss/icalssutil.c b/src/libicalss/icalssutil.c
new file mode 100644
index 00000000..5ff4a0a8
--- /dev/null
+++ b/src/libicalss/icalssutil.c
@@ -0,0 +1,29 @@
+/* -*- Mode: C -*-
+ ======================================================================
+ FILE: icalssutil.c
+ CREATOR: ebusboom 23 aug 2000
+
+ $Id: icalssutil.c,v 1.3 2008-01-02 20:15:45 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
diff --git a/src/libicalss/icalssutil.h b/src/libicalss/icalssutil.h
new file mode 100644
index 00000000..43ce6f96
--- /dev/null
+++ b/src/libicalss/icalssutil.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C -*- */
+/*======================================================================
+ FILE: icalssutil.h
+ CREATOR: eric 21 Aug 2000
+
+
+ $Id: icalssutil.h,v 1.3 2008-01-02 20:15:45 dothebart Exp $
+ $Locker: $
+
+ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+
+ =========================================================================*/
+
+#include <libical/ical.h>
+
diff --git a/src/libicalss/icalssyacc.c b/src/libicalss/icalssyacc.c
new file mode 100644
index 00000000..58961200
--- /dev/null
+++ b/src/libicalss/icalssyacc.c
@@ -0,0 +1,1863 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse ssparse
+#define yylex sslex
+#define yyerror sserror
+#define yylval sslval
+#define yychar sschar
+#define yydebug ssdebug
+#define yynerrs ssnerrs
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ STRING = 258,
+ SELECT = 259,
+ FROM = 260,
+ WHERE = 261,
+ COMMA = 262,
+ QUOTE = 263,
+ EQUALS = 264,
+ NOTEQUALS = 265,
+ LESS = 266,
+ GREATER = 267,
+ LESSEQUALS = 268,
+ GREATEREQUALS = 269,
+ AND = 270,
+ OR = 271,
+ EOL = 272,
+ END = 273,
+ IS = 274,
+ NOT = 275,
+ SQLNULL = 276
+ };
+#endif
+/* Tokens. */
+#define STRING 258
+#define SELECT 259
+#define FROM 260
+#define WHERE 261
+#define COMMA 262
+#define QUOTE 263
+#define EQUALS 264
+#define NOTEQUALS 265
+#define LESS 266
+#define GREATER 267
+#define LESSEQUALS 268
+#define GREATEREQUALS 269
+#define AND 270
+#define OR 271
+#define EOL 272
+#define END 273
+#define IS 274
+#define NOT 275
+#define SQLNULL 276
+
+
+
+
+/* Copy the first part of user declarations. */
+
+/* -*- Mode: C -*- */
+/* ====================================================================== */
+/* FILE: icalssyacc.y */
+/* CREATOR: eric 08 Aug 2000 */
+/* */
+/* DESCRIPTION: */
+/* */
+/* $Id: icalssyacc.y,v 1.10 2008-01-14 00:35:26 dothebart Exp $ */
+/* $Locker: $ */
+/* */
+/* (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of either: */
+/* */
+/* The LGPL as published by the Free Software Foundation, version */
+/* 2.1, available at: http://www.fsf.org/copyleft/lesser.html */
+/* */
+/* Or: */
+/* */
+/* The Mozilla Public License Version 1.0. You may obtain a copy of */
+/* the License at http://www.mozilla.org/MPL/ */
+/* */
+/* The Original Code is eric. The Initial Developer of the Original */
+/* Code is Eric Busboom */
+/* */
+/* ====================================================================== */
+#define YYDEBUG 1
+#include <stdlib.h>
+#include <string.h> /* for strdup() */
+#include <limits.h> /* for SHRT_MAX*/
+#include <libical/ical.h>
+#include "icalgauge.h"
+#include "icalgaugeimpl.h"
+
+extern struct icalgauge_impl *icalss_yy_gauge;
+
+#define YYPARSE_PARAM yy_globals
+#define YYLEX_PARAM yy_globals
+#define YY_EXTRA_TYPE icalgauge_impl*
+
+
+void sserror(char *s);
+
+static void ssyacc_add_where(struct icalgauge_impl* impl, char* prop,
+ icalgaugecompare compare , char* value);
+static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1);
+static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1);
+static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l);
+
+/* Don't know why I need this.... */
+
+/* older flex version (such as included in OpenBSD) takes a different calling syntax */
+#ifdef YYPARSE_PARAM
+int sslex(void *YYPARSE_PARAM);
+#else
+int sslex(void);
+#endif
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+ char* v_string;
+}
+/* Line 187 of yacc.c. */
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 6
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 31
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 22
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 6
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 20
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 38
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 276
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 10, 15, 17, 19, 23, 25, 29,
+ 30, 34, 38, 43, 47, 51, 55, 59, 63, 65,
+ 69
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 23, 0, -1, 4, 24, 5, 25, 6, 27, -1,
+ 4, 24, 5, 25, -1, 1, -1, 3, -1, 24,
+ 7, 3, -1, 3, -1, 25, 7, 3, -1, -1,
+ 3, 9, 3, -1, 3, 19, 21, -1, 3, 19,
+ 20, 21, -1, 3, 10, 3, -1, 3, 11, 3,
+ -1, 3, 12, 3, -1, 3, 13, 3, -1, 3,
+ 14, 3, -1, 26, -1, 27, 15, 26, -1, 27,
+ 16, 26, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint8 yyrline[] =
+{
+ 0, 73, 73, 74, 75, 82, 83, 88, 89, 92,
+ 94, 95, 96, 97, 98, 99, 100, 101, 105, 106,
+ 107
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "STRING", "SELECT", "FROM", "WHERE",
+ "COMMA", "QUOTE", "EQUALS", "NOTEQUALS", "LESS", "GREATER", "LESSEQUALS",
+ "GREATEREQUALS", "AND", "OR", "EOL", "END", "IS", "NOT", "SQLNULL",
+ "$accept", "query_min", "select_list", "from_list", "where_clause",
+ "where_list", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 22, 23, 23, 23, 24, 24, 25, 25, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
+ 27
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 6, 4, 1, 1, 3, 1, 3, 0,
+ 3, 3, 4, 3, 3, 3, 3, 3, 1, 3,
+ 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 4, 0, 0, 5, 0, 1, 0, 0, 7,
+ 3, 6, 9, 0, 0, 18, 2, 8, 0, 0,
+ 0, 0, 0, 0, 0, 9, 9, 10, 13, 14,
+ 15, 16, 17, 0, 11, 19, 20, 12
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 3, 5, 10, 15, 16
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -10
+static const yytype_int8 yypact[] =
+{
+ 5, -10, 9, 20, -10, 6, -10, 18, 19, -10,
+ 1, -10, 21, 22, -9, -10, -1, -10, 23, 24,
+ 25, 26, 27, 28, -4, 21, 21, -10, -10, -10,
+ -10, -10, -10, 2, -10, -10, -10, -10
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -10, -10, -10, -10, -7, -10
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 18, 19, 20, 21, 22, 23, 1, 12, 13, 2,
+ 24, 7, 4, 8, 25, 26, 33, 34, 35, 36,
+ 6, 9, 11, 37, 14, 17, 27, 28, 29, 30,
+ 31, 32
+};
+
+static const yytype_uint8 yycheck[] =
+{
+ 9, 10, 11, 12, 13, 14, 1, 6, 7, 4,
+ 19, 5, 3, 7, 15, 16, 20, 21, 25, 26,
+ 0, 3, 3, 21, 3, 3, 3, 3, 3, 3,
+ 3, 3
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 1, 4, 23, 3, 24, 0, 5, 7, 3,
+ 25, 3, 6, 7, 3, 26, 27, 3, 9, 10,
+ 11, 12, 13, 14, 19, 15, 16, 3, 3, 3,
+ 3, 3, 3, 20, 21, 26, 26, 21
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+ {
+ yyclearin;
+ YYABORT;
+ }
+ break;
+
+ case 5:
+ {ssyacc_add_select(icalss_yy_gauge,(yyvsp[(1) - (1)].v_string));}
+ break;
+
+ case 6:
+ {ssyacc_add_select(icalss_yy_gauge,(yyvsp[(3) - (3)].v_string));}
+ break;
+
+ case 7:
+ {ssyacc_add_from(icalss_yy_gauge,(yyvsp[(1) - (1)].v_string));}
+ break;
+
+ case 8:
+ {ssyacc_add_from(icalss_yy_gauge,(yyvsp[(3) - (3)].v_string));}
+ break;
+
+ case 10:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_EQUAL,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 11:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_ISNULL,""); }
+ break;
+
+ case 12:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (4)].v_string),ICALGAUGECOMPARE_ISNOTNULL,""); }
+ break;
+
+ case 13:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_NOTEQUAL,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 14:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_LESS,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 15:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_GREATER,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 16:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_LESSEQUAL,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 17:
+ {ssyacc_add_where(icalss_yy_gauge,(yyvsp[(1) - (3)].v_string),ICALGAUGECOMPARE_GREATEREQUAL,(yyvsp[(3) - (3)].v_string)); }
+ break;
+
+ case 18:
+ {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_NONE);}
+ break;
+
+ case 19:
+ {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_AND);}
+ break;
+
+ case 20:
+ {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_OR);}
+ break;
+
+
+/* Line 1267 of yacc.c. */
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+static void ssyacc_add_where(struct icalgauge_impl* impl, char* str1,
+ icalgaugecompare compare , char* value_str)
+{
+
+ struct icalgauge_where *where;
+ char *compstr, *propstr, *c, *s,*l;
+
+ if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return;
+ }
+
+ memset(where,0,sizeof(struct icalgauge_where));
+ where->logic = ICALGAUGELOGIC_NONE;
+ where->compare = ICALGAUGECOMPARE_NONE;
+ where->comp = ICAL_NO_COMPONENT;
+ where->prop = ICAL_NO_PROPERTY;
+
+ /* remove enclosing quotes */
+ s = value_str;
+ if(*s == '\''){
+ s++;
+ }
+ l = s+strlen(s)-1;
+ if(*l == '\''){
+ *l=0;
+ }
+
+ where->value = strdup(s);
+
+ /* Is there a period in str1 ? If so, the string specified both a */
+ /* component and a property */
+ if( (c = strrchr(str1,'.')) != 0){
+ compstr = str1;
+ propstr = c+1;
+ *c = '\0';
+ } else {
+ compstr = 0;
+ propstr = str1;
+ }
+
+
+ /* Handle the case where a component was specified */
+ if(compstr != 0){
+ where->comp = icalenum_string_to_component_kind(compstr);
+ } else {
+ where->comp = ICAL_NO_COMPONENT;
+ }
+
+ where->prop = icalenum_string_to_property_kind(propstr);
+
+ where->compare = compare;
+
+ if(where->value == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ free(where->value);
+ return;
+ }
+
+ pvl_push(impl->where,where);
+}
+
+static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l)
+{
+ pvl_elem e = pvl_tail(impl->where);
+ struct icalgauge_where *where = pvl_data(e);
+
+ where->logic = l;
+
+}
+
+
+
+static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1)
+{
+ char *c, *compstr, *propstr;
+ struct icalgauge_where *where;
+
+ /* Uses only the prop and comp fields of the where structure */
+ if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return;
+ }
+
+ memset(where,0,sizeof(struct icalgauge_where));
+ where->logic = ICALGAUGELOGIC_NONE;
+ where->compare = ICALGAUGECOMPARE_NONE;
+ where->comp = ICAL_NO_COMPONENT;
+ where->prop = ICAL_NO_PROPERTY;
+
+ /* Is there a period in str1 ? If so, the string specified both a */
+ /* component and a property */
+ if( (c = strrchr(str1,'.')) != 0){
+ compstr = str1;
+ propstr = c+1;
+ *c = '\0';
+ } else {
+ compstr = 0;
+ propstr = str1;
+ }
+
+
+ /* Handle the case where a component was specified */
+ if(compstr != 0){
+ where->comp = icalenum_string_to_component_kind(compstr);
+ } else {
+ where->comp = ICAL_NO_COMPONENT;
+ }
+
+
+ /* If the property was '*', then accept all properties */
+ if(strcmp("*",propstr) == 0) {
+ where->prop = ICAL_ANY_PROPERTY;
+ } else {
+ where->prop = icalenum_string_to_property_kind(propstr);
+ }
+
+
+ if(where->prop == ICAL_NO_PROPERTY){
+ free(where);
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return;
+ }
+
+ pvl_push(impl->select,where);
+}
+
+static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1)
+{
+ icalcomponent_kind ckind;
+
+ ckind = icalenum_string_to_component_kind(str1);
+
+ if(ckind == ICAL_NO_COMPONENT){
+ assert(0);
+ }
+
+ pvl_push(impl->from,(void*)ckind);
+
+}
+
+
+void sserror(char *s){
+ fprintf(stderr,"Parse error \'%s\'\n", s);
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+}
+
diff --git a/src/libicalss/icalssyacc.h b/src/libicalss/icalssyacc.h
new file mode 100644
index 00000000..f97cc4a7
--- /dev/null
+++ b/src/libicalss/icalssyacc.h
@@ -0,0 +1,100 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ STRING = 258,
+ SELECT = 259,
+ FROM = 260,
+ WHERE = 261,
+ COMMA = 262,
+ QUOTE = 263,
+ EQUALS = 264,
+ NOTEQUALS = 265,
+ LESS = 266,
+ GREATER = 267,
+ LESSEQUALS = 268,
+ GREATEREQUALS = 269,
+ AND = 270,
+ OR = 271,
+ EOL = 272,
+ END = 273,
+ IS = 274,
+ NOT = 275,
+ SQLNULL = 276
+ };
+#endif
+/* Tokens. */
+#define STRING 258
+#define SELECT 259
+#define FROM 260
+#define WHERE 261
+#define COMMA 262
+#define QUOTE 263
+#define EQUALS 264
+#define NOTEQUALS 265
+#define LESS 266
+#define GREATER 267
+#define LESSEQUALS 268
+#define GREATEREQUALS 269
+#define AND 270
+#define OR 271
+#define EOL 272
+#define END 273
+#define IS 274
+#define NOT 275
+#define SQLNULL 276
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+ char* v_string;
+}
+/* Line 1489 of yacc.c. */
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE sslval;
+
diff --git a/src/libicalss/icalssyacc.y b/src/libicalss/icalssyacc.y
new file mode 100644
index 00000000..03e1d922
--- /dev/null
+++ b/src/libicalss/icalssyacc.y
@@ -0,0 +1,258 @@
+%{
+/* -*- Mode: C -*- */
+/* ====================================================================== */
+/* FILE: icalssyacc.y */
+/* CREATOR: eric 08 Aug 2000 */
+/* */
+/* DESCRIPTION: */
+/* */
+/* $Id: icalssyacc.y,v 1.10 2008-01-14 00:35:26 dothebart Exp $ */
+/* $Locker: $ */
+/* */
+/* (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of either: */
+/* */
+/* The LGPL as published by the Free Software Foundation, version */
+/* 2.1, available at: http://www.fsf.org/copyleft/lesser.html */
+/* */
+/* Or: */
+/* */
+/* The Mozilla Public License Version 1.0. You may obtain a copy of */
+/* the License at http://www.mozilla.org/MPL/ */
+/* */
+/* The Original Code is eric. The Initial Developer of the Original */
+/* Code is Eric Busboom */
+/* */
+/* ====================================================================== */
+/*#define YYDEBUG 1*/
+#include <stdlib.h>
+#include <string.h> /* for strdup() */
+#include <limits.h> /* for SHRT_MAX*/
+#include <libical/ical.h>
+#include "icalgauge.h"
+#include "icalgaugeimpl.h"
+
+extern struct icalgauge_impl *icalss_yy_gauge;
+
+#define YYPARSE_PARAM yy_globals
+#define YYLEX_PARAM yy_globals
+#define YY_EXTRA_TYPE icalgauge_impl*
+
+
+void sserror(char *s);
+
+static void ssyacc_add_where(struct icalgauge_impl* impl, char* prop,
+ icalgaugecompare compare , char* value);
+static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1);
+static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1);
+static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l);
+
+/* Don't know why I need this.... */
+
+/* older flex version (such as included in OpenBSD) takes a different calling syntax */
+#ifdef YYPARSE_PARAM
+int sslex(void *YYPARSE_PARAM);
+#else
+int sslex(void);
+#endif
+%}
+
+%union {
+ char* v_string;
+}
+
+
+%token <v_string> STRING
+%token SELECT FROM WHERE COMMA QUOTE EQUALS NOTEQUALS LESS GREATER LESSEQUALS
+%token GREATEREQUALS AND OR EOL END IS NOT SQLNULL
+
+%%
+
+query_min: SELECT select_list FROM from_list WHERE where_list
+ | SELECT select_list FROM from_list
+ | error {
+ yyclearin;
+ YYABORT;
+ }
+ ;
+
+select_list:
+ STRING {ssyacc_add_select(icalss_yy_gauge,$1);}
+ | select_list COMMA STRING {ssyacc_add_select(icalss_yy_gauge,$3);}
+ ;
+
+
+from_list:
+ STRING {ssyacc_add_from(icalss_yy_gauge,$1);}
+ | from_list COMMA STRING {ssyacc_add_from(icalss_yy_gauge,$3);}
+ ;
+
+where_clause:
+ /* Empty */
+ | STRING EQUALS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_EQUAL,$3); }
+ | STRING IS SQLNULL {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_ISNULL,""); }
+ | STRING IS NOT SQLNULL {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_ISNOTNULL,""); }
+ | STRING NOTEQUALS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_NOTEQUAL,$3); }
+ | STRING LESS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_LESS,$3); }
+ | STRING GREATER STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_GREATER,$3); }
+ | STRING LESSEQUALS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_LESSEQUAL,$3); }
+ | STRING GREATEREQUALS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_GREATEREQUAL,$3); }
+ ;
+
+where_list:
+ where_clause {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_NONE);}
+ | where_list AND where_clause {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_AND);}
+ | where_list OR where_clause {set_logic(icalss_yy_gauge,ICALGAUGELOGIC_OR);}
+ ;
+
+
+%%
+
+static void ssyacc_add_where(struct icalgauge_impl* impl, char* str1,
+ icalgaugecompare compare , char* value_str)
+{
+
+ struct icalgauge_where *where;
+ char *compstr, *propstr, *c, *s,*l;
+
+ if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return;
+ }
+
+ memset(where,0,sizeof(struct icalgauge_where));
+ where->logic = ICALGAUGELOGIC_NONE;
+ where->compare = ICALGAUGECOMPARE_NONE;
+ where->comp = ICAL_NO_COMPONENT;
+ where->prop = ICAL_NO_PROPERTY;
+
+ /* remove enclosing quotes */
+ s = value_str;
+ if(*s == '\''){
+ s++;
+ }
+ l = s+strlen(s)-1;
+ if(*l == '\''){
+ *l=0;
+ }
+
+ where->value = strdup(s);
+
+ /* Is there a period in str1 ? If so, the string specified both a */
+ /* component and a property */
+ if( (c = strrchr(str1,'.')) != 0){
+ compstr = str1;
+ propstr = c+1;
+ *c = '\0';
+ } else {
+ compstr = 0;
+ propstr = str1;
+ }
+
+
+ /* Handle the case where a component was specified */
+ if(compstr != 0){
+ where->comp = icalenum_string_to_component_kind(compstr);
+ } else {
+ where->comp = ICAL_NO_COMPONENT;
+ }
+
+ where->prop = icalenum_string_to_property_kind(propstr);
+
+ where->compare = compare;
+
+ if(where->value == 0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ free(where->value);
+ return;
+ }
+
+ pvl_push(impl->where,where);
+}
+
+static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l)
+{
+ pvl_elem e = pvl_tail(impl->where);
+ struct icalgauge_where *where = pvl_data(e);
+
+ where->logic = l;
+
+}
+
+
+
+static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1)
+{
+ char *c, *compstr, *propstr;
+ struct icalgauge_where *where;
+
+ /* Uses only the prop and comp fields of the where structure */
+ if ( (where = malloc(sizeof(struct icalgauge_where))) ==0){
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return;
+ }
+
+ memset(where,0,sizeof(struct icalgauge_where));
+ where->logic = ICALGAUGELOGIC_NONE;
+ where->compare = ICALGAUGECOMPARE_NONE;
+ where->comp = ICAL_NO_COMPONENT;
+ where->prop = ICAL_NO_PROPERTY;
+
+ /* Is there a period in str1 ? If so, the string specified both a */
+ /* component and a property */
+ if( (c = strrchr(str1,'.')) != 0){
+ compstr = str1;
+ propstr = c+1;
+ *c = '\0';
+ } else {
+ compstr = 0;
+ propstr = str1;
+ }
+
+
+ /* Handle the case where a component was specified */
+ if(compstr != 0){
+ where->comp = icalenum_string_to_component_kind(compstr);
+ } else {
+ where->comp = ICAL_NO_COMPONENT;
+ }
+
+
+ /* If the property was '*', then accept all properties */
+ if(strcmp("*",propstr) == 0) {
+ where->prop = ICAL_ANY_PROPERTY;
+ } else {
+ where->prop = icalenum_string_to_property_kind(propstr);
+ }
+
+
+ if(where->prop == ICAL_NO_PROPERTY){
+ free(where);
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return;
+ }
+
+ pvl_push(impl->select,where);
+}
+
+static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1)
+{
+ icalcomponent_kind ckind;
+
+ ckind = icalenum_string_to_component_kind(str1);
+
+ if(ckind == ICAL_NO_COMPONENT){
+ assert(0);
+ }
+
+ pvl_push(impl->from,(void*)ckind);
+
+}
+
+
+void sserror(char *s){
+ fprintf(stderr,"Parse error \'%s\'\n", s);
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+}
diff --git a/src/libicalss/libicalss.dsp b/src/libicalss/libicalss.dsp
new file mode 100644
index 00000000..356aad3a
--- /dev/null
+++ b/src/libicalss/libicalss.dsp
@@ -0,0 +1,212 @@
+# Microsoft Developer Studio Project File - Name="libicalss" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libicalss - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libicalss.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libicalss.mak" CFG="libicalss - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libicalss - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libicalss - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libicalss - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../libical" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "YY_NO_UNISTD_H" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libicalss - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "libicalss___Win32_Debug"
+# PROP BASE Intermediate_Dir "libicalss___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\libical" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "YY_NO_UNISTD_H" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libicalss - Win32 Release"
+# Name "libicalss - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\icalcalendar.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalclassify.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalcluster.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icaldirset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalfileset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalgauge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalmessage.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalset.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalspanlist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalsslexer.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalssyacc.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\icalbdbset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalbdbsetimpl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalcalendar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalcaputil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalclassify.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalcluster.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalclusterimpl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalcsdb.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icaldirset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icaldirsetimpl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalfileset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalfilesetimpl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalgauge.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalgaugeimpl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalmessage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalset.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalspanlist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalss.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\icalssyacc.h
+# End Source File
+# End Group
+# End Target
+# End Project