Libical API Documentation 4.0 UNRELEASED Go to the stable 3.0 documentation
Loading...
Searching...
No Matches
icalfileset.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalfileset.c
3 CREATOR: eric 23 December 1999
4
5 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7
8 The Original Code is eric. The Initial Developer of the Original
9 Code is Eric Busboom
10======================================================================*/
11//krazy:excludeall=cpp
12
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include "icalfileset.h"
24#include "icalfilesetimpl.h"
25#include "icalerror_p.h"
26#include "icalparser.h"
27#include "icalvalue.h"
28#include "icalmemory.h"
29
30#include <errno.h>
31#include <stdlib.h>
32
33#if defined(_MSC_VER)
34typedef int mode_t;
35#endif
36
37#if defined(_WIN32_WCE)
38#include <winbase.h>
39#endif
40
42icalfileset_options icalfileset_options_default = {O_RDWR | O_CREAT, 0644, 0, NULL};
43
44static int _compare_ids(const char *compid, const char *matchid);
45
46static int icalfileset_lock(icalfileset *set);
47static int icalfileset_unlock(icalfileset *set);
48static icalerrorenum icalfileset_read_file(icalfileset *set, int mode);
49static long icalfileset_filesize(icalfileset *set);
50
51icalset *icalfileset_new(const char *path)
52{
54}
55
56icalset *icalfileset_new_reader(const char *path)
57{
59
60 reader_options.flags = O_RDONLY;
61
62 return icalset_new(ICAL_FILE_SET, path, &reader_options);
63}
64
65icalset *icalfileset_new_writer(const char *path)
66{
68
69 writer_options.flags = O_RDONLY;
70
71 return icalset_new(ICAL_FILE_SET, path, &writer_options);
72}
73
74icalset *icalfileset_init(icalset *set, const char *path, void *options_in)
75{
76 const icalfileset_options *options = (options_in) ? options_in : &icalfileset_options_default;
77 icalfileset *fset = (icalfileset *)set;
78 int flags;
79 int mode;
80 long cluster_file_size;
81
83 icalerror_check_arg_rz((path != 0), "path");
84 icalerror_check_arg_rz((fset != 0), "fset");
85
86 fset->path = strdup(path);
87 fset->options = *options;
88
89 flags = options->flags;
90 mode = options->mode;
91
92 cluster_file_size = icalfileset_filesize(fset);
93
94 if (cluster_file_size < 0) {
95 icalfileset_free(set);
96 return 0;
97 }
98
99 fset->fd = open(fset->path, flags, (mode_t)mode);
100
101 if (fset->fd < 0) {
103 icalfileset_free(set);
104 return 0;
105 }
106
107 (void)icalfileset_lock(fset);
108
109 if (cluster_file_size > 0) {
110 if (icalfileset_read_file(fset, mode) != ICAL_NO_ERROR) {
111 icalfileset_free(set);
112 return 0;
113 }
114 }
115
116 if (options->cluster) {
117 fset->cluster = icalcomponent_clone(icalcluster_get_component(options->cluster));
118 fset->changed = 1;
119 }
120
121 if (fset->cluster == 0) {
123 }
124
125 return set;
126}
127
128icalcluster *icalfileset_produce_icalcluster(const char *path)
129{
130 icalset *fileset;
131 icalcluster *ret;
132
133 bool errstate = icalerror_get_errors_are_fatal();
134
136
137 fileset = icalfileset_new_reader(path);
138
139 if (fileset == 0 || icalerrno == ICAL_FILE_ERROR) {
140 /* file does not exist */
141 ret = icalcluster_new(path, NULL);
142 } else {
143 ret = icalcluster_new(path, ((icalfileset *)fileset)->cluster);
144 icalfileset_free(fileset);
145 }
146
149 return ret;
150}
151
152static char *icalfileset_read_from_file(char *s, size_t size, void *d)
153{
154 char *p;
155 icalfileset *set = d;
156
157 /* Simulate fgets -- read single characters and stop at '\n' */
158
159 for (p = s; p < s + size - 1; p++) {
160 if (read(set->fd, p, 1) != 1 || *p == '\n') {
161 p++;
162 break;
163 }
164 }
165
166 *p = '\0';
167
168 if (*s == 0) {
169 return 0;
170 } else {
171 return s;
172 }
173}
174
175icalerrorenum icalfileset_read_file(icalfileset *set, int mode)
176{
177 icalparser *parser;
178
179 _unused(mode);
180
181 parser = icalparser_new();
182
183 icalparser_set_gen_data(parser, set);
184 set->cluster = icalparser_parse(parser, icalfileset_read_from_file);
185 icalparser_free(parser);
186
187 if (set->cluster == 0 || icalerrno != ICAL_NO_ERROR) {
189 /*return ICAL_PARSE_ERROR; */
190 }
191
192 if (icalcomponent_isa(set->cluster) != ICAL_XROOT_COMPONENT) {
193 /* The parser got a single component, so it did not put it in
194 an XROOT. */
195 icalcomponent *cl = set->cluster;
196
198 icalcomponent_add_component(set->cluster, cl);
199 }
200
201 return ICAL_NO_ERROR;
202}
203
204long icalfileset_filesize(icalfileset *fset)
205{
206 struct stat sbuf;
207
208 if (!fset || !fset->path || fset->path[0] == '\0') {
209 return -1;
210 }
211
212 if (stat(fset->path, &sbuf) != 0) {
213 /* A file by the given name does not exist, or there was
214 another error */
215 if (errno == ENOENT) {
216 /* It was because the file does not exist */
217 return 0;
218 } else {
219 /* It was because of another error */
221 return -1;
222 }
223 } else {
224 /* A file by the given name exists, but is it a regular file? */
225
226 if (!S_ISREG(sbuf.st_mode)) {
227 /* Nope, not a regular file */
229 return -1;
230 } else {
231 /* Let's assume that it is a file of the right type */
232 return (long)sbuf.st_size;
233 }
234 }
235}
236
237void icalfileset_free(icalset *set)
238{
239 icalfileset *fset;
240
241 icalerror_check_arg_rv((set != 0), "set");
242
243 fset = (icalfileset *)set;
244
245 if (fset->cluster != 0) {
246 (void)icalfileset_commit(set);
247 icalcomponent_free(fset->cluster);
248 fset->cluster = 0;
249 }
250
251 if (fset->gauge != 0) {
252 icalgauge_free(fset->gauge);
253 fset->gauge = 0;
254 }
255
256 if (fset->fd > 0) {
257 (void)icalfileset_unlock(fset);
258 close(fset->fd);
259 fset->fd = -1;
260 }
261
262 if (fset->path != 0) {
263 free(fset->path);
264 fset->path = 0;
265 }
266}
267
268const char *icalfileset_path(icalset *set)
269{
270 icalerror_check_arg_rz((set != 0), "set");
271
272 return ((icalfileset *)set)->path;
273}
274
275int icalfileset_lock(icalfileset *set)
276{
277#if !defined(_WIN32)
278 struct flock lock;
279 int rtrn;
280
281 icalerror_check_arg_rz((set->fd > 0), "set->fd");
282 errno = 0;
283 lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
284 lock.l_start = 0; /* byte offset relative to l_whence */
285 lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
286 lock.l_len = 0; /* #bytes (0 means to EOF) */
287
288 rtrn = fcntl(set->fd, F_SETLKW, &lock);
289
290 return rtrn;
291#else
292 _unused(set);
293 return 0;
294#endif
295}
296
297int icalfileset_unlock(icalfileset *set)
298{
299#if !defined(_WIN32)
300 struct flock lock;
301
302 icalerror_check_arg_rz((set->fd > 0), "set->fd");
303
304 lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
305 lock.l_start = 0; /* byte offset relative to l_whence */
306 lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
307 lock.l_len = 0; /* #bytes (0 means to EOF) */
308
309 return (fcntl(set->fd, F_UNLCK, &lock));
310#else
311 _unused(set);
312 return 0;
313#endif
314}
315
316/* Lifted from https://stackoverflow.com/questions/29079011/copy-file-function-in-c */
317static int file_copy(const char *fileSource, const char *fileDestination)
318{
319 char c[1024]; // or any other constant you like
320 FILE *stream_R, *stream_W;
321
322 if ((stream_R = fopen(fileSource, "r")) == (FILE *)NULL) {
323 return -1;
324 }
325 if ((stream_W = fopen(fileDestination, "w")) == (FILE *)NULL) {
326 fclose(stream_R);
327 return -1;
328 }
329
330 while (!feof(stream_R) && !ferror(stream_R)) {
331 size_t bytes = fread(c, 1, sizeof(c), stream_R);
332 if (bytes) {
333 (void)fwrite(c, 1, bytes, stream_W);
334 }
335 }
336
337 //close streams
338 fclose(stream_R);
339 fclose(stream_W);
340
341 return 0;
342}
343
344icalerrorenum icalfileset_commit(icalset *set)
345{
346 char backupFile[MAXPATHLEN];
347 char *str;
348 icalcomponent *c;
349#if !defined(_WIN32)
350 size_t write_size = 0;
351#endif
352 icalfileset *fset = (icalfileset *)set;
353
354 icalerror_check_arg_re((fset != 0), "set", ICAL_BADARG_ERROR);
355
356 icalerror_check_arg_re((fset->fd > 0), "set->fd is invalid", ICAL_INTERNAL_ERROR);
357
358 if (fset->changed == 0) {
359 return ICAL_NO_ERROR;
360 }
361
362 if (fset->options.safe_saves == 1) {
363 strncpy(backupFile, fset->path, MAXPATHLEN - 4);
364 strncat(backupFile, ".bak", MAXPATHLEN - 1);
365 if (file_copy(fset->path, backupFile) != 0) {
367 return ICAL_FILE_ERROR;
368 }
369 }
370
371 if (lseek(fset->fd, 0, SEEK_SET) < 0) {
373 return ICAL_FILE_ERROR;
374 }
375
377 c != 0; c = icalcomponent_get_next_component(fset->cluster, ICAL_ANY_COMPONENT)) {
378 IO_SSIZE_T sz;
379
381
382 sz = write(fset->fd, str, (IO_SIZE_T)strlen(str));
383 if (sz != (IO_SSIZE_T)strlen(str)) {
384 perror("write");
387 return ICAL_FILE_ERROR;
388 }
389
391#if !defined(_WIN32)
392 write_size += (size_t)sz;
393#endif
394 }
395
396 fset->changed = 0;
397
398#if !defined(_WIN32)
399 if (ftruncate(fset->fd, (off_t)write_size) < 0) {
400 return ICAL_FILE_ERROR;
401 }
402#else
403#if !defined(_WIN32_WCE)
404 chsize(fset->fd, tell(fset->fd));
405#else
406 SetEndOfFile(fset->fd);
407#endif
408#endif
409
410 return ICAL_NO_ERROR;
411}
412
413void icalfileset_mark(icalset *set)
414{
415 icalerror_check_arg_rv((set != 0), "set");
416
417 ((icalfileset *)set)->changed = 1;
418}
419
420icalcomponent *icalfileset_get_component(icalset *set)
421{
422 const icalfileset *fset;
423
424 icalerror_check_arg_rz((set != 0), "set");
425
426 fset = (icalfileset *)set;
427 return fset->cluster;
428}
429
430/* manipulate the components in the set */
431
432icalerrorenum icalfileset_add_component(icalset *set, icalcomponent *child)
433{
434 icalfileset *fset;
435
436 icalerror_check_arg_re((set != 0), "set", ICAL_BADARG_ERROR);
437 icalerror_check_arg_re((child != 0), "child", ICAL_BADARG_ERROR);
438
439 fset = (icalfileset *)set;
440 icalcomponent_add_component(fset->cluster, child);
441
442 icalfileset_mark(set);
443
444 return ICAL_NO_ERROR;
445}
446
447icalerrorenum icalfileset_remove_component(icalset *set, icalcomponent *child)
448{
449 icalfileset *fset;
450
451 icalerror_check_arg_re((set != 0), "set", ICAL_BADARG_ERROR);
452 icalerror_check_arg_re((child != 0), "child", ICAL_BADARG_ERROR);
453
454 fset = (icalfileset *)set;
455 icalcomponent_remove_component(fset->cluster, child);
456
457 icalfileset_mark(set);
458
459 return ICAL_NO_ERROR;
460}
461
462int icalfileset_count_components(icalset *set, icalcomponent_kind kind)
463{
464 icalfileset *fset;
465
466 if (set == 0) {
468 return -1;
469 }
470
471 fset = (icalfileset *)set;
472 return icalcomponent_count_components(fset->cluster, kind);
473}
474
475icalerrorenum icalfileset_select(icalset *set, icalgauge *gauge)
476{
477 icalfileset *fset;
478
479 icalerror_check_arg_re(gauge != 0, "gauge", ICAL_BADARG_ERROR);
480
481 fset = (icalfileset *)set;
482 fset->gauge = gauge;
483
484 return ICAL_NO_ERROR;
485}
486
487void icalfileset_clear(icalset *set)
488{
489 icalfileset *fset;
490
491 icalerror_check_arg_rv(set != 0, "set");
492
493 fset = (icalfileset *)set;
494 fset->gauge = 0;
495}
496
497icalcomponent *icalfileset_fetch(icalset *set, icalcomponent_kind kind, const char *uid)
498{
499 icalfileset *fset;
500 icalcompiter i;
501
502 _unused(kind);
503
504 icalerror_check_arg_rz(set != 0, "set");
505 fset = (icalfileset *)set;
506
507 for (i = icalcomponent_begin_component(fset->cluster, ICAL_ANY_COMPONENT);
509 icalcomponent *this = icalcompiter_deref(&i);
510 icalcomponent *inner;
511
513 inner != 0; inner = icalcomponent_get_next_component(this, ICAL_ANY_COMPONENT)) {
514 icalproperty *p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
515 if (p) {
516 const char *this_uid = icalproperty_get_uid(p);
517
518 if (this_uid == 0) {
519 icalerror_warn("icalfileset_fetch found a component with no UID");
520 continue;
521 }
522
523 if (strcmp(uid, this_uid) == 0) {
524 return this;
525 }
526 }
527 }
528 }
529
530 return 0;
531}
532
533int icalfileset_has_uid(icalset *set, const char *uid)
534{
535 _unused(set);
536 _unused(uid);
537 assert(0); /* HACK, not implemented */
538 return 0;
539}
540
541/******* support routines for icalfileset_fetch_match *********/
542
543struct icalfileset_id {
544 char *uid;
545 char *recurrence_id;
546 int sequence;
547};
548
549static void icalfileset_id_free(struct icalfileset_id *id)
550{
551 if (id->recurrence_id != 0) {
552 free(id->recurrence_id);
553 }
554
555 if (id->uid != 0) {
556 free(id->uid);
557 }
558}
559
560static struct icalfileset_id icalfileset_get_id(const icalcomponent *comp)
561{
562 icalcomponent *inner;
563 struct icalfileset_id id;
564 icalproperty *p;
565
567
568 p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
569
570 assert(p != 0);
571
572 id.uid = strdup(icalproperty_get_uid(p));
573
574 p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
575
576 if (p == 0) {
577 id.sequence = 0;
578 } else {
579 id.sequence = icalproperty_get_sequence(p);
580 }
581
582 p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
583
584 if (p == 0) {
585 id.recurrence_id = NULL;
586 } else {
587 icalvalue *v;
588
590 id.recurrence_id = icalvalue_as_ical_string_r(v);
591
592 assert(id.recurrence_id != 0);
593 }
594
595 return id;
596}
597
598/* Find the component that is related to the given
599 component. Currently, it just matches based on UID and
600 RECURRENCE-ID */
601
602static int _compare_ids(const char *compid, const char *matchid)
603{
604 if (compid != NULL && matchid != NULL) {
605 if (strcmp(compid, matchid) == 0) {
606 return 1;
607 }
608 }
609
610 if (compid == NULL && matchid == NULL) {
611 return 1;
612 }
613
614 return 0;
615}
616
617icalcomponent *icalfileset_fetch_match(icalset *set, const icalcomponent *comp)
618{
619 icalfileset *fset = (icalfileset *)set;
620 icalcompiter i;
621
622 struct icalfileset_id comp_id, match_id;
623
624 comp_id = icalfileset_get_id(comp);
625
626 for (i = icalcomponent_begin_component(fset->cluster, ICAL_ANY_COMPONENT);
628 icalcomponent *match = icalcompiter_deref(&i);
629
630 match_id = icalfileset_get_id(match);
631
632 if (_compare_ids(comp_id.uid, match_id.uid) &&
633 _compare_ids(comp_id.recurrence_id, match_id.recurrence_id)) {
634 /* HACK. What to do with SEQUENCE? */
635
636 icalfileset_id_free(&match_id);
637 icalfileset_id_free(&comp_id);
638 return match;
639 }
640
641 icalfileset_id_free(&match_id);
642 }
643
644 icalfileset_id_free(&comp_id);
645 return 0;
646}
647
648icalerrorenum icalfileset_modify(icalset *set, icalcomponent *old, icalcomponent *new)
649{
650 _unused(set);
651 _unused(old);
652 _unused(new);
653 assert(0); /* HACK, not implemented */
654 return ICAL_NO_ERROR;
655}
656
657/* Iterate through components */
658icalcomponent *icalfileset_get_current_component(icalset *set)
659{
660 icalfileset *fset;
661
662 icalerror_check_arg_rz((set != 0), "set");
663
664 fset = (icalfileset *)set;
665 return icalcomponent_get_current_component(fset->cluster);
666}
667
668icalcomponent *icalfileset_get_first_component(icalset *set)
669{
670 icalcomponent *c = 0;
671 icalfileset *fset;
672
673 icalerror_check_arg_rz((set != 0), "set");
674 fset = (icalfileset *)set;
675
676 do {
677 if (c == 0) {
679 } else {
681 }
682
683 if (c != 0 && (fset->gauge == 0 || icalgauge_compare(fset->gauge, c) == 1)) {
684 return c;
685 }
686
687 } while (c != 0);
688
689 return 0;
690}
691
692icalcomponent *icalfileset_get_next_component(icalset *set)
693{
694 icalfileset *fset;
695 icalcomponent *c;
696
697 icalerror_check_arg_rz((set != 0), "set");
698 fset = (icalfileset *)set;
699
700 do {
702
703 if (c != 0 && (fset->gauge == 0 || icalgauge_compare(fset->gauge, c) == 1)) {
704 return c;
705 }
706
707 } while (c != 0);
708
709 return 0;
710}
711
712/*
713icalsetiter icalfileset_begin_component(icalset* set, icalcomponent_kind kind, icalgauge* gauge)
714{
715 icalsetiter itr = icalsetiter_null;
716 icalcomponent* comp = NULL;
717 icalcompiter citr;
718 icalfileset *fset = (icalfileset*)set;
719
720 icalerror_check_arg_re((set!=0), "set", icalsetiter_null);
721
722 itr.gauge = gauge;
723
724 citr = icalcomponent_begin_component(fset->cluster, kind);
725 comp = icalcompiter_deref(&citr);
726
727 while (comp != 0) {
728 comp = icalcompiter_deref(&citr);
729 if (gauge == 0 || icalgauge_compare(itr.gauge, comp) == 1) {
730 itr.iter = citr;
731 return itr;
732 }
733 comp = icalcompiter_next(&citr);
734 }
735
736 return icalsetiter_null;
737}
738
739*/
740
741icalsetiter icalfileset_begin_component(icalset *set, icalcomponent_kind kind, icalgauge *gauge,
742 const char *tzid)
743{
745 icalcomponent *comp = NULL;
746 icalcompiter citr;
747 icalfileset *fset;
748 struct icaltimetype start, next;
749 icalproperty *rrule;
750
751 _unused(tzid);
752
753 icalerror_check_arg_re((set != 0), "set", icalsetiter_null);
754
755 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
756 itr.gauge = gauge;
757
758 fset = (icalfileset *)set;
759 citr = icalcomponent_begin_component(fset->cluster, kind);
760 comp = icalcompiter_deref(&citr);
761
762 if (gauge == 0) {
763 itr.iter = citr;
764 return itr;
765 }
766
767 while (comp != 0) {
768 /* check if it is a recurring component and with gauge expand, if so
769 we need to add recurrence-id property to the given component */
770 rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
771 struct icalrecurrencetype *recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
772 int g = icalgauge_get_expand(gauge);
773 if (recur != 0 && g == 1) {
775 icalproperty *dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
776 if (dtstart) {
777 start = icalproperty_get_dtstart(dtstart);
778 }
779 } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
780 icalproperty *due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
781 if (due) {
782 start = icalproperty_get_due(due);
783 }
784 }
785
786 if (itr.last_component == NULL) {
787 itr.ritr = icalrecur_iterator_new(recur, start);
788 next = icalrecur_iterator_next(itr.ritr);
789 itr.last_component = comp;
790 } else {
791 next = icalrecur_iterator_next(itr.ritr);
792 if (icaltime_is_null_time(next)) {
793 itr.last_component = NULL;
794 icalrecur_iterator_free(itr.ritr);
795 itr.ritr = NULL;
796 return icalsetiter_null;
797 } else {
798 itr.last_component = comp;
799 }
800 }
801
802 /* add recurrence-id to the component
803 if there is a recurrence-id already, remove it, then add the new one */
804 icalproperty *prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
805 if (prop) {
807 }
808 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
809 }
810
811 if (icalgauge_compare(itr.gauge, comp) == 1) {
812 /* matches and returns */
813 itr.iter = citr;
814 return itr;
815 }
816
817 /* if there is no previous component pending, then get the next component */
818 if (itr.last_component == NULL) {
819 comp = icalcompiter_next(&citr);
820 }
821 }
822
823 return icalsetiter_null;
824}
825
826icalcomponent *icalfileset_form_a_matched_recurrence_component(icalsetiter *itr)
827{
828 icalcomponent *comp = NULL;
829 struct icaltimetype start, next;
830 icalproperty *rrule, *prop;
831 struct icalrecurrencetype *recur;
832
833 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
834 comp = itr->last_component;
835
836 if (comp == NULL || itr->gauge == NULL) {
837 return NULL;
838 }
839
840 rrule = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
841 recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
842
843 if (recur == NULL) {
844 return NULL;
845 }
846
848 icalproperty *dtstart = icalcomponent_get_first_property(comp, ICAL_DTSTART_PROPERTY);
849 if (dtstart) {
850 start = icalproperty_get_dtstart(dtstart);
851 }
852 } else if (icalcomponent_isa(comp) == ICAL_VTODO_COMPONENT) {
853 icalproperty *due = icalcomponent_get_first_property(comp, ICAL_DUE_PROPERTY);
854 if (due) {
855 start = icalproperty_get_due(due);
856 }
857 }
858
859 if (itr->ritr == NULL) {
860 itr->ritr = icalrecur_iterator_new(recur, start);
861 next = icalrecur_iterator_next(itr->ritr);
862 itr->last_component = comp;
863 } else {
864 next = icalrecur_iterator_next(itr->ritr);
865 if (icaltime_is_null_time(next)) {
866 /* no more recurrence, returns */
867 itr->last_component = NULL;
868 icalrecur_iterator_free(itr->ritr);
869 itr->ritr = NULL;
870 return NULL;
871 } else {
872 itr->last_component = comp;
873 }
874 }
875
876 /* add recurrence-id to the component
877 * if there is a recurrence-id already, remove it, then add the new one */
878 prop = icalcomponent_get_first_property(comp, ICAL_RECURRENCEID_PROPERTY);
879 if (prop) {
881 }
882 icalcomponent_add_property(comp, icalproperty_new_recurrenceid(next));
883
884 if (itr->gauge == 0 || icalgauge_compare(itr->gauge, comp) == 1) {
885 /* matches and returns */
886 return comp;
887 }
888 /* not matched */
889 return NULL;
890}
891
892icalcomponent *icalfilesetiter_to_next(icalset *set, icalsetiter *i)
893{
894 icalcomponent *c = NULL;
895 struct icaltimetype start, next;
896 icalproperty *dtstart, *rrule, *prop, *due;
897 struct icalrecurrencetype *recur;
898 int g = 0;
899
900 _unused(set);
901
902 start = icaltime_from_timet_with_zone(time(0), 0, NULL);
903 next = icaltime_from_timet_with_zone(time(0), 0, NULL);
904
905 do {
906 c = icalcompiter_next(&(i->iter));
907
908 if (c == 0) {
909 continue;
910 }
911 if (i->gauge == 0) {
912 return c;
913 }
914
915 rrule = icalcomponent_get_first_property(c, ICAL_RRULE_PROPERTY);
916 recur = rrule ? icalproperty_get_rrule(rrule) : NULL;
917 g = icalgauge_get_expand(i->gauge);
918
919 /* a recurring component with expand query */
920 if (recur != 0 && g == 1) {
922 dtstart = icalcomponent_get_first_property(c, ICAL_DTSTART_PROPERTY);
923 if (dtstart) {
924 start = icalproperty_get_dtstart(dtstart);
925 }
926 } else if (icalcomponent_isa(c) == ICAL_VTODO_COMPONENT) {
927 due = icalcomponent_get_first_property(c, ICAL_DUE_PROPERTY);
928 if (due) {
929 start = icalproperty_get_due(due);
930 }
931 }
932
933 if (i->ritr == NULL) {
934 i->ritr = icalrecur_iterator_new(recur, start);
935 next = icalrecur_iterator_next(i->ritr);
936 i->last_component = c;
937 } else {
938 next = icalrecur_iterator_next(i->ritr);
939 if (icaltime_is_null_time(next)) {
940 /* no more recurrence, returns */
941 i->last_component = NULL;
943 i->ritr = NULL;
944 return NULL;
945 } else {
946 i->last_component = c;
947 }
948 }
949 }
950
951 /* add recurrence-id to the component
952 * if there is a recurrence-id already, remove it, then add the new one */
953 prop = icalcomponent_get_first_property(c, ICAL_RECURRENCEID_PROPERTY);
954 if (prop) {
956 }
957 icalcomponent_add_property(c, icalproperty_new_recurrenceid(next));
958
959 if ((i->gauge == 0 || icalgauge_compare(i->gauge, c) == 1)) {
960 return c;
961 }
962 } while (true);
963
964 return 0;
965}
icalcluster * icalcluster_new(const char *key, icalcomponent *data)
Create a cluster with a key/value pair.
Definition icalcluster.c:39
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_property(icalcomponent *component, icalproperty *property)
void icalcomponent_remove_component(icalcomponent *parent, icalcomponent *child)
icalcomponent * icalcompiter_deref(icalcompiter *i)
icalcomponent * icalcomponent_new(icalcomponent_kind kind)
icalcomponent * icalcomponent_get_first_real_component(const icalcomponent *c)
icalcomponent * icalcomponent_clone(const icalcomponent *old)
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_ANY_COMPONENT
Definition icalenums.h:31
void icalerror_set_errors_are_fatal(bool fatal)
Change if errors are fatal.
Definition icalerror.c:31
bool icalerror_get_errors_are_fatal(void)
Determine if errors are fatal.
Definition icalerror.c:36
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
void icalerror_clear_errno(void)
Resets icalerrno to ICAL_NO_ERROR.
Definition icalerror.c:85
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
@ ICAL_PARSE_ERROR
Definition icalerror.h:59
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:130
icalerrorenum icalfileset_select(icalset *set, icalgauge *gauge)
icalerrorenum icalfileset_modify(icalset *set, icalcomponent *old, icalcomponent *new)
Modifies components according to the MODIFY method of CAP.
void icalfileset_clear(icalset *set)
Clears the gauge.
icalcomponent * icalfileset_get_component(icalset *set)
icalfileset_options icalfileset_options_default
Definition icalfileset.c:42
icalcomponent * icalfileset_fetch(icalset *set, icalcomponent_kind kind, const char *uid)
Gets and searches for a component by uid.
Manages a database of ical components and offers interfaces for reading, writing and searching for co...
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
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:353
Common memory management routines.
icalcomponent * icalparser_parse(icalparser *parser, icalparser_line_gen_func line_gen_func)
Message oriented parsing.
Definition icalparser.c:588
void icalparser_free(icalparser *parser)
Frees an icalparser object.
Definition icalparser.c:112
icalparser * icalparser_new(void)
Creates a new icalparser.
Definition icalparser.c:89
void icalparser_set_gen_data(icalparser *parser, void *data)
Sets the data that icalparser_parse will give to the line_gen_func as the parameter 'd'.
Definition icalparser.c:129
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_FILE_SET
Definition icalset.h:39
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_null_time(const struct icaltimetype t)
Definition icaltime.c:626
char * icalvalue_as_ical_string_r(const icalvalue *value)
Definition icalvalue.c:1220
Defines the data structure representing iCalendar parameter values.
Options for opening an icalfileset.
icalcluster * cluster