Libical API Documentation 4.0 UNRELEASED Go to the stable 3.0 documentation
Loading...
Searching...
No Matches
icalbdbset.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalbdbset.c
3
4 SPDX-FileCopyrightText: 2001, Critical Path
5 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
6======================================================================*/
7
14
15#ifdef HAVE_CONFIG_H
16#include <config.h>
17#endif
18
19#include "icalbdbset.h"
20#include "icalbdbsetimpl.h"
21
22#include "icalerror_p.h"
23#include "icalparser.h"
24#include "icaltimezone.h"
25#include "icalvalue.h"
26
27#include <errno.h>
28#include <stdlib.h>
29
30#define MAX_RETRY 5
31
32#if !defined(DB_VERSION_MAJOR)
33#define DB_VERSION_MAJOR 1 //assume ancient version
34#endif
35
36static int _compare_ids(const char *compid, const char *matchid);
37#if DB_VERSION_MAJOR > 5
38static int _compare_keys(DB *dbp, const DBT *a, const DBT *b, size_t *locp);
39#else
40static int _compare_keys(DB *dbp, const DBT *a, const DBT *b);
41#endif
42
44static icalbdbset_options icalbdbset_options_default =
45 {
46 ICALBDB_EVENTS, DB_BTREE, 0644, 0, NULL, NULL};
47
48static DB_ENV *ICAL_DB_ENV = 0;
49
51
52int icalbdbset_init_dbenv(char *db_env_dir,
53 void (*logDbFunc)(const DB_ENV *, const char *, const char *))
54{
55 int ret;
56 u_int32_t flags;
57
58 if (db_env_dir) {
59 struct stat env_dir_sb;
60
61 if (stat(db_env_dir, &env_dir_sb)) {
62 fprintf(stderr, "The directory '%s' is missing, please create it.\n", db_env_dir);
63 return EINVAL;
64 }
65 }
66
67 ret = db_env_create(&ICAL_DB_ENV, 0);
68
69 if (ret) {
70 /* some kind of error... */
71 return ret;
72 }
73
74 /* Do deadlock detection internally */
75 if ((ret = ICAL_DB_ENV->set_lk_detect(ICAL_DB_ENV, DB_LOCK_DEFAULT)) != 0) {
76 /*char *foo = db_strerror(ret); */
77 fprintf(stderr, "Could not initialize the database locking environment\n");
78 return ret;
79 }
80
81 flags = (u_int32_t)(DB_INIT_LOCK | DB_INIT_TXN | DB_CREATE | DB_THREAD |
82 DB_RECOVER | DB_INIT_LOG | DB_INIT_MPOOL);
83#if defined(_WIN32) //krazy:exclude=cpp
84 ret = ICAL_DB_ENV->open(ICAL_DB_ENV, db_env_dir, flags, 0 /*ignored on Windows*/);
85#else
86 ret = ICAL_DB_ENV->open(ICAL_DB_ENV, db_env_dir, flags, S_IRUSR | S_IWUSR);
87#endif
88
89 if (ret) {
90 /*char *foo = db_strerror(ret); */
91 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "dbenv->open");
92 return ret;
93 }
94
95 /* display additional error messages */
96 if (logDbFunc != NULL) {
97 ICAL_DB_ENV->set_errcall(ICAL_DB_ENV, logDbFunc);
98 }
99
100 return ret;
101}
102
103void icalbdbset_checkpoint(void)
104{
105 int ret;
106
107 switch (ret = ICAL_DB_ENV->txn_checkpoint(ICAL_DB_ENV, 0, 0, 0)) {
108 case 0:
109 break;
110 default:
111 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "checkpoint failed");
112 abort();
113 }
114}
115
116void icalbdbset_rmdbLog(void)
117{
118 char **listp;
119
120 /* remove log files that are can be archived (ie. no longer needed) */
121 if (ICAL_DB_ENV->log_archive(ICAL_DB_ENV, &listp, DB_ARCH_ABS) == 0) {
122 if (*listp != NULL) {
123 int ii = 0;
124
125 while (listp[ii] != NULL) {
126 (void)unlink(listp[ii]);
127 ii++;
128 }
129 free((void *)listp);
130 }
131 }
132}
133
134int icalbdbset_cleanup(void)
135{
136 int ret = 0;
137
138 /* one last checkpoint.. */
139 icalbdbset_checkpoint();
140
141 /* remove logs that are not needed anymore */
142 icalbdbset_rmdbLog();
143
144 if (ICAL_DB_ENV) {
145 ret = ICAL_DB_ENV->close(ICAL_DB_ENV, 0);
146 }
147
148 return ret;
149}
150
151DB_ENV *icalbdbset_get_env(void)
152{
153 return ICAL_DB_ENV;
154}
155
162
163/* This populates a cluster with the entire contents of a database */
164static icalerrorenum icalbdbset_read_database(icalbdbset *bset, char *(*pfunc)(const DBT *dbt))
165{
166 DB *dbp;
167 DBC *dbcp;
168 DBT key, data;
169 char *str;
170 int ret = EINVAL;
171 char keystore[256];
172 char datastore[1024];
173 char *more_mem = NULL;
174 DB_TXN *tid;
175
176 _unused(pfunc);
177
178 memset(&key, 0, sizeof(DBT));
179 memset(&data, 0, sizeof(DBT));
180
181 if (bset->sdbp) {
182 dbp = bset->sdbp;
183 } else {
184 dbp = bset->dbp;
185 }
186
187 if (!dbp) {
188 return ICAL_FILE_ERROR;
189 }
190
192
193 if (ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0) != 0) {
194 abort();
195 }
196
197 /* acquire a cursor for the database */
198 if ((ret = dbp->cursor(dbp, tid, &dbcp, 0)) != 0) {
199 dbp->err(dbp, ret, "primary index");
200 goto err1;
201 }
202
203 key.flags = DB_DBT_USERMEM;
204 key.data = keystore;
205 key.ulen = (u_int32_t)sizeof(keystore);
206
207 data.flags = DB_DBT_USERMEM;
208 data.data = datastore;
209 data.ulen = (u_int32_t)sizeof(datastore);
210
211 /* fetch the key/data pair */
212 while (1) {
213 ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
214 if (ret == DB_NOTFOUND) {
215 break;
216 } else if (ret == ENOMEM) {
217 if (more_mem) {
218 free(more_mem);
219 }
220 more_mem = malloc(data.ulen + 1024);
221 data.data = more_mem;
222 data.ulen = data.ulen + 1024;
223 } else if (ret == DB_LOCK_DEADLOCK) {
224 /*char *foo = db_strerror(ret); */
225 abort(); /* should retry in case of DB_LOCK_DEADLOCK */
226 } else if (ret) {
227 /*char *foo = db_strerror(ret); */
228 /* some other weird-ass error */
229 dbp->err(dbp, ret, "cursor");
230 abort();
231 } else {
232 icalcomponent *cl;
233
234 /* this prevents an array read bounds error */
235 if ((str = (char *)calloc(data.size + 1, sizeof(char))) == NULL) {
236 goto err2;
237 }
238 memcpy(str, (char *)data.data, data.size);
239
240 cl = icalparser_parse_string(str);
241
242 icalcomponent_add_component(bset->cluster, cl);
243 free(str);
244 }
245 }
246 if (ret != DB_NOTFOUND) {
247 goto err2;
248 }
249
250 if (more_mem) {
251 free(more_mem);
252 more_mem = NULL;
253 }
254
255 if (dbcp->c_close(dbcp) != 0) {
256 abort(); /* should retry in case of DB_LOCK_DEADLOCK */
257 }
258
259 if (tid->commit(tid, 0) != 0) {
260 abort();
261 }
262
263 return ICAL_NO_ERROR;
264
265err2:
266 if (more_mem) {
267 free(more_mem);
268 }
269 dbcp->c_close(dbcp);
270 abort(); /* should retry in case of DB_LOCK_DEADLOCK */
271 return ICAL_INTERNAL_ERROR;
272
273err1:
274 dbp->err(dbp, ret, "cursor index");
275 abort();
276 return ICAL_FILE_ERROR;
277}
278
279icalset *icalbdbset_init(icalset *set, const char *dsn, void *options_in)
280{
281 icalbdbset *bset = (icalbdbset *)set;
282 icalbdbset_options *options = (icalbdbset_options *)options_in;
283 DB *cal_db;
284 const char *subdb_name = NULL;
285
286 _unused(dsn);
287
288 if (options == (icalbdbset_options *)NULL) {
289 options = &icalbdbset_options_default;
290 }
291
292 switch (options->subdb) {
293 case ICALBDB_CALENDARS:
294 subdb_name = "calendars";
295 break;
296 case ICALBDB_EVENTS:
297 subdb_name = "events";
298 break;
299 case ICALBDB_TODOS:
300 subdb_name = "todos";
301 break;
302 case ICALBDB_REMINDERS:
303 subdb_name = "reminders";
304 break;
305 }
306
307 cal_db = icalbdbset_bdb_open(set->dsn,
308 subdb_name, options->dbtype, options->mode, options->flag);
309 if (cal_db == NULL) {
310 return NULL;
311 }
312
313 bset->dbp = cal_db;
314 bset->sdbp = NULL;
315 bset->gauge = 0;
316 bset->cluster = 0;
317
318 if (icalbdbset_read_database(bset, options->pfunc) != ICAL_NO_ERROR) {
319 return NULL;
320 }
321
322 return (icalset *)bset;
323}
324
329
330icalset *icalbdbset_new(const char *database_filename, icalbdbset_subdb_type subdb_type, int dbtype,
331 u_int32_t flag)
332{
333 icalbdbset_options options = icalbdbset_options_default;
334
335 options.subdb = subdb_type;
336 options.dbtype = dbtype;
337 options.flag = flag;
338
339 /* this will in turn call icalbdbset_init */
340 return icalset_new(ICAL_BDB_SET, database_filename, &options);
341}
342
349
350DB *icalbdbset_bdb_open_secondary(DB *dbp, const char *database, const char *sub_database,
351 int (*callback)(DB *db, const DBT *dbt1, const DBT *dbt2,
352 DBT *dbt3),
353 int type)
354{
355 int ret;
356 u_int32_t flags;
357 DB *sdbp = NULL;
358
359 if (!sub_database) {
360 return NULL;
361 }
362
363 if (!ICAL_DB_ENV) {
364 if (icalbdbset_init_dbenv(NULL, NULL) != 0) {
365 return NULL;
366 }
367 }
368
369 /* Open/create secondary */
370 if ((ret = db_create(&sdbp, ICAL_DB_ENV, 0)) != 0) {
371 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "secondary index: %s", sub_database);
372 return NULL;
373 }
374
375 if ((ret = sdbp->set_flags(sdbp, (u_int32_t)(DB_DUP | DB_DUPSORT))) != 0) {
376 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "set_flags error for secondary index: %s", sub_database);
377 return NULL;
378 }
379
380 flags = (u_int32_t)(DB_CREATE | DB_THREAD);
381 ret = sdbp->open(sdbp, NULL, database, sub_database, (DBTYPE)type, (u_int32_t)flags, 0644);
382 if (ret != 0) {
383 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to open secondary index: %s", sub_database);
384 if (ret == DB_RUNRECOVERY) {
385 abort();
386 } else {
387 return NULL;
388 }
389 }
390
391 /* Associate the primary index with a secondary */
392 if ((ret = dbp->associate(dbp, NULL, sdbp, callback, 0)) != 0) {
393 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "failed to associate secondary index: %s", sub_database);
394 return NULL;
395 }
396
397 return sdbp;
398}
399
400DB *icalbdbset_bdb_open(const char *path, const char *subdb, int dbtype, int mode, u_int32_t flag)
401{
402 DB *dbp = NULL;
403 int ret;
404 u_int32_t flags;
405
406 /* Initialize the correct set of db subsystems (see capdb.c) */
407 flags = (u_int32_t)(DB_CREATE | DB_THREAD);
408
409 /* should just abort here instead of opening an env in the current dir.. */
410 if (!ICAL_DB_ENV) {
411 if (icalbdbset_init_dbenv(NULL, NULL) != 0) {
412 return NULL;
413 }
414 }
415
416 /* Create and initialize database object, open the database. */
417 if (db_create(&dbp, ICAL_DB_ENV, 0) != 0) {
418 return NULL;
419 }
420
421 /* set comparison function, if BTREE */
422 if (dbtype == DB_BTREE) {
423 dbp->set_bt_compare(dbp, _compare_keys);
424 }
425
426 /* set DUP, DUPSORT */
427 if (flag != 0) {
428 dbp->set_flags(dbp, flag);
429 }
430
431 if ((ret = dbp->open(dbp, NULL, path, subdb, (DBTYPE)dbtype, flags, mode)) != 0) {
432 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "%s (database: %s): open failed.", path, subdb);
433 if (ret == DB_RUNRECOVERY) {
434 abort();
435 } else {
436 return NULL;
437 }
438 }
439
440 return dbp;
441}
442
443/* icalbdbset_parse_data -- parses using pfunc to unpack data. */
444char *icalbdbset_parse_data(DBT *dbt, char *(*pfunc)(const DBT *dbt))
445{
446 char *ret;
447
448 if (pfunc) {
449 ret = (char *)pfunc(dbt);
450 } else {
451 ret = (char *)dbt->data;
452 }
453
454 return ret;
455}
456
457/* XXX add more to this */
458void icalbdbset_free(icalset *set)
459{
460 icalbdbset *bset = (icalbdbset *)set;
461
462 icalerror_check_arg_rv((bset != 0), "bset");
463
464 if (bset->cluster != 0) {
465 (void)icalbdbset_commit(set);
466 icalcomponent_free(bset->cluster);
467 bset->cluster = 0;
468 }
469
470 if (bset->gauge != 0) {
471 icalgauge_free(bset->gauge);
472 }
473
474 if (bset->path != 0) {
475 free((char *)bset->path);
476 bset->path = 0;
477 }
478
479 if (bset->sindex != 0) {
480 free((char *)bset->sindex);
481 bset->sindex = 0;
482 }
483
484 if (bset->dbp && (bset->dbp->close(bset->dbp, 0) != 0)) {
485 /* ?? */
486 }
487 bset->dbp = NULL;
488}
489
490/* return cursor is in rdbcp */
491int icalbdbset_acquire_cursor(DB *dbp, DB_TXN *tid, DBC **rdbcp)
492{
493 int ret = 0;
494
495 if ((ret = dbp->cursor(dbp, tid, rdbcp, 0)) != 0) {
496 dbp->err(dbp, ret, "couldn't open cursor");
497 goto err1;
498 }
499
500 return ICAL_NO_ERROR;
501
502err1:
503 return ICAL_FILE_ERROR;
504}
505
506/* returns key/data in arguments */
507int icalbdbset_get_first(DBC *dbcp, DBT *key, DBT *data)
508{
509 return icalbdbset_cget(dbcp, key, data, DB_FIRST);
510}
511
512int icalbdbset_get_next(DBC *dbcp, DBT *key, DBT *data)
513{
514 return icalbdbset_cget(dbcp, key, data, DB_NEXT);
515}
516
517int icalbdbset_get_last(DBC *dbcp, DBT *key, DBT *data)
518{
519 return icalbdbset_cget(dbcp, key, data, DB_LAST);
520}
521
522int icalbdbset_get_key(DBC *dbcp, DBT *key, DBT *data)
523{
524 return icalbdbset_cget(dbcp, key, data, DB_SET);
525}
526
527int icalbdbset_delete(DB *dbp, DBT *key)
528{
529 DB_TXN *tid;
530 int ret = 0;
531 int done = 0;
532 int retry = 0;
533
534 while ((retry < MAX_RETRY) && !done) {
535 if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
536 if (ret == DB_LOCK_DEADLOCK) {
537 retry++;
538 continue;
539 } else {
540 /*char *foo = db_strerror(ret); */
541 abort();
542 }
543 }
544
545 if ((ret = dbp->del(dbp, tid, key, 0)) != 0) {
546 if (ret == DB_NOTFOUND) {
547 /* do nothing - not an error condition */
548 } else if (ret == DB_LOCK_DEADLOCK) {
549 tid->abort(tid);
550 retry++;
551 continue;
552 } else {
553 char *strError = db_strerror(ret);
554
555 icalerror_warn("icalbdbset_delete failed: ");
556 icalerror_warn(strError);
557 tid->abort(tid);
558 return ICAL_FILE_ERROR;
559 }
560 }
561
562 if ((ret = tid->commit(tid, 0)) != 0) {
563 if (ret == DB_LOCK_DEADLOCK) {
564 tid->abort(tid);
565 retry++;
566 continue;
567 } else {
568 /*char *foo = db_strerror(ret); */
569 abort();
570 }
571 }
572
573 done = 1; /* all is well */
574 }
575
576 if (!done) {
577 if (tid != NULL) {
578 tid->abort(tid);
579 }
580 }
581
582 return ret;
583}
584
585int icalbdbset_cget(DBC *dbcp, DBT *key, DBT *data, u_int32_t access_method)
586{
587 key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
588 data->flags |= DB_DBT_MALLOC;
589
590 /* fetch the key/data pair */
591 if (dbcp->c_get(dbcp, key, data, access_method) != 0) {
592 goto err1;
593 }
594
595 return ICAL_NO_ERROR;
596
597err1:
598 return ICAL_FILE_ERROR;
599}
600
601int icalbdbset_cput(DBC *dbcp, DBT *key, DBT *data, u_int32_t access_method)
602{
603 _unused(access_method);
604
605 key->flags |= DB_DBT_MALLOC; /* change these to DB_DBT_USERMEM */
606 data->flags |= DB_DBT_MALLOC;
607
608 /* fetch the key/data pair */
609 if (dbcp->c_put(dbcp, key, data, 0) != 0) {
610 goto err1;
611 }
612
613 return ICAL_NO_ERROR;
614
615err1:
616 return ICAL_FILE_ERROR;
617}
618
619int icalbdbset_put(DB *dbp, DBT *key, DBT *data, u_int32_t access_method)
620{
621 DB_TXN *tid = NULL;
622 int retry = 0;
623 int done = 0;
624
625 while ((retry < MAX_RETRY) && !done) {
626 int ret;
627 if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
628 if (ret == DB_LOCK_DEADLOCK) {
629 retry++;
630 continue;
631 } else {
632 /*char *foo = db_strerror(ret); */
633 abort();
634 }
635 }
636
637 if ((ret = dbp->put(dbp, tid, key, data, access_method)) != 0) {
638 if (ret == DB_LOCK_DEADLOCK) {
639 tid->abort(tid);
640 retry++;
641 continue;
642 } else {
643 char *strError = db_strerror(ret);
644
645 icalerror_warn("icalbdbset_put failed: ");
646 icalerror_warn(strError);
647 tid->abort(tid);
648 return ICAL_FILE_ERROR;
649 }
650 }
651
652 if ((ret = tid->commit(tid, 0)) != 0) {
653 if (ret == DB_LOCK_DEADLOCK) {
654 tid->abort(tid);
655 retry++;
656 continue;
657 } else {
658 /*char *foo = db_strerror(ret); */
659 abort();
660 }
661 }
662
663 done = 1; /* all is well */
664 }
665
666 if (!done) {
667 if (tid != NULL) {
668 tid->abort(tid);
669 }
670 return ICAL_FILE_ERROR;
671 } else {
672 return ICAL_NO_ERROR;
673 }
674}
675
676int icalbdbset_get(DB *dbp, DB_TXN *tid, DBT *key, DBT *data, u_int32_t flags)
677{
678 return dbp->get(dbp, tid, key, data, flags);
679}
680
682
683/* cppcheck-suppress constParameterPointer */
684const char *icalbdbset_path(icalset *set)
685{
686 icalerror_check_arg_rz((set != 0), "set");
687
688 return set->dsn;
689}
690
691const char *icalbdbset_subdb(icalset *set)
692{
693 const icalbdbset *bset = (icalbdbset *)set;
694
695 icalerror_check_arg_rz((bset != 0), "bset");
696
697 return bset->subdb;
698}
699
702
704{
705 DB *dbp;
706 DBC *dbcp;
707 DBT key, data;
708 icalcomponent *c;
709 char *str = NULL;
711 char keystore[256];
712 char uidbuf[256];
713 char datastore[1024];
714 char *more_mem = NULL;
715 DB_TXN *tid = NULL;
716 icalbdbset *bset = (icalbdbset *)set;
717 int bad_uid_counter = 0;
718 int retry = 0, done = 0, completed = 0, deadlocked = 0;
719
720 icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR);
721
722 dbp = bset->dbp;
723 icalerror_check_arg_re((dbp != 0), "dbp is invalid", ICAL_BADARG_ERROR);
724
725 if (bset->changed == 0) {
726 return ICAL_NO_ERROR;
727 }
728
729 memset(&key, 0, sizeof(key));
730 memset(&data, 0, sizeof(data));
731
732 key.flags = DB_DBT_USERMEM;
733 key.data = keystore;
734 key.ulen = (u_int32_t)sizeof(keystore);
735
736 data.flags = DB_DBT_USERMEM;
737 data.data = datastore;
738 data.ulen = (u_int32_t)sizeof(datastore);
739
740 if (!ICAL_DB_ENV) {
741 if (icalbdbset_init_dbenv(NULL, NULL) != 0) {
742 return ICAL_INTERNAL_ERROR;
743 }
744 }
745
746 while ((retry < MAX_RETRY) && !done) {
747 int ret;
748 if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) {
749 if (ret == DB_LOCK_DEADLOCK) {
750 retry++;
751 continue;
752 } else if (ret == DB_RUNRECOVERY) {
753 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit: txn_begin failed");
754 abort();
755 } else {
756 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit");
757 return ICAL_INTERNAL_ERROR;
758 }
759 }
760
761 /* first delete everything in the database, because there could be removed components */
762 if ((ret = dbp->cursor(dbp, tid, &dbcp, DB_DIRTY_READ)) != 0) {
763 tid->abort(tid);
764 if (ret == DB_LOCK_DEADLOCK) {
765 retry++;
766 continue;
767 } else if (ret == DB_RUNRECOVERY) {
768 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
769 abort();
770 } else {
771 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed");
772 /* leave bset->changed set to true */
773 return ICAL_INTERNAL_ERROR;
774 }
775 }
776
777 /* fetch the key/data pair, then delete it */
778 completed = 0;
779 while (!completed && !deadlocked) {
780 ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT);
781 if (ret == DB_NOTFOUND) {
782 completed = 1;
783 } else if (ret == ENOMEM) {
784 if (more_mem) {
785 free(more_mem);
786 }
787 more_mem = malloc(data.ulen + 1024);
788 data.data = more_mem;
789 data.ulen = data.ulen + 1024;
790 } else if (ret == DB_LOCK_DEADLOCK) {
791 deadlocked = 1;
792 } else if (ret == DB_RUNRECOVERY) {
793 tid->abort(tid);
794 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_get failed.");
795 abort();
796 } else if (ret == 0) {
797 if ((ret = dbcp->c_del(dbcp, 0)) != 0) {
798 dbp->err(dbp, ret, "cursor");
799 if (ret == DB_KEYEMPTY) {
800 /* never actually created, continue onward.. */
801 /* do nothing - break; */
802 } else if (ret == DB_LOCK_DEADLOCK) {
803 deadlocked = 1;
804 } else {
805 /*char *foo = db_strerror(ret); */
806 abort();
807 }
808 }
809 } else { /* some other non-fatal error */
810 dbcp->c_close(dbcp);
811 tid->abort(tid);
812 if (more_mem) {
813 free(more_mem);
814 more_mem = NULL;
815 }
816 return ICAL_INTERNAL_ERROR;
817 }
818 }
819
820 if (more_mem) {
821 free(more_mem);
822 more_mem = NULL;
823 }
824
825 if (deadlocked) {
826 dbcp->c_close(dbcp);
827 tid->abort(tid);
828 retry++;
829 continue; /* next retry */
830 }
831
832 deadlocked = 0;
834 c != 0 && !deadlocked;
836 memset(&key, 0, sizeof(key));
837 memset(&data, 0, sizeof(data));
838
839 /* Note that we're always inserting into a primary index. */
841 char *uidstr = (char *)icalcomponent_get_uid(c);
842
843 if (!uidstr) { /* this shouldn't happen */
844 /* no uid string, we need to add one */
845 snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
846 key.data = uidbuf;
847 } else {
848 key.data = uidstr;
849 }
850 } else {
851 char *relcalid = NULL;
852
853 relcalid = (char *)icalcomponent_get_relcalid(c);
854 if (relcalid == NULL) {
855 snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++);
856 key.data = uidbuf;
857 } else {
858 key.data = relcalid;
859 }
860 }
861 key.size = (u_int32_t)strlen(key.data);
862
864 data.data = str;
865 data.size = (u_int32_t)strlen(str);
866
867 if ((ret = dbcp->c_put(dbcp, &key, &data, DB_KEYLAST)) != 0) {
868 if (ret == DB_LOCK_DEADLOCK) {
869 deadlocked = 1;
870 } else if (ret == DB_RUNRECOVERY) {
871 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed.");
872 abort();
873 } else {
874 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed %s.", str);
875 /* continue to try to put as many icalcomponent as possible */
876 reterr = ICAL_INTERNAL_ERROR;
877 }
878 }
879 }
880
881 if (deadlocked) {
882 dbcp->c_close(dbcp);
883 tid->abort(tid);
884 retry++;
885 continue;
886 }
887
888 if ((ret = dbcp->c_close(dbcp)) != 0) {
889 tid->abort(tid);
890 if (ret == DB_LOCK_DEADLOCK) {
891 retry++;
892 continue;
893 } else if (ret == DB_RUNRECOVERY) {
894 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
895 abort();
896 } else {
897 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed.");
898 reterr = ICAL_INTERNAL_ERROR;
899 }
900 }
901
902 if ((ret = tid->commit(tid, 0)) != 0) {
903 tid->abort(tid);
904 if (ret == DB_LOCK_DEADLOCK) {
905 retry++;
906 continue;
907 } else if (ret == DB_RUNRECOVERY) {
908 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
909 abort();
910 } else {
911 ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed.");
912 reterr = ICAL_INTERNAL_ERROR;
913 }
914 }
915
916 done = 1;
917 }
918
919 bset->changed = 0;
920 return reterr;
921}
922
923void icalbdbset_mark(icalset *set)
924{
925 icalbdbset *bset = (icalbdbset *)set;
926
927 icalerror_check_arg_rv((bset != 0), "bset");
928
929 bset->changed = 1;
930}
931
932icalcomponent *icalbdbset_get_component(icalset *set)
933{
934 const icalbdbset *bset = (icalbdbset *)set;
935
936 icalerror_check_arg_rz((bset != 0), "bset");
937
938 return bset->cluster;
939}
940
941/* manipulate the components in the cluster */
942
943icalerrorenum icalbdbset_add_component(icalset *set, icalcomponent *child)
944{
945 icalbdbset *bset = (icalbdbset *)set;
946
947 icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR);
948 icalerror_check_arg_re((child != 0), "child", ICAL_BADARG_ERROR);
949
950 icalcomponent_add_component(bset->cluster, child);
951
952 icalbdbset_mark(set);
953
954 return ICAL_NO_ERROR;
955}
956
957icalerrorenum icalbdbset_remove_component(icalset *set, icalcomponent *child)
958{
959 icalbdbset *bset = (icalbdbset *)set;
960
961 icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR);
962 icalerror_check_arg_re((child != 0), "child", ICAL_BADARG_ERROR);
963
964 icalcomponent_remove_component(bset->cluster, child);
965
966 icalbdbset_mark(set);
967
968 return ICAL_NO_ERROR;
969}
970
971int icalbdbset_count_components(icalset *set, icalcomponent_kind kind)
972{
973 icalbdbset *bset;
974
975 if (set == 0) {
977 return -1;
978 }
979
980 bset = (icalbdbset *)set;
981 return icalcomponent_count_components(bset->cluster, kind);
982}
983
985
986icalerrorenum icalbdbset_select(icalset *set, icalgauge *gauge)
987{
988 icalbdbset *bset = (icalbdbset *)set;
989
990 icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR);
991 icalerror_check_arg_re(gauge != 0, "gauge", ICAL_BADARG_ERROR);
992
993 bset->gauge = gauge;
994
995 return ICAL_NO_ERROR;
996}
997
999
1000void icalbdbset_clear(icalset *set)
1001{
1002 icalbdbset *bset = (icalbdbset *)set;
1003
1004 icalerror_check_arg_rv((bset != 0), "bset");
1005
1006 bset->gauge = 0;
1007}
1008
1009icalcomponent *icalbdbset_fetch(icalset *set, icalcomponent_kind kind, const char *uid)
1010{
1011 icalcompiter i;
1012 icalbdbset *bset = (icalbdbset *)set;
1013
1014 icalerror_check_arg_rz((bset != 0), "bset");
1015
1016 for (i = icalcomponent_begin_component(bset->cluster, kind);
1017 icalcompiter_deref(&i) != 0; icalcompiter_next(&i)) {
1018 icalcomponent *this = icalcompiter_deref(&i);
1019
1020 if (this != 0) {
1021 const char *this_uid = NULL;
1022 if (kind == ICAL_VAGENDA_COMPONENT) {
1023 icalproperty *p = icalcomponent_get_first_property(this, ICAL_RELCALID_PROPERTY);
1024 if (p != NULL) {
1025 this_uid = icalproperty_get_relcalid(p);
1026 }
1027 } else {
1028 icalproperty *p = icalcomponent_get_first_property(this, ICAL_UID_PROPERTY);
1029 if (p != NULL) {
1030 this_uid = icalproperty_get_uid(p);
1031 }
1032 }
1033
1034 if (this_uid == NULL) {
1035 icalerror_warn("icalbdbset_fetch found a component with no UID");
1036 continue;
1037 }
1038
1039 if (strcmp(uid, this_uid) == 0) {
1040 return this;
1041 }
1042 }
1043 }
1044
1045 return 0;
1046}
1047
1048int icalbdbset_has_uid(icalset *set, const char *uid) // return an int for icalset_bdbset_init
1049{
1050 _unused(set);
1051 _unused(uid);
1052 assert(0); /* HACK, not implemented */
1053 return 0;
1054}
1055
1056/******* support routines for icalbdbset_fetch_match *********/
1057
1058struct icalbdbset_id {
1059 char *uid;
1060 char *recurrence_id;
1061 int sequence;
1062};
1063
1064static void icalbdbset_id_free(struct icalbdbset_id *id)
1065{
1066 if (id->recurrence_id != 0) {
1067 free(id->recurrence_id);
1068 }
1069
1070 if (id->uid != 0) {
1071 free(id->uid);
1072 }
1073}
1074
1075struct icalbdbset_id icalbdbset_get_id(const icalcomponent *comp)
1076{
1077 icalcomponent *inner;
1078 struct icalbdbset_id id;
1079 icalproperty *p;
1080
1082
1083 p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
1084
1085 assert(p != 0);
1086
1087 id.uid = strdup(icalproperty_get_uid(p));
1088
1089 p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
1090
1091 if (p == 0) {
1092 id.sequence = 0;
1093 } else {
1094 id.sequence = icalproperty_get_sequence(p);
1095 }
1096
1097 p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
1098
1099 if (p == 0) {
1100 id.recurrence_id = NULL;
1101 } else {
1102 icalvalue *v;
1103
1105 id.recurrence_id = icalvalue_as_ical_string_r(v);
1106
1107 assert(id.recurrence_id != 0);
1108 }
1109
1110 return id;
1111}
1112
1113/* Find the component that is related to the given
1114 component. Currently, it just matches based on UID and
1115 RECURRENCE-ID */
1116
1117static int _compare_ids(const char *compid, const char *matchid)
1118{
1119 if (compid != NULL && matchid != NULL) {
1120 if (strcmp(compid, matchid) == 0) {
1121 return 1;
1122 }
1123 }
1124
1125 if (compid == NULL && matchid == NULL) {
1126 return 1;
1127 }
1128
1129 return 0;
1130}
1131
1132icalcomponent *icalbdbset_fetch_match(icalset *set, const icalcomponent *comp)
1133{
1134 icalbdbset *bset = (icalbdbset *)set;
1135 icalcompiter i;
1136 struct icalbdbset_id comp_id, match_id;
1137
1138 icalerror_check_arg_rz((bset != 0), "bset");
1139 comp_id = icalbdbset_get_id(comp);
1140
1141 for (i = icalcomponent_begin_component(bset->cluster, ICAL_ANY_COMPONENT);
1142 icalcompiter_deref(&i) != 0; icalcompiter_next(&i)) {
1143 icalcomponent *match = icalcompiter_deref(&i);
1144
1145 match_id = icalbdbset_get_id(match);
1146
1147 if (_compare_ids(comp_id.uid, match_id.uid) &&
1148 _compare_ids(comp_id.recurrence_id, match_id.recurrence_id)) {
1149 /* HACK. What to do with SEQUENCE? */
1150
1151 icalbdbset_id_free(&match_id);
1152 icalbdbset_id_free(&comp_id);
1153 return match;
1154 }
1155
1156 icalbdbset_id_free(&match_id);
1157 }
1158
1159 icalbdbset_id_free(&comp_id);
1160 return 0;
1161}
1162
1163icalerrorenum icalbdbset_modify(icalset *set, icalcomponent *old, icalcomponent *newc)
1164{
1165 _unused(set);
1166 _unused(old);
1167 _unused(newc);
1168 assert(0); /* HACK, not implemented */
1169 return ICAL_NO_ERROR;
1170}
1171
1172/* caller is responsible to cal icalbdbset_free_cluster first */
1173icalerrorenum icalbdbset_set_cluster(icalset *set, icalcomponent *cluster)
1174{
1175 icalbdbset *bset = (icalbdbset *)set;
1176
1177 icalerror_check_arg_rz((bset != 0), "bset");
1178
1179 bset->cluster = cluster;
1180 return ICAL_NO_ERROR;
1181}
1182
1183icalerrorenum icalbdbset_free_cluster(icalset *set)
1184{
1185 icalbdbset *bset = (icalbdbset *)set;
1186
1187 icalerror_check_arg_rz((bset != 0), "bset");
1188
1189 if (bset->cluster != NULL) {
1190 icalcomponent_free(bset->cluster);
1191 }
1192 return ICAL_NO_ERROR;
1193}
1194
1195icalcomponent *icalbdbset_get_cluster(icalset *set)
1196{
1197 const icalbdbset *bset = (icalbdbset *)set;
1198
1199 icalerror_check_arg_rz((bset != 0), "bset");
1200
1201 return bset->cluster;
1202}
1203
1205icalcomponent *icalbdbset_get_current_component(icalset *set)
1206{
1207 icalbdbset *bset = (icalbdbset *)set;
1208
1209 icalerror_check_arg_rz((bset != 0), "bset");
1210
1211 return icalcomponent_get_current_component(bset->cluster);
1212}
1213
1214icalcomponent *icalbdbset_get_first_component(icalset *set)
1215{
1216 icalbdbset *bset = (icalbdbset *)set;
1217 icalcomponent *c = 0;
1218
1219 icalerror_check_arg_rz((bset != 0), "bset");
1220
1221 do {
1222 if (c == 0) {
1224 } else {
1226 }
1227
1228 if (c != 0 && (bset->gauge == 0 || icalgauge_compare(bset->gauge, c) == 1)) {
1229 return c;
1230 }
1231
1232 } while (c != 0);
1233
1234 return 0;
1235}
1236
1237icalsetiter icalbdbset_begin_component(icalset *set, icalcomponent_kind kind,
1238 icalgauge *gauge, const char *tzid)
1239{
1241 icalcomponent *comp = NULL;
1242 icalcompiter citr;
1243 icalbdbset *bset;
1244 struct icaltimetype start, next;
1245 icalproperty *dtstart, *rrule, *prop, *due;
1246 struct icalrecurrencetype *recur;
1247 icaltimezone *u_zone;
1248 int g;
1249 int orig_time_was_utc = 0;
1250
1251 icalerror_check_arg_re((set != 0), "set", icalsetiter_null);
1252 bset = (icalbdbset *)set;
1253
1254 itr.gauge = gauge;
1255 itr.tzid = tzid;
1256
1257 citr = icalcomponent_begin_component(bset->cluster, kind);
1258 comp = icalcompiter_deref(&citr);
1259
1260 if (gauge == 0) {
1261 itr.iter = citr;
1262 return itr;
1263 }
1264
1265 /* if there is a gauge, the first matched component is returned */
1266 while (comp != 0) {
1267 /* check if it is a recurring component and with gauge expand, if so
1268 * we need to add recurrence-id property to the given component */
1269 rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
1270 recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
1271 g = icalgauge_get_expand(gauge);
1272
1273 if (recur != 0 && g == 1) {
1274 /* it is a recurring event */
1275
1276 u_zone = icaltimezone_get_builtin_timezone(itr.tzid);
1277
1278 /* use UTC, if that's all we have. */
1279 if (!u_zone) {
1281 }
1282
1283 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
1284
1286 dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
1287 if (dtstart) {
1288 start = icalproperty_get_dtstart(dtstart);
1289 }
1290 } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
1291 due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
1292 if (due) {
1293 start = icalproperty_get_due(due);
1294 }
1295 }
1296
1297 /* Convert to the user's timezone in order to be able to compare
1298 * the results from the rrule iterator. */
1299 if (icaltime_is_utc(start)) {
1300 start = icaltime_convert_to_zone(start, u_zone);
1301 orig_time_was_utc = 1;
1302 }
1303
1304 if (itr.last_component == NULL) {
1305 itr.ritr = icalrecur_iterator_new(recur, start);
1306 next = icalrecur_iterator_next(itr.ritr);
1307 itr.last_component = comp;
1308 } else {
1309 next = icalrecur_iterator_next(itr.ritr);
1310 if (icaltime_is_null_time(next)) {
1311 itr.last_component = NULL;
1312 icalrecur_iterator_free(itr.ritr);
1313 itr.ritr = NULL;
1314 /* no matched occurrence */
1315 goto getNextComp;
1316 } else {
1317 itr.last_component = comp;
1318 }
1319 }
1320
1321 /* if it is excluded, do next one */
1322 if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
1323 next = icalrecur_iterator_next(itr.ritr);
1324 continue;
1325 }
1326
1327 /* add recurrence-id value to the property if the property already exist;
1328 * add the recurrence id property and the value if the property does not exist */
1329 prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
1330 if (prop == 0) {
1331 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
1332 } else {
1333 icalproperty_set_recurrenceid(prop, next);
1334 }
1335
1336 /* convert the next recurrence time into the user's timezone */
1337 if (orig_time_was_utc) {
1339 }
1340 }
1341 /* end of a recurring event */
1342 if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
1343 /* find a matched and return it */
1344 itr.iter = citr;
1345 return itr;
1346 }
1347
1348 /* if it is a recurring but no matched occurrence has been found OR
1349 * it is not a recurring and no matched component has been found,
1350 * read the next component to find out */
1351 getNextComp:
1352 if ((rrule != NULL && itr.last_component == NULL) || (rrule == NULL)) {
1353 (void)icalcompiter_next(&citr);
1354 comp = icalcompiter_deref(&citr);
1355 }
1356 } /* while */
1357
1358 /* no matched component has found */
1359 return icalsetiter_null;
1360}
1361
1362icalcomponent *icalbdbset_form_a_matched_recurrence_component(icalsetiter *itr)
1363{
1364 icalcomponent *comp = NULL;
1365 struct icaltimetype start, next;
1366 icalproperty *rrule, *prop;
1367 struct icalrecurrencetype *recur;
1368 icaltimezone *u_zone;
1369 int orig_time_was_utc = 0;
1370
1371 comp = itr->last_component;
1372
1373 if (comp == NULL || itr->gauge == NULL) {
1374 return NULL;
1375 }
1376
1377 rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
1378 recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
1379 /* if there is no RRULE, simply return to the caller */
1380 if (recur == NULL) {
1381 return NULL;
1382 }
1383
1384 u_zone = icaltimezone_get_builtin_timezone(itr->tzid);
1385
1386 /* use UTC, if that's all we have. */
1387 if (!u_zone) {
1389 }
1390
1391 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
1392
1394 icalproperty *dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
1395 if (dtstart) {
1396 start = icalproperty_get_dtstart(dtstart);
1397 }
1398 } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
1399 icalproperty *due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
1400 if (due) {
1401 start = icalproperty_get_due(due);
1402 }
1403 }
1404
1405 /* Convert to the user's timezone in order to be able to compare the results
1406 * from the rrule iterator. */
1407 if (icaltime_is_utc(start)) {
1408 start = icaltime_convert_to_zone(start, u_zone);
1409 orig_time_was_utc = 1;
1410 }
1411
1412 if (itr->ritr == NULL) {
1413 itr->ritr = icalrecur_iterator_new(recur, start);
1414 next = icalrecur_iterator_next(itr->ritr);
1415 itr->last_component = comp;
1416 } else {
1417 next = icalrecur_iterator_next(itr->ritr);
1418 if (icaltime_is_null_time(next)) {
1419 /* no more recurrence, returns */
1420 itr->last_component = NULL;
1421 icalrecur_iterator_free(itr->ritr);
1422 itr->ritr = NULL;
1423 /* no more pending matched occurrence,
1424 * all the pending matched occurrences have been returned */
1425 return NULL;
1426 } else {
1427 itr->last_component = comp;
1428 }
1429 }
1430
1431 /* if it is excluded, return NULL to the caller */
1432 if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
1433 (void)icalrecur_iterator_next(itr->ritr);
1434 return NULL;
1435 }
1436
1437 /* set recurrence-id value to the property if the property already exist;
1438 * add the recurrence id property and the value if the property does not exist */
1439 prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
1440 if (prop == 0) {
1441 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
1442 } else {
1443 icalproperty_set_recurrenceid(prop, next);
1444 }
1445
1446 if (orig_time_was_utc) {
1448 }
1449
1450 if (itr->gauge == 0 || icalgauge_compare(itr->gauge, comp) == 1) {
1451 /* find a matched and return it */
1452 return comp;
1453 }
1454
1455 /* not matched */
1456 return NULL;
1457}
1458
1459icalcomponent *icalbdbsetiter_to_next(icalset *set, icalsetiter *i)
1460{
1461 icalcomponent *comp = NULL;
1462 struct icaltimetype start, next;
1463 icalproperty *rrule, *prop;
1464 int orig_time_was_utc = 0;
1465
1466 _unused(set);
1467
1468 do {
1469 /* no pending occurrence, read the next component */
1470 if (i->last_component == NULL) {
1471 comp = icalcompiter_next(&(i->iter));
1472 } else {
1473 comp = i->last_component;
1474 }
1475
1476 /* no next component, simply return */
1477 if (comp == 0) {
1478 return NULL;
1479 }
1480
1481 if (i->gauge == 0) {
1482 return comp;
1483 }
1484
1485 /* finding the next matched component and return it to the caller */
1486
1487 rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
1488 struct icalrecurrencetype *recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
1489 int g = icalgauge_get_expand(i->gauge);
1490
1491 /* a recurring component with expand query */
1492 if (recur != 0 && g == 1) {
1494
1495 /* use UTC, if that's all we have. */
1496 if (!u_zone) {
1498 }
1499
1500 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
1501
1503 icalproperty *dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
1504 if (dtstart) {
1505 start = icalproperty_get_dtstart(dtstart);
1506 }
1507 } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
1508 icalproperty *due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
1509 if (due) {
1510 start = icalproperty_get_due(due);
1511 }
1512 }
1513
1514 /* Convert to the user's timezone in order to be able to compare
1515 * the results from the rrule iterator. */
1516 if (icaltime_is_utc(start)) {
1517 start = icaltime_convert_to_zone(start, u_zone);
1518 orig_time_was_utc = 1;
1519 }
1520
1521 if (i->ritr == NULL) {
1522 i->ritr = icalrecur_iterator_new(recur, start);
1523 next = icalrecur_iterator_next(i->ritr);
1524 i->last_component = comp;
1525 } else {
1526 next = icalrecur_iterator_next(i->ritr);
1527 if (icaltime_is_null_time(next)) {
1528 i->last_component = NULL;
1529 icalrecur_iterator_free(i->ritr);
1530 i->ritr = NULL;
1531 /* no more occurrence, should go to get next component */
1532 continue;
1533 } else {
1534 i->last_component = comp;
1535 }
1536 }
1537
1538 /* if it is excluded, do next one */
1539 if (icalproperty_recurrence_is_excluded(comp, &start, &next)) {
1540 next = icalrecur_iterator_next(i->ritr);
1541 continue;
1542 }
1543
1544 /* set recurrence-id value to the property if the property already exist;
1545 * add the recurrence id property and the value if the property does not exist */
1546 prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
1547 if (prop == 0) {
1548 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
1549 } else {
1550 icalproperty_set_recurrenceid(prop, next);
1551 }
1552
1553 if (orig_time_was_utc) {
1555 }
1556 }
1557 /* end of recurring event with expand query */
1558 if ((i->gauge == 0 || icalgauge_compare(i->gauge, comp) == 1)) {
1559 /* found a matched, return it */
1560 return comp;
1561 }
1562 } while (comp != 0);
1563
1564 /* coverity[dead_error_line] */
1565 return NULL; /*unreachable */
1566}
1567
1568icalcomponent *icalbdbset_get_next_component(icalset *set)
1569{
1570 icalbdbset *bset = (icalbdbset *)set;
1571 icalcomponent *c = 0;
1572
1573 icalerror_check_arg_rz((bset != 0), "bset");
1574
1575 do {
1577 if (c != 0 && (bset->gauge == 0 || icalgauge_compare(bset->gauge, c) == 1)) {
1578 return c;
1579 }
1580
1581 } while (c != 0);
1582
1583 return 0;
1584}
1585
1586int icalbdbset_begin_transaction(DB_TXN *parent_id, DB_TXN **txnid)
1587{
1588 return ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, parent_id, txnid, 0);
1589}
1590
1591int icalbdbset_commit_transaction(DB_TXN *txnid)
1592{
1593 return txnid->commit(txnid, 0);
1594}
1595
1596#if DB_VERSION_MAJOR > 5
1597static int _compare_keys(DB *dbp, const DBT *a, const DBT *b, size_t *locp)
1598#else
1599static int _compare_keys(DB *dbp, const DBT *a, const DBT *b)
1600#endif
1601{
1602#if DB_VERSION_MAJOR > 5
1603 _unused(locp);
1604#endif
1605 /*
1606 * Returns:
1607 * < 0 if a < b
1608 * = 0 if a = b
1609 * > 0 if a > b
1610 */
1611
1612 const char *ac = a->data;
1613 const char *bc = b->data;
1614
1615 _unused(dbp);
1616 return strncmp(ac, bc, a->size);
1617}
icalerrorenum icalbdbset_select(icalset *set, icalgauge *gauge)
Definition icalbdbset.c:986
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)
Definition icalbdbset.c:350
void icalbdbset_clear(icalset *set)
int icalbdbset_init_dbenv(char *db_env_dir, void(*logDbFunc)(const DB_ENV *, const char *, const char *))
Definition icalbdbset.c:52
const char * icalbdbset_path(icalset *set)
Definition icalbdbset.c:684
icalcomponent * icalbdbset_get_current_component(icalset *set)
icalset * icalbdbset_new(const char *database_filename, icalbdbset_subdb_type subdb_type, int dbtype, u_int32_t flag)
Definition icalbdbset.c:330
icalerrorenum icalbdbset_commit(icalset *set)
Definition icalbdbset.c:703
Manages a Berkeley database of ical components and offers interfaces for reading, writing and searchi...
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)
icalcomponent * icalcompiter_next(icalcompiter *i)
icalcomponent * icalcomponent_get_next_component(icalcomponent *c, icalcomponent_kind kind)
icalcomponent * icalcomponent_get_first_component(icalcomponent *c, icalcomponent_kind kind)
icalcomponent * icalcomponent_get_current_component(icalcomponent *component)
void icalcomponent_remove_component(icalcomponent *parent, icalcomponent *child)
icalcomponent * icalcompiter_deref(icalcompiter *i)
icalcomponent * icalcomponent_new(icalcomponent_kind kind)
const char * icalcomponent_get_relcalid(icalcomponent *comp)
icalcomponent * icalcomponent_get_first_real_component(const icalcomponent *c)
bool icalproperty_recurrence_is_excluded(icalcomponent *comp, struct icaltimetype *dtstart, struct icaltimetype *recurtime)
Decides if a recurrence is acceptable.
const char * icalcomponent_get_uid(icalcomponent *comp)
void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
icalcompiter icalcomponent_begin_component(icalcomponent *component, icalcomponent_kind kind)
char * icalcomponent_as_ical_string_r(const icalcomponent *component)
icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
void icalcomponent_free(icalcomponent *c)
void icalcomponent_add_component(icalcomponent *parent, icalcomponent *child)
int icalcomponent_count_components(icalcomponent *component, icalcomponent_kind kind)
icalcomponent_kind
Definition icalenums.h:29
@ ICAL_XROOT_COMPONENT
Definition icalenums.h:32
@ ICAL_VTODO_COMPONENT
Definition icalenums.h:35
@ ICAL_VEVENT_COMPONENT
Definition icalenums.h:34
@ ICAL_VAGENDA_COMPONENT
Definition icalenums.h:38
@ ICAL_ANY_COMPONENT
Definition icalenums.h:31
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
icalerrorenum
Represents the different types of errors that can be triggered in libical.
Definition icalerror.h:42
@ ICAL_BADARG_ERROR
Definition icalerror.h:47
@ ICAL_FILE_ERROR
Definition icalerror.h:65
@ ICAL_INTERNAL_ERROR
Definition icalerror.h:62
@ ICAL_NO_ERROR
Definition icalerror.h:44
bool icalgauge_compare(icalgauge *gauge, icalcomponent *comp)
Definition icalgauge.c:216
void icalgauge_free(icalgauge *gauge)
Definition icalgauge.c:72
int icalgauge_get_expand(const icalgauge *gauge)
Definition icalgauge.c:66
icalcomponent * icalparser_parse_string(const char *str)
Parses a string and returns the parsed icalcomponent.
Line-oriented parsing.
icalvalue * icalproperty_get_value(const icalproperty *prop)
void icalrecur_iterator_free(icalrecur_iterator *impl)
Definition icalrecur.c:2408
icalrecur_iterator * icalrecur_iterator_new(struct icalrecurrencetype *rule, struct icaltimetype dtstart)
Definition icalrecur.c:2280
struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *impl)
Definition icalrecur.c:3651
icalsetiter icalsetiter_null
Definition icalset.c:413
icalset * icalset_new(icalset_kind kind, const char *dsn, void *options)
Definition icalset.c:193
@ ICAL_BDB_SET
Definition icalset.h:41
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition icaltime.c:209
bool icaltime_is_utc(const struct icaltimetype t)
Definition icaltime.c:621
struct icaltimetype icaltime_convert_to_zone(const struct icaltimetype tt, icaltimezone *zone)
Definition icaltime.c:855
bool icaltime_is_null_time(const struct icaltimetype t)
Definition icaltime.c:626
icaltimezone * icaltimezone_get_builtin_timezone(const char *location)
icaltimezone * icaltimezone_get_utc_timezone(void)
Timezone handling routines.
struct _icaltimezone icaltimezone
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition icalvalue.c:1220
Defines the data structure representing iCalendar parameter values.