Libical API Documentation 4.0 UNRELEASED Go to the stable 3.0 documentation
Loading...
Searching...
No Matches
icaldirset.c
Go to the documentation of this file.
1/*
2======================================================================
3 FILE: icaldirset.c
4 CREATOR: eric 28 November 1999
5
6 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
7 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
8
9 The Original Code is eric. The Initial Developer of the Original
10 Code is Eric Busboom
11 ======================================================================*/
12
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include "icaldirset.h"
24#include "icaldirsetimpl.h"
25#include "icalerror_p.h"
26#include "icalfileset.h"
27#include "icalpvl_p.h"
28
29#include <stdio.h>
30#include <stdlib.h>
31
32#if defined(HAVE_DIRENT_H)
33#include <dirent.h>
34#endif
35
36#if defined(HAVE_SYS_UTSNAME_H)
37#include <sys/utsname.h>
38#endif
39
41static icaldirset_options icaldirset_options_default = {O_RDWR | O_CREAT};
42
43const char *icaldirset_path(icalset *set)
44{
45 const icaldirset *dset = (icaldirset *)set;
46
47 return dset->dir;
48}
49
50void icaldirset_mark(icalset *set)
51{
52 icaldirset *dset = (icaldirset *)set;
53
54 icalcluster_mark(dset->cluster);
55}
56
57icalerrorenum icaldirset_commit(icalset *set)
58{
59 icaldirset *dset = (icaldirset *)set;
60 icalset *fileset;
62
63 options.cluster = dset->cluster;
64
65 fileset = icalset_new(ICAL_FILE_SET, icalcluster_key(dset->cluster), &options);
66
67 (void)fileset->commit(fileset);
68 fileset->free(fileset);
69
70 return ICAL_NO_ERROR;
71}
72
73static void icaldirset_lock(const char *dir)
74{
75 _unused(dir);
76}
77
78static void icaldirset_unlock(const char *dir)
79{
80 _unused(dir);
81}
82
83/* Load the contents of the store directory into the store's internal directory list*/
84static icalerrorenum icaldirset_read_directory(icaldirset *dset)
85{
86 char *str;
87
88#if defined(HAVE_DIRENT_H)
89 const struct dirent *de;
90 DIR *dp;
91
92 dp = opendir(dset->dir);
93
94 if (dp == 0) {
96 return ICAL_FILE_ERROR;
97 }
98
99 /* clear contents of directory list */
100 while ((str = icalpvl_pop(dset->directory))) {
101 free(str);
102 }
103
104 /* load all of the cluster names in the directory list */
105 for (de = readdir(dp); de != 0; de = readdir(dp)) {
106 /* Remove known directory names '.' and '..' */
107 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) {
108 continue;
109 }
110
111 icalpvl_push(dset->directory, (void *)strdup(de->d_name));
112 }
113
114 closedir(dp);
115#else
116 struct _finddata_t c_file;
117 intptr_t hFile;
118
119 /* Find first .c file in current directory */
120 if ((hFile = _findfirst("*", &c_file)) == -1L) {
122 return ICAL_FILE_ERROR;
123 } else {
124 while ((str = icalpvl_pop(dset->directory))) {
125 free(str);
126 }
127
128 /* load all of the cluster names in the directory list */
129 do {
130 /* Remove known directory names '.' and '..' */
131 if (strcmp(c_file.name, ".") == 0 || strcmp(c_file.name, "..") == 0) {
132 continue;
133 }
134
135 icalpvl_push(dset->directory, (void *)strdup(c_file.name));
136 } while (_findnext(hFile, &c_file) == 0);
137
138 _findclose(hFile);
139 }
140
141#endif
142
143 return ICAL_NO_ERROR;
144}
145
146/* cppcheck-suppress constParameterPointer */
147icalset *icaldirset_init(icalset *set, const char *dir, void *options_in)
148{
149 icaldirset *dset;
150 const icaldirset_options *options = options_in;
151 struct stat sbuf;
152
153 icalerror_check_arg_rz((dir != 0), "dir");
154 icalerror_check_arg_rz((set != 0), "set");
155 dset = (icaldirset *)set;
156
157 if (stat(dir, &sbuf) != 0) {
159 return 0;
160 }
161
162 /* dir is not the name of a direectory */
163 if (!S_ISDIR(sbuf.st_mode)) {
165 return 0;
166 }
167
168 icaldirset_lock(dir);
169
170 dset->dir = (char *)strdup(dir);
171 dset->options = *options;
172 dset->directory = icalpvl_newlist();
173 dset->directory_iterator = 0;
174 dset->gauge = 0;
175 dset->first_component = 0;
176 dset->cluster = 0;
177
178 return set;
179}
180
181icalset *icaldirset_new(const char *dir)
182{
183 return icalset_new(ICAL_DIR_SET, dir, &icaldirset_options_default);
184}
185
186icalset *icaldirset_new_reader(const char *dir)
187{
188 icaldirset_options reader_options = icaldirset_options_default;
189
190 reader_options.flags = O_RDONLY;
191
192 return icalset_new(ICAL_DIR_SET, dir, &reader_options);
193}
194
195icalset *icaldirset_new_writer(const char *dir)
196{
197 icaldirset_options writer_options = icaldirset_options_default;
198
199 writer_options.flags = O_RDWR | O_CREAT;
200
201 return icalset_new(ICAL_DIR_SET, dir, &writer_options);
202}
203
204void icaldirset_free(icalset *s)
205{
206 icaldirset *dset = (icaldirset *)s;
207 char *str;
208
209 icaldirset_unlock(dset->dir);
210
211 if (dset->dir != 0) {
212 free(dset->dir);
213 dset->dir = 0;
214 }
215
216 if (dset->gauge != 0) {
217 icalgauge_free(dset->gauge);
218 dset->gauge = 0;
219 }
220
221 if (dset->cluster != 0) {
222 icalcluster_free(dset->cluster);
223 }
224
225 while (dset->directory != 0 && (str = icalpvl_pop(dset->directory)) != 0) {
226 free(str);
227 }
228
229 if (dset->directory != 0) {
230 icalpvl_free(dset->directory);
231 dset->directory = 0;
232 }
233
234 dset->directory_iterator = 0;
235 dset->first_component = 0;
236}
237
238static icalerrorenum icaldirset_next_cluster(icaldirset *dset)
239{
240 char path[MAXPATHLEN];
241
242 if (dset->directory_iterator == 0) {
244 return ICAL_INTERNAL_ERROR;
245 }
246 dset->directory_iterator = icalpvl_next(dset->directory_iterator);
247
248 if (dset->directory_iterator == 0) {
249 /* There are no more clusters */
250 if (dset->cluster != 0) {
251 icalcluster_free(dset->cluster);
252 dset->cluster = 0;
253 }
254 return ICAL_NO_ERROR;
255 }
256
257 snprintf(path, sizeof(path), "%s/%s", dset->dir, (char *)icalpvl_data(dset->directory_iterator));
258
259 icalcluster_free(dset->cluster);
260 dset->cluster = icalfileset_produce_icalcluster(path);
261
262 return icalerrno;
263}
264
265static void icaldirset_add_uid(icalcomponent *comp)
266{
267 char uidstring[MAXPATHLEN] = {0};
268 icalproperty *uid;
269
270#if defined(HAVE_SYS_UTSNAME_H)
271 struct utsname unamebuf;
272#endif
273
274 icalerror_check_arg_rv((comp != 0), "comp");
275
276 uid = icalcomponent_get_first_property(comp, ICAL_UID_PROPERTY);
277
278 if (uid == 0) {
279#if defined(HAVE_SYS_UTSNAME_H)
280 uname(&unamebuf);
281 snprintf(uidstring, sizeof(uidstring), "%d-%s", (int)getpid(), unamebuf.nodename);
282#else
283 /* FIXME: There must be an easy get the system name */
284 snprintf(uidstring, sizeof(uidstring), "%d-%s", (int)getpid(), "WINDOWS");
285#endif
286 uid = icalproperty_new_uid(uidstring);
288 } else {
289 strncpy(uidstring, icalproperty_get_uid(uid), MAXPATHLEN - 1);
290 }
291}
292
293icalerrorenum icaldirset_add_component(icalset *set, icalcomponent *comp)
294{
295 char clustername[MAXPATHLEN] = {0};
296 icalproperty *dt = 0;
297 icalvalue *v;
298 struct icaltimetype tm;
300 icalcomponent *inner;
301 icaldirset *dset;
302
303 icalerror_check_arg_rz((set != 0), "set");
304 icalerror_check_arg_rz((comp != 0), "comp");
305
306 dset = (icaldirset *)set;
307
308 icaldirset_add_uid(comp);
309
310 /* Determine which cluster this object belongs in. This is a HACK */
311
313 inner != 0; inner = icalcomponent_get_next_component(comp, ICAL_ANY_COMPONENT)) {
314 dt = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY);
315
316 if (dt != 0) {
317 break;
318 }
319 }
320
321 if (dt == 0) {
323 inner != 0; inner = icalcomponent_get_next_component(comp, ICAL_ANY_COMPONENT)) {
324 dt = icalcomponent_get_first_property(inner, ICAL_DTSTART_PROPERTY);
325
326 if (dt != 0) {
327 break;
328 }
329 }
330 }
331
332 if (dt == 0) {
333 icalerror_warn("The component does not have a DTSTAMP or DTSTART property, "
334 "so it cannot be added to the store");
336 return ICAL_BADARG_ERROR;
337 }
338
340 tm = icalvalue_get_datetime(v);
341
342 snprintf(clustername, MAXPATHLEN, "%s/%04d%02d", dset->dir, tm.year, tm.month);
343
344 /* Load the cluster and insert the object */
345 if (dset->cluster != 0 && strcmp(clustername, icalcluster_key(dset->cluster)) != 0) {
346 icalcluster_free(dset->cluster);
347 dset->cluster = 0;
348 }
349
350 if (dset->cluster == 0) {
351 dset->cluster = icalfileset_produce_icalcluster(clustername);
352
353 if (dset->cluster == 0) {
354 error = icalerrno;
355 }
356 }
357
358 if (error != ICAL_NO_ERROR) {
359 icalerror_set_errno(error);
360 return error;
361 }
362
363 /* Add the component to the cluster */
364 (void)icalcluster_add_component(dset->cluster, comp);
365
366 /* icalcluster_mark(cluster->cluster); */
367
368 return ICAL_NO_ERROR;
369}
370
371icalerrorenum icaldirset_remove_component(icalset *set, icalcomponent *comp)
372{
373 icaldirset *dset;
374 icalcomponent *filecomp;
375 icalcompiter i;
376 int found = 0;
377
378 icalerror_check_arg_re((set != 0), "set", ICAL_BADARG_ERROR);
379 icalerror_check_arg_re((comp != 0), "comp", ICAL_BADARG_ERROR);
380
381 dset = (icaldirset *)set;
382 icalerror_check_arg_re((dset->cluster != 0), "Cluster pointer", ICAL_USAGE_ERROR);
383
384 filecomp = icalcluster_get_component(dset->cluster);
385
388 const icalcomponent *this = icalcompiter_deref(&i);
389 if (this == comp) {
390 found = 1;
391 break;
392 }
393 }
394
395 if (found != 1) {
396 icalerror_warn("icaldirset_remove_component: component is not part of current cluster");
398 return ICAL_USAGE_ERROR;
399 }
400
401 (void)icalcluster_remove_component(dset->cluster, comp);
402
403 /* icalcluster_mark(cluster->cluster); */
404
405 /* If the removal emptied the fileset, get the next fileset */
406 if (icalcluster_count_components(dset->cluster, ICAL_ANY_COMPONENT) == 0) {
407 icalerrorenum error = icaldirset_next_cluster(dset);
408
409 if (dset->cluster != 0 && error == ICAL_NO_ERROR) {
410 (void)icalcluster_get_first_component(dset->cluster);
411 } else {
412 /* HACK. Not strictly correct for cluster->cluster==0 */
413 return error;
414 }
415 } else {
416 /* Do nothing */
417 }
418
419 return ICAL_NO_ERROR;
420}
421
422int icaldirset_count_components(icalset *store, icalcomponent_kind kind)
423{
424 _unused(store);
425 _unused(kind);
426
427 /* NOT IMPLEMENTED */
428 assert(0);
429
430 return 0;
431}
432
433icalcomponent *icaldirset_fetch_match(icalset *set, const icalcomponent *c)
434{
435 _unused(set);
436 _unused(c);
437
438 fprintf(stderr, " icaldirset_fetch_match is not implemented\n");
439 assert(0);
440 return 0;
441}
442
443icalcomponent *icaldirset_fetch(icalset *set, icalcomponent_kind kind, const char *uid)
444{
445 icaldirset *dset;
446 icalgauge *gauge;
447 icalgauge *old_gauge;
448 icalcomponent *c;
449 char sql[256];
450
451 _unused(kind);
452
453 icalerror_check_arg_rz((set != 0), "set");
454 icalerror_check_arg_rz((uid != 0), "uid");
455
456 snprintf(sql, 256, "SELECT * FROM VEVENT WHERE UID = \"%s\"", uid);
457
458 gauge = icalgauge_new_from_sql(sql, 0);
459 dset = (icaldirset *)set;
460 old_gauge = dset->gauge;
461 dset->gauge = gauge;
462
463 c = icaldirset_get_first_component(set);
464
465 dset->gauge = old_gauge;
466
467 if (gauge) {
468 icalgauge_free(gauge);
469 }
470
471 return c;
472}
473
474int icaldirset_has_uid(icalset *set, const char *uid)
475{
476 const icalcomponent *c;
477
478 icalerror_check_arg_rz((set != 0), "set");
479 icalerror_check_arg_rz((uid != 0), "uid");
480
481 /* HACK. This is a temporary implementation. _has_uid should use a
482 database, and _fetch should use _has_uid, not the other way
483 around */
484 c = icaldirset_fetch(set, 0, uid);
485
486 return c != 0;
487}
488
489icalerrorenum icaldirset_select(icalset *set, icalgauge *gauge)
490{
491 icaldirset *dset;
492
493 icalerror_check_arg_re((set != 0), "set", ICAL_BADARG_ERROR);
494 icalerror_check_arg_re((gauge != 0), "gauge", ICAL_BADARG_ERROR);
495
496 dset = (icaldirset *)set;
497 dset->gauge = gauge;
498
499 return ICAL_NO_ERROR;
500}
501
502icalerrorenum icaldirset_modify(icalset *set, icalcomponent *oldcomp, icalcomponent *newcomp)
503{
504 _unused(set);
505 _unused(oldcomp);
506 _unused(newcomp);
507
508 /* NOT IMPLEMENTED */
509 assert(0);
510 return ICAL_NO_ERROR;
511}
512
513void icaldirset_clear(icalset *set)
514{
515 _unused(set);
516
517 /* NOT IMPLEMENTED */
518 assert(0);
519}
520
521icalcomponent *icaldirset_get_current_component(icalset *set)
522{
523 icaldirset *dset = (icaldirset *)set;
524
525 icalerror_check_arg_rz((dset != 0), "dset");
526
527 if (dset->cluster == 0) {
528 return icaldirset_get_first_component(set);
529 } else {
530 return icalcluster_get_current_component(dset->cluster);
531 }
532}
533
534icalcomponent *icaldirset_get_first_component(icalset *set)
535{
536 icaldirset *dset = (icaldirset *)set;
537
538 icalerrorenum error;
539 char path[MAXPATHLEN];
540
541 error = icaldirset_read_directory(dset);
542
543 if (error != ICAL_NO_ERROR) {
544 icalerror_set_errno(error);
545 return 0;
546 }
547
548 dset->directory_iterator = icalpvl_head(dset->directory);
549
550 if (dset->directory_iterator == 0) {
551 icalerror_set_errno(error);
552 return 0;
553 }
554
555 snprintf(path, MAXPATHLEN, "%s/%s", dset->dir, (char *)icalpvl_data(dset->directory_iterator));
556
557 /* If the next cluster we need is different than the current cluster,
558 delete the current one and get a new one */
559
560 if (dset->cluster != 0 && strcmp(path, icalcluster_key(dset->cluster)) != 0) {
561 icalcluster_free(dset->cluster);
562 dset->cluster = 0;
563 }
564
565 if (dset->cluster == 0) {
566 dset->cluster = icalfileset_produce_icalcluster(path);
567
568 if (dset->cluster == 0) {
569 error = icalerrno;
570 }
571 }
572
573 if (error != ICAL_NO_ERROR) {
574 icalerror_set_errno(error);
575 return 0;
576 }
577
578 dset->first_component = 1;
579
580 return icaldirset_get_next_component(set);
581}
582
583icalcomponent *icaldirset_get_next_component(icalset *set)
584{
585 icaldirset *dset;
586 icalcomponent *c;
587 icalerrorenum error;
588
589 icalerror_check_arg_rz((set != 0), "set");
590 dset = (icaldirset *)set;
591
592 if (dset->cluster == 0) {
593 icalerror_warn("icaldirset_get_next_component called with a NULL cluster "
594 "(Caller must call icaldirset_get_first_component first)");
596 return 0;
597 }
598
599 /* Set the component iterator for the following for loop */
600 if (dset->first_component == 1) {
601 (void)icalcluster_get_first_component(dset->cluster);
602 dset->first_component = 0;
603 } else {
604 (void)icalcluster_get_next_component(dset->cluster);
605 }
606
607 while (1) {
608 /* Iterate through all of the objects in the cluster */
609 for (c = icalcluster_get_current_component(dset->cluster);
610 c != 0; c = icalcluster_get_next_component(dset->cluster)) {
611 /* If there is a gauge defined and the component does not
612 pass the gauge, skip the rest of the loop */
613
614 if (dset->gauge != 0 && icalgauge_compare(dset->gauge, c) == 0) {
615 continue;
616 }
617
618 /* Either there is no gauge, or the component passed the
619 gauge, so return it */
620
621 return c;
622 }
623
624 /* Fell through the loop, so the component we want is not
625 in this cluster. Load a new cluster and try again. */
626
627 error = icaldirset_next_cluster(dset);
628
629 if (dset->cluster == 0 || error != ICAL_NO_ERROR) {
630 /* No more clusters */
631 return 0;
632 } else {
633 c = icalcluster_get_first_component(dset->cluster);
634
635 return c;
636 }
637 }
638
639 return 0; /* Should never get here */
640}
641
642icalsetiter icaldirset_begin_component(icalset *set, icalcomponent_kind kind, icalgauge *gauge,
643 const char *tzid)
644{
645 _unused(set);
646 _unused(kind);
647 _unused(gauge);
648 _unused(tzid);
649 /*
650 icalsetiter itr = icalsetiter_null;
651 icaldirset *fset = (icaldirset*) set;
652
653 icalerror_check_arg_re((fset!=0), "set", icalsetiter_null);
654
655 itr.iter.kind = kind;
656 itr.gauge = gauge;
657 */
658 /* TO BE IMPLEMENTED */
659 return icalsetiter_null;
660}
661
662icalcomponent *icaldirsetiter_to_next(icalset *set, icalsetiter *i)
663{
664 _unused(set);
665 _unused(i);
666 /* TO BE IMPLEMENTED */
667 return NULL;
668}
669
670icalcomponent *icaldirsetiter_to_prior(icalset *set, icalsetiter *i)
671{
672 _unused(set);
673 _unused(i);
674 /* TO BE IMPLEMENTED */
675 return NULL;
676}
icalcomponent * icalcluster_get_current_component(icalcluster *cluster)
Iterate through components.
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 * icalcompiter_deref(icalcompiter *i)
void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
icalcompiter icalcomponent_begin_component(icalcomponent *component, icalcomponent_kind kind)
icalerrorenum icaldirset_add_component(icalset *set, icalcomponent *comp)
Definition icaldirset.c:293
icalerrorenum icaldirset_remove_component(icalset *set, icalcomponent *comp)
Definition icaldirset.c:371
Manages a database of ical components and offers interfaces for reading, writing and searching for co...
icalcomponent_kind
Definition icalenums.h:29
@ 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
@ ICAL_USAGE_ERROR
Definition icalerror.h:68
#define icalerrno
Access the current icalerrno value.
Definition icalerror.h:130
icalfileset_options icalfileset_options_default
Definition icalfileset.c:42
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
icalgauge * icalgauge_new_from_sql(const char *sql, int expand)
Definition icalgauge.c:38
icalvalue * icalproperty_get_value(const icalproperty *prop)
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
@ ICAL_DIR_SET
Definition icalset.h:40
Options for opening an icalfileset.
icalcluster * cluster