$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
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 
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 
35 static 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 
60 static 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 
81 icalspanlist *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;
106  c = icalset_get_next_component(set)) {
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) {
139  icalspanlist_free(sl);
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) {
169  icalspanlist_free(sl);
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 
183 void 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 
202 void 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 
216 struct icalperiodtype icalspanlist_next_free_time(icalspanlist *sl, struct icaltimetype t)
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 
280 int *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 
343 icalcomponent *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 
356  utc_zone = icaltimezone_get_utc_timezone();
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 
389 icalspanlist *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) {
419  icalspanlist_free(sl);
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 }
Timezone handling routines.
icalproperty * icalcomponent_get_next_property(icalcomponent *c, icalproperty_kind kind)
void icalspanlist_dump(icalspanlist *sl)
Definition: icalspanlist.c:202
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)
icalcomponent * icalcomponent_get_inner(icalcomponent *comp)
icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
Definition: icaltime.c:292
icalspanlist * icalspanlist_new(icalset *set, struct icaltimetype start, struct icaltimetype end)
Definition: icalspanlist.c:81
icalcomponent * icalspanlist_as_vfreebusy(icalspanlist *sl, const char *organizer, const char *attendee)
Definition: icalspanlist.c:343
struct icaldurationtype duration
Definition: icalperiod.h:36
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
void icalproperty_add_parameter(icalproperty *p, icalparameter *parameter)
Definition: icalproperty.c:483
void icalerror_clear_errno(void)
Resets icalerrno to ICAL_NO_ERROR.
Definition: icalerror.c:85
struct icalperiodtype icalspanlist_next_free_time(icalspanlist *sl, struct icaltimetype t)
Definition: icalspanlist.c:216
struct icaltimetype icaltime_null_time(void)
Definition: icaltime.c:579
struct icaltimetype end
Definition: icalperiod.h:34
struct _icaltimezone icaltimezone
Definition: icaltimezone.h:29
int * icalspanlist_as_freebusy_matrix(icalspanlist *spanlist, int delta_t)
Definition: icalspanlist.c:280
struct icaltimetype start
Definition: icalperiod.h:31
icaltimezone * icaltimezone_get_utc_timezone(void)
struct icaldurationtype icaldurationtype_null_duration(void)
Creates a duration with zero length.
Definition: icalduration.c:261
icalparameter * icalproperty_get_first_parameter(icalproperty *p, icalparameter_kind kind)
Definition: icalproperty.c:704
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition: icaltime.c:209
icalcomponent_kind
Definition: icalenums.h:28
icalcomponent_kind icalcomponent_isa(const icalcomponent *component)
icalcomponent * icalset_get_first_component(icalset *set)
Definition: icalset.c:403
icaltime_t icaltime_as_timet(const struct icaltimetype tt)
Definition: icaltime.c:259
bool icaltime_is_null_time(const struct icaltimetype t)
Definition: icaltime.c:630
icalspanlist * icalspanlist_from_vfreebusy(icalcomponent *comp)
Definition: icalspanlist.c:389
void icalspanlist_free(icalspanlist *sl)
Definition: icalspanlist.c:183
void icalcomponent_add_property(icalcomponent *component, icalproperty *property)
Code that supports collections of free/busy spans of time.
icalcomponent * icalset_get_next_component(icalset *set)
Definition: icalset.c:408
icalcomponent * icalcomponent_new_vfreebusy(void)
icalproperty * icalcomponent_get_first_property(icalcomponent *c, icalproperty_kind kind)