diff options
Diffstat (limited to 'libical/src/libicalss')
33 files changed, 4560 insertions, 1079 deletions
diff --git a/libical/src/libicalss/.cvsignore b/libical/src/libicalss/.cvsignore index 04a3e1b036..25846dfca6 100644 --- a/libical/src/libicalss/.cvsignore +++ b/libical/src/libicalss/.cvsignore @@ -1,10 +1,6 @@ Makefile .deps -Makefile.in +.libs *.lo *.la -.libs -y.output -icalsslexer.c -icalssyacc.c icalss.h diff --git a/libical/src/libicalss/Makefile.am b/libical/src/libicalss/Makefile.am index 9e11bc3fc8..ebb755c95a 100644 --- a/libical/src/libicalss/Makefile.am +++ b/libical/src/libicalss/Makefile.am @@ -1,26 +1,89 @@ -lib_LTLIBRARIES = libicalss.la +#====================================================================== +# FILE: Makefile.am +# CREATOR: eric +# +# $Id: Makefile.am,v 1.19 2003/09/11 22:04:30 hansp 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/ +# +# +# +#====================================================================== -YFLAGS =-d -v -p ss -LFLAGS = -Pss + +AM_YFLAGS =-d -v -p ss +AM_LFLAGS = -Pss LEX_OUTPUT_ROOT = lex.ss all: icalss.h +# just to get it built +$(srcdir)/icalgauge.c: icalssyacc.h +$(srcdir)/icalsslexer.c: icalssyacc.h + + +if WITH_BDB4 +BDB_INCLUDE=-I@BDB_DIR_INCLUDE@ -DWITH_BDB4 +BDB_SOURCEFILES=icalbdbset.c icalbdbset.h icalbdbsetimpl.h +BDB_HEADERFILES=$(srcdir)/icalbdbset.h +libicalssinclude_BDBHEADERS=icalbdbset.h icalbdbsetimpl.h +BDB_LIBFILES=@BDB_DIR_LIB@/@BDB_LIB@ +else +BDB_INCLUDE= +BDB_SOURCEFILES= +BDB_HEADERFILES= +endif + +if WITH_CXX +cxx_lib=libicalss_cxx.la +cxx_headers=icalspanlist_cxx.h +else +cxx_lib= +cxx_headers= +endif + +lib_LTLIBRARIES = libicalss.la $(cxx_lib) + INCLUDES = \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -I$(top_srcdir)/src/libical \ - -I$(top_builddir)/src/libical + -I$(top_builddir)/libical \ + $(BDB_INCLUDE) libicalss_la_LDFLAGS = -version-info 0:0:0 +libicalss_la_LIBADD = $(BDB_LIBFILES) + +if DEV +libicalss_la_DEVSOURCES = icalsslexer.l icalssyacc.y +else +libicalss_la_DEVSOURCES = icalsslexer.c icalssyacc.c +endif libicalss_la_SOURCES = \ + 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 \ @@ -28,42 +91,58 @@ libicalss_la_SOURCES = \ icalfilesetimpl.h \ icalset.c \ icalset.h \ - icalsslexer.l \ icalssyacc.h \ - icalssyacc.y \ icalspanlist.c \ icalspanlist.h \ icalmessage.c \ icalmessage.h \ - icalcstpclient.c \ - icalcstpclient.h \ - icalcstpserver.c \ - icalcstpserver.h \ - icalcstp.c \ - icalcstp.h + $(BDB_SOURCEFILES) \ + $(libicalss_la_DEVSOURCES) libicalssincludedir = $(includedir) COMBINEDHEADERS = \ $(srcdir)/icalgauge.h \ $(srcdir)/icalset.h \ + $(srcdir)/icalcluster.h \ $(srcdir)/icalfileset.h \ $(srcdir)/icaldirset.h \ + $(BDB_HEADERFILES) \ $(srcdir)/icalcalendar.h \ $(srcdir)/icalclassify.h \ $(srcdir)/icalspanlist.h \ - $(srcdir)/icalmessage.h \ - $(srcdir)/icalcstp.h \ - $(srcdir)/icalcstpclient.h \ - $(srcdir)/icalcstpserver.h + $(srcdir)/icalmessage.h icalss.h: $(COMBINEDHEADERS) - cat $(COMBINEDHEADERS) | egrep -v "#include.*\"ical" \ - | egrep -v "#include.*\"pvl\.h\"" > icalss.h + echo '#ifdef __cplusplus' > icalss.h + echo 'extern "C" {' >> icalss.h + echo '#endif' >> icalss.h + echo '/*' >> icalss.h + echo ' $$''Id''$$' >> icalss.h + echo '*/' >> icalss.h + cat $(COMBINEDHEADERS) \ + | egrep -v "#include.*\"ical" \ + | egrep -v "#include.*\"pvl\.h\"" \ + | egrep -v '\$$(Id|Locker): .+\$$'>> icalss.h + echo '#ifdef __cplusplus' >> icalss.h + echo '};' >> icalss.h + echo '#endif' >> icalss.h + + +if WITH_CXX +libicalss_cxx_la_SOURCES = \ + $(libicalss_la_SOURCES) \ + icalspanlist_cxx.h \ + icalspanlist_cxx.cpp + +# c++ needs ical.h auto-generated. +icalspanlist_cxx.lo: icalss.h + +endif -libicalssinclude_HEADERS = icalss.h +libicalssinclude_HEADERS = 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 $(libicalssinclude_BDBHEADERS) $(cxx_headers) CONFIG_CLEAN_FILES = y.output diff --git a/libical/src/libicalss/icalbdbset.c b/libical/src/libicalss/icalbdbset.c new file mode 100644 index 0000000000..6b11e46741 --- /dev/null +++ b/libical/src/libicalss/icalbdbset.c @@ -0,0 +1,1598 @@ +/* -*- 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 */ +#include <unistd.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(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; + } + } + } + + 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 = strdup(icalvalue_as_ical_string(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/libical/src/libicalss/icalbdbset.h b/libical/src/libicalss/icalbdbset.h new file mode 100644 index 0000000000..c5c835fae3 --- /dev/null +++ b/libical/src/libicalss/icalbdbset.h @@ -0,0 +1,147 @@ +/* -*- Mode: C -*- */ +/*====================================================================== + FILE: icalbdbset.h + CREATOR: dml 12 December 2001 + (C) COPYRIGHT 2001, Critical Path + + $Id$ + $Locker$ +======================================================================*/ + +#ifndef ICALBDBSET_H +#define ICALBDBSET_H + +#include "ical.h" +#include "icalset.h" +#include "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/libical/src/libicalss/icalbdbset_cxx.h b/libical/src/libicalss/icalbdbset_cxx.h new file mode 100644 index 0000000000..678adaa299 --- /dev/null +++ b/libical/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 "ical.h" +#include "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/libical/src/libicalss/icalbdbsetimpl.h b/libical/src/libicalss/icalbdbsetimpl.h new file mode 100644 index 0000000000..281a4834d4 --- /dev/null +++ b/libical/src/libicalss/icalbdbsetimpl.h @@ -0,0 +1,41 @@ +/* -*- Mode: C -*- + ====================================================================== + FILE: icalbdbsetimpl.h + CREATOR: dml 12 December 2001 + (C) COPYRIGHT 2001, Critical Path + + $Id$ + $Locker$ + ======================================================================*/ + +#ifndef ICALBDBSETIMPL_H +#define ICALBDBSETIMPL_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "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/libical/src/libicalss/icalcalendar.c b/libical/src/libicalss/icalcalendar.c index e63b5330ad..1f24f88db6 100644 --- a/libical/src/libicalss/icalcalendar.c +++ b/libical/src/libicalss/icalcalendar.c @@ -34,7 +34,16 @@ #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> @@ -47,13 +56,13 @@ struct icalcalendar_impl { char* dir; - icalcomponent* freebusy; - icalcomponent* properties; + icalset* freebusy; + icalset* properties; icalset* booked; icalset* incoming; }; -struct icalcalendar_impl* icalcalendar_new_impl() +struct icalcalendar_impl* icalcalendar_new_impl(void) { struct icalcalendar_impl* impl; @@ -119,29 +128,26 @@ icalcalendar* icalcalendar_new(char* dir) return impl; } -void icalcalendar_free(icalcalendar* calendar) +void icalcalendar_free(icalcalendar* impl) { - - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; - if (impl->dir !=0){ free(impl->dir); } if (impl->freebusy !=0){ - icalfileset_free(impl->freebusy); + icalset_free(impl->booked); } if (impl->properties !=0){ - icalfileset_free(impl->properties); + icalset_free(impl->properties); } if (impl->booked !=0){ - icaldirset_free(impl->booked); + icalset_free(impl->booked); } if (impl->incoming !=0){ - icaldirset_free(impl->incoming); + icalset_free(impl->incoming); } impl->dir = 0; @@ -155,37 +161,32 @@ void icalcalendar_free(icalcalendar* calendar) } -int icalcalendar_lock(icalcalendar* calendar) +int icalcalendar_lock(icalcalendar* impl) { - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); return 0; } -int icalcalendar_unlock(icalcalendar* calendar) +int icalcalendar_unlock(icalcalendar* impl) { - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); return 0; } -int icalcalendar_islocked(icalcalendar* calendar) +int icalcalendar_islocked(icalcalendar* impl) { - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); return 0; } -int icalcalendar_ownlock(icalcalendar* calendar) +int icalcalendar_ownlock(icalcalendar* impl) { - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); return 0; } -icalset* icalcalendar_get_booked(icalcalendar* calendar) +icalset* icalcalendar_get_booked(icalcalendar* impl) { - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; char dir[PATH_MAX]; icalerror_check_arg_rz((impl != 0),"impl"); @@ -205,10 +206,9 @@ icalset* icalcalendar_get_booked(icalcalendar* calendar) } -icalset* icalcalendar_get_incoming(icalcalendar* calendar) +icalset* icalcalendar_get_incoming(icalcalendar* impl) { char path[PATH_MAX]; - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); path[0] = '\0'; @@ -223,10 +223,9 @@ icalset* icalcalendar_get_incoming(icalcalendar* calendar) return impl->properties; } -icalset* icalcalendar_get_properties(icalcalendar* calendar) +icalset* icalcalendar_get_properties(icalcalendar* impl) { char path[PATH_MAX]; - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); path[0] = '\0'; @@ -241,10 +240,9 @@ icalset* icalcalendar_get_properties(icalcalendar* calendar) return impl->properties; } -icalset* icalcalendar_get_freebusy(icalcalendar* calendar) +icalset* icalcalendar_get_freebusy(icalcalendar* impl) { char path[PATH_MAX]; - struct icalcalendar_impl *impl = (struct icalcalendar_impl*)calendar; icalerror_check_arg_rz((impl != 0),"impl"); path[0] = '\0'; diff --git a/libical/src/libicalss/icalcalendar.h b/libical/src/libicalss/icalcalendar.h index f07457c60d..2a0c15196a 100644 --- a/libical/src/libicalss/icalcalendar.h +++ b/libical/src/libicalss/icalcalendar.h @@ -38,7 +38,7 @@ * components. It also has interfaces to access the free/busy list * and a list of calendar properties */ -typedef void icalcalendar; +typedef struct icalcalendar_impl icalcalendar; icalcalendar* icalcalendar_new(char* dir); diff --git a/libical/src/libicalss/icalcaputil.h b/libical/src/libicalss/icalcaputil.h new file mode 100644 index 0000000000..4f9bcb31c4 --- /dev/null +++ b/libical/src/libicalss/icalcaputil.h @@ -0,0 +1,58 @@ +/* -*- Mode: C -*- */ +/*====================================================================== + FILE: icalutil.h + CREATOR: eric 23 December 1999 + + + $Id$ + $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/libical/src/libicalss/icalclassify.c b/libical/src/libicalss/icalclassify.c index ad2d6d6fd8..61ddbd3a76 100644 --- a/libical/src/libicalss/icalclassify.c +++ b/libical/src/libicalss/icalclassify.c @@ -29,6 +29,7 @@ #include "ical.h" #include "icalclassify.h" #include "icalmemory.h" + #include <ctype.h> /* For tolower() */ #include <string.h> /* for index() */ #include <stdlib.h> /* for malloc and free */ @@ -36,15 +37,16 @@ struct icalclassify_parts { - icalcomponent *c; - icalproperty_method method; - char* organizer; - icalparameter_partstat reply_partstat; - char* reply_attendee; - char* uid; - int sequence; - struct icaltimetype dtstamp; - struct icaltimetype recurrence_id; + 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; }; @@ -121,27 +123,48 @@ icalproperty* icalclassify_find_attendee(icalcomponent *c, const char* attendee) { icalproperty *p; - char* lattendee = icalclassify_lowercase(attendee); - char* upn = strchr(lattendee,':'); - icalcomponent *inner = icalcomponent_get_first_real_component(c); + 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)) { - const char* this_attendee + char* this_attendee = icalclassify_lowercase(icalproperty_get_attendee(p)); char* this_upn = strchr(this_attendee,':'); if(this_upn == 0){ continue; - } + } else { + this_upn++; + } if(strcmp(this_upn,upn)==0){ + free(lattendee); + free(this_attendee); return p; } + free(this_attendee); } + free(lattendee); return 0; @@ -191,6 +214,8 @@ void icalssutil_get_parts(icalcomponent* c, 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){ parts->organizer = strdup(icalproperty_get_organizer(p)); @@ -263,7 +288,7 @@ int icalssutil_is_rescheduled(icalcomponent* a,icalcomponent* b) p1 = icalcomponent_get_first_property(i1,kind_array[i]); p2 = icalcomponent_get_first_property(i2,kind_array[i]); - if( (p1!=0)^(p1!=0) ){ + if( (p1!=0)^(p2!=0) ){ /* Return true if the property exists in one component and not the other */ return 1; @@ -293,7 +318,7 @@ int icalclassify_publish_new(struct icalclassify_parts *comp, icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && - match == 0){ + match == 0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } @@ -308,7 +333,7 @@ int icalclassify_publish_update(struct icalclassify_parts *comp, icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && - match !=0 ){ + match !=0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } @@ -323,7 +348,7 @@ int icalclassify_publish_freebusy(struct icalclassify_parts *comp, icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && - match == 0){ + comp->inner_kind == ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } @@ -392,11 +417,19 @@ int icalclassify_request_delegate( struct icalclassify_parts *match, const char* user) { - icalclassify_pre + icalproperty* attendee; + icalparameter* param; + icalclassify_pre; - if (match->c != 0 && - comp->sequence > match->sequence && - icalssutil_is_rescheduled(comp->c,match->c)){ + 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; } @@ -411,7 +444,7 @@ int icalclassify_request_new_organizer( { /* Organizer has changed between match and component */ icalclassify_pre - + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } @@ -422,6 +455,7 @@ int icalclassify_request_status( const char* user) { icalclassify_pre + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } @@ -431,6 +465,7 @@ int icalclassify_request_forward( const char* user) { icalclassify_pre + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } @@ -440,6 +475,7 @@ int icalclassify_request_freebusy( const char* user) { icalclassify_pre + icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } @@ -477,6 +513,22 @@ int icalclassify_reply_decline( } icalclassify_post } +int icalclassify_reply_delegate( + struct icalclassify_parts *comp, + struct icalclassify_parts *match, + const char* user) +{ + icalproperty* attendee; + icalclassify_pre; + + 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, @@ -498,7 +550,6 @@ int icalclassify_reply_crasher_decline( struct icalclassify_parts *match, const char* user) { - icalparameter_partstat partstat; icalproperty* attendee; icalclassify_pre; @@ -594,45 +645,47 @@ int icalclassify_delinecounter( struct icalclassify_map { icalproperty_method method; int (*fn)(struct icalclassify_parts *comp,struct icalclassify_parts *match, const char* user); - ical_class class; + icalproperty_xlicclass class; } icalclassify_map[] = -{ {ICAL_METHOD_PUBLISH,icalclassify_publish_new,ICAL_PUBLISH_NEW_CLASS}, - {ICAL_METHOD_PUBLISH,icalclassify_publish_update,ICAL_PUBLISH_UPDATE_CLASS}, - {ICAL_METHOD_PUBLISH,icalclassify_publish_freebusy,ICAL_PUBLISH_FREEBUSY_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_new,ICAL_REQUEST_NEW_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_update,ICAL_REQUEST_UPDATE_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_reschedule,ICAL_REQUEST_RESCHEDULE_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_delegate,ICAL_REQUEST_DELEGATE_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_new_organizer,ICAL_REQUEST_NEW_ORGANIZER_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_forward,ICAL_REQUEST_FORWARD_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_status,ICAL_REQUEST_STATUS_CLASS}, - {ICAL_METHOD_REQUEST,icalclassify_request_freebusy,ICAL_REQUEST_FREEBUSY_CLASS}, - - {ICAL_METHOD_REPLY,icalclassify_reply_accept,ICAL_REPLY_ACCEPT_CLASS}, - {ICAL_METHOD_REPLY,icalclassify_reply_decline,ICAL_REPLY_DECLINE_CLASS}, - {ICAL_METHOD_REPLY,icalclassify_reply_crasher_accept,ICAL_REPLY_CRASHER_ACCEPT_CLASS}, - {ICAL_METHOD_REPLY,icalclassify_reply_crasher_decline,ICAL_REPLY_CRASHER_DECLINE_CLASS}, - - {ICAL_METHOD_ADD,icalclassify_add_instance,ICAL_ADD_INSTANCE_CLASS}, - - {ICAL_METHOD_CANCEL,icalclassify_cancel_event,ICAL_CANCEL_EVENT_CLASS}, - {ICAL_METHOD_CANCEL,icalclassify_cancel_instance,ICAL_CANCEL_INSTANCE_CLASS}, - {ICAL_METHOD_CANCEL,icalclassify_cancel_all,ICAL_CANCEL_ALL_CLASS}, - - {ICAL_METHOD_REFRESH,icalclassify_refesh,ICAL_REFRESH_CLASS}, - {ICAL_METHOD_COUNTER,icalclassify_counter,ICAL_COUNTER_CLASS}, - {ICAL_METHOD_DECLINECOUNTER,icalclassify_delinecounter,ICAL_DECLINECOUNTER_CLASS}, - {ICAL_METHOD_NONE,0,ICAL_NO_CLASS} +{ {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} }; -ical_class icalclassify(icalcomponent* c,icalcomponent* match, +icalproperty_xlicclass icalclassify(icalcomponent* c,icalcomponent* match, const char* user) { icalcomponent *inner; icalproperty *p; icalproperty_method method; - ical_class class = ICAL_UNKNOWN_CLASS; + icalproperty_xlicclass class = ICAL_XLICCLASS_UNKNOWN; int i; @@ -642,7 +695,7 @@ ical_class icalclassify(icalcomponent* c,icalcomponent* match, inner = icalcomponent_get_first_real_component(c); if (inner == 0) { - return ICAL_NO_CLASS; + return ICAL_XLICCLASS_NONE; } icalssutil_get_parts(c,&comp_parts); @@ -659,7 +712,8 @@ ical_class icalclassify(icalcomponent* c,icalcomponent* match, icaltime_compare(comp_parts.dtstamp,match_parts.dtstamp)>0) { /* comp has a smaller sequence and a later DTSTAMP */ - return ICAL_MISSEQUENCED_CLASS; + class = ICAL_XLICCLASS_MISSEQUENCED; + goto CLEANUP; } if( (comp_parts.sequence<match_parts.sequence ) @@ -668,14 +722,16 @@ ical_class icalclassify(icalcomponent* c,icalcomponent* match, ( comp_parts.sequence == match_parts.sequence && icaltime_compare(comp_parts.dtstamp,match_parts.dtstamp)<=0)){ - return ICAL_OBSOLETE_CLASS; + class = ICAL_XLICCLASS_OBSOLETE; + goto CLEANUP; } } p = icalcomponent_get_first_property(c,ICAL_METHOD_PROPERTY); if (p == 0) { - return ICAL_UNKNOWN_CLASS; + class = ICAL_XLICCLASS_UNKNOWN; + goto CLEANUP; } method = icalproperty_get_method(p); @@ -688,9 +744,11 @@ ical_class icalclassify(icalcomponent* c,icalcomponent* match, } } +CLEANUP: icalssutil_free_parts(&comp_parts); icalssutil_free_parts(&match_parts); return class; } + diff --git a/libical/src/libicalss/icalclassify.h b/libical/src/libicalss/icalclassify.h index ae76434378..aceabc0a20 100644 --- a/libical/src/libicalss/icalclassify.h +++ b/libical/src/libicalss/icalclassify.h @@ -29,42 +29,14 @@ #include "ical.h" #include "icalset.h" - -typedef enum icalclass { - ICAL_NO_CLASS, - ICAL_PUBLISH_NEW_CLASS, - ICAL_PUBLISH_UPDATE_CLASS, - ICAL_PUBLISH_FREEBUSY_CLASS, - ICAL_REQUEST_NEW_CLASS, - ICAL_REQUEST_UPDATE_CLASS, - ICAL_REQUEST_RESCHEDULE_CLASS, - ICAL_REQUEST_DELEGATE_CLASS, - ICAL_REQUEST_NEW_ORGANIZER_CLASS, - ICAL_REQUEST_FORWARD_CLASS, - ICAL_REQUEST_STATUS_CLASS, - ICAL_REQUEST_FREEBUSY_CLASS, - ICAL_REPLY_ACCEPT_CLASS, - ICAL_REPLY_DECLINE_CLASS, - ICAL_REPLY_CRASHER_ACCEPT_CLASS, - ICAL_REPLY_CRASHER_DECLINE_CLASS, - ICAL_ADD_INSTANCE_CLASS, - ICAL_CANCEL_EVENT_CLASS, - ICAL_CANCEL_INSTANCE_CLASS, - ICAL_CANCEL_ALL_CLASS, - ICAL_REFRESH_CLASS, - ICAL_COUNTER_CLASS, - ICAL_DECLINECOUNTER_CLASS, - ICAL_MALFORMED_CLASS, - ICAL_OBSOLETE_CLASS, /* 21 */ - ICAL_MISSEQUENCED_CLASS, /* 22 */ - ICAL_UNKNOWN_CLASS /* 23 */ -} ical_class; - -ical_class icalclassify(icalcomponent* c,icalcomponent* match, +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/libical/src/libicalss/icalcluster.c b/libical/src/libicalss/icalcluster.c new file mode 100644 index 0000000000..6d11078a72 --- /dev/null +++ b/libical/src/libicalss/icalcluster.c @@ -0,0 +1,245 @@ +/* -*- Mode: C -*- + ====================================================================== + FILE: icalcluster.c + CREATOR: acampi 13 March 2002 + + $Id$ + $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" + +#ifdef WIN32 +#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) { + icalerror_warn("The top component is not an XROOT"); + fprintf(stderr, "%s\n", icalcomponent_as_ical_string(impl->data)); + 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/libical/src/libicalss/icalcluster.h b/libical/src/libicalss/icalcluster.h new file mode 100644 index 0000000000..f4eb041b04 --- /dev/null +++ b/libical/src/libicalss/icalcluster.h @@ -0,0 +1,61 @@ +/* -*- Mode: C -*- */ +/*====================================================================== + FILE: icalcluster.h + CREATOR: eric 23 December 1999 + + + $Id$ + $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 "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/libical/src/libicalss/icalclusterimpl.h b/libical/src/libicalss/icalclusterimpl.h new file mode 100644 index 0000000000..ef80e1af81 --- /dev/null +++ b/libical/src/libicalss/icalclusterimpl.h @@ -0,0 +1,45 @@ +/* -*- Mode: C -*- + ====================================================================== + FILE: icalfilesetimpl.h + CREATOR: eric 23 December 1999 + + $Id$ + $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/libical/src/libicalss/icaldirset.c b/libical/src/libicalss/icaldirset.c index f5da125459..4a20fe1978 100644 --- a/libical/src/libicalss/icaldirset.c +++ b/libical/src/libicalss/icaldirset.c @@ -26,9 +26,10 @@ ======================================================================*/ -/* +/** + @file icaldirset.c - icaldirset manages a database of ical components and offers + @brief icaldirset manages a database of ical components and offers interfaces for reading, writting and searching for components. icaldirset groups components in to clusters based on their DTSTAMP @@ -36,12 +37,13 @@ together in a single file. All files in a sotre are kept in a single directory. - The primary interfaces are icaldirset_first and icaldirset_next. These - routine iterate through all of the components in the store, subject - to the current gauge. A gauge is an icalcomponent that is tested - against other componets for a match. If a gauge has been set with - icaldirset_select, icaldirset_first and icaldirset_next will only - return componentes that match the gauge. + 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 & @@ -57,64 +59,74 @@ #include "ical.h" #include "icaldirset.h" -#include "pvl.h" -#include "icalerror.h" -#include "icalparser.h" #include "icaldirset.h" #include "icalfileset.h" #include "icalfilesetimpl.h" +#include "icalcluster.h" #include "icalgauge.h" #include <limits.h> /* For PATH_MAX */ +#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 <dirent.h> /* for opendir() */ #include <sys/stat.h> /* for stat */ -#include <unistd.h> /* for stat, getpid */ #include <time.h> /* for clock() */ #include <stdlib.h> /* for rand(), srand() */ -#include <sys/utsname.h> /* for uname */ #include <string.h> /* for strdup */ #include "icaldirsetimpl.h" -struct icaldirset_impl* icaldirset_new_impl() -{ - struct icaldirset_impl* impl; +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp - if ( ( impl = (struct icaldirset_impl*) - malloc(sizeof(struct icaldirset_impl))) == 0) { - icalerror_set_errno(ICAL_NEWFAILED_ERROR); - return 0; - } +#define _S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask)) - strcpy(impl->id,ICALDIRSET_ID); +#define S_ISDIR(mode) _S_ISTYPE((mode), _S_IFDIR) +#define S_ISREG(mode) _S_ISTYPE((mode), _S_IFREG) +#endif - return impl; -} +/** Default options used when NULL is passed to icalset_new() **/ +icaldirset_options icaldirset_options_default = {O_RDWR|O_CREAT}; -const char* icaldirset_path(icaldirset* cluster) -{ - struct icaldirset_impl *impl = icaldirset_new_impl(); - return impl->dir; +const char* icaldirset_path(icalset* set) +{ + icaldirset *dset = (icaldirset*)set; + return dset->dir; } -void icaldirset_mark(icaldirset* store) + +void icaldirset_mark(icalset* set) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; + icaldirset *dset = (icaldirset*)set; - icalfileset_mark(impl->cluster); + icalcluster_mark(dset->cluster); } -icalerrorenum icaldirset_commit(icaldirset* store) +icalerrorenum icaldirset_commit(icalset* set) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; + icaldirset *dset = (icaldirset*)set; + icalset *fileset; + icalfileset_options options = icalfileset_options_default; - return icalfileset_commit(impl->cluster); + 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) @@ -127,21 +139,22 @@ void icaldirset_unlock(const char* dir) } /* Load the contents of the store directory into the store's internal directory list*/ -icalerrorenum icaldirset_read_directory(struct icaldirset_impl* impl) +icalerrorenum icaldirset_read_directory(icaldirset *dset) { + char *str; +#ifndef WIN32 struct dirent *de; DIR* dp; - char *str; - dp = opendir(impl->dir); + dp = opendir(dset->dir); - if ( dp == 0) { + if (dp == 0) { icalerror_set_errno(ICAL_FILE_ERROR); return ICAL_FILE_ERROR; } /* clear contents of directory list */ - while((str = pvl_pop(impl->directory))){ + while((str = pvl_pop(dset->directory))){ free(str); } @@ -156,24 +169,52 @@ icalerrorenum icaldirset_read_directory(struct icaldirset_impl* impl) continue; } - pvl_push(impl->directory, (void*)strdup(de->d_name)); + pvl_push(dset->directory, (void*)strdup(de->d_name)); } closedir(dp); +#else + struct _finddata_t c_file; + long 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; } -icaldirset* icaldirset_new(const char* dir) + +icalset* icaldirset_init(icalset* set, const char* dir, void* options_in) { - struct icaldirset_impl *impl = icaldirset_new_impl(); + icaldirset *dset = (icaldirset*)set; + icaldirset_options *options = options_in; struct stat sbuf; - if (impl == 0){ - return 0; - } - 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); @@ -188,68 +229,83 @@ icaldirset* icaldirset_new(const char* dir) icaldirset_lock(dir); - impl = icaldirset_new_impl(); + 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); +} - if (impl ==0){ - icalerror_set_errno(ICAL_NEWFAILED_ERROR); - return 0; - } - impl->directory = pvl_newlist(); - impl->directory_iterator = 0; - impl->dir = (char*)strdup(dir); - impl->gauge = 0; - impl->first_component = 0; - impl->cluster = 0; +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; - icaldirset_read_directory(impl); + writer_options.flags = O_RDWR|O_CREAT; - return (icaldirset*) impl; + return icalset_new(ICAL_DIR_SET, dir, &writer_options); } -void icaldirset_free(icaldirset* s) + +void icaldirset_free(icalset* s) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)s; + icaldirset *dset = (icaldirset*)s; char* str; - icaldirset_unlock(impl->dir); + icaldirset_unlock(dset->dir); - if(impl->dir !=0){ - free(impl->dir); + if(dset->dir !=0){ + free(dset->dir); + dset->dir = 0; } - if(impl->gauge !=0){ - icalcomponent_free(impl->gauge); + if(dset->gauge !=0){ + icalgauge_free(dset->gauge); + dset->gauge = 0; } - if(impl->cluster !=0){ - icalfileset_free(impl->cluster); + if(dset->cluster !=0){ + icalcluster_free(dset->cluster); } - while(impl->directory !=0 && (str=pvl_pop(impl->directory)) != 0){ + while(dset->directory !=0 && (str=pvl_pop(dset->directory)) != 0){ free(str); } - if(impl->directory != 0){ - pvl_free(impl->directory); + if(dset->directory != 0){ + pvl_free(dset->directory); + dset->directory = 0; } - impl->directory = 0; - impl->directory_iterator = 0; - impl->dir = 0; - impl->gauge = 0; - impl->first_component = 0; - - free(impl); - + 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* store) +int icaldirset_next_uid_number(icaldirset* dset) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; char sequence = 0; char temp[128]; char filename[ICAL_PATH_MAX]; @@ -257,9 +313,9 @@ int icaldirset_next_uid_number(icaldirset* store) FILE *f; struct stat sbuf; - icalerror_check_arg_rz( (store!=0), "store"); + icalerror_check_arg_rz( (dset!=0), "dset"); - sprintf(filename,"%s/%s",impl->dir,"SEQUENCE"); + sprintf(filename,"%s/%s",dset->dir,"SEQUENCE"); /* Create the file if it does not exist.*/ if (stat(filename,&sbuf) == -1 || !S_ISREG(sbuf.st_mode)){ @@ -272,7 +328,6 @@ int icaldirset_next_uid_number(icaldirset* store) icalerror_warn("Can't create SEQUENCE file in icaldirset_next_uid_number"); return 0; } - } if ( (f = fopen(filename,"r+")) != 0){ @@ -298,85 +353,85 @@ int icaldirset_next_uid_number(icaldirset* store) icalerror_warn("Can't create SEQUENCE file in icaldirset_next_uid_number"); return 0; } - } -icalerrorenum icaldirset_next_cluster(icaldirset* store) +icalerrorenum icaldirset_next_cluster(icaldirset* dset) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; char path[ICAL_PATH_MAX]; - if (impl->directory_iterator == 0){ + if (dset->directory_iterator == 0){ icalerror_set_errno(ICAL_INTERNAL_ERROR); return ICAL_INTERNAL_ERROR; } - impl->directory_iterator = pvl_next(impl->directory_iterator); + dset->directory_iterator = pvl_next(dset->directory_iterator); - if (impl->directory_iterator == 0){ + if (dset->directory_iterator == 0){ /* There are no more clusters */ - if(impl->cluster != 0){ - icalfileset_free(impl->cluster); - impl->cluster = 0; + if(dset->cluster != 0){ + icalcluster_free(dset->cluster); + dset->cluster = 0; } return ICAL_NO_ERROR; } - sprintf(path,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator)); - - icalfileset_free(impl->cluster); + sprintf(path,"%s/%s", dset->dir,(char*)pvl_data(dset->directory_iterator)); - impl->cluster = icalfileset_new(path); + icalcluster_free(dset->cluster); + dset->cluster = icalfileset_produce_icalcluster(path); return icalerrno; } -void icaldirset_add_uid(icaldirset* store, icaldirset* comp) +static void icaldirset_add_uid(icalcomponent* comp) { char uidstring[ICAL_PATH_MAX]; icalproperty *uid; +#ifndef WIN32 struct utsname unamebuf; +#endif - icalerror_check_arg_rv( (store!=0), "store"); icalerror_check_arg_rv( (comp!=0), "comp"); uid = icalcomponent_get_first_property(comp,ICAL_UID_PROPERTY); if (uid == 0) { +#ifndef WIN32 uname(&unamebuf); sprintf(uidstring,"%d-%s",(int)getpid(),unamebuf.nodename); +#else + sprintf(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 { - strcpy(uidstring,icalproperty_get_uid(uid)); } } -/* This assumes that the top level component is a VCALENDAR, and there +/** + 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 DTAMP property */ + component must have a DSTAMP property +*/ -icalerrorenum icaldirset_add_component(icaldirset* store, icaldirset* comp) +icalerrorenum icaldirset_add_component(icalset* set, icalcomponent* comp) { - struct icaldirset_impl *impl; char clustername[ICAL_PATH_MAX]; - icalproperty *dt; + icalproperty *dt = 0; icalvalue *v; struct icaltimetype tm; icalerrorenum error = ICAL_NO_ERROR; icalcomponent *inner; + icaldirset *dset = (icaldirset*) set; - impl = (struct icaldirset_impl*)store; - icalerror_check_arg_rz( (store!=0), "store"); + icalerror_check_arg_rz( (dset!=0), "dset"); icalerror_check_arg_rz( (comp!=0), "comp"); - errno = 0; - - icaldirset_add_uid(store,comp); + icaldirset_add_uid(comp); /* Determine which cluster this object belongs in. This is a HACK */ @@ -386,52 +441,44 @@ icalerrorenum icaldirset_add_component(icaldirset* store, icaldirset* comp) dt = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY); - if (dt != 0){ + if (dt != 0) break; } - } - - if (dt == 0){ + 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){ + 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",impl->dir,tm.year,tm.month); + snprintf(clustername,ICAL_PATH_MAX,"%s/%04d%02d",dset->dir, tm.year, tm.month); /* Load the cluster and insert the object */ - - if(impl->cluster != 0 && - strcmp(clustername,icalfileset_path(impl->cluster)) != 0 ){ - icalfileset_free(impl->cluster); - impl->cluster = 0; + if(dset->cluster != 0 && + strcmp(clustername,icalcluster_key(dset->cluster)) != 0 ){ + icalcluster_free(dset->cluster); + dset->cluster = 0; } - if (impl->cluster == 0){ - impl->cluster = icalfileset_new(clustername); + if (dset->cluster == 0){ + dset->cluster = icalfileset_produce_icalcluster(clustername); - if (impl->cluster == 0){ + if (dset->cluster == 0){ error = icalerrno; } } @@ -442,33 +489,31 @@ icalerrorenum icaldirset_add_component(icaldirset* store, icaldirset* comp) } /* Add the component to the cluster */ - - icalfileset_add_component(impl->cluster,comp); + icalcluster_add_component(dset->cluster,comp); - icalfileset_mark(impl->cluster); + /* icalcluster_mark(impl->cluster); */ return ICAL_NO_ERROR; } -/* Remove a component in the current cluster. HACK. This routine is a +/** + 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(icaldirset* store, icaldirset* comp) -{ - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; - - struct icalfileset_impl *filesetimpl = - (struct icalfileset_impl*)impl->cluster; + no other use. + */ - icalcomponent *filecomp = filesetimpl->cluster; +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((store!=0),"store",ICAL_BADARG_ERROR); + icalerror_check_arg_re((set!=0),"set",ICAL_BADARG_ERROR); icalerror_check_arg_re((comp!=0),"comp",ICAL_BADARG_ERROR); - icalerror_check_arg_re((impl->cluster!=0),"Cluster pointer",ICAL_USAGE_ERROR); + 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)){ @@ -487,17 +532,16 @@ icalerrorenum icaldirset_remove_component(icaldirset* store, icaldirset* comp) return ICAL_USAGE_ERROR; } - icalfileset_remove_component(impl->cluster,comp); + icalcluster_remove_component(dset->cluster,comp); - icalfileset_mark(impl->cluster); + /* icalcluster_mark(impl->cluster); */ /* If the removal emptied the fileset, get the next fileset */ - if( icalfileset_count_components(impl->cluster,ICAL_ANY_COMPONENT)==0){ - - icalerrorenum error = icaldirset_next_cluster(store); + if( icalcluster_count_components(dset->cluster,ICAL_ANY_COMPONENT)==0){ + icalerrorenum error = icaldirset_next_cluster(dset); - if(impl->cluster != 0 && error == ICAL_NO_ERROR){ - icalfileset_get_first_component(impl->cluster); + 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; @@ -511,95 +555,84 @@ icalerrorenum icaldirset_remove_component(icaldirset* store, icaldirset* comp) -int icaldirset_count_components(icaldirset* store, +int icaldirset_count_components(icalset* store, icalcomponent_kind kind) { /* HACK, not implemented */ - assert(0); return 0; } -icalcomponent* icaldirset_fetch_match(icaldirset* set, icalcomponent *c) +icalcomponent* icaldirset_fetch_match(icalset* set, icalcomponent *c) { fprintf(stderr," icaldirset_fetch_match is not implemented\n"); assert(0); + return 0; } -icalcomponent* icaldirset_fetch(icaldirset* store, const char* uid) +icalcomponent* icaldirset_fetch(icalset* set, const char* uid) { - icalcomponent *gauge; - icalcomponent *old_gauge; + icaldirset *dset = (icaldirset*)set; + icalgauge *gauge; + icalgauge *old_gauge; icalcomponent *c; - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; + char sql[256]; - icalerror_check_arg_rz( (store!=0), "store"); + icalerror_check_arg_rz( (set!=0), "set"); icalerror_check_arg_rz( (uid!=0), "uid"); - gauge = - icalcomponent_vanew( - ICAL_VCALENDAR_COMPONENT, - icalcomponent_vanew( - ICAL_VEVENT_COMPONENT, - icalproperty_vanew_uid( - uid, - icalparameter_new_xliccomparetype( - ICAL_XLICCOMPARETYPE_EQUAL), - 0), - 0), - 0); + snprintf(sql, 256, "SELECT * FROM VEVENT WHERE UID = \"%s\"", uid); + + gauge = icalgauge_new_from_sql(sql, 0); - old_gauge = impl->gauge; - impl->gauge = gauge; + old_gauge = dset->gauge; + dset->gauge = gauge; - c= icaldirset_get_first_component(store); + c= icaldirset_get_first_component(set); - impl->gauge = old_gauge; + dset->gauge = old_gauge; - icalcomponent_free(gauge); + icalgauge_free(gauge); return c; } -int icaldirset_has_uid(icaldirset* store, const char* uid) +int icaldirset_has_uid(icalset* set, const char* uid) { icalcomponent *c; - icalerror_check_arg_rz( (store!=0), "store"); + 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(store,uid); + c = icaldirset_fetch(set,uid); return c!=0; } -icalerrorenum icaldirset_select(icaldirset* store, icalcomponent* gauge) - { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; +icalerrorenum icaldirset_select(icalset* set, icalgauge* gauge) +{ + icaldirset *dset = (icaldirset*)set; - icalerror_check_arg_re( (store!=0), "store",ICAL_BADARG_ERROR); + icalerror_check_arg_re( (set!=0), "set",ICAL_BADARG_ERROR); icalerror_check_arg_re( (gauge!=0), "gauge",ICAL_BADARG_ERROR); - if (!icalcomponent_is_valid(gauge)){ - return ICAL_BADARG_ERROR; - } - - impl->gauge = gauge; + dset->gauge = gauge; return ICAL_NO_ERROR; } -icalerrorenum icaldirset_modify(icaldirset* store, icalcomponent *old, +icalerrorenum icaldirset_modify(icalset* set, + icalcomponent *old, icalcomponent *new) { assert(0); @@ -608,7 +641,7 @@ icalerrorenum icaldirset_modify(icaldirset* store, icalcomponent *old, } -void icaldirset_clear(icaldirset* store) +void icaldirset_clear(icalset* set) { assert(0); @@ -616,53 +649,58 @@ void icaldirset_clear(icaldirset* store) /* HACK, not implemented */ } -icalcomponent* icaldirset_get_current_component(icaldirset* store) +icalcomponent* icaldirset_get_current_component(icalset* set) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; + icaldirset *dset = (icaldirset*)set; - if(impl->cluster == 0){ - icaldirset_get_first_component(store); + if (dset->cluster == 0){ + icaldirset_get_first_component(set); + } + if(dset->cluster == 0){ + return 0; } - return icalfileset_get_current_component(impl->cluster); - + return icalcluster_get_current_component(dset->cluster); } -icalcomponent* icaldirset_get_first_component(icaldirset* store) +icalcomponent* icaldirset_get_first_component(icalset* set) { - struct icaldirset_impl *impl = (struct icaldirset_impl*)store; + icaldirset *dset = (icaldirset*)set; + icalerrorenum error; char path[ICAL_PATH_MAX]; - error = icaldirset_read_directory(impl); + error = icaldirset_read_directory(dset); if (error != ICAL_NO_ERROR){ icalerror_set_errno(error); return 0; } - impl->directory_iterator = pvl_head(impl->directory); + dset->directory_iterator = pvl_head(dset->directory); - if (impl->directory_iterator == 0){ + if (dset->directory_iterator == 0){ icalerror_set_errno(error); return 0; } - snprintf(path,ICAL_PATH_MAX,"%s/%s",impl->dir,(char*)pvl_data(impl->directory_iterator)); + 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(impl->cluster != 0 && strcmp(path,icalfileset_path(impl->cluster)) != 0 ){ - icalfileset_free(impl->cluster); - impl->cluster = 0; + if(dset->cluster != 0 && strcmp(path,icalcluster_key(dset->cluster)) != 0 ){ + icalcluster_free(dset->cluster); + dset->cluster = 0; } - if (impl->cluster == 0){ - impl->cluster = icalfileset_new(path); + if (dset->cluster == 0){ + dset->cluster = icalfileset_produce_icalcluster(path); - if (impl->cluster == 0){ + if (dset->cluster == 0){ error = icalerrno; } } @@ -672,23 +710,22 @@ icalcomponent* icaldirset_get_first_component(icaldirset* store) return 0; } - impl->first_component = 1; + dset->first_component = 1; - return icaldirset_get_next_component(store); + return icaldirset_get_next_component(set); } -icalcomponent* icaldirset_get_next_component(icaldirset* store) + +icalcomponent* icaldirset_get_next_component(icalset* set) { - struct icaldirset_impl *impl; + icaldirset *dset = (icaldirset*)set; icalcomponent *c; icalerrorenum error; - icalerror_check_arg_rz( (store!=0), "store"); - - impl = (struct icaldirset_impl*)store; + icalerror_check_arg_rz( (set!=0), "set"); - if(impl->cluster == 0){ + 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; @@ -696,30 +733,26 @@ icalcomponent* icaldirset_get_next_component(icaldirset* store) } /* Set the component iterator for the following for loop */ - if (impl->first_component == 1){ - icalfileset_get_first_component(impl->cluster); - impl->first_component = 0; + if (dset->first_component == 1){ + icalcluster_get_first_component(dset->cluster); + dset->first_component = 0; } else { - icalfileset_get_next_component(impl->cluster); + icalcluster_get_next_component(dset->cluster); } - while(1){ /* Iterate through all of the objects in the cluster*/ - for( c = icalfileset_get_current_component(impl->cluster); + for( c = icalcluster_get_current_component(dset->cluster); c != 0; - c = icalfileset_get_next_component(impl->cluster)){ + 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 0 /* HACK */ - if (impl->gauge != 0 && icalgauge_test(c,impl->gauge) == 0){ + if (dset->gauge != 0 && icalgauge_compare(dset->gauge,c) == 0){ continue; } -#else - assert(0); /* icalgauge_test needs to be fixed */ -#endif + /* Either there is no gauge, or the component passed the gauge, so return it*/ @@ -729,13 +762,13 @@ icalcomponent* icaldirset_get_next_component(icaldirset* store) /* 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(store); + error = icaldirset_next_cluster(dset); - if(impl->cluster == 0 || error != ICAL_NO_ERROR){ + if(dset->cluster == 0 || error != ICAL_NO_ERROR){ /* No more clusters */ return 0; } else { - c = icalfileset_get_first_component(impl->cluster); + c = icalcluster_get_first_component(dset->cluster); return c; } @@ -745,9 +778,28 @@ icalcomponent* icaldirset_get_next_component(icaldirset* store) 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/libical/src/libicalss/icaldirset.h b/libical/src/libicalss/icaldirset.h index 7d205ecf0a..a2d577dc34 100644 --- a/libical/src/libicalss/icaldirset.h +++ b/libical/src/libicalss/icaldirset.h @@ -30,51 +30,67 @@ #define ICALDIRSET_H #include "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 void icaldirset; +typedef struct icaldirset_impl icaldirset; +icalset* icaldirset_new(const char* path); -icaldirset* icaldirset_new(const char* path); +icalset* icaldirset_new_reader(const char* path); +icalset* icaldirset_new_writer(const char* path); -void icaldirset_free(icaldirset* store); -const char* icaldirset_path(icaldirset* store); +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(icaldirset* store); -icalerrorenum icaldirset_commit(icaldirset* store); +void icaldirset_mark(icalset* set); +icalerrorenum icaldirset_commit(icalset* set); -icalerrorenum icaldirset_add_component(icaldirset* store, icalcomponent* comp); -icalerrorenum icaldirset_remove_component(icaldirset* store, icalcomponent* comp); +icalerrorenum icaldirset_add_component(icalset* store, icalcomponent* comp); +icalerrorenum icaldirset_remove_component(icalset* store, icalcomponent* comp); -int icaldirset_count_components(icaldirset* store, +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(icaldirset* store, icalcomponent* gauge); -void icaldirset_clear(icaldirset* store); +icalerrorenum icaldirset_select(icalset* store, icalgauge* gauge); +void icaldirset_clear(icalset* store); /* Get a component by uid */ -icalcomponent* icaldirset_fetch(icaldirset* store, const char* uid); -int icaldirset_has_uid(icaldirset* store, const char* uid); -icalcomponent* icaldirset_fetch_match(icaldirset* set, icalcomponent *c); +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(icaldirset* store, icalcomponent *oldc, +icalerrorenum icaldirset_modify(icalset* store, icalcomponent *oldc, icalcomponent *newc); -/* Iterate through the components. If a guage has been defined, these +/* 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(icaldirset* store); -icalcomponent* icaldirset_get_first_component(icaldirset* store); -icalcomponent* icaldirset_get_next_component(icaldirset* store); +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/libical/src/libicalss/icaldirsetimpl.h b/libical/src/libicalss/icaldirsetimpl.h index 0e69ba2f2e..332a369b02 100644 --- a/libical/src/libicalss/icaldirsetimpl.h +++ b/libical/src/libicalss/icaldirsetimpl.h @@ -30,18 +30,19 @@ #include "config.h" #endif +#include "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*/ -#define ICALDIRSET_ID "dset" - struct icaldirset_impl { - char id[5]; /* "dset" */ - char* dir; - icalcomponent* gauge; - icaldirset* cluster; - int first_component; - pvl_list directory; - pvl_elem directory_iterator; + 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/libical/src/libicalss/icalfileset.c b/libical/src/libicalss/icalfileset.c index b6e3430f7d..389cec7587 100644 --- a/libical/src/libicalss/icalfileset.c +++ b/libical/src/libicalss/icalfileset.c @@ -34,98 +34,151 @@ #include "icalgauge.h" #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 <stdlib.h> #include <string.h> #include <fcntl.h> /* for fcntl */ -#include <unistd.h> /* for fcntl */ #include "icalfilesetimpl.h" +#include "icalclusterimpl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#define strcasecmp stricmp + +#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) +#endif extern int errno; -int icalfileset_lock(icalfileset *cluster); -int icalfileset_unlock(icalfileset *cluster); -icalerrorenum icalfileset_read_file(icalfileset* cluster, mode_t mode); -int icalfileset_filesize(icalfileset* cluster); +/** 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); -icalfileset* icalfileset_new_impl() +icalset* icalfileset_new(const char* path) { - struct icalfileset_impl* impl; - - if ( ( impl = (struct icalfileset_impl*) - malloc(sizeof(struct icalfileset_impl))) == 0) { - icalerror_set_errno(ICAL_NEWFAILED_ERROR); - errno = ENOMEM; - return 0; - } - - memset(impl,0,sizeof(struct icalfileset_impl)); - - strcpy(impl->id,ICALFILESET_ID); - - return impl; + return icalset_new(ICAL_FILE_SET, path, &icalfileset_options_default); } - -icalfileset* icalfileset_new(const char* path) +icalset* icalfileset_new_reader(const char* path) { - return icalfileset_new_open(path, O_RDWR|O_CREAT, 0664); + icalfileset_options reader_options = icalfileset_options_default; + reader_options.flags = O_RDONLY; + + return icalset_new(ICAL_FILE_SET, path, &reader_options); } -icalfileset* icalfileset_new_open(const char* path, int flags, mode_t mode) +icalset* icalfileset_new_writer(const char* path) { - struct icalfileset_impl *impl = icalfileset_new_impl(); - struct icaltimetype tt; - off_t cluster_file_size; + icalfileset_options writer_options = icalfileset_options_default; + writer_options.flags = O_RDONLY; - memset(&tt,0,sizeof(struct icaltimetype)); + return icalset_new(ICAL_FILE_SET, path, &writer_options); +} - icalerror_clear_errno(); - icalerror_check_arg_rz( (path!=0), "path"); +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; - if (impl == 0){ - return 0; - } + icalerror_clear_errno(); + icalerror_check_arg_rz( (path!=0), "path"); + icalerror_check_arg_rz( (fset!=0), "fset"); - impl->path = strdup(path); + fset->path = strdup(path); + fset->options = *options; - cluster_file_size = icalfileset_filesize(impl); - - if(cluster_file_size < 0){ - icalfileset_free(impl); - return 0; - } + flags = options->flags; + mode = options->mode; + + cluster_file_size = icalfileset_filesize(fset); + + if(cluster_file_size < 0){ + icalfileset_free(set); + return 0; + } - impl->fd = open(impl->path,flags, mode); +#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 (impl->fd < 0){ - icalerror_set_errno(ICAL_FILE_ERROR); - icalfileset_free(impl); - return 0; - } + if (fset->fd < 0){ + icalerror_set_errno(ICAL_FILE_ERROR); + icalfileset_free(set); + return 0; + } - icalfileset_lock(impl); +#ifndef WIN32 + icalfileset_lock(fset); +#endif if(cluster_file_size > 0 ){ icalerrorenum error; - if((error = icalfileset_read_file(impl,mode))!= ICAL_NO_ERROR){ - icalfileset_free(impl); - return 0; + if((error = icalfileset_read_file(fset,mode))!= ICAL_NO_ERROR){ + icalfileset_free(set); + return 0; } } - if(impl->cluster == 0){ - impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT); - } + 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; - return impl; + 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; int fd = (int)d; @@ -150,42 +203,38 @@ char* icalfileset_read_from_file(char *s, size_t size, void *d) } -icalerrorenum icalfileset_read_file(icalfileset* cluster,mode_t mode) +icalerrorenum icalfileset_read_file(icalfileset* set,mode_t mode) { - icalparser *parser; - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; - parser = icalparser_new(); - icalparser_set_gen_data(parser,(void*)impl->fd); - impl->cluster = icalparser_parse(parser,icalfileset_read_from_file); + + icalparser_set_gen_data(parser,(void*)set->fd); + set->cluster = icalparser_parse(parser,icalfileset_read_from_file); icalparser_free(parser); - if (impl->cluster == 0 || icalerrno != ICAL_NO_ERROR){ + if (set->cluster == 0 || icalerrno != ICAL_NO_ERROR){ icalerror_set_errno(ICAL_PARSE_ERROR); - return ICAL_PARSE_ERROR; + /*return ICAL_PARSE_ERROR;*/ } - if (icalcomponent_isa(impl->cluster) != ICAL_XROOT_COMPONENT){ + 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 = impl->cluster; - impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT); - icalcomponent_add_component(impl->cluster,cl); + 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* cluster) +int icalfileset_filesize(icalfileset* fset) { - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; int cluster_file_size; struct stat sbuf; - - if (stat(impl->path,&sbuf) != 0){ + + if (stat(fset->path,&sbuf) != 0){ /* A file by the given name does not exist, or there was another error */ @@ -214,120 +263,110 @@ int icalfileset_filesize(icalfileset* cluster) /*return -1; not reached*/ } -void icalfileset_free(icalfileset* cluster) +void icalfileset_free(icalset* set) { - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_rv((cluster!=0),"cluster"); + icalerror_check_arg_rv((set!=0),"set"); - if (impl->cluster != 0){ - icalfileset_commit(cluster); - icalcomponent_free(impl->cluster); - impl->cluster=0; + if (fset->cluster != 0){ + icalfileset_commit(set); + icalcomponent_free(fset->cluster); + fset->cluster=0; } - if(impl->fd > 0){ - icalfileset_unlock(impl); - close(impl->fd); - impl->fd = -1; + if (fset->gauge != 0){ + icalgauge_free(fset->gauge); + fset->gauge=0; } - if(impl->path != 0){ - free(impl->path); - impl->path = 0; + if(fset->fd > 0){ + icalfileset_unlock(fset); + close(fset->fd); + fset->fd = -1; } - free(impl); + if(fset->path != 0){ + free(fset->path); + fset->path = 0; + } } -const char* icalfileset_path(icalfileset* cluster) -{ - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; - icalerror_check_arg_rz((cluster!=0),"cluster"); +const char* icalfileset_path(icalset* set) { + icalerror_check_arg_rz((set!=0),"set"); - return impl->path; + return ((icalfileset*)set)->path; } -int icalfileset_lock(icalfileset *cluster) +int icalfileset_lock(icalfileset *set) { - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; +#ifndef WIN32 struct flock lock; int rtrn; - icalerror_check_arg_rz((impl->fd>0),"impl->fd"); + 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(impl->fd, F_SETLKW, &lock); + rtrn = fcntl(set->fd, F_SETLKW, &lock); return rtrn; +#else + return 0; +#endif } -int icalfileset_unlock(icalfileset *cluster) +int icalfileset_unlock(icalfileset *set) { - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; +#ifndef WIN32 struct flock lock; - icalerror_check_arg_rz((impl->fd>0),"impl->fd"); + 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(impl->fd, F_UNLCK, &lock)); - -} - -#ifdef ICAL_SAFESAVES -int icalfileset_safe_saves=1; + return (fcntl(set->fd, F_UNLCK, &lock)); #else -int icalfileset_safe_saves=0; + return 0; #endif +} -icalerrorenum icalfileset_commit(icalfileset* cluster) +icalerrorenum icalfileset_commit(icalset* set) { char tmp[ICAL_PATH_MAX]; char *str; icalcomponent *c; off_t write_size=0; + icalfileset *fset = (icalfileset*) set; + + icalerror_check_arg_re((fset!=0),"set",ICAL_BADARG_ERROR); - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; - - icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR); - - icalerror_check_arg_re((impl->fd>0),"impl->fd is invalid", + icalerror_check_arg_re((fset->fd>0),"set->fd is invalid", ICAL_INTERNAL_ERROR) ; - if (impl->changed == 0 ){ + if (fset->changed == 0 ){ return ICAL_NO_ERROR; } - if(icalfileset_safe_saves == 1){ - snprintf(tmp,ICAL_PATH_MAX,"cp %s %s.bak",impl->path,impl->path); - - if(system(tmp) < 0){ - icalerror_set_errno(ICAL_FILE_ERROR); - return ICAL_FILE_ERROR; - } - } - - if(lseek(impl->fd,SEEK_SET,0) < 0){ + if(lseek(fset->fd, 0, SEEK_SET) < 0){ icalerror_set_errno(ICAL_FILE_ERROR); return ICAL_FILE_ERROR; } - for(c = icalcomponent_get_first_component(impl->cluster,ICAL_ANY_COMPONENT); + for(c = icalcomponent_get_first_component(fset->cluster,ICAL_ANY_COMPONENT); c != 0; - c = icalcomponent_get_next_component(impl->cluster,ICAL_ANY_COMPONENT)){ + c = icalcomponent_get_next_component(fset->cluster,ICAL_ANY_COMPONENT)){ int sz; str = icalcomponent_as_ical_string(c); - sz=write(impl->fd,str,strlen(str)); + sz=write(fset->fd,str,strlen(str)); if ( sz != strlen(str)){ perror("write"); @@ -338,132 +377,138 @@ icalerrorenum icalfileset_commit(icalfileset* cluster) write_size += sz; } - impl->changed = 0; + fset->changed = 0; - if(ftruncate(impl->fd,write_size) < 0){ +#ifndef WIN32 + if(ftruncate(fset->fd,write_size) < 0){ return ICAL_FILE_ERROR; } +#else + chsize( fset->fd, tell( fset->fd ) ); +#endif return ICAL_NO_ERROR; - } -void icalfileset_mark(icalfileset* cluster){ - - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; - - icalerror_check_arg_rv((impl!=0),"cluster"); - - impl->changed = 1; +void icalfileset_mark(icalset* set) { + icalerror_check_arg_rv((set!=0),"set"); + ((icalfileset*)set)->changed = 1; } -icalcomponent* icalfileset_get_component(icalfileset* cluster){ - struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; +icalcomponent* icalfileset_get_component(icalset* set){ + icalfileset *fset = (icalfileset*) set; + icalerror_check_arg_rz((set!=0),"set"); - icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR); - - return impl->cluster; + return fset->cluster; } -/* manipulate the components in the cluster */ +/* manipulate the components in the set */ -icalerrorenum icalfileset_add_component(icalfileset *cluster, +icalerrorenum icalfileset_add_component(icalset *set, icalcomponent* child) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_re((cluster!=0),"cluster", ICAL_BADARG_ERROR); + icalerror_check_arg_re((set!=0),"set", ICAL_BADARG_ERROR); icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR); - icalcomponent_add_component(impl->cluster,child); + icalcomponent_add_component(fset->cluster,child); - icalfileset_mark(cluster); + icalfileset_mark(set); return ICAL_NO_ERROR; - } -icalerrorenum icalfileset_remove_component(icalfileset *cluster, +icalerrorenum icalfileset_remove_component(icalset *set, icalcomponent* child) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_re((cluster!=0),"cluster",ICAL_BADARG_ERROR); + icalerror_check_arg_re((set!=0),"set",ICAL_BADARG_ERROR); icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR); - icalcomponent_remove_component(impl->cluster,child); + icalcomponent_remove_component(fset->cluster,child); - icalfileset_mark(cluster); + icalfileset_mark(set); return ICAL_NO_ERROR; } -int icalfileset_count_components(icalfileset *cluster, +int icalfileset_count_components(icalset *set, icalcomponent_kind kind) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; - if(cluster == 0){ + if (set == 0){ icalerror_set_errno(ICAL_BADARG_ERROR); return -1; } - return icalcomponent_count_components(impl->cluster,kind); + return icalcomponent_count_components(fset->cluster,kind); } -icalerrorenum icalfileset_select(icalfileset* set, icalgauge* gauge) +icalerrorenum icalfileset_select(icalset* set, icalgauge* gauge) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)set; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_re(gauge!=0,"guage",ICAL_BADARG_ERROR); + icalerror_check_arg_re(gauge!=0,"gauge",ICAL_BADARG_ERROR); - impl->gauge = gauge; + fset->gauge = gauge; return ICAL_NO_ERROR; } -void icalfileset_clear(icalfileset* gauge) +void icalfileset_clear(icalset* set) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)gauge; - - impl->gauge = 0; + icalfileset *fset = (icalfileset*) set; + + icalerror_check_arg_rv(set!=0,"set"); + fset->gauge = 0; } -icalcomponent* icalfileset_fetch(icalfileset* store,const char* uid) +icalcomponent* icalfileset_fetch(icalset* set,const char* uid) { + icalfileset *fset = (icalfileset*) set; icalcompiter i; - struct icalfileset_impl* impl = (struct icalfileset_impl*)store; + + icalerror_check_arg_rz(set!=0,"set"); - for(i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT); + for(i = icalcomponent_begin_component(fset->cluster,ICAL_ANY_COMPONENT); icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){ - icalcomponent *this = icalcompiter_deref(&i); - icalcomponent *inner = icalcomponent_get_first_real_component(this); - icalcomponent *p; - const char *this_uid; - - if(inner != 0){ - p = icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY); - 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; - } + 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(icalfileset* store,const char* uid) +int icalfileset_has_uid(icalset* set,const char* uid) { assert(0); /* HACK, not implemented */ return 0; @@ -486,12 +531,11 @@ void icalfileset_id_free(struct icalfileset_id *id) if(id->uid != 0){ free(id->uid); } - } + struct icalfileset_id icalfileset_get_id(icalcomponent* comp) { - icalcomponent *inner; struct icalfileset_id id; icalproperty *p; @@ -527,19 +571,20 @@ struct icalfileset_id icalfileset_get_id(icalcomponent* comp) 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(icalfileset* set, icalcomponent *comp) +icalcomponent* icalfileset_fetch_match(icalset* set, icalcomponent *comp) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)set; + icalfileset *fset = (icalfileset*) set; icalcompiter i; struct icalfileset_id comp_id, match_id; comp_id = icalfileset_get_id(comp); - for(i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT); + for(i = icalcomponent_begin_component(fset->cluster,ICAL_ANY_COMPONENT); icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){ icalcomponent *match = icalcompiter_deref(&i); @@ -567,43 +612,45 @@ icalcomponent* icalfileset_fetch_match(icalfileset* set, icalcomponent *comp) } -icalerrorenum icalfileset_modify(icalfileset* store, icalcomponent *old, +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 (icalfileset* cluster) +icalcomponent* icalfileset_get_current_component (icalset* set) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_rz((cluster!=0),"cluster"); + icalerror_check_arg_rz((set!=0),"set"); - return icalcomponent_get_current_component(impl->cluster); + return icalcomponent_get_current_component(fset->cluster); } -icalcomponent* icalfileset_get_first_component(icalfileset* cluster) +icalcomponent* icalfileset_get_first_component(icalset* set) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalcomponent *c=0; + icalfileset *fset = (icalfileset*) set; - icalerror_check_arg_rz((cluster!=0),"cluster"); + icalerror_check_arg_rz((set!=0),"set"); do { if (c == 0){ - c = icalcomponent_get_first_component(impl->cluster, + c = icalcomponent_get_first_component(fset->cluster, ICAL_ANY_COMPONENT); } else { - c = icalcomponent_get_next_component(impl->cluster, + c = icalcomponent_get_next_component(fset->cluster, ICAL_ANY_COMPONENT); } - if(c != 0 && (impl->gauge == 0 || - icalgauge_compare(impl->gauge,c) == 1)){ + if(c != 0 && (fset->gauge == 0 || + icalgauge_compare(fset->gauge, c) == 1)){ return c; } @@ -613,19 +660,19 @@ icalcomponent* icalfileset_get_first_component(icalfileset* cluster) return 0; } -icalcomponent* icalfileset_get_next_component(icalfileset* cluster) +icalcomponent* icalfileset_get_next_component(icalset* set) { - struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; + icalfileset *fset = (icalfileset*) set; icalcomponent *c; - icalerror_check_arg_rz((cluster!=0),"cluster"); + icalerror_check_arg_rz((set!=0),"set"); do { - c = icalcomponent_get_next_component(impl->cluster, + c = icalcomponent_get_next_component(fset->cluster, ICAL_ANY_COMPONENT); - if(c != 0 && (impl->gauge == 0 || - icalgauge_compare(impl->gauge,c) == 1)){ + if(c != 0 && (fset->gauge == 0 || + icalgauge_compare(fset->gauge,c) == 1)){ return c; } @@ -634,4 +681,241 @@ icalcomponent* icalfileset_get_next_component(icalfileset* cluster) 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); + + 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 */ + if (prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY)) + 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; + + 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 */ + if (prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY)) + 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; + + + 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 */ + if (prop = icalcomponent_get_first_property(c, ICAL_RECURRENCEID_PROPERTY)) + 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/libical/src/libicalss/icalfileset.h b/libical/src/libicalss/icalfileset.h index c785921463..1a42307525 100644 --- a/libical/src/libicalss/icalfileset.h +++ b/libical/src/libicalss/icalfileset.h @@ -31,73 +31,99 @@ #include "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 */ -extern int icalfileset_safe_saves; +#ifdef WIN32 +#define mode_t int +#endif -typedef void icalfileset; +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); -/* icalfileset - icalfilesetfile - icalfilesetdir -*/ +icalset* icalfileset_init(icalset *set, const char *dsn, void* options); +icalfileset* icalfileset_new_from_cluster(const char* path, icalcluster *cluster); -icalfileset* icalfileset_new(const char* path); +icalcluster* icalfileset_produce_icalcluster(const char *path); -/* Like _new, but takes open() flags for opening the file */ -icalfileset* icalfileset_new_open(const char* path, - int flags, mode_t mode); +void icalfileset_free(icalset* cluster); -void icalfileset_free(icalfileset* cluster); - -const char* icalfileset_path(icalfileset* 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(icalfileset* cluster); -icalerrorenum icalfileset_commit(icalfileset* cluster); +void icalfileset_mark(icalset* set); +icalerrorenum icalfileset_commit(icalset* set); -icalerrorenum icalfileset_add_component(icalfileset* cluster, +icalerrorenum icalfileset_add_component(icalset* set, icalcomponent* child); -icalerrorenum icalfileset_remove_component(icalfileset* cluster, +icalerrorenum icalfileset_remove_component(icalset* set, icalcomponent* child); -int icalfileset_count_components(icalfileset* cluster, +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(icalfileset* store, icalgauge* gauge); -void icalfileset_clear(icalfileset* store); +/** + * 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(icalfileset* cluster, const char* uid); -int icalfileset_has_uid(icalfileset* cluster, const char* uid); -icalcomponent* icalfileset_fetch_match(icalfileset* set, icalcomponent *c); +/** 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(icalfileset* store, icalcomponent *oldcomp, +/** + * 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 guage has been defined, these +/* 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 (icalfileset* cluster); -icalcomponent* icalfileset_get_first_component(icalfileset* cluster); -icalcomponent* icalfileset_get_next_component(icalfileset* cluster); -/* Return a reference to the internal component. You probably should +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(icalfileset* cluster); +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 */ + icalcluster *cluster; /**< use this cluster to initialize data */ +} icalfileset_options; +extern icalfileset_options icalfileset_options_default; #endif /* !ICALFILESET_H */ diff --git a/libical/src/libicalss/icalfilesetimpl.h b/libical/src/libicalss/icalfilesetimpl.h index fcd3415121..fe39604225 100644 --- a/libical/src/libicalss/icalfilesetimpl.h +++ b/libical/src/libicalss/icalfilesetimpl.h @@ -25,6 +25,8 @@ ======================================================================*/ +#ifndef ICALFILESETIMPL_H +#define ICALFILESETIMPL_H #ifdef HAVE_CONFIG_H #include "config.h" @@ -38,12 +40,14 @@ #define ICALFILESET_ID "fset" struct icalfileset_impl { - - char id[5]; /*fset*/ - char *path; - icalcomponent* cluster; - icalgauge* gauge; - int changed; - int fd; /* file descriptor */ + 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/libical/src/libicalss/icalgauge.c b/libical/src/libicalss/icalgauge.c index b958ecfc9d..f4854c747b 100644 --- a/libical/src/libicalss/icalgauge.c +++ b/libical/src/libicalss/icalgauge.c @@ -31,15 +31,17 @@ #include "icalgaugeimpl.h" #include <stdlib.h> -extern char* input_buffer; -extern char* input_buffer_p; -int ssparse(void); +#include "icalssyacc.h" -struct icalgauge_impl *icalss_yy_gauge; +typedef void* yyscan_t; -icalgauge* icalgauge_new_from_sql(char* sql) +int ssparse(yyscan_t ); + + +icalgauge* icalgauge_new_from_sql(char* sql, int expand) { struct icalgauge_impl *impl; + yyscan_t yy_globals = NULL; int r; @@ -52,60 +54,82 @@ icalgauge* icalgauge_new_from_sql(char* sql) impl->select = pvl_newlist(); impl->from = pvl_newlist(); impl->where = pvl_newlist(); + impl->expand = expand; + + sslex_init(&yy_globals); + + ssset_extra(impl, yy_globals); - icalss_yy_gauge = impl; + ss_scan_string(sql, yy_globals); - input_buffer_p = input_buffer = sql; - r = ssparse(); + r = ssparse(yy_globals); + sslex_destroy(yy_globals); - return impl; + 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_impl *impl = (struct icalgauge_impl*)gauge; struct icalgauge_where *w; - assert(impl->select != 0); - assert(impl->where != 0); - assert(impl->from != 0); + assert(gauge->select != 0); + assert(gauge->where != 0); + assert(gauge->from != 0); - if(impl->select){ - while( (w=pvl_pop(impl->select)) != 0){ + if(gauge->select){ + while( (w=pvl_pop(gauge->select)) != 0){ if(w->value != 0){ free(w->value); } free(w); } - pvl_free(impl->select); + pvl_free(gauge->select); + gauge->select = 0; } - if(impl->where){ - while( (w=pvl_pop(impl->where)) != 0){ + if(gauge->where){ + while( (w=pvl_pop(gauge->where)) != 0){ if(w->value != 0){ free(w->value); } free(w); } - pvl_free(impl->where); + pvl_free(gauge->where); + gauge->where = 0; } - if(impl->from){ - pvl_free(impl->from); + if(gauge->from){ + pvl_free(gauge->from); + gauge->from = 0; } + + free(gauge); } -/* Convert a VQUERY component into a gauge */ + +/** Convert a VQUERY component into a gauge */ icalcomponent* icalgauge_make_gauge(icalcomponent* query); -/* icaldirset_test compares a component against a gauge, and returns +/** + 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 guage holds a collection of VEVENT, VTODO or + 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 @@ -252,26 +276,45 @@ int icalgauge_compare_recurse(icalcomponent* comp, icalcomponent* gauge) int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) { - struct icalgauge_impl *impl = (struct icalgauge_impl*)gauge; 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"); + if (gauge == 0 || comp == 0) return 0; + inner = icalcomponent_get_first_real_component(comp); if(inner == 0){ - icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); - return 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(impl->from);e!=0;e=pvl_next(e)){ + 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)){ @@ -284,8 +327,8 @@ int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) } - /* Check each where clause against the component */ - for(e = pvl_head(impl->where);e!=0;e=pvl_next(e)){ + /**** 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; @@ -301,11 +344,14 @@ int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) vk = icalenum_property_kind_to_value_kind(w->prop); if(vk == ICAL_NO_VALUE){ - icalerror_set_errno(ICAL_INTERNAL_ERROR); + icalerror_set_errno(ICAL_INTERNAL_ERROR); return 0; } - v = icalvalue_new_from_string(vk,w->value); + 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*/ @@ -324,14 +370,46 @@ int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) } } + /* 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 = 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); @@ -355,34 +433,40 @@ int icalgauge_compare(icalgauge* gauge,icalcomponent* comp) } } + 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_AND) { + } 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(icalcomponent* gauge) +void icalgauge_dump(icalgauge* gauge) { - pvl_elem *p; - struct icalgauge_impl *impl = (struct icalgauge_impl*)gauge; - + pvl_elem p; printf("--- Select ---\n"); - for(p = pvl_head(impl->select);p!=0;p=pvl_next(p)){ + 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){ @@ -407,14 +491,14 @@ void icalgauge_dump(icalcomponent* gauge) } printf("--- From ---\n"); - for(p = pvl_head(impl->from);p!=0;p=pvl_next(p)){ + 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(impl->where);p!=0;p=pvl_next(p)){ + for(p = pvl_head(gauge->where);p!=0;p=pvl_next(p)){ struct icalgauge_where *w = pvl_data(p); if(w->logic != ICALGAUGELOGIC_NONE){ @@ -441,7 +525,5 @@ void icalgauge_dump(icalcomponent* gauge) printf("\n"); } - - } diff --git a/libical/src/libicalss/icalgauge.h b/libical/src/libicalss/icalgauge.h index 1caf0ac7d1..c35b4f7508 100644 --- a/libical/src/libicalss/icalgauge.h +++ b/libical/src/libicalss/icalgauge.h @@ -29,23 +29,33 @@ #ifndef ICALGAUGE_H #define ICALGAUGE_H -typedef void icalgauge; +/** @file icalgauge.h + * @brief Routines implementing a filter for ical components + */ -icalgauge* icalgauge_new_from_sql(char* sql); +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(icalcomponent* gauge); +void icalgauge_dump(icalgauge* gauge); + -/* Return true is comp matches the gauge. The component must be in - cannonical form -- a VCALENDAR with one VEVENT, VTODO or VJOURNAL - sub component */ +/** @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 */ +/** 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/libical/src/libicalss/icalgaugeimpl.h b/libical/src/libicalss/icalgaugeimpl.h index 73a2813242..e56b1c01c1 100644 --- a/libical/src/libicalss/icalgaugeimpl.h +++ b/libical/src/libicalss/icalgaugeimpl.h @@ -24,8 +24,6 @@ #include "ical.h" -#include "pvl.h" - typedef enum icalgaugecompare { ICALGAUGECOMPARE_EQUAL=ICAL_XLICCOMPARETYPE_EQUAL, ICALGAUGECOMPARE_LESS=ICAL_XLICCOMPARETYPE_LESS, @@ -34,6 +32,8 @@ typedef enum icalgaugecompare { 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; @@ -54,10 +54,10 @@ struct icalgauge_where { 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 */ + 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/libical/src/libicalss/icalmessage.c b/libical/src/libicalss/icalmessage.c index e1e8d8015c..731a2c7cfc 100644 --- a/libical/src/libicalss/icalmessage.c +++ b/libical/src/libicalss/icalmessage.c @@ -40,7 +40,7 @@ icalcomponent* icalmessage_get_inner(icalcomponent* comp) } } -char* lowercase(const char* str) +static char* lowercase(const char* str) { char* p = 0; char* n = icalmemory_strdup(str); @@ -158,8 +158,13 @@ icalcomponent *icalmessage_new_reply_base(icalcomponent* c, icalcomponent_add_property(reply,icalproperty_new_version("2.0")); +#ifndef WIN32 sprintf(tmp, "-//SoftwareStudio//NONSGML %s %s //EN",PACKAGE,VERSION); +#else + sprintf(tmp, + "-//SoftwareStudio//NONSGML %s %s //EN",ICAL_PACKAGE,ICAL_VERSION); +#endif icalcomponent_add_property(reply,icalproperty_new_prodid(tmp)); return reply; @@ -230,11 +235,11 @@ icalcomponent* icalmessage_new_counterpropose_reply(icalcomponent* oldc, icalerror_check_arg_rz(oldc,"oldc"); icalerror_check_arg_rz(newc,"newc"); - reply = icalcomponent_new_clone(newc); + reply = icalmessage_new_reply_base(newc,user,msg); icalcomponent_set_method(reply,ICAL_METHOD_COUNTER); - return newc; + return reply; } @@ -353,10 +358,7 @@ icalcomponent* icalmessage_new_error_reply(icalcomponent* c, rs.debug = debug; icalcomponent_add_property(inner, - icalproperty_new_requeststatus( - icalreqstattype_as_string(rs) - ) - ); + icalproperty_new_requeststatus(rs)); } else { /* code == ICAL_UNKNOWN_STATUS */ /* Copy all of the request status properties */ diff --git a/libical/src/libicalss/icalset.c b/libical/src/libicalss/icalset.c index 2120609928..0ad22696f7 100644 --- a/libical/src/libicalss/icalset.c +++ b/libical/src/libicalss/icalset.c @@ -41,33 +41,26 @@ #include "icaldirset.h" #include "icaldirsetimpl.h" #include <stdlib.h> -/*#include "icalheapset.h"*/ -/*#include "icalmysqlset.h"*/ - -#define ICALSET_ID "set " - -struct icalset_fp { - 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, icalcomponent* 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 *new); - icalcomponent* (*get_current_component)(icalset* set); - icalcomponent* (*get_first_component)(icalset* set); - icalcomponent* (*get_next_component)(icalset* set); -}; - -struct icalset_fp icalset_dirset_fp = { +#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, @@ -83,11 +76,18 @@ struct icalset_fp icalset_dirset_fp = { icaldirset_modify, icaldirset_get_current_component, icaldirset_get_first_component, - icaldirset_get_next_component + icaldirset_get_next_component, + icaldirset_begin_component, + icaldirsetiter_to_next, + icaldirsetiter_to_prior }; -struct icalset_fp icalset_fileset_fp = { +static icalset icalset_fileset_init = { + ICAL_FILE_SET, + sizeof(icalfileset), + NULL, + icalfileset_init, icalfileset_free, icalfileset_path, icalfileset_mark, @@ -103,265 +103,391 @@ struct icalset_fp icalset_fileset_fp = { icalfileset_modify, icalfileset_get_current_component, icalfileset_get_first_component, - icalfileset_get_next_component + icalfileset_get_next_component, + icalfileset_begin_component, + icalfilesetiter_to_next, + NULL }; -struct icalset_impl { +#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 - char id[5]; /* "set " */ +#ifdef _DLOPEN_TEST +static int icalset_init_done = 0; +static pvl_list icalset_kinds = 0; - void *derived_impl; - struct icalset_fp *fp; -}; +typedef icalset *(*fptr)(void); -/* Figure out what was actually passed in as the set. This could be a - set or and of the derived types such as dirset or fileset. Note - this routine returns a value, not a reference, to avoid memory - leaks in the methods */ -struct icalset_impl icalset_get_impl(icalset* set) -{ - struct icalset_impl impl; - - memset(&impl,0,sizeof(impl)); - icalerror_check_arg_re( (set!=0),"set",impl); - - if(strcmp((char*)set,ICALSET_ID)==0) { - /* It is actually a set, so just sent the reference back out. */ - return *(struct icalset_impl*)set; - } else if(strcmp((char*)set,ICALFILESET_ID)==0) { - /* Make a new set from the fileset */ - impl.fp = &icalset_fileset_fp; - impl.derived_impl = set; - strcpy(impl.id,ICALFILESET_ID);/* HACK. Is this necessary? */ - return impl; - } else if(strcmp((char*)set,ICALDIRSET_ID)==0) { - /* Make a new set from the dirset */ - impl.fp = &icalset_dirset_fp; - impl.derived_impl = set; - strcpy(impl.id,ICALDIRSET_ID);/* HACK. Is this necessary? */ - return impl; - } else { - /* The type of set is unknown, so throw an error */ - icalerror_assert((0),"Unknown set type"); - return impl; - } +/** + * 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; -struct icalset_impl* icalset_new_impl() -{ - - struct icalset_impl* impl; + strcpy(buf, path); + bufptr = buf + strlen(buf); - if ( ( impl = (struct icalset_impl*) - malloc(sizeof(struct icalset_impl))) == 0) { - icalerror_set_errno(ICAL_NEWFAILED_ERROR); - return 0; - } + if (*(bufptr-1) != '/') + *bufptr++ = '/'; - strcpy(impl->id,ICALSET_ID); + if ((d = opendir(path)) == 0) { + perror("opendir"); + return 0; + } - impl->derived_impl = 0; - impl->fp = 0; + while ((dp = readdir(d)) != 0) { + if (strncmp(dp->d_name, "mod_", 4)) continue; - return impl; -} + strcpy(bufptr, dp->d_name); -struct icalset_impl* icalset_new_file_from_ref(icalfileset *fset) -{ - struct icalset_impl *impl = icalset_new_impl(); + load(buf); + tot++; + } + (void)closedir(d); - icalerror_check_arg_rz( (fset!=0),"fset"); + return 1; +} - if(impl == 0){ - free(impl); - return 0; - } +int icalset_register_class(icalset *set); - impl->derived_impl = fset; +static void icalset_init(void) { + assert(icalset_kinds == 0); + icalset_kinds = pvl_newlist(); - if (impl->derived_impl == 0){ - free(impl); - return 0; - } + 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 - impl->fp = &icalset_fileset_fp; +#ifdef EXT_PATH + icalset_loaddir(EXT_PATH); +#endif - return (struct icalset_impl*)impl; + icalset_init_done++; } -icalset* icalset_new_file(const char* path) -{ - icalfileset *fset = icalfileset_new(path); +int icalset_register_class(icalset *set) { - if(fset == 0){ - return 0; - } + if (!icalset_init_done) + icalset_init(); - return (icalset*)icalset_new_file_from_ref(fset); + pvl_push(icalset_kinds, set); + return 1; } -icalset* icalset_new_dir_from_ref(icaldirset *dset) -{ +#endif - struct icalset_impl *impl = icalset_new_impl(); +icalset* icalset_new(icalset_kind kind, const char* dsn, void* options) { + icalset *data = NULL; + icalset *ret = NULL; - icalerror_check_arg_rz( (dset!=0),"dset"); +#ifdef _DLOPEN_TEST + pvl_elem e; + icalset *impl; - if(impl == 0){ - return 0; + 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); } - impl->derived_impl = dset; + data = (icalset*)malloc(impl->size); + if (data == 0) { + icalerror_set_errno(ICAL_NEWFAILED_ERROR); + errno = ENOMEM; + return 0; + } - if (impl->derived_impl == 0){ - free(impl); + /* 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); + } + + if ( data == 0) { + icalerror_set_errno(ICAL_NEWFAILED_ERROR); + return 0; + } + data->kind = kind; + data->dsn = strdup(dsn); +#endif - impl->fp = &icalset_dirset_fp; + /** call the implementation specific initializer **/ + if ((ret = data->init(data, dsn, options)) == NULL) + icalset_free(data); - return impl; + return ret; } -icalset* icalset_new_dir(const char* path) +icalset* icalset_new_file(const char* path) { - icaldirset *dset = icaldirset_new(path); - - if(dset == 0){ - return 0; - } + return icalset_new(ICAL_FILE_SET, path, NULL); +} - return icalset_new_dir_from_ref(dset); +icalset* icalset_new_file_writer(const char* path) +{ + return icalfileset_new_writer(path); } -icalset* icalset_new_heap(void) +icalset* icalset_new_file_reader(const char* path) { - struct icalset_impl *impl = icalset_new_impl(); + return icalfileset_new_reader(path); +} - if(impl == 0){ - free(impl); - return 0; - } +icalset* icalset_new_dir(const char* path) +{ + return icalset_new(ICAL_DIR_SET, path, NULL); +} - return 0; +icalset* icalset_new_dir_writer(const char* path) +{ + return icaldirset_new_writer(path); } -icalset* icalset_new_mysql(const char* path) +icalset* icalset_new_dir_reader(const char* path) { - struct icalset_impl *impl = icalset_new_impl(); + return icaldirset_new_reader(path); +} - if(impl == 0){ - free(impl); - return 0; - } - return 0; -} + +/* Functions for built-in methods */ + +/** + * free memory associated with this icalset + * automatically calls the implementation specific free routine + */ void icalset_free(icalset* set) { - struct icalset_impl impl = icalset_get_impl(set); - (*(impl.fp->free))(impl.derived_impl); + if (set->free) + set->free(set); - if(strcmp((char*)set,ICALSET_ID)) { - free(set); - } -} + if (set->dsn) + free(set->dsn); -const char* icalset_path(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->path))(impl.derived_impl); + free(set); } -void icalset_mark(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - (*(impl.fp->mark))(impl.derived_impl); + +const char* icalset_path(icalset* set) { + return set->path(set); } -icalerrorenum icalset_commit(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->commit))(impl.derived_impl); +void icalset_mark(icalset* set) { + set->mark(set); } -icalerrorenum icalset_add_component(icalset* set, icalcomponent* comp) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->add_component))(impl.derived_impl,comp); +icalerrorenum icalset_commit(icalset* set) { + return set->commit(set); } -icalerrorenum icalset_remove_component(icalset* set, icalcomponent* comp) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->remove_component))(impl.derived_impl,comp); +icalerrorenum icalset_add_component(icalset* set, icalcomponent* comp) { + return set->add_component(set,comp); } -int icalset_count_components(icalset* set,icalcomponent_kind kind) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->count_components))(impl.derived_impl,kind); +icalerrorenum icalset_remove_component(icalset* set, icalcomponent* comp) { + return set->remove_component(set,comp); } -icalerrorenum icalset_select(icalset* set, icalcomponent* gauge) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->select))(impl.derived_impl,gauge); +int icalset_count_components(icalset* set,icalcomponent_kind kind) { + return set->count_components(set,kind); } -void icalset_clear(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - (*(impl.fp->clear))(impl.derived_impl); +icalerrorenum icalset_select(icalset* set, icalgauge* gauge) { + return set->select(set, gauge); } -icalcomponent* icalset_fetch(icalset* set, const char* uid) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->fetch))(impl.derived_impl,uid); +void icalset_clear(icalset* set) { + set->clear(set); } -icalcomponent* icalset_fetch_match(icalset* set, icalcomponent *comp) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->fetch_match))(impl.derived_impl,comp); +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) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->has_uid))(impl.derived_impl,uid); +int icalset_has_uid(icalset* set, const char* uid) { + return set->has_uid(set, uid); } icalerrorenum icalset_modify(icalset* set, icalcomponent *old, - icalcomponent *new) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->modify))(impl.derived_impl,old,new); + icalcomponent *new) { + return set->modify(set, old, new); } -icalcomponent* icalset_get_current_component(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->get_current_component))(impl.derived_impl); +icalcomponent* icalset_get_current_component(icalset* set) { + return set->get_current_component(set); } -icalcomponent* icalset_get_first_component(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->get_first_component))(impl.derived_impl); +icalcomponent* icalset_get_first_component(icalset* set) { + return set->get_first_component(set); } -icalcomponent* icalset_get_next_component(icalset* set) -{ - struct icalset_impl impl = icalset_get_impl(set); - return (*(impl.fp->get_next_component))(impl.derived_impl); +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/libical/src/libicalss/icalset.h b/libical/src/libicalss/icalset.h index 7b083dae24..4008c6216f 100644 --- a/libical/src/libicalss/icalset.h +++ b/libical/src/libicalss/icalset.h @@ -1,17 +1,19 @@ /* -*- Mode: C -*- */ -/*====================================================================== - FILE: icalset.h - CREATOR: eric 28 November 1999 - +/** + @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 componetns in a single file + 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$ $Locker$ @@ -39,7 +41,7 @@ #include <limits.h> /* For PATH_MAX */ #include "ical.h" -#include "icalerror.h" +#include "icalgauge.h" #ifdef PATH_MAX #define ICAL_PATH_MAX PATH_MAX @@ -48,33 +50,86 @@ #endif - - -typedef void icalset; +typedef struct icalset_impl icalset; typedef enum icalset_kind { ICAL_FILE_SET, ICAL_DIR_SET, - ICAL_HEAP_SET, - ICAL_MYSQL_SET, - ICAL_CAP_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); -/* Create a specific derived type of set */ 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_heap(void); -icalset* icalset_new_mysql(const char* path); -/*icalset* icalset_new_cap(icalcstp* cstp);*/ +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. Commit writes to disk immediately*/ +/** 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); @@ -83,28 +138,46 @@ 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. _clear removes the gauge. */ -icalerrorenum icalset_select(icalset* set, icalcomponent* gauge); +/** 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 */ +/** 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 +/** 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 +/** 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/libical/src/libicalss/icalspanlist.c b/libical/src/libicalss/icalspanlist.c index cab6a81c68..f42ff41ed8 100644 --- a/libical/src/libicalss/icalspanlist.c +++ b/libical/src/libicalss/icalspanlist.c @@ -28,14 +28,27 @@ #include "ical.h" #include "icalspanlist.h" -#include "pvl.h" + #include <stdlib.h> /* for free and malloc */ +#include <string.h> struct icalspanlist_impl { - pvl_list spans; + pvl_list spans; /**< list of icaltime_span data **/ + struct icaltimetype start; /**< start time of span **/ + struct icaltimetype end; /**< end time of span **/ }; -int compare_span(void* a, void* b) +/** @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 ; @@ -49,20 +62,52 @@ int compare_span(void* a, void* b) } } -icalcomponent* icalspanlist_get_inner(icalcomponent* comp) + +/** @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) { - if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){ - return icalcomponent_get_first_real_component(comp); - } else { - return comp; - } + 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); } + -void print_span(int c, struct icaltime_span span ); +/** @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. + */ - -/* Make a free list from a set of component */ icalspanlist* icalspanlist_new(icalset *set, struct icaltimetype start, struct icaltimetype end) @@ -71,7 +116,7 @@ icalspanlist* icalspanlist_new(icalset *set, pvl_elem itr; icalcomponent *c,*inner; icalcomponent_kind kind, inner_kind; - struct icalspanlist_impl *sl; + icalspanlist *sl; struct icaltime_span *freetime; if ( ( sl = (struct icalspanlist_impl*) @@ -81,14 +126,12 @@ icalspanlist* icalspanlist_new(icalset *set, } sl->spans = pvl_newlist(); + sl->start = start; + sl->end = end; range.start = icaltime_as_timet(start); range.end = icaltime_as_timet(end); - printf("Range start: %s",ctime(&range.start)); - printf("Range end : %s",ctime(&range.end)); - - /* Get a list of spans of busy time from the events in the set and order the spans based on the start time */ @@ -96,8 +139,6 @@ icalspanlist* icalspanlist_new(icalset *set, c != 0; c = icalset_get_next_component(set)){ - struct icaltime_span span; - kind = icalcomponent_isa(c); inner = icalcomponent_get_inner(c); @@ -113,31 +154,12 @@ icalspanlist* icalspanlist_new(icalset *set, } icalerror_clear_errno(); - - span = icalcomponent_get_span(c); - span.is_busy = 1; - - if(icalerrno != ICAL_NO_ERROR){ - continue; - } - - if ((range.start < span.end && icaltime_is_null_time(end)) || - (range.start < span.end && range.end > span.start )){ - - struct icaltime_span *s; - - if ((s=(struct icaltime_span *) - malloc(sizeof(struct icaltime_span))) == 0){ - icalerror_set_errno(ICAL_NEWFAILED_ERROR); - return 0; - } - - memcpy(s,&span,sizeof(span)); - - pvl_insert_ordered(sl->spans,compare_span,(void*)s); - - } - } + + 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 @@ -148,7 +170,7 @@ icalspanlist* icalspanlist_new(icalset *set, itr != 0; itr = pvl_next(itr)) { - struct icaltime_span *s = (icalproperty*)pvl_data(itr); + struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); if ((freetime=(struct icaltime_span *) malloc(sizeof(struct icaltime_span))) == 0){ @@ -178,7 +200,7 @@ icalspanlist* icalspanlist_new(icalset *set, if( icaltime_is_null_time(end)){ struct icaltime_span* last_span; - last_span = pvl_data(pvl_tail(sl->spans)); + last_span = (struct icaltime_span*)pvl_data(pvl_tail(sl->spans)); if (last_span != 0){ @@ -197,35 +219,46 @@ icalspanlist* icalspanlist_new(icalset *set, return sl; - } +/** @brief Destructor. + * @param s A valid icalspanlist + * + * Free memory associated with the spanlist + */ + void icalspanlist_free(icalspanlist* s) { struct icaltime_span *span; - struct icalspanlist_impl* impl = (struct icalspanlist_impl*)s; - - while( (span=pvl_pop(impl->spans)) != 0){ + + if (s == NULL) + return; + + while( (span=pvl_pop(s->spans)) != 0){ free(span); } - pvl_free(impl->spans); + pvl_free(s->spans); - impl->spans = 0; + s->spans = 0; + + free(s); } -void icalspanlist_dump(icalspanlist* s){ +/** @brief (Debug) print out spanlist to stdout. + * @param sl A valid icalspanlist. + */ +void icalspanlist_dump(icalspanlist* sl){ int i = 0; - struct icalspanlist_impl* sl = (struct icalspanlist_impl*)s; pvl_elem itr; for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) { - struct icaltime_span *s = (icalproperty*)pvl_data(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)); @@ -236,10 +269,19 @@ void icalspanlist_dump(icalspanlist* s){ 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) { - struct icalspanlist_impl* impl = (struct icalspanlist_impl*)sl; pvl_elem itr; struct icalperiodtype period; struct icaltime_span *s; @@ -249,22 +291,22 @@ struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl, period.start = icaltime_null_time(); period.end = icaltime_null_time(); - /* Is the reference time before the first span? If so, assume - that the reference time is free */ - itr = pvl_head(impl->spans); - s = (icalproperty*)pvl_data(itr); + 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 == 0){ + if (s->is_busy == 1){ period.end = icaltime_from_timet(s->start,0); } else { period.end = icaltime_from_timet(s->end,0); @@ -275,12 +317,11 @@ struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl, /* Otherwise, find the first free span that contains the reference time. */ - - for( itr = pvl_head(impl->spans); + for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) { - s = (icalproperty*)pvl_data(itr); + s = (struct icaltime_span *)pvl_data(itr); if(s->is_busy == 0 && s->start >= rangett && ( rangett < s->end || s->end == s->start)){ @@ -307,3 +348,220 @@ struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl, 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); + 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; + 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/libical/src/libicalss/icalspanlist.h b/libical/src/libicalss/icalspanlist.h index 83cb1c8a6d..91f0acb8c1 100644 --- a/libical/src/libicalss/icalspanlist.h +++ b/libical/src/libicalss/icalspanlist.h @@ -28,26 +28,49 @@ #include "ical.h" #include "icalset.h" -typedef void icalspanlist; +/** @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 + */ -/* 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 free or busy time after time t. all times are in UTC */ +/** 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/libical/src/libicalss/icalspanlist_cxx.cpp b/libical/src/libicalss/icalspanlist_cxx.cpp new file mode 100644 index 0000000000..38761af4c6 --- /dev/null +++ b/libical/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/libical/src/libicalss/icalspanlist_cxx.h b/libical/src/libicalss/icalspanlist_cxx.h new file mode 100644 index 0000000000..fce901c3db --- /dev/null +++ b/libical/src/libicalss/icalspanlist_cxx.h @@ -0,0 +1,53 @@ +/* -*- 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 "ical.h" +#include "icalss.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/libical/src/libicalss/icalsslexer.l b/libical/src/libicalss/icalsslexer.l index 848a9bc74f..6ea9f0ef2a 100644 --- a/libical/src/libicalss/icalsslexer.l +++ b/libical/src/libicalss/icalsslexer.l @@ -6,7 +6,7 @@ DESCRIPTION: - $Id: icalsslexer.l,v 1.1.1.2 2001/01/23 19:20:41 jpr Exp $ + $Id: icalsslexer.l,v 1.2 2003/09/11 22:04:30 hansp Exp $ $Locker: $ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org @@ -33,16 +33,12 @@ #include <string.h> /* For strdup() */ -int icalparser_flex_input(char* buf, int max_size); -void icalparser_clear_flex_input(); - -#undef YY_INPUT -#define YY_INPUT(b,r,ms) ( r= icalparser_flex_input(b,ms)) +#undef YYPURE +#define YYPURE #undef SS_FATAL_ERROR #define SS_FATAL_ERROR(msg) sserror(msg) - %} crlf \x0D?\x0A @@ -61,6 +57,7 @@ digit [0-9] %array /* Make yytext an array. Slow, but handy. HACK */ %option caseless +%option reentrant-bison %s sql string_value @@ -77,6 +74,7 @@ FROM { return FROM; } WHERE { return WHERE; } , { return COMMA; } "=" { return EQUALS; } +"==" { return EQUALS; } "!=" { return NOTEQUALS; } "<" { return LESS; } ">" { return GREATER; } @@ -84,29 +82,35 @@ WHERE { return WHERE; } ">=" { 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(); + +\'[\@\*A-Za-z0-9\-\.\:\ ]+\' { + int c = input(yy_globals); unput(c); if(c!='\''){ - sslval.v_string= icalmemory_tmp_copy(sstext); + yylvalp->v_string= icalmemory_tmp_copy(yytext); return STRING; } else { /*ssmore();*/ } } -[\*A-Za-z0-9\-\.]+ { sslval.v_string= icalmemory_tmp_copy(sstext); - return STRING; } +[\@\*A-Za-z0-9\-\.]+ { + yylval->v_string= icalmemory_tmp_copy(yytext); + return STRING; +} . { return yytext[0]; } %% -int sswrap() +int yywrap(yyscan_t yy_globals) { return 1; } diff --git a/libical/src/libicalss/icalssyacc.h b/libical/src/libicalss/icalssyacc.h index 9a933dc735..6d03a0f5ae 100644 --- a/libical/src/libicalss/icalssyacc.h +++ b/libical/src/libicalss/icalssyacc.h @@ -1,22 +1,31 @@ +#ifndef BISON_Y_TAB_H +# define BISON_Y_TAB_H + +#ifndef YYSTYPE typedef union { char* v_string; -} YYSTYPE; -#define STRING 257 -#define SELECT 258 -#define FROM 259 -#define WHERE 260 -#define COMMA 261 -#define QUOTE 262 -#define EQUALS 263 -#define NOTEQUALS 264 -#define LESS 265 -#define GREATER 266 -#define LESSEQUALS 267 -#define GREATEREQUALS 268 -#define AND 269 -#define OR 270 -#define EOL 271 -#define END 272 +} yystype; +# define YYSTYPE yystype +#endif +# define STRING 257 +# define SELECT 258 +# define FROM 259 +# define WHERE 260 +# define COMMA 261 +# define QUOTE 262 +# define EQUALS 263 +# define NOTEQUALS 264 +# define LESS 265 +# define GREATER 266 +# define LESSEQUALS 267 +# define GREATEREQUALS 268 +# define AND 269 +# define OR 270 +# define EOL 271 +# define END 272 +# define IS 273 +# define NOT 274 +# define SQLNULL 275 -extern YYSTYPE sslval; +#endif /* not BISON_Y_TAB_H */ diff --git a/libical/src/libicalss/icalssyacc.y b/libical/src/libicalss/icalssyacc.y index 047b158e93..224841f520 100644 --- a/libical/src/libicalss/icalssyacc.y +++ b/libical/src/libicalss/icalssyacc.y @@ -1,3 +1,5 @@ +%pure_parser + %{ /* -*- Mode: C -*- ====================================================================== @@ -6,7 +8,7 @@ DESCRIPTION: - $Id: icalssyacc.y,v 1.1.1.2 2001/01/23 19:20:41 jpr Exp $ + $Id: icalssyacc.y,v 1.2 2003/09/11 22:04:30 hansp Exp $ $Locker: $ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org @@ -26,26 +28,28 @@ Code is Eric Busboom ======================================================================*/ - +/*#define YYDEBUG 1*/ #include <stdlib.h> #include <string.h> /* for strdup() */ #include <limits.h> /* for SHRT_MAX*/ #include "ical.h" -#include "pvl.h" #include "icalgauge.h" #include "icalgaugeimpl.h" -extern struct icalgauge_impl *icalss_yy_gauge; - -void ssyacc_add_where(struct icalgauge_impl* impl, char* prop, - icalgaugecompare compare , char* value); -void ssyacc_add_select(struct icalgauge_impl* impl, char* str1); -void ssyacc_add_from(struct icalgauge_impl* impl, char* str1); -void set_logic(struct icalgauge_impl* impl,icalgaugelogic l); -void sserror(char *s); /* Don't know why I need this.... */ +#define YYPARSE_PARAM yy_globals +#define YYLEX_PARAM yy_globals +#define YY_EXTRA_TYPE icalgauge_impl* + /* ick...*/ +#define yyextra ((struct icalgauge_impl*)ssget_extra(yy_globals)) +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); +void sserror(char *s); /* Don't know why I need this.... */ %} @@ -56,49 +60,51 @@ void sserror(char *s); /* Don't know why I need this.... */ %token <v_string> STRING %token SELECT FROM WHERE COMMA QUOTE EQUALS NOTEQUALS LESS GREATER LESSEQUALS -%token GREATEREQUALS AND OR EOL END +%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 { - icalparser_clear_flex_input(); yyclearin; + YYABORT; } ; select_list: - STRING {ssyacc_add_select(icalss_yy_gauge,$1);} - | select_list COMMA STRING {ssyacc_add_select(icalss_yy_gauge,$3);} + STRING {ssyacc_add_select(yyextra,$1);} + | select_list COMMA STRING {ssyacc_add_select(yyextra,$3);} ; from_list: - STRING {ssyacc_add_from(icalss_yy_gauge,$1);} - | from_list COMMA STRING {ssyacc_add_from(icalss_yy_gauge,$3);} + STRING {ssyacc_add_from(yyextra,$1);} + | from_list COMMA STRING {ssyacc_add_from(yyextra,$3);} ; where_clause: /* Empty */ - | STRING EQUALS STRING {ssyacc_add_where(icalss_yy_gauge,$1,ICALGAUGECOMPARE_EQUAL,$3); } - - | 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); } + | STRING EQUALS STRING {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_EQUAL,$3); } + | STRING IS SQLNULL {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_ISNULL,""); } + | STRING IS NOT SQLNULL {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_ISNOTNULL,""); } + | STRING NOTEQUALS STRING {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_NOTEQUAL,$3); } + | STRING LESS STRING {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_LESS,$3); } + | STRING GREATER STRING {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_GREATER,$3); } + | STRING LESSEQUALS STRING {ssyacc_add_where(yyextra,$1,ICALGAUGECOMPARE_LESSEQUAL,$3); } + | STRING GREATEREQUALS STRING {ssyacc_add_where(yyextra,$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);} + where_clause {set_logic(yyextra,ICALGAUGELOGIC_NONE);} + | where_list AND where_clause {set_logic(yyextra,ICALGAUGELOGIC_AND);} + | where_list OR where_clause {set_logic(yyextra,ICALGAUGELOGIC_OR);} ; %% -void ssyacc_add_where(struct icalgauge_impl* impl, char* str1, +static void ssyacc_add_where(struct icalgauge_impl* impl, char* str1, icalgaugecompare compare , char* value_str) { @@ -160,7 +166,7 @@ void ssyacc_add_where(struct icalgauge_impl* impl, char* str1, pvl_push(impl->where,where); } -void set_logic(struct icalgauge_impl* impl,icalgaugelogic l) +static void set_logic(struct icalgauge_impl* impl,icalgaugelogic l) { pvl_elem e = pvl_tail(impl->where); struct icalgauge_where *where = pvl_data(e); @@ -171,7 +177,7 @@ void set_logic(struct icalgauge_impl* impl,icalgaugelogic l) -void ssyacc_add_select(struct icalgauge_impl* impl, char* str1) +static void ssyacc_add_select(struct icalgauge_impl* impl, char* str1) { char *c, *compstr, *propstr; struct icalgauge_where *where; @@ -217,15 +223,15 @@ void ssyacc_add_select(struct icalgauge_impl* impl, char* str1) if(where->prop == ICAL_NO_PROPERTY){ - icalgauge_free(where); - icalerror_set_errno(ICAL_BADARG_ERROR); - return; + free(where); + icalerror_set_errno(ICAL_BADARG_ERROR); + return; } pvl_push(impl->select,where); } -void ssyacc_add_from(struct icalgauge_impl* impl, char* str1) +static void ssyacc_add_from(struct icalgauge_impl* impl, char* str1) { icalcomponent_kind ckind; @@ -241,5 +247,6 @@ void ssyacc_add_from(struct icalgauge_impl* impl, char* str1) void sserror(char *s){ - fprintf(stderr,"Parse error \'%s\'\n", s); + fprintf(stderr,"Parse error \'%s\'\n", s); + icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); } |