Libical API Documentation 4.0 UNRELEASED Go to the stable 3.0 documentation
Loading...
Searching...
No Matches
icalspanlist.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalspanlist.c
3 CREATOR: ebusboom 23 aug 2000
4
5 SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7 ======================================================================*/
8
13
14#ifdef HAVE_CONFIG_H
15#include <config.h>
16#endif
17
18#include "icalspanlist.h"
19#include "icalpvl_p.h"
20#include "icalerror_p.h"
21#include "icaltimezone.h"
22
23#include <stdlib.h>
24
34
35static int compare_span(void *a, void *b)
36{
37 const struct icaltime_span *span_a = (struct icaltime_span *)a;
38 const struct icaltime_span *span_b = (struct icaltime_span *)b;
39
40 if (span_a->start == span_b->start) {
41 return 0;
42 } else if (span_a->start < span_b->start) {
43 return -1;
44 } else { /*if(span_a->start > span->b.start) */
45 return 1;
46 }
47}
48
59
60static void icalspanlist_new_callback(icalcomponent *comp, const struct icaltime_span *span, void *data)
61{
62 icaltime_span *s;
63 icalspanlist *sl = (icalspanlist *)data;
64
65 _unused(comp);
66
67 if (span->is_busy == 0) {
68 return;
69 }
70
71 if ((s = (icaltime_span *)malloc(sizeof(icaltime_span))) == 0) {
73 return;
74 }
75
76 /* copy span data into allocated memory.. **/
77 *s = *span;
78 icalpvl_insert_ordered(sl->spans, compare_span, (void *)s);
79}
80
81icalspanlist *icalspanlist_new(icalset *set, struct icaltimetype start, struct icaltimetype end)
82{
83 struct icaltime_span range;
84 icalpvl_elem itr;
85 icalcomponent_kind inner_kind;
86 icalspanlist *sl;
87 struct icaltime_span *freetime;
88
89 if ((sl = (struct icalspanlist_impl *)malloc(sizeof(struct icalspanlist_impl))) == 0) {
91 return 0;
92 }
93
94 sl->spans = icalpvl_newlist();
95 sl->start = start;
96 sl->end = end;
97
98 range.start = icaltime_as_timet(start);
99 range.end = icaltime_as_timet(end);
100
101 /* Gets a list of spans of busy time from the events in the set
102 and order the spans based on the start time */
103
104 for (icalcomponent *c = icalset_get_first_component(set);
105 c != 0;
108 icalcomponent *inner = icalcomponent_get_inner(c);
109
110 if (!inner) {
111 continue;
112 }
113
114 inner_kind = icalcomponent_isa(inner);
115
116 if (kind != ICAL_VEVENT_COMPONENT && inner_kind != ICAL_VEVENT_COMPONENT) {
117 continue;
118 }
119
121
122 icalcomponent_foreach_recurrence(c, start, end, icalspanlist_new_callback, (void *)sl);
123 }
124
125 /* Now Fill in the free time spans. loop through the spans. if the
126 start of the range is not within the span, create a free entry
127 that runs from the start of the range to the start of the
128 span. */
129
130 for (itr = icalpvl_head(sl->spans); itr != 0; itr = icalpvl_next(itr)) {
131 const struct icaltime_span *s = (struct icaltime_span *)icalpvl_data(itr);
132
133 if (!s) {
134 continue;
135 }
136
137 if ((freetime = (struct icaltime_span *)malloc(sizeof(struct icaltime_span))) == 0) {
140 return 0;
141 }
142
143 if (range.start < s->start) {
144 freetime->start = range.start;
145 freetime->end = s->start;
146
147 freetime->is_busy = 0;
148
149 icalpvl_insert_ordered(sl->spans, compare_span, (void *)freetime);
150 } else {
151 free(freetime);
152 }
153
154 range.start = s->end;
155 }
156
157 /* If the end of the range is null, then assume that everything
158 after the last item in the calendar is open and add a span
159 that indicates this */
160
161 if (icaltime_is_null_time(end)) {
162 const struct icaltime_span *last_span;
163
164 last_span = (struct icaltime_span *)icalpvl_data(icalpvl_tail(sl->spans));
165
166 if (last_span != 0) {
167 if ((freetime = (struct icaltime_span *)malloc(sizeof(struct icaltime_span))) == 0) {
170 return 0;
171 }
172
173 freetime->is_busy = 0;
174 freetime->start = last_span->end;
175 freetime->end = freetime->start;
176 icalpvl_insert_ordered(sl->spans, compare_span, (void *)freetime);
177 }
178 }
179
180 return sl;
181}
182
183void icalspanlist_free(icalspanlist *sl)
184{
185 struct icaltime_span *span;
186
187 if (sl == NULL) {
188 return;
189 }
190
191 while ((span = icalpvl_pop(sl->spans)) != 0) {
192 free(span);
193 }
194
195 icalpvl_free(sl->spans);
196
197 sl->spans = 0;
198
199 free(sl);
200}
201
202void icalspanlist_dump(icalspanlist *sl)
203{
204 int i = 0;
205 icalpvl_elem itr;
206
207 for (itr = icalpvl_head(sl->spans); itr != 0; itr = icalpvl_next(itr)) {
208 struct icaltime_span *s = (struct icaltime_span *)icalpvl_data(itr);
209 if (s) {
210 printf("#%02d %d start: %s", ++i, s->is_busy, icalctime(&s->start));
211 printf(" end : %s", icalctime(&s->end));
212 }
213 }
214}
215
217{
218 icalpvl_elem itr;
219 struct icalperiodtype period;
220 struct icaltime_span *s;
221
222 icaltime_t rangett = icaltime_as_timet(t);
223
224 period.start = icaltime_null_time();
225 period.end = icaltime_null_time();
227
228 itr = icalpvl_head(sl->spans);
229 s = (struct icaltime_span *)icalpvl_data(itr);
230
231 if (s == 0) {
232 /* No elements in span */
233 return period;
234 }
235
236 /* Is the reference time before the first span? If so, assume
237 that the reference time is free */
238 if (rangett < s->start) {
239 /* End of period is start of first span if span is busy, end
240 of the span if it is free */
241 period.start = t;
242
243 if (s->is_busy == 1) {
244 period.end = icaltime_from_timet_with_zone(s->start, 0, NULL);
245 } else {
246 period.end = icaltime_from_timet_with_zone(s->end, 0, NULL);
247 }
248
249 return period;
250 }
251
252 /* Otherwise, find the first free span that contains the
253 reference time. */
254 for (itr = icalpvl_head(sl->spans); itr != 0; itr = icalpvl_next(itr)) {
255 s = (struct icaltime_span *)icalpvl_data(itr);
256
257 if (!s) {
258 continue;
259 }
260
261 if (s->is_busy == 0 && s->start >= rangett && (rangett < s->end || s->end == s->start)) {
262 if (rangett < s->start) {
263 period.start = icaltime_from_timet_with_zone(s->start, 0, NULL);
264 } else {
265 period.start = icaltime_from_timet_with_zone(rangett, 0, NULL);
266 }
267
268 period.end = icaltime_from_timet_with_zone(s->end, 0, NULL);
269
270 return period;
271 }
272 }
273
274 period.start = icaltime_null_time();
275 period.end = icaltime_null_time();
276
277 return period;
278}
279
280int *icalspanlist_as_freebusy_matrix(icalspanlist *spanlist, int delta_t)
281{
282 icalpvl_elem itr;
283 icaltime_t spanduration_secs;
284 int *matrix;
285 icaltime_t matrix_slots;
286 icaltime_t sl_start, sl_end;
287
288 icalerror_check_arg_rz((spanlist != 0), "spanlist");
289
290 if (!delta_t) {
291 delta_t = 3600;
292 }
293
294 /* calculate the start and end time as icaltime_t **/
295 sl_start = icaltime_as_timet_with_zone(spanlist->start, icaltimezone_get_utc_timezone());
297
298 /* insure that the time period falls on a time boundary divisible
299 by delta_t */
300
301 sl_start /= delta_t;
302 sl_start *= delta_t;
303
304 sl_end /= delta_t;
305 sl_end *= delta_t;
306
307 /* find the duration of this spanlist **/
308 spanduration_secs = sl_end - sl_start;
309
310 /* malloc our matrix, add one extra slot for a final -1 **/
311 matrix_slots = spanduration_secs / delta_t + 1;
312
313 matrix = (int *)malloc(sizeof(int) * (size_t)matrix_slots);
314 if (matrix == NULL) {
316 return NULL;
317 }
318 memset(matrix, 0, sizeof(int) * (size_t)matrix_slots);
319 matrix[matrix_slots - 1] = -1;
320
321 /* loop through each span and mark the slots in the array */
322
323 for (itr = icalpvl_head(spanlist->spans); itr != 0; itr = icalpvl_next(itr)) {
324 const struct icaltime_span *s = (struct icaltime_span *)icalpvl_data(itr);
325
326 if (s && s->is_busy == 1) {
327 icaltime_t offset_start = s->start / delta_t - sl_start / delta_t;
328 icaltime_t offset_end = (s->end - 1) / delta_t - sl_start / delta_t + 1;
329 icaltime_t i;
330
331 if (offset_end >= matrix_slots) {
332 offset_end = matrix_slots - 1;
333 }
334
335 for (i = offset_start; i < offset_end; i++) {
336 matrix[i]++;
337 }
338 }
339 }
340 return matrix;
341}
342
343icalcomponent *icalspanlist_as_vfreebusy(icalspanlist *sl,
344 const char *organizer, const char *attendee)
345{
346 icalcomponent *comp;
347 struct icaltimetype atime = icaltime_from_timet_with_zone(time(0), 0, NULL);
348 icalpvl_elem itr;
349 icaltimezone *utc_zone;
350
351 if (!attendee) {
353 return 0;
354 }
355
357
359
360 icalcomponent_add_property(comp, icalproperty_new_dtstart(sl->start));
361 icalcomponent_add_property(comp, icalproperty_new_dtend(sl->end));
362 icalcomponent_add_property(comp, icalproperty_new_dtstamp(atime));
363
364 if (organizer) {
365 icalcomponent_add_property(comp, icalproperty_new_organizer(organizer));
366 }
367 icalcomponent_add_property(comp, icalproperty_new_attendee(attendee));
368
369 /* now add the freebusy sections.. */
370
371 for (itr = icalpvl_head(sl->spans); itr != 0; itr = icalpvl_next(itr)) {
372 struct icaltime_span *s = (struct icaltime_span *)icalpvl_data(itr);
373
374 if (s && s->is_busy == 1) {
375 struct icalperiodtype period;
376 period.start = icaltime_from_timet_with_zone(s->start, 0, utc_zone);
377 period.end = icaltime_from_timet_with_zone(s->end, 0, utc_zone);
379
380 icalproperty *p = icalproperty_new_freebusy(period);
381 icalproperty_add_parameter(p, icalparameter_new_fbtype(ICAL_FBTYPE_BUSY));
383 }
384 }
385
386 return comp;
387}
388
389icalspanlist *icalspanlist_from_vfreebusy(icalcomponent *comp)
390{
391 icalcomponent *inner;
392 icalproperty *prop;
393 icalspanlist *sl;
394
395 icalerror_check_arg_rz((comp != NULL), "comp");
396
397 inner = icalcomponent_get_inner(comp);
398 if (!inner) {
399 return NULL;
400 }
401
402 if ((sl = (icalspanlist *)malloc(sizeof(icalspanlist))) == 0) {
404 return 0;
405 }
406 sl->spans = icalpvl_newlist();
407
408 /* cycle through each FREEBUSY property, adding to the spanlist */
409 for (prop = icalcomponent_get_first_property(inner, ICAL_FREEBUSY_PROPERTY);
410 prop != NULL;
411 prop = icalcomponent_get_next_property(inner, ICAL_FREEBUSY_PROPERTY)) {
412 icaltime_span *s = (icaltime_span *)malloc(sizeof(icaltime_span));
413 icalparameter *param;
414 struct icalperiodtype period;
415 icalparameter_fbtype fbtype;
416
417 if (s == 0) {
420 return 0;
421 }
422
423 param = icalproperty_get_first_parameter(prop, ICAL_FBTYPE_PARAMETER);
424 fbtype = (param) ? icalparameter_get_fbtype(param) : ICAL_FBTYPE_BUSY;
425
426 switch (fbtype) {
427 case ICAL_FBTYPE_FREE:
428 case ICAL_FBTYPE_NONE:
429 case ICAL_FBTYPE_X:
430 s->is_busy = 1;
431 break;
432 default:
433 s->is_busy = 0;
434 }
435
436 period = icalproperty_get_freebusy(prop);
439
440 icalpvl_insert_ordered(sl->spans, compare_span, (void *)s);
441 }
443 return sl;
444}
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)
icalcomponent * icalcomponent_new_vfreebusy(void)
icalcomponent * icalcomponent_get_inner(icalcomponent *comp)
void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
void icalcomponent_foreach_recurrence(icalcomponent *comp, struct icaltimetype start, struct icaltimetype end, void(*callback)(icalcomponent *comp, const struct icaltime_span *span, void *data), void *callback_data)
icalproperty * icalcomponent_get_next_property(icalcomponent *c, icalproperty_kind kind)
struct icaldurationtype icaldurationtype_null_duration(void)
Creates a duration with zero length.
icalcomponent_kind
Definition icalenums.h:29
@ ICAL_VEVENT_COMPONENT
Definition icalenums.h:34
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
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_USAGE_ERROR
Definition icalerror.h:68
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
icalcomponent * icalset_get_first_component(icalset *set)
Definition icalset.c:403
icalcomponent * icalset_get_next_component(icalset *set)
Definition icalset.c:408
void icalspanlist_dump(icalspanlist *sl)
icalspanlist * icalspanlist_from_vfreebusy(icalcomponent *comp)
int * icalspanlist_as_freebusy_matrix(icalspanlist *spanlist, int delta_t)
void icalspanlist_free(icalspanlist *sl)
icalspanlist * icalspanlist_new(icalset *set, struct icaltimetype start, struct icaltimetype end)
icalcomponent * icalspanlist_as_vfreebusy(icalspanlist *sl, const char *organizer, const char *attendee)
struct icalperiodtype icalspanlist_next_free_time(icalspanlist *sl, struct icaltimetype t)
Code that supports collections of free/busy spans of time.
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
icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
Definition icaltime.c:292
icaltime_t icaltime_as_timet(const struct icaltimetype tt)
Definition icaltime.c:259
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition icaltime.c:209
icaltime_t icaltime_as_timet(const struct icaltimetype tt)
Definition icaltime.c:259
struct icaltimetype icaltime_null_time(void)
Definition icaltime.c:575
icaltimezone * icaltimezone_get_utc_timezone(void)
Timezone handling routines.
struct _icaltimezone icaltimezone
struct icaldurationtype duration
Definition icalperiod.h:36
struct icaltimetype end
Definition icalperiod.h:34
struct icaltimetype start
Definition icalperiod.h:31