Back to index

lightning-sunbird  0.9+nobinonly
icalbdbset.c
Go to the documentation of this file.
00001 /* -*- Mode: C -*-
00002   ======================================================================
00003   FILE: icalbdbset.c
00004  ======================================================================*/
00005 
00006 
00007 #ifdef HAVE_CONFIG_H
00008 #include "config.h"
00009 #endif
00010 
00011 #include "icalbdbset.h"
00012 #include "icalgauge.h"
00013 #include <errno.h>
00014 #include <sys/stat.h> /* for stat */
00015 #include <stdio.h>
00016 
00017 #ifndef WIN32
00018 #include <unistd.h> /* for stat, getpid, unlink */
00019 #include <fcntl.h> /* for fcntl */
00020 #include <unistd.h> /* for fcntl */
00021 #else
00022 #define       S_IRUSR       S_IREAD              /* R for owner */
00023 #define       S_IWUSR       S_IWRITE      /* W for owner */
00024 #endif
00025 #include <stdlib.h>
00026 #include <string.h>
00027 
00028 #include "icalbdbsetimpl.h"
00029 
00030 #define STRBUF_LEN 255
00031 #define MAX_RETRY 5
00032 
00033 extern int errno;
00034 
00035 
00036 
00037 /* these are just stub functions */
00038 icalerrorenum icalbdbset_read_database(icalbdbset* bset, char *(*pfunc)(const DBT *dbt));
00039 icalerrorenum icalbdbset_create_cluster(const char *path);
00040 int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, int access_method);
00041 
00042 static int _compare_keys(DB *dbp, const DBT *a, const DBT *b);
00043 
00044     
00046 icalbdbset_options icalbdbset_options_default = {ICALBDB_EVENTS, DB_BTREE, 0644, 0, NULL, NULL};
00047 
00048 
00049 static DB_ENV *ICAL_DB_ENV = 0;
00050 
00053 int icalbdbset_init_dbenv(char *db_env_dir, void (*logDbFunc)(const char*, char*)) {
00054   int ret;
00055   int flags;
00056 
00057   if (db_env_dir) {
00058     struct stat env_dir_sb;
00059     
00060     if (stat(db_env_dir, &env_dir_sb)) {
00061       fprintf(stderr, "The directory '%s' is missing, please create it.\n", db_env_dir);
00062       return EINVAL;
00063     }
00064   }
00065   
00066   ret = db_env_create(&ICAL_DB_ENV, 0);
00067 
00068   if (ret) {
00069     /* some kind of error... */
00070     return ret;
00071   }
00072 
00073   /* Do deadlock detection internally */
00074   if ((ret = ICAL_DB_ENV->set_lk_detect(ICAL_DB_ENV, DB_LOCK_DEFAULT)) != 0) {
00075     char * foo = db_strerror(ret);
00076     fprintf(stderr, "Could not initialize the database locking environment\n");
00077     return ret;
00078   }    
00079 
00080   flags = DB_INIT_LOCK | DB_INIT_TXN | DB_CREATE | DB_THREAD | \
00081     DB_RECOVER | DB_INIT_LOG | DB_INIT_MPOOL;
00082   ret = ICAL_DB_ENV->open(ICAL_DB_ENV, db_env_dir,  flags, S_IRUSR|S_IWUSR);
00083   
00084   if (ret) {
00085     char * foo = db_strerror(ret);
00086     ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "dbenv->open");
00087     return ret;
00088   }
00089 
00090   /* display additional error messages */
00091   if (logDbFunc != NULL) {
00092      ICAL_DB_ENV->set_errcall(ICAL_DB_ENV, logDbFunc);
00093   }
00094 
00095   return ret;
00096 }
00097 
00098 void icalbdbset_checkpoint(void)
00099 {
00100   int ret;
00101   char *err;
00102 
00103   switch (ret = ICAL_DB_ENV->txn_checkpoint(ICAL_DB_ENV, 0,0,0)) {
00104   case 0:
00105   case DB_INCOMPLETE:
00106     break;
00107   default:
00108     err = db_strerror(ret);
00109     ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "checkpoint failed");
00110     abort();
00111   }
00112 }
00113 
00114 void icalbdbset_rmdbLog(void)
00115 {
00116     int      ret = 0;
00117     char**   listp;
00118 
00119     /* remove log files that are archivable (ie. no longer needed) */
00120     if (ICAL_DB_ENV->log_archive(ICAL_DB_ENV, &listp, DB_ARCH_ABS) == 0) {
00121        if (listp != NULL) {
00122           int ii = 0;
00123           while (listp[ii] != NULL) {
00124               ret = unlink(listp[ii]);
00125               ii++;
00126           }
00127           free(listp);
00128        }
00129     }
00130 }
00131 
00132 int icalbdbset_cleanup(void)
00133 {
00134   int ret = 0;
00135 
00136   /* one last checkpoint.. */
00137   icalbdbset_checkpoint();
00138 
00139     /* remove logs that are not needed anymore */
00140     icalbdbset_rmdbLog();
00141 
00142   if (ICAL_DB_ENV) 
00143      ret = ICAL_DB_ENV->close(ICAL_DB_ENV, 0);
00144 
00145   return ret;
00146 }
00147 
00148 DB_ENV *icalbdbset_get_env(void) {
00149   return ICAL_DB_ENV;
00150 }
00151 
00152 
00160 icalset* icalbdbset_init(icalset* set, const char* dsn, void* options_in)
00161 {
00162     icalbdbset *bset = (icalbdbset*)set;
00163     icalbdbset_options *options = options_in;
00164     int ret;
00165     DB *cal_db;
00166     char *subdb_name;
00167 
00168     if (options == NULL) 
00169       *options = icalbdbset_options_default;
00170 
00171     switch (options->subdb) {
00172     case ICALBDB_CALENDARS:
00173       subdb_name = "calendars";
00174       break;
00175     case ICALBDB_EVENTS:
00176       subdb_name = "events";
00177       break;
00178     case ICALBDB_TODOS:
00179       subdb_name = "todos";
00180       break;
00181     case ICALBDB_REMINDERS:
00182       subdb_name = "reminders";
00183       break;
00184     }
00185   
00186     cal_db = icalbdbset_bdb_open(set->dsn, 
00187                              subdb_name, 
00188                              options->dbtype, 
00189                              options->mode,
00190                              options->flag);
00191     if (cal_db == NULL)
00192       return NULL;
00193 
00194     bset->dbp = cal_db;
00195     bset->sdbp = NULL;
00196     bset->gauge = 0;
00197     bset->cluster = 0;
00198   
00199     if ((ret = icalbdbset_read_database(bset, options->pfunc)) != ICAL_NO_ERROR) {
00200       return NULL;
00201     }
00202 
00203     return (icalset *)bset;
00204 }
00205 
00206 
00212 icalset* icalbdbset_new(const char* database_filename, 
00213                      icalbdbset_subdb_type subdb_type,
00214                      int dbtype, int flag)
00215 {
00216   icalbdbset_options options = icalbdbset_options_default;
00217 
00218   options.subdb = subdb_type;
00219   options.dbtype = dbtype;
00220   options.flag = flag;
00221   
00222   /* this will in turn call icalbdbset_init */
00223   return icalset_new(ICAL_BDB_SET, database_filename, &options);
00224 }
00225 
00233 DB * icalbdbset_bdb_open_secondary(DB *dbp,
00234                             const char *database,
00235                             const char *sub_database, 
00236                             int (*callback) (DB *db, 
00237                                           const DBT *dbt1, 
00238                                           const DBT *dbt2, 
00239                                           DBT *dbt3),
00240                             int type)
00241 {
00242   int ret;
00243   int flags;
00244     DB  *sdbp = NULL;
00245 
00246   if (!sub_database) 
00247         return NULL;
00248 
00249   if (!ICAL_DB_ENV)
00250         icalbdbset_init_dbenv(NULL, NULL);
00251 
00252   /* Open/create secondary */
00253   if((ret = db_create(&sdbp, ICAL_DB_ENV, 0)) != 0) {
00254         ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "secondary index: %s", sub_database);
00255         return NULL;
00256   }
00257 
00258   if ((ret = sdbp->set_flags(sdbp, DB_DUP | DB_DUPSORT)) != 0) {
00259         ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "set_flags error for secondary index: %s", sub_database);
00260         return NULL;
00261   }
00262 
00263   flags = DB_CREATE  | DB_THREAD;
00264   if ((ret = sdbp->open(sdbp, database, sub_database, type, (u_int32_t) flags, 0644)) != 0) {
00265         ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to open secondary index: %s", sub_database);
00266         if (ret == DB_RUNRECOVERY)
00267             abort();
00268         else
00269             return NULL;
00270   }
00271 
00272   /* Associate the primary index with a secondary */
00273   if((ret = dbp->associate(dbp, sdbp, callback, 0)) != 0) {
00274         ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to associate secondary index: %s", sub_database);
00275         return NULL;
00276   }
00277 
00278   return sdbp;
00279 }
00280 
00281 DB* icalbdbset_bdb_open(const char* path, 
00282                               const char *subdb, 
00283                             int dbtype, 
00284                             mode_t mode,
00285                             int flag)
00286 {
00287     DB  *dbp = NULL;
00288   int ret;
00289   int flags;
00290 
00291   /* Initialize the correct set of db subsystems (see capdb.c) */
00292   flags =  DB_CREATE | DB_THREAD;
00293 
00294   /* should just abort here instead of opening an env in the current dir..  */
00295   if (!ICAL_DB_ENV)
00296         icalbdbset_init_dbenv(NULL, NULL);
00297 
00298   /* Create and initialize database object, open the database. */
00299   if ((ret = db_create(&dbp, ICAL_DB_ENV, 0)) != 0) {
00300         return (NULL);
00301   }
00302 
00303   /* set comparison function, if BTREE */
00304   if (dbtype == DB_BTREE)
00305     dbp->set_bt_compare(dbp, _compare_keys);
00306 
00307   /* set DUP, DUPSORT */
00308   if (flag != 0)
00309     dbp->set_flags(dbp, flag);
00310 
00311   if ((ret = dbp->open(dbp, path, subdb, dbtype, flags, mode)) != 0) {
00312         ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "%s (database: %s): open failed.", path, subdb);
00313         if (ret == DB_RUNRECOVERY)
00314     abort();
00315         else
00316             return NULL;
00317   }
00318 
00319   return (dbp);
00320 }
00321 
00322     
00323 /* icalbdbset_parse_data -- parses using pfunc to unpack data. */
00324 char *icalbdbset_parse_data(DBT *dbt, char *(*pfunc)(const DBT *dbt)) 
00325 {
00326   char *ret;
00327 
00328   if(pfunc) {
00329     ret = (char *)pfunc(dbt);
00330   } else {
00331     ret = (char *) dbt->data;
00332   }
00333 
00334   return (ret);
00335 }
00336 
00337 /* This populates a cluster with the entire contents of a database */
00338 icalerrorenum icalbdbset_read_database(icalbdbset* bset, char *(*pfunc)(const DBT *dbt))
00339 {
00340 
00341   DB *dbp;
00342   DBC *dbcp;
00343   DBT key, data;
00344   char *str, *szpstr;
00345   int ret;
00346   char keystore[256];
00347   char datastore[1024];
00348   char *more_mem = NULL;
00349   DB_TXN *tid;
00350 
00351   memset(&key, 0, sizeof(DBT));
00352   memset(&data, 0, sizeof(DBT));
00353 
00354   if (bset->sdbp) { dbp = bset->sdbp; }
00355   else { dbp = bset->dbp; }
00356      
00357   if(!dbp) { goto err1; }
00358 
00359   bset->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT);
00360 
00361   if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
00362        char *foo = db_strerror(ret);
00363        abort();
00364   }
00365 
00366   /* acquire a cursor for the database */
00367   if ((ret = dbp->cursor(dbp, tid, &dbcp, 0)) != 0) {
00368     dbp->err(dbp, ret, "primary index");
00369     goto err1;
00370   }
00371 
00372   key.flags = DB_DBT_USERMEM;
00373   key.data = keystore;
00374   key.ulen = sizeof(keystore);
00375 
00376   data.flags= DB_DBT_USERMEM;
00377   data.data = datastore;
00378   data.ulen = sizeof(datastore);
00379 
00380 
00381   /* fetch the key/data pair */
00382   while (1) {
00383     ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
00384     if (ret == DB_NOTFOUND) {
00385       break;
00386     } else if (ret == ENOMEM) {
00387       if (more_mem) free (more_mem);
00388       more_mem = malloc(data.ulen+1024);
00389       data.data = more_mem;
00390       data.ulen = data.ulen+1024;
00391     } else if (ret == DB_LOCK_DEADLOCK) {
00392       char *foo = db_strerror(ret);
00393       abort(); /* should retry in case of DB_LOCK_DEADLOCK */
00394     } else if (ret) {
00395       char *foo = db_strerror(ret);
00396       /* some other weird-ass error  */
00397       dbp->err(dbp, ret, "cursor");
00398       abort();
00399     } else {
00400       icalcomponent *cl;
00401       
00402       /* this prevents an array read bounds error */
00403       if((str = (char *)calloc(data.size + 1, sizeof(char)))==NULL)
00404        goto err2;
00405       memcpy(str, (char *)data.data, data.size);
00406       
00407       cl = icalparser_parse_string(str);
00408       
00409       icalcomponent_add_component(bset->cluster, cl);
00410       free(str);
00411     }
00412   }
00413   if(ret != DB_NOTFOUND) {
00414       goto err2;
00415   }
00416 
00417 
00418   if (more_mem) {
00419       free(more_mem);
00420       more_mem = NULL;
00421   }
00422 
00423   if ((ret = dbcp->c_close(dbcp)) != 0) {
00424         char * foo = db_strerror(ret);
00425         abort(); /* should retry in case of DB_LOCK_DEADLOCK */
00426   }
00427 
00428     if ((ret = tid->commit(tid, 0)) != 0) {
00429         char * foo = db_strerror(ret);
00430         abort();
00431     }
00432 
00433   return ICAL_NO_ERROR;
00434 
00435  err2:
00436   if (more_mem) free(more_mem);
00437   dbcp->c_close(dbcp);
00438   abort(); /* should retry in case of DB_LOCK_DEADLOCK */
00439   return ICAL_INTERNAL_ERROR;
00440 
00441  err1:
00442   dbp->err(dbp, ret, "cursor index");
00443   abort();
00444   return (ICAL_FILE_ERROR);
00445 }
00446 
00447 
00448 /* XXX add more to this */
00449 void icalbdbset_free(icalset* set)
00450 {
00451     icalbdbset *bset = (icalbdbset*)set;
00452     int ret;
00453 
00454     icalerror_check_arg_rv((bset!=0),"bset");
00455 
00456     if (bset->cluster != 0){
00457        icalbdbset_commit(set);
00458        icalcomponent_free(bset->cluster);
00459        bset->cluster=0;
00460     }
00461 
00462     if(bset->gauge !=0){
00463        icalgauge_free(bset->gauge);
00464     }
00465 
00466     if(bset->path != 0){
00467        free((char *)bset->path);
00468        bset->path = 0;
00469     }
00470 
00471     if(bset->sindex != 0) {
00472       free((char *)bset->sindex);
00473       bset->sindex = 0;
00474     }
00475 
00476     if (bset->dbp && 
00477        ((ret = bset->dbp->close(bset->dbp, 0)) != 0)) {
00478     }
00479     bset->dbp = NULL;
00480 }
00481 
00482 /* return cursor is in rdbcp */
00483 int icalbdbset_acquire_cursor(DB *dbp, DB_TXN *tid, DBC **rdbcp) {
00484   int ret=0;
00485 
00486   if((ret = dbp->cursor(dbp, tid, rdbcp, 0)) != 0) {
00487     dbp->err(dbp, ret, "couldn't open cursor");
00488     goto err1;
00489   }
00490 
00491   return ICAL_NO_ERROR;
00492 
00493  err1:
00494   return ICAL_FILE_ERROR;
00495 
00496 }
00497 
00498 /* returns key/data in arguments */
00499 int icalbdbset_get_first(DBC *dbcp, DBT *key, DBT *data) {
00500   return icalbdbset_cget(dbcp, key, data, DB_FIRST);
00501 }
00502 
00503 int icalbdbset_get_next(DBC *dbcp, DBT *key, DBT *data) {
00504   return icalbdbset_cget(dbcp, key, data, DB_NEXT);
00505 }
00506 
00507 int icalbdbset_get_last(DBC *dbcp, DBT *key, DBT *data) {
00508   return icalbdbset_cget(dbcp, key, data, DB_LAST);
00509 }
00510 
00511 int icalbdbset_get_key(DBC *dbcp, DBT *key, DBT *data) {
00512   return icalbdbset_cget(dbcp, key, data, DB_SET);
00513 }
00514 
00515 int icalbdbset_delete(DB *dbp, DBT *key) {
00516   DB_TXN *tid;
00517   int ret;
00518     int done = 0;
00519     int retry = 0;
00520 
00521     while ((retry < MAX_RETRY) && !done) {
00522 
00523   if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
00524             if (ret == DB_LOCK_DEADLOCK) {
00525                 retry++;
00526                 continue;
00527             }
00528             else {
00529        char *foo = db_strerror(ret);
00530        abort();
00531   }
00532         }
00533 
00534         if ((ret = dbp->del(dbp, tid, key, 0)) != 0) {
00535             if (ret == DB_NOTFOUND) {
00536                 /* do nothing - not an error condition */
00537             }
00538             else if (ret == DB_LOCK_DEADLOCK) {
00539                 tid->abort(tid);
00540                 retry++;
00541                 continue;
00542             }
00543             else {
00544                 char *strError = db_strerror(ret);
00545                 icalerror_warn("icalbdbset_delete faild: ");
00546                 icalerror_warn(strError);
00547                 tid->abort(tid);
00548                 return ICAL_FILE_ERROR;
00549             }
00550   }
00551 
00552   if ((ret = tid->commit(tid, 0)) != 0) {
00553             if (ret == DB_LOCK_DEADLOCK) {
00554                 tid->abort(tid);
00555                 retry++;
00556                 continue;
00557             }
00558             else {
00559         char * foo = db_strerror(ret);
00560         abort();
00561   }
00562        }
00563 
00564        done = 1;   /* all is well */
00565     }
00566 
00567     if (!done) {
00568         if (tid != NULL) tid->abort(tid);
00569     }
00570 
00571   return ret;
00572 }
00573 
00574 int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, int access_method) {
00575   int ret=0;
00576 
00577   key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
00578   data->flags |= DB_DBT_MALLOC;
00579 
00580   /* fetch the key/data pair */
00581   if((ret = dbcp->c_get(dbcp, key, data, access_method)) != 0) {
00582     goto err1;
00583   }
00584 
00585   return ICAL_NO_ERROR;
00586 
00587  err1:
00588   return ICAL_FILE_ERROR;
00589 }
00590 
00591 
00592 int icalbdbset_cput(DBC *dbcp, DBT *key, DBT *data, int access_method) {
00593   int ret=0;
00594 
00595   key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
00596   data->flags |= DB_DBT_MALLOC;
00597 
00598   /* fetch the key/data pair */
00599   if((ret = dbcp->c_put(dbcp, key, data, 0)) != 0) {
00600     goto err1;
00601   }
00602 
00603   return ICAL_NO_ERROR;
00604 
00605  err1:
00606   return ICAL_FILE_ERROR;
00607 }
00608 
00609 
00610 int icalbdbset_put(DB *dbp, DBT *key, DBT *data, int access_method)
00611 {
00612     int     ret   = 0;
00613     DB_TXN *tid   = NULL;
00614     int     retry = 0;
00615     int     done  = 0;
00616 
00617     while ((retry < MAX_RETRY) && !done) {
00618 
00619   if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
00620             if (ret == DB_LOCK_DEADLOCK) {
00621                 retry++;
00622                 continue;
00623             }
00624             else {
00625        char *foo = db_strerror(ret);
00626        abort();
00627   }
00628         }
00629   
00630         if ((ret = dbp->put(dbp, tid, key, data, access_method)) != 0) {
00631             if (ret == DB_LOCK_DEADLOCK) {
00632                 tid->abort(tid);
00633                 retry++;
00634                 continue;
00635             }
00636             else {
00637     char *strError = db_strerror(ret);
00638     icalerror_warn("icalbdbset_put faild: ");
00639     icalerror_warn(strError);
00640     tid->abort(tid);
00641     return ICAL_FILE_ERROR;
00642   }
00643         }
00644 
00645   if ((ret = tid->commit(tid, 0)) != 0) {
00646             if (ret == DB_LOCK_DEADLOCK) {
00647                 tid->abort(tid);
00648                 retry++;
00649                 continue;
00650             }
00651             else {
00652         char * foo = db_strerror(ret);
00653         abort();
00654   }
00655        }
00656 
00657        done = 1;   /* all is well */
00658     }
00659 
00660     if (!done) {
00661         if (tid != NULL) tid->abort(tid);
00662         return ICAL_FILE_ERROR;
00663     }
00664     else
00665   return ICAL_NO_ERROR;
00666 }
00667 
00668 int icalbdbset_get(DB *dbp, DB_TXN *tid, DBT *key, DBT *data, int flags)
00669 {
00670     return (dbp->get(dbp, tid, key, data, flags));
00671 }
00672 
00675 const char* icalbdbset_path(icalset* set)
00676 {
00677     icalerror_check_arg_rz((set!=0),"set");
00678 
00679     return set->dsn;
00680 }
00681 
00682 const char* icalbdbset_subdb(icalset* set)
00683 {
00684     icalbdbset *bset = (icalbdbset*)set;
00685     icalerror_check_arg_rz((bset!=0),"bset");
00686 
00687     return bset->subdb;
00688 }
00689 
00690 
00694 icalerrorenum icalbdbset_commit(icalset *set) {
00695   DB *dbp;
00696   DBC *dbcp;
00697   DBT key, data;
00698   icalcomponent *c;
00699   char *str;
00700   int ret=0;
00701     int           reterr = ICAL_NO_ERROR;
00702   char keystore[256];
00703     char          uidbuf[256];
00704   char datastore[1024];
00705   char *more_mem = NULL;
00706     DB_TXN        *tid = NULL;
00707   icalbdbset *bset = (icalbdbset*)set;
00708   int bad_uid_counter = 0;
00709     int           retry = 0, done = 0, completed = 0, deadlocked = 0;
00710 
00711   icalerror_check_arg_re((bset!=0),"bset",ICAL_BADARG_ERROR);  
00712 
00713   dbp = bset->dbp;
00714   icalerror_check_arg_re((dbp!=0),"dbp is invalid",ICAL_BADARG_ERROR);
00715 
00716   if (bset->changed == 0)
00717     return ICAL_NO_ERROR;
00718 
00719   memset(&key, 0, sizeof(key));
00720   memset(&data, 0, sizeof(data));
00721 
00722   key.flags = DB_DBT_USERMEM; 
00723   key.data = keystore;
00724   key.ulen = sizeof(keystore);
00725 
00726   data.flags = DB_DBT_USERMEM;
00727   data.data = datastore;
00728   data.ulen = sizeof(datastore);
00729   
00730   if (!ICAL_DB_ENV)
00731         icalbdbset_init_dbenv(NULL, NULL);
00732 
00733     while ((retry < MAX_RETRY) && !done) {
00734 
00735   if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
00736             if (ret ==  DB_LOCK_DEADLOCK) {
00737                 retry++;
00738                 continue;
00739             }
00740             else if (ret == DB_RUNRECOVERY) {
00741                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit: txn_begin failed");
00742        abort();
00743   }
00744             else {
00745                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit");
00746                 return ICAL_INTERNAL_ERROR;
00747             }
00748         }
00749 
00750   /* first delete everything in the database, because there could be removed components */
00751   if ((ret = dbp->cursor(dbp, tid, &dbcp, DB_DIRTY_READ)) != 0) {
00752             tid->abort(tid);
00753             if (ret == DB_LOCK_DEADLOCK) {
00754                 retry++;
00755                 continue;
00756             }
00757             else if (ret == DB_RUNRECOVERY) {
00758                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
00759     abort();
00760             }
00761             else {
00762                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
00763     /* leave bset->changed set to true */
00764     return ICAL_INTERNAL_ERROR;
00765   }
00766         }
00767 
00768   /* fetch the key/data pair, then delete it */
00769         completed = 0;
00770         while (!completed && !deadlocked) {
00771     ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
00772     if (ret == DB_NOTFOUND) {
00773                 completed = 1;
00774     } else if (ret == ENOMEM)  {
00775       if (more_mem) free(more_mem);
00776       more_mem = malloc(data.ulen+1024);
00777       data.data = more_mem;
00778       data.ulen = data.ulen+1024;
00779     } else if (ret == DB_LOCK_DEADLOCK) {
00780                 deadlocked = 1;
00781             } else if (ret == DB_RUNRECOVERY) {
00782                 tid->abort(tid);
00783                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_get failed.");
00784       abort();
00785             } else if (ret == 0) {
00786        if ((ret = dbcp->c_del(dbcp,0))!=0) {
00787          dbp->err(dbp, ret, "cursor");
00788          if (ret == DB_KEYEMPTY) {
00789            /* never actually created, continue onward.. */
00790                         /* do nothing - break; */
00791          } else if (ret == DB_LOCK_DEADLOCK) {
00792                         deadlocked = 1;
00793          } else {
00794             char *foo = db_strerror(ret);
00795             abort();
00796          }
00797        }
00798             } else {  /* some other non-fatal error */
00799                 dbcp->c_close(dbcp);
00800                 tid->abort(tid);
00801                 if (more_mem) {
00802                     free(more_mem);
00803                     more_mem = NULL;
00804                 }
00805                 return ICAL_INTERNAL_ERROR;
00806     }
00807   }
00808 
00809   if (more_mem) {
00810          free(more_mem);
00811          more_mem = NULL;
00812   }
00813 
00814         if (deadlocked) {
00815             dbcp->c_close(dbcp);
00816             tid->abort(tid);
00817             retry++;
00818             continue;  /* next retry */
00819         }
00820 
00821         deadlocked = 0;
00822         for (c = icalcomponent_get_first_component(bset->cluster,ICAL_ANY_COMPONENT);
00823              c != 0 && !deadlocked;
00824       c = icalcomponent_get_next_component(bset->cluster,ICAL_ANY_COMPONENT)) {
00825 
00826             memset(&key, 0, sizeof(key));
00827             memset(&data, 0, sizeof(data));
00828 
00829     /* Note that we're always inserting into a primary index. */
00830     if (icalcomponent_isa(c) != ICAL_VAGENDA_COMPONENT)  {
00831       char *uidstr = (char *)icalcomponent_get_uid(c);
00832                 if (!uidstr) {   /* this shouldn't happen */
00833                     /* no uid string, we need to add one */
00834                     snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
00835                     key.data = uidbuf;
00836       } else {
00837                     key.data = uidstr;
00838       }
00839     } else {
00840       char *relcalid = NULL;
00841       relcalid = (char*)icalcomponent_get_relcalid(c);
00842       if (relcalid == NULL) {
00843                     snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
00844                     key.data = uidbuf;
00845       } else {
00846                     key.data = relcalid;
00847       }
00848     }
00849     key.size = strlen(key.data);
00850 
00851             str = icalcomponent_as_ical_string(c);
00852             data.data = str;
00853     data.size = strlen(str);
00854 
00855     if ((ret = dbcp->c_put(dbcp, &key, &data, DB_KEYLAST)) != 0) {
00856                 if (ret == DB_LOCK_DEADLOCK) {
00857                     deadlocked = 1;
00858                 }
00859                 else if (ret == DB_RUNRECOVERY) {
00860                     ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed.");
00861                     abort();
00862                 }
00863                 else {
00864                     ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed %s.", str);
00865                     /* continue to try to put as many icalcomponent as possible */
00866                     reterr = ICAL_INTERNAL_ERROR;
00867                 }
00868             }
00869     }
00870 
00871         if (deadlocked) {
00872             dbcp->c_close(dbcp);
00873             tid->abort(tid);
00874             retry++;
00875             continue;
00876   } 
00877 
00878   if ((ret = dbcp->c_close(dbcp)) != 0) {
00879             tid->abort(tid);
00880             if (ret == DB_LOCK_DEADLOCK) {
00881                 retry++;
00882                 continue;
00883             }
00884             else if (ret == DB_RUNRECOVERY) {
00885                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
00886                 abort();
00887             }
00888             else {
00889                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
00890                 reterr = ICAL_INTERNAL_ERROR;
00891             }
00892   }
00893 
00894   if ((ret = tid->commit(tid, 0)) != 0) {
00895             tid->abort(tid);
00896             if (ret == DB_LOCK_DEADLOCK) {
00897                 retry++;
00898                 continue;
00899             }
00900             else if (ret == DB_RUNRECOVERY) {
00901                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
00902     abort();
00903   }
00904             else {
00905                 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
00906                 reterr = ICAL_INTERNAL_ERROR;
00907             }
00908         }
00909 
00910         done = 1;
00911     }
00912 
00913   bset->changed = 0;    
00914     return reterr;
00915 } 
00916 
00917 
00918 void icalbdbset_mark(icalset* set)
00919 {
00920     icalbdbset *bset = (icalbdbset*)set;
00921     icalerror_check_arg_rv((bset!=0),"bset");
00922 
00923     bset->changed = 1;
00924 }
00925 
00926 
00927 icalcomponent* icalbdbset_get_component(icalset* set)
00928 {
00929     icalbdbset *bset = (icalbdbset*)set;
00930     icalerror_check_arg_rz((bset!=0),"bset");
00931 
00932     return bset->cluster;
00933 }
00934 
00935 
00936 /* manipulate the components in the cluster */
00937 
00938 icalerrorenum icalbdbset_add_component(icalset *set,
00939                                    icalcomponent* child)
00940 {
00941     icalbdbset *bset = (icalbdbset*)set;
00942     icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
00943     icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
00944 
00945     icalcomponent_add_component(bset->cluster,child);
00946 
00947     icalbdbset_mark(set);
00948 
00949     return ICAL_NO_ERROR;
00950 }
00951 
00952 
00953 icalerrorenum icalbdbset_remove_component(icalset *set,
00954                                       icalcomponent* child)
00955 {
00956     icalbdbset *bset = (icalbdbset*)set;
00957     icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
00958     icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR);
00959 
00960     icalcomponent_remove_component(bset->cluster,child);
00961 
00962     icalbdbset_mark(set);
00963 
00964     return ICAL_NO_ERROR;
00965 }
00966 
00967 
00968 int icalbdbset_count_components(icalset *set,
00969                              icalcomponent_kind kind)
00970 {
00971     icalbdbset *bset = (icalbdbset*)set;
00972 
00973     if(set == 0){
00974        icalerror_set_errno(ICAL_BADARG_ERROR);
00975        return -1;
00976     }
00977 
00978     return icalcomponent_count_components(bset->cluster,kind);
00979 }
00980 
00981 
00984 icalerrorenum icalbdbset_select(icalset* set, icalgauge* gauge)
00985 {
00986     icalbdbset *bset = (icalbdbset*)set;
00987     icalerror_check_arg_re((bset!=0),"bset", ICAL_BADARG_ERROR);
00988     icalerror_check_arg_re(gauge!=0,"gauge",ICAL_BADARG_ERROR);
00989 
00990     bset->gauge = gauge;
00991 
00992     return ICAL_NO_ERROR;
00993 }
00994 
00995     
00998 void icalbdbset_clear(icalset* set)
00999 {
01000   icalbdbset *bset = (icalbdbset*)set;
01001   icalerror_check_arg_rv((bset!=0),"bset");
01002     
01003   bset->gauge = 0;
01004 }
01005 
01006 
01007 icalcomponent* icalbdbset_fetch(icalset* set, icalcomponent_kind kind, const char* uid)
01008 {
01009     icalcompiter i;    
01010   icalbdbset *bset = (icalbdbset*)set;
01011   icalerror_check_arg_rz((bset!=0),"bset");
01012     
01013   for(i = icalcomponent_begin_component(bset->cluster, kind);
01014        icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
01015        
01016        icalcomponent *this = icalcompiter_deref(&i);
01017        icalproperty  *p = NULL;
01018        const char    *this_uid = NULL;
01019 
01020        if (this != 0){
01021            if (kind == ICAL_VAGENDA_COMPONENT) {
01022               p = icalcomponent_get_first_property(this,ICAL_RELCALID_PROPERTY);
01023               if (p != NULL) this_uid = icalproperty_get_relcalid(p);
01024            } else {
01025               p = icalcomponent_get_first_property(this,ICAL_UID_PROPERTY);
01026               if (p != NULL) this_uid = icalproperty_get_uid(p);
01027            }
01028 
01029            if(this_uid==NULL){
01030               icalerror_warn("icalbdbset_fetch found a component with no UID");
01031               continue;
01032            }
01033 
01034            if (strcmp(uid,this_uid)==0){
01035               return this;
01036            }
01037        }
01038     }
01039 
01040     return 0;
01041 }
01042 
01043 
01044 int icalbdbset_has_uid(icalset* store,const char* uid)
01045 {
01046     assert(0); /* HACK, not implemented */
01047     return 0;
01048 }
01049 
01050 
01051 /******* support routines for icalbdbset_fetch_match *********/
01052 
01053 struct icalbdbset_id {
01054     char* uid;
01055     char* recurrence_id;
01056     int sequence;
01057 };
01058 
01059 void icalbdbset_id_free(struct icalbdbset_id *id)
01060 {
01061     if(id->recurrence_id != 0){
01062        free(id->recurrence_id);
01063     }
01064 
01065     if(id->uid != 0){
01066        free(id->uid);
01067     }
01068 
01069 }
01070 
01071 struct icalbdbset_id icalbdbset_get_id(icalcomponent* comp)
01072 {
01073 
01074     icalcomponent *inner;
01075     struct icalbdbset_id id;
01076     icalproperty *p;
01077 
01078     inner = icalcomponent_get_first_real_component(comp);
01079     
01080     p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
01081 
01082     assert(p!= 0);
01083 
01084     id.uid = strdup(icalproperty_get_uid(p));
01085 
01086     p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
01087 
01088     if(p == 0) {
01089        id.sequence = 0;
01090     } else { 
01091        id.sequence = icalproperty_get_sequence(p);
01092     }
01093 
01094     p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
01095 
01096     if (p == 0){
01097        id.recurrence_id = 0;
01098     } else {
01099        icalvalue *v;
01100        v = icalproperty_get_value(p);
01101        id.recurrence_id = strdup(icalvalue_as_ical_string(v));
01102 
01103        assert(id.recurrence_id != 0);
01104     }
01105 
01106     return id;
01107 }
01108 
01109 /* Find the component that is related to the given
01110    component. Currently, it just matches based on UID and
01111    RECURRENCE-ID */
01112 
01113 icalcomponent* icalbdbset_fetch_match(icalset* set, icalcomponent *comp)
01114 {
01115     icalbdbset *bset = (icalbdbset*)set;
01116     icalcompiter i;    
01117     struct icalbdbset_id comp_id, match_id;
01118     
01119     icalerror_check_arg_rz((bset!=0),"bset");
01120     comp_id = icalbdbset_get_id(comp);
01121 
01122     for(i = icalcomponent_begin_component(bset->cluster,ICAL_ANY_COMPONENT);
01123        icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){
01124        
01125        icalcomponent *match = icalcompiter_deref(&i);
01126 
01127        match_id = icalbdbset_get_id(match);
01128 
01129        if(strcmp(comp_id.uid, match_id.uid) == 0 &&
01130           ( comp_id.recurrence_id ==0 || 
01131             strcmp(comp_id.recurrence_id, match_id.recurrence_id) ==0 )){
01132 
01133            /* HACK. What to do with SEQUENCE? */
01134 
01135            icalbdbset_id_free(&match_id);
01136            icalbdbset_id_free(&comp_id);
01137            return match;
01138            
01139        }
01140        
01141        icalbdbset_id_free(&match_id);
01142     }
01143 
01144     icalbdbset_id_free(&comp_id);
01145     return 0;
01146 
01147 }
01148 
01149 
01150 icalerrorenum icalbdbset_modify(icalset* set, icalcomponent *old,
01151                              icalcomponent *newc)
01152 {
01153     assert(0); /* HACK, not implemented */
01154     return ICAL_NO_ERROR;
01155 }
01156 
01157 /* caller is responsible to cal icalbdbset_free_cluster first */
01158 icalerrorenum  icalbdbset_set_cluster(icalset* set, icalcomponent* cluster)
01159 {
01160     icalbdbset *bset = (icalbdbset*)set;
01161     icalerror_check_arg_rz((bset!=0),"bset"); 
01162 
01163     bset->cluster = cluster;
01164 }
01165 
01166 icalerrorenum  icalbdbset_free_cluster(icalset* set)
01167 {
01168     icalbdbset *bset = (icalbdbset*)set;
01169     icalerror_check_arg_rz((bset!=0),"bset");
01170 
01171     if (bset->cluster != NULL) icalcomponent_free(bset->cluster);
01172 }
01173 
01174 icalcomponent* icalbdbset_get_cluster(icalset* set)
01175 {
01176     icalbdbset *bset = (icalbdbset*)set;
01177     icalerror_check_arg_rz((bset!=0),"bset");
01178 
01179     return (bset->cluster);
01180 }
01181 
01182 
01184 icalcomponent* icalbdbset_get_current_component (icalset* set)
01185 {
01186     icalbdbset *bset = (icalbdbset*)set;
01187 
01188     icalerror_check_arg_rz((bset!=0),"bset");
01189 
01190     return icalcomponent_get_current_component(bset->cluster);
01191 }
01192 
01193 
01194 icalcomponent* icalbdbset_get_first_component(icalset* set)
01195 {
01196     icalbdbset *bset = (icalbdbset*)set;
01197     icalcomponent *c=0;
01198 
01199     icalerror_check_arg_rz((bset!=0),"bset");
01200 
01201     do {
01202         if (c == 0)
01203            c = icalcomponent_get_first_component(bset->cluster,
01204                                             ICAL_ANY_COMPONENT);
01205         else
01206            c = icalcomponent_get_next_component(bset->cluster,
01207                                            ICAL_ANY_COMPONENT);
01208 
01209             if(c != 0 && (bset->gauge == 0 ||
01210                     icalgauge_compare(bset->gauge,c) == 1)){
01211            return c;
01212        }
01213 
01214       } while (c!=0);
01215 
01216     return 0;
01217 }
01218 
01219 
01220 icalsetiter icalbdbset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge, const char* tzid)
01221 {
01222     icalsetiter itr = icalsetiter_null;
01223     icalcomponent* comp = NULL;
01224     icalcompiter citr;
01225     icalbdbset *bset = (icalbdbset*) set;
01226     struct icaltimetype start, next, end;
01227     icalproperty *dtstart, *rrule, *prop, *due;
01228     struct icalrecurrencetype recur;
01229     icaltimezone *u_zone;
01230     int g = 0;
01231     int orig_time_was_utc = 0;
01232 
01233     icalerror_check_arg_re((set!=0), "set", icalsetiter_null);
01234 
01235     itr.gauge = gauge;
01236     itr.tzid = tzid;
01237 
01238     citr = icalcomponent_begin_component(bset->cluster, kind);
01239     comp = icalcompiter_deref(&citr);
01240 
01241     if (gauge == 0) {
01242         itr.iter = citr;
01243         return itr;
01244     }
01245 
01246     /* if there is a gauge, the first matched component is returned */
01247     while (comp != 0) {
01248 
01249         /* check if it is a recurring component and with guage expand, if so
01250          * we need to add recurrence-id property to the given component */
01251         rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
01252         g = icalgauge_get_expand(gauge);
01253 
01254         if (rrule != 0
01255             && g == 1) {
01256 
01257             /* it is a recurring event */
01258 
01259             u_zone = icaltimezone_get_builtin_timezone(itr.tzid);
01260 
01261            /* use UTC, if that's all we have. */
01262             if (!u_zone)
01263                 u_zone = icaltimezone_get_utc_timezone();
01264 
01265 
01266             recur = icalproperty_get_rrule(rrule);
01267 
01268             if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
01269                 dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
01270                 if (dtstart)
01271                     start = icalproperty_get_dtstart(dtstart);
01272             } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
01273                     due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
01274                     if (due)
01275                         start = icalproperty_get_due(due);
01276             }
01277 
01278             /* Convert to the user's timezone in order to be able to compare
01279              * the results from the rrule iterator. */
01280             if (icaltime_is_utc(start)) {
01281                start = icaltime_convert_to_zone(start, u_zone);
01282                 orig_time_was_utc = 1;
01283             }
01284 
01285             if (itr.last_component == NULL) {
01286                 itr.ritr = icalrecur_iterator_new(recur, start);
01287                 next = icalrecur_iterator_next(itr.ritr);
01288                 itr.last_component = comp;
01289             }
01290             else {
01291                 next = icalrecur_iterator_next(itr.ritr);
01292                 if (icaltime_is_null_time(next)){
01293                     itr.last_component = NULL;
01294                     icalrecur_iterator_free(itr.ritr);
01295                     itr.ritr = NULL;
01296                     /* no matched occurrence */
01297                     goto getNextComp;
01298                 } else {
01299                     itr.last_component = comp;
01300                 }
01301             }
01302 
01303             /* if it is excluded, do next one */
01304             if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
01305                icalrecur_iterator_decrement_count(itr.ritr);
01306                 continue;
01307             }
01308 
01309             /* add recurrence-id value to the property if the property already exist;
01310              * add the recurrence id property and the value if the property does not exist */
01311             prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
01312             if (prop == 0)
01313                 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
01314             else
01315                 icalproperty_set_recurrenceid(prop, next);
01316 
01317             /* convert the next recurrence time into the user's timezone */
01318             if (orig_time_was_utc) 
01319                 next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
01320 
01321         } /* end of a recurring event */
01322 
01323         if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
01324            /* find a matched and return it */
01325             itr.iter = citr;
01326             return itr;
01327         }
01328        
01329         /* if it is a recurring but no matched occurrence has been found OR
01330          * it is not a recurring and no matched component has been found,
01331          * read the next component to find out */
01332 getNextComp: 
01333         if ((rrule != NULL && itr.last_component == NULL) ||
01334            (rrule == NULL)) {
01335             comp =  icalcompiter_next(&citr);
01336             comp = icalcompiter_deref(&citr);
01337     }
01338     } /* while */
01339 
01340     /* no matched component has found */
01341     return icalsetiter_null;
01342 }
01343 
01344 icalcomponent* icalbdbset_form_a_matched_recurrence_component(icalsetiter* itr)
01345 {
01346     icalcomponent* comp = NULL;
01347     struct icaltimetype start, next, end;
01348     icalproperty *dtstart, *rrule, *prop, *due;
01349     struct icalrecurrencetype recur;
01350     icaltimezone *u_zone;
01351     int g = 0;
01352     int orig_time_was_utc = 0;
01353 
01354     comp = itr->last_component;
01355 
01356     if (comp == NULL || itr->gauge == NULL) {
01357         return NULL;
01358     }
01359 
01360 
01361     rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
01362     /* if there is no RRULE, simply return to the caller */
01363     if (rrule == NULL)
01364         return NULL;
01365 
01366     u_zone = icaltimezone_get_builtin_timezone(itr->tzid);
01367 
01368     /* use UTC, if that's all we have. */
01369     if (!u_zone)
01370         u_zone = icaltimezone_get_utc_timezone();
01371 
01372     recur = icalproperty_get_rrule(rrule);
01373 
01374     if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
01375         dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
01376         if (dtstart)
01377             start = icalproperty_get_dtstart(dtstart);
01378     } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
01379         due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
01380         if (due)
01381             start = icalproperty_get_due(due);
01382     }
01383 
01384     /* Convert to the user's timezone in order to be able to compare the results
01385      * from the rrule iterator. */
01386     if (icaltime_is_utc(start)) {
01387         start = icaltime_convert_to_zone(start, u_zone);
01388         orig_time_was_utc = 1;
01389     }
01390 
01391     if (itr->ritr == NULL) {
01392         itr->ritr = icalrecur_iterator_new(recur, start);
01393         next = icalrecur_iterator_next(itr->ritr);
01394         itr->last_component = comp;
01395     } else {
01396         next = icalrecur_iterator_next(itr->ritr);
01397         if (icaltime_is_null_time(next)){
01398             /* no more recurrence, returns */
01399             itr->last_component = NULL;
01400             icalrecur_iterator_free(itr->ritr);
01401             itr->ritr = NULL;
01402             /* no more pending matched occurrence,
01403              * all the pending matched occurrences have been returned */
01404             return NULL;
01405         } else {
01406             itr->last_component = comp;
01407         }
01408     }
01409 
01410     /* if it is excluded, return NULL to the caller */
01411     if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
01412         icalrecur_iterator_decrement_count(itr->ritr);
01413        return NULL; 
01414     }
01415 
01416     /* set recurrence-id value to the property if the property already exist;
01417      * add the recurrence id property and the value if the property does not exist */
01418     prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
01419     if (prop == 0)
01420         icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
01421     else
01422         icalproperty_set_recurrenceid(prop, next);
01423 
01424     if (orig_time_was_utc) {
01425         next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
01426     }
01427 
01428 
01429      if (itr->gauge == 0 || icalgauge_compare(itr->gauge, comp) == 1) {
01430          /* find a matched and return it */
01431          return comp;
01432      } 
01433 
01434      /* not matched */
01435      return NULL;
01436 
01437 }
01438 
01439 icalcomponent* icalbdbsetiter_to_next(icalset *set, icalsetiter* i)
01440 {
01441 
01442     icalcomponent* comp = NULL;
01443     icalbdbset *bset = (icalbdbset*) set;
01444     struct icaltimetype start, next, end;
01445     icalproperty *dtstart, *rrule, *prop, *due;
01446     struct icalrecurrencetype recur;
01447     icaltimezone *u_zone;
01448     int g = 0;
01449     int orig_time_was_utc = 0;
01450 
01451     do {
01452 
01453         /* no pending occurrence, read the next component */
01454         if (i->last_component == NULL) {
01455             comp = icalcompiter_next(&(i->iter));
01456         }
01457         else {
01458             comp = i->last_component;
01459         }
01460 
01461         /* no next component, simply return */
01462         if (comp == 0) return NULL;
01463         if (i->gauge == 0) return comp;
01464 
01465         /* finding the next matched component and return it to the caller */
01466 
01467         rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
01468         g = icalgauge_get_expand(i->gauge);
01469 
01470         /* a recurring component with expand query */
01471         if (rrule != 0
01472             && g == 1) {
01473 
01474             u_zone = icaltimezone_get_builtin_timezone(i->tzid);
01475 
01476             /* use UTC, if that's all we have. */
01477             if (!u_zone)
01478                 u_zone = icaltimezone_get_utc_timezone();
01479 
01480             recur = icalproperty_get_rrule(rrule);
01481 
01482             if (icalcomponent_isa(comp) == ICAL_VEVENT_COMPONENT) {
01483                 dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
01484                 if (dtstart)
01485                     start = icalproperty_get_dtstart(dtstart);
01486             } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
01487                 due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
01488                 if (due)
01489                     start = icalproperty_get_due(due);
01490             }
01491 
01492             /* Convert to the user's timezone in order to be able to compare
01493              * the results from the rrule iterator. */
01494             if (icaltime_is_utc(start)) {
01495                 start = icaltime_convert_to_zone(start, u_zone);
01496                 orig_time_was_utc = 1;
01497             }
01498 
01499             if (i->ritr == NULL) {
01500                 i->ritr = icalrecur_iterator_new(recur, start);
01501                 next = icalrecur_iterator_next(i->ritr);
01502                 i->last_component = comp;
01503             } else {
01504                 next = icalrecur_iterator_next(i->ritr);
01505                 if (icaltime_is_null_time(next)) {
01506                     i->last_component = NULL;
01507                     icalrecur_iterator_free(i->ritr);
01508                     i->ritr = NULL;
01509                     /* no more occurrence, should go to get next component */
01510                     continue;
01511                 } else {
01512                     i->last_component = comp;
01513                 }
01514             }
01515 
01516             /* if it is excluded, do next one */
01517             if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
01518                 icalrecur_iterator_decrement_count(i->ritr);
01519                 continue;
01520             }
01521 
01522             /* set recurrence-id value to the property if the property already exist;
01523              * add the recurrence id property and the value if the property does not exist */
01524             prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
01525             if (prop == 0)
01526                icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
01527             else
01528                icalproperty_set_recurrenceid(prop, next);
01529 
01530             if (orig_time_was_utc) {
01531                 next = icaltime_convert_to_zone(next, icaltimezone_get_utc_timezone());
01532             }
01533  
01534         } /* end of recurring event with expand query */
01535 
01536         if(comp != 0 && (i->gauge == 0 ||
01537             icalgauge_compare(i->gauge, comp) == 1)){
01538            /* found a matched, return it */ 
01539             return comp;
01540         }
01541     } while (comp != 0);
01542 
01543     return 0;
01544 
01545 }
01546 
01547 icalcomponent* icalbdbset_get_next_component(icalset* set)
01548 {
01549     icalbdbset *bset = (icalbdbset*)set;
01550     icalcomponent *c=0;
01551 
01552     struct icaltimetype start, next;
01553     icalproperty *dtstart, *rrule, *prop, *due;
01554     struct icalrecurrencetype recur;
01555     int g = 0;
01556 
01557     icalerror_check_arg_rz((bset!=0),"bset");
01558     
01559     do {
01560             c = icalcomponent_get_next_component(bset->cluster,
01561                                         ICAL_ANY_COMPONENT);
01562                 if(c != 0 && (bset->gauge == 0 ||
01563                     icalgauge_compare(bset->gauge,c) == 1)){
01564                     return c;
01565                 }
01566 
01567     } while(c != 0);
01568     
01569     return 0;
01570 }
01571 
01572 int icalbdbset_begin_transaction(DB_TXN* parent_tid, DB_TXN** tid)
01573 {
01574     return (ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, parent_tid, tid, 0));
01575 }
01576 
01577 int icalbdbset_commit_transaction(DB_TXN* txnid)
01578 {
01579     return (txnid->commit(txnid, 0));
01580 }
01581 
01582 
01583 static int _compare_keys(DB *dbp, const DBT *a, const DBT *b)
01584 {
01585 /* 
01586  * Returns: 
01587  * < 0 if a < b 
01588  * = 0 if a = b 
01589  * > 0 if a > b 
01590  */ 
01591        
01592     char*  ac = (char*)a->data;
01593     char*  bc = (char*)b->data;
01594     return (strncmp(ac, bc, a->size));
01595 }
01596 
01597 
01598