aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src/libicalss/icalbdbset.c
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src/libicalss/icalbdbset.c')
-rw-r--r--libical/src/libicalss/icalbdbset.c1598
1 files changed, 1598 insertions, 0 deletions
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));
+}
+
+
+