diff options
Diffstat (limited to 'src/libicalss')
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 |