Diffstat (limited to 'libical/src/libicalss/icalspanlist.c') (more/less context) (show whitespace changes)
-rw-r--r-- | libical/src/libicalss/icalspanlist.c | 374 |
1 files changed, 316 insertions, 58 deletions
diff --git a/libical/src/libicalss/icalspanlist.c b/libical/src/libicalss/icalspanlist.c index cab6a81..f42ff41 100644 --- a/libical/src/libicalss/icalspanlist.c +++ b/libical/src/libicalss/icalspanlist.c | |||
@@ -1,309 +1,567 @@ | |||
1 | /* -*- Mode: C -*- | 1 | /* -*- Mode: C -*- |
2 | ====================================================================== | 2 | ====================================================================== |
3 | FILE: icalspanlist.c | 3 | FILE: icalspanlist.c |
4 | CREATOR: ebusboom 23 aug 2000 | 4 | CREATOR: ebusboom 23 aug 2000 |
5 | 5 | ||
6 | $Id$ | 6 | $Id$ |
7 | $Locker$ | 7 | $Locker$ |
8 | 8 | ||
9 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org | 9 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org |
10 | 10 | ||
11 | This program is free software; you can redistribute it and/or modify | 11 | This program is free software; you can redistribute it and/or modify |
12 | it under the terms of either: | 12 | it under the terms of either: |
13 | 13 | ||
14 | The LGPL as published by the Free Software Foundation, version | 14 | The LGPL as published by the Free Software Foundation, version |
15 | 2.1, available at: http://www.fsf.org/copyleft/lesser.html | 15 | 2.1, available at: http://www.fsf.org/copyleft/lesser.html |
16 | 16 | ||
17 | Or: | 17 | Or: |
18 | 18 | ||
19 | The Mozilla Public License Version 1.0. You may obtain a copy of | 19 | The Mozilla Public License Version 1.0. You may obtain a copy of |
20 | the License at http://www.mozilla.org/MPL/ | 20 | the License at http://www.mozilla.org/MPL/ |
21 | 21 | ||
22 | 22 | ||
23 | ======================================================================*/ | 23 | ======================================================================*/ |
24 | 24 | ||
25 | #ifdef HAVE_CONFIG_H | 25 | #ifdef HAVE_CONFIG_H |
26 | #include "config.h" | 26 | #include "config.h" |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #include "ical.h" | 29 | #include "ical.h" |
30 | #include "icalspanlist.h" | 30 | #include "icalspanlist.h" |
31 | #include "pvl.h" | 31 | |
32 | #include <stdlib.h> /* for free and malloc */ | 32 | #include <stdlib.h> /* for free and malloc */ |
33 | #include <string.h> | ||
33 | 34 | ||
34 | struct icalspanlist_impl { | 35 | struct icalspanlist_impl { |
35 | pvl_list spans; | 36 | pvl_list spans; /**< list of icaltime_span data **/ |
37 | struct icaltimetype start; /**< start time of span **/ | ||
38 | struct icaltimetype end;/**< end time of span **/ | ||
36 | }; | 39 | }; |
37 | 40 | ||
38 | int compare_span(void* a, void* b) | 41 | /** @brief Internal comparison function for two spans |
42 | * | ||
43 | * @param a a spanlist. | ||
44 | * @param b another spanlist. | ||
45 | * | ||
46 | * @return -1, 0, 1 depending on the comparison of the start times. | ||
47 | * | ||
48 | * Used to insert spans into the tree in sorted order. | ||
49 | */ | ||
50 | |||
51 | static int compare_span(void* a, void* b) | ||
39 | { | 52 | { |
40 | struct icaltime_span *span_a = (struct icaltime_span *)a ; | 53 | struct icaltime_span *span_a = (struct icaltime_span *)a ; |
41 | struct icaltime_span *span_b = (struct icaltime_span *)b ; | 54 | struct icaltime_span *span_b = (struct icaltime_span *)b ; |
42 | 55 | ||
43 | if(span_a->start == span_b->start){ | 56 | if(span_a->start == span_b->start){ |
44 | return 0; | 57 | return 0; |
45 | } else if(span_a->start < span_b->start){ | 58 | } else if(span_a->start < span_b->start){ |
46 | return -1; | 59 | return -1; |
47 | } else { /*if(span_a->start > span->b.start)*/ | 60 | } else { /*if(span_a->start > span->b.start)*/ |
48 | return 1; | 61 | return 1; |
49 | } | 62 | } |
50 | } | 63 | } |
51 | 64 | ||
52 | icalcomponent* icalspanlist_get_inner(icalcomponent* comp) | 65 | |
66 | /** @brief callback function for collecting spanlists of a | ||
67 | * series of events. | ||
68 | * | ||
69 | * @param comp A valid icalcomponent. | ||
70 | * @param span The span to insert into data. | ||
71 | * @param data The actual spanlist to insert into | ||
72 | * | ||
73 | * This callback is used by icalcomponent_foreach_recurrence() | ||
74 | * to build up a spanlist. | ||
75 | */ | ||
76 | |||
77 | static void icalspanlist_new_callback(icalcomponent *comp, | ||
78 | struct icaltime_span *span, | ||
79 | void *data) | ||
53 | { | 80 | { |
54 | if (icalcomponent_isa(comp) == ICAL_VCALENDAR_COMPONENT){ | 81 | icaltime_span *s; |
55 | return icalcomponent_get_first_real_component(comp); | 82 | icalspanlist *sl = (icalspanlist*) data; |
56 | } else { | 83 | |
57 | return comp; | 84 | if (span->is_busy == 0) |
85 | return; | ||
86 | |||
87 | if ((s=(icaltime_span *) malloc(sizeof(icaltime_span))) == 0) { | ||
88 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
89 | return; | ||
58 | } | 90 | } |
91 | |||
92 | /** copy span data into allocated memory.. **/ | ||
93 | *s = *span; | ||
94 | pvl_insert_ordered(sl->spans, compare_span, (void*)s); | ||
59 | } | 95 | } |
60 | 96 | ||
61 | 97 | ||
62 | void print_span(int c, struct icaltime_span span ); | ||
63 | 98 | ||
99 | /** @brief Make a free list from a set of VEVENT components. | ||
100 | * | ||
101 | * @param set A valid icalset containing VEVENTS | ||
102 | * @param start The free list starts at this date/time | ||
103 | * @param end The free list ends at this date/time | ||
104 | * | ||
105 | * @return A spanlist corresponding to the VEVENTS | ||
106 | * | ||
107 | * Given a set of components, a start time and an end time | ||
108 | * return a spanlist that contains the free/busy times. | ||
109 | */ | ||
64 | 110 | ||
65 | /* Make a free list from a set of component */ | ||
66 | icalspanlist* icalspanlist_new(icalset *set, | 111 | icalspanlist* icalspanlist_new(icalset *set, |
67 | struct icaltimetype start, | 112 | struct icaltimetype start, |
68 | struct icaltimetype end) | 113 | struct icaltimetype end) |
69 | { | 114 | { |
70 | struct icaltime_span range; | 115 | struct icaltime_span range; |
71 | pvl_elem itr; | 116 | pvl_elem itr; |
72 | icalcomponent *c,*inner; | 117 | icalcomponent *c,*inner; |
73 | icalcomponent_kind kind, inner_kind; | 118 | icalcomponent_kind kind, inner_kind; |
74 | struct icalspanlist_impl *sl; | 119 | icalspanlist *sl; |
75 | struct icaltime_span *freetime; | 120 | struct icaltime_span *freetime; |
76 | 121 | ||
77 | if ( ( sl = (struct icalspanlist_impl*) | 122 | if ( ( sl = (struct icalspanlist_impl*) |
78 | malloc(sizeof(struct icalspanlist_impl))) == 0) { | 123 | malloc(sizeof(struct icalspanlist_impl))) == 0) { |
79 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | 124 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); |
80 | return 0; | 125 | return 0; |
81 | } | 126 | } |
82 | 127 | ||
83 | sl->spans = pvl_newlist(); | 128 | sl->spans = pvl_newlist(); |
129 | sl->start = start; | ||
130 | sl->end = end; | ||
84 | 131 | ||
85 | range.start = icaltime_as_timet(start); | 132 | range.start = icaltime_as_timet(start); |
86 | range.end = icaltime_as_timet(end); | 133 | range.end = icaltime_as_timet(end); |
87 | 134 | ||
88 | printf("Range start: %s",ctime(&range.start)); | ||
89 | printf("Range end : %s",ctime(&range.end)); | ||
90 | |||
91 | |||
92 | /* Get a list of spans of busy time from the events in the set | 135 | /* Get a list of spans of busy time from the events in the set |
93 | and order the spans based on the start time */ | 136 | and order the spans based on the start time */ |
94 | 137 | ||
95 | for(c = icalset_get_first_component(set); | 138 | for(c = icalset_get_first_component(set); |
96 | c != 0; | 139 | c != 0; |
97 | c = icalset_get_next_component(set)){ | 140 | c = icalset_get_next_component(set)){ |
98 | 141 | ||
99 | struct icaltime_span span; | ||
100 | |||
101 | kind = icalcomponent_isa(c); | 142 | kind = icalcomponent_isa(c); |
102 | inner = icalcomponent_get_inner(c); | 143 | inner = icalcomponent_get_inner(c); |
103 | 144 | ||
104 | if(!inner){ | 145 | if(!inner){ |
105 | continue; | 146 | continue; |
106 | } | 147 | } |
107 | 148 | ||
108 | inner_kind = icalcomponent_isa(inner); | 149 | inner_kind = icalcomponent_isa(inner); |
109 | 150 | ||
110 | if( kind != ICAL_VEVENT_COMPONENT && | 151 | if( kind != ICAL_VEVENT_COMPONENT && |
111 | inner_kind != ICAL_VEVENT_COMPONENT){ | 152 | inner_kind != ICAL_VEVENT_COMPONENT){ |
112 | continue; | 153 | continue; |
113 | } | 154 | } |
114 | 155 | ||
115 | icalerror_clear_errno(); | 156 | icalerror_clear_errno(); |
116 | 157 | ||
117 | span = icalcomponent_get_span(c); | 158 | icalcomponent_foreach_recurrence(c, start, end, |
118 | span.is_busy = 1; | 159 | icalspanlist_new_callback, |
160 | (void*)sl); | ||
119 | 161 | ||
120 | if(icalerrno != ICAL_NO_ERROR){ | ||
121 | continue; | ||
122 | } | ||
123 | |||
124 | if ((range.start < span.end && icaltime_is_null_time(end)) || | ||
125 | (range.start < span.end && range.end > span.start )){ | ||
126 | |||
127 | struct icaltime_span *s; | ||
128 | |||
129 | if ((s=(struct icaltime_span *) | ||
130 | malloc(sizeof(struct icaltime_span))) == 0){ | ||
131 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | memcpy(s,&span,sizeof(span)); | ||
136 | |||
137 | pvl_insert_ordered(sl->spans,compare_span,(void*)s); | ||
138 | |||
139 | } | ||
140 | } | 162 | } |
141 | 163 | ||
142 | /* Now Fill in the free time spans. loop through the spans. if the | 164 | /* Now Fill in the free time spans. loop through the spans. if the |
143 | start of the range is not within the span, create a free entry | 165 | start of the range is not within the span, create a free entry |
144 | that runs from the start of the range to the start of the | 166 | that runs from the start of the range to the start of the |
145 | span. */ | 167 | span. */ |
146 | 168 | ||
147 | for( itr = pvl_head(sl->spans); | 169 | for( itr = pvl_head(sl->spans); |
148 | itr != 0; | 170 | itr != 0; |
149 | itr = pvl_next(itr)) | 171 | itr = pvl_next(itr)) |
150 | { | 172 | { |
151 | struct icaltime_span *s = (icalproperty*)pvl_data(itr); | 173 | struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); |
152 | 174 | ||
153 | if ((freetime=(struct icaltime_span *) | 175 | if ((freetime=(struct icaltime_span *) |
154 | malloc(sizeof(struct icaltime_span))) == 0){ | 176 | malloc(sizeof(struct icaltime_span))) == 0){ |
155 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | 177 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); |
156 | return 0; | 178 | return 0; |
157 | } | 179 | } |
158 | 180 | ||
159 | if(range.start < s->start){ | 181 | if(range.start < s->start){ |
160 | freetime->start = range.start; | 182 | freetime->start = range.start; |
161 | freetime->end = s->start; | 183 | freetime->end = s->start; |
162 | 184 | ||
163 | freetime->is_busy = 0; | 185 | freetime->is_busy = 0; |
164 | 186 | ||
165 | 187 | ||
166 | pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); | 188 | pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); |
167 | } else { | 189 | } else { |
168 | free(freetime); | 190 | free(freetime); |
169 | } | 191 | } |
170 | 192 | ||
171 | range.start = s->end; | 193 | range.start = s->end; |
172 | } | 194 | } |
173 | 195 | ||
174 | /* If the end of the range is null, then assume that everything | 196 | /* If the end of the range is null, then assume that everything |
175 | after the last item in the calendar is open and add a span | 197 | after the last item in the calendar is open and add a span |
176 | that indicates this */ | 198 | that indicates this */ |
177 | 199 | ||
178 | if( icaltime_is_null_time(end)){ | 200 | if( icaltime_is_null_time(end)){ |
179 | struct icaltime_span* last_span; | 201 | struct icaltime_span* last_span; |
180 | 202 | ||
181 | last_span = pvl_data(pvl_tail(sl->spans)); | 203 | last_span = (struct icaltime_span*)pvl_data(pvl_tail(sl->spans)); |
182 | 204 | ||
183 | if (last_span != 0){ | 205 | if (last_span != 0){ |
184 | 206 | ||
185 | if ((freetime=(struct icaltime_span *) | 207 | if ((freetime=(struct icaltime_span *) |
186 | malloc(sizeof(struct icaltime_span))) == 0){ | 208 | malloc(sizeof(struct icaltime_span))) == 0){ |
187 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | 209 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); |
188 | return 0; | 210 | return 0; |
189 | } | 211 | } |
190 | 212 | ||
191 | freetime->is_busy = 0; | 213 | freetime->is_busy = 0; |
192 | freetime->start = last_span->end; | 214 | freetime->start = last_span->end; |
193 | freetime->end = freetime->start; | 215 | freetime->end = freetime->start; |
194 | pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); | 216 | pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); |
195 | } | 217 | } |
196 | } | 218 | } |
197 | 219 | ||
198 | 220 | ||
199 | return sl; | 221 | return sl; |
200 | |||
201 | } | 222 | } |
202 | 223 | ||
224 | /** @brief Destructor. | ||
225 | * @param s A valid icalspanlist | ||
226 | * | ||
227 | * Free memory associated with the spanlist | ||
228 | */ | ||
229 | |||
203 | void icalspanlist_free(icalspanlist* s) | 230 | void icalspanlist_free(icalspanlist* s) |
204 | { | 231 | { |
205 | struct icaltime_span *span; | 232 | struct icaltime_span *span; |
206 | struct icalspanlist_impl* impl = (struct icalspanlist_impl*)s; | ||
207 | 233 | ||
208 | while( (span=pvl_pop(impl->spans)) != 0){ | 234 | if (s == NULL) |
235 | return; | ||
236 | |||
237 | while( (span=pvl_pop(s->spans)) != 0){ | ||
209 | free(span); | 238 | free(span); |
210 | } | 239 | } |
211 | 240 | ||
212 | pvl_free(impl->spans); | 241 | pvl_free(s->spans); |
242 | |||
243 | s->spans = 0; | ||
213 | 244 | ||
214 | impl->spans = 0; | 245 | free(s); |
215 | } | 246 | } |
216 | 247 | ||
217 | 248 | ||
218 | void icalspanlist_dump(icalspanlist* s){ | 249 | /** @brief (Debug) print out spanlist to stdout. |
250 | * @param sl A valid icalspanlist. | ||
251 | */ | ||
219 | 252 | ||
253 | void icalspanlist_dump(icalspanlist* sl){ | ||
220 | int i = 0; | 254 | int i = 0; |
221 | struct icalspanlist_impl* sl = (struct icalspanlist_impl*)s; | ||
222 | pvl_elem itr; | 255 | pvl_elem itr; |
223 | 256 | ||
224 | for( itr = pvl_head(sl->spans); | 257 | for( itr = pvl_head(sl->spans); |
225 | itr != 0; | 258 | itr != 0; |
226 | itr = pvl_next(itr)) | 259 | itr = pvl_next(itr)) |
227 | { | 260 | { |
228 | struct icaltime_span *s = (icalproperty*)pvl_data(itr); | 261 | struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); |
229 | 262 | ||
230 | printf("#%02d %d start: %s",++i,s->is_busy,ctime(&s->start)); | 263 | printf("#%02d %d start: %s",++i,s->is_busy,ctime(&s->start)); |
231 | printf(" end : %s",ctime(&s->end)); | 264 | printf(" end : %s",ctime(&s->end)); |
232 | 265 | ||
233 | } | 266 | } |
234 | } | 267 | } |
235 | 268 | ||
236 | icalcomponent* icalspanlist_make_free_list(icalspanlist* sl); | 269 | icalcomponent* icalspanlist_make_free_list(icalspanlist* sl); |
237 | icalcomponent* icalspanlist_make_busy_list(icalspanlist* sl); | 270 | icalcomponent* icalspanlist_make_busy_list(icalspanlist* sl); |
238 | 271 | ||
272 | |||
273 | /** @brief Find next free time span in a spanlist. | ||
274 | * | ||
275 | * @param sl The spanlist to search. | ||
276 | * @param t The time to start looking. | ||
277 | * | ||
278 | * Given a spanlist and a time, find the next period of time | ||
279 | * that is free | ||
280 | */ | ||
281 | |||
239 | struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl, | 282 | struct icalperiodtype icalspanlist_next_free_time(icalspanlist* sl, |
240 | struct icaltimetype t) | 283 | struct icaltimetype t) |
241 | { | 284 | { |
242 | struct icalspanlist_impl* impl = (struct icalspanlist_impl*)sl; | ||
243 | pvl_elem itr; | 285 | pvl_elem itr; |
244 | struct icalperiodtype period; | 286 | struct icalperiodtype period; |
245 | struct icaltime_span *s; | 287 | struct icaltime_span *s; |
246 | 288 | ||
247 | time_t rangett= icaltime_as_timet(t); | 289 | time_t rangett= icaltime_as_timet(t); |
248 | 290 | ||
249 | period.start = icaltime_null_time(); | 291 | period.start = icaltime_null_time(); |
250 | period.end = icaltime_null_time(); | 292 | period.end = icaltime_null_time(); |
251 | 293 | ||
252 | /* Is the reference time before the first span? If so, assume | 294 | itr = pvl_head(sl->spans); |
253 | that the reference time is free */ | 295 | s = (struct icaltime_span *)pvl_data(itr); |
254 | itr = pvl_head(impl->spans); | ||
255 | s = (icalproperty*)pvl_data(itr); | ||
256 | 296 | ||
257 | if (s == 0){ | 297 | if (s == 0){ |
258 | /* No elements in span */ | 298 | /* No elements in span */ |
259 | return period; | 299 | return period; |
260 | } | 300 | } |
261 | 301 | ||
302 | /* Is the reference time before the first span? If so, assume | ||
303 | that the reference time is free */ | ||
262 | if(rangett <s->start ){ | 304 | if(rangett <s->start ){ |
263 | /* End of period is start of first span if span is busy, end | 305 | /* End of period is start of first span if span is busy, end |
264 | of the span if it is free */ | 306 | of the span if it is free */ |
265 | period.start = t; | 307 | period.start = t; |
266 | 308 | ||
267 | if (s->is_busy == 0){ | 309 | if (s->is_busy == 1){ |
268 | period.end = icaltime_from_timet(s->start,0); | 310 | period.end = icaltime_from_timet(s->start,0); |
269 | } else { | 311 | } else { |
270 | period.end = icaltime_from_timet(s->end,0); | 312 | period.end = icaltime_from_timet(s->end,0); |
271 | } | 313 | } |
272 | 314 | ||
273 | return period; | 315 | return period; |
274 | } | 316 | } |
275 | 317 | ||
276 | /* Otherwise, find the first free span that contains the | 318 | /* Otherwise, find the first free span that contains the |
277 | reference time. */ | 319 | reference time. */ |
278 | 320 | for( itr = pvl_head(sl->spans); | |
279 | for( itr = pvl_head(impl->spans); | ||
280 | itr != 0; | 321 | itr != 0; |
281 | itr = pvl_next(itr)) | 322 | itr = pvl_next(itr)) |
282 | { | 323 | { |
283 | s = (icalproperty*)pvl_data(itr); | 324 | s = (struct icaltime_span *)pvl_data(itr); |
284 | 325 | ||
285 | if(s->is_busy == 0 && s->start >= rangett && | 326 | if(s->is_busy == 0 && s->start >= rangett && |
286 | ( rangett < s->end || s->end == s->start)){ | 327 | ( rangett < s->end || s->end == s->start)){ |
287 | 328 | ||
288 | if (rangett < s->start){ | 329 | if (rangett < s->start){ |
289 | period.start = icaltime_from_timet(s->start,0); | 330 | period.start = icaltime_from_timet(s->start,0); |
290 | } else { | 331 | } else { |
291 | period.start = icaltime_from_timet(rangett,0); | 332 | period.start = icaltime_from_timet(rangett,0); |
292 | } | 333 | } |
293 | 334 | ||
294 | period.end = icaltime_from_timet(s->end,0); | 335 | period.end = icaltime_from_timet(s->end,0); |
295 | 336 | ||
296 | return period; | 337 | return period; |
297 | } | 338 | } |
298 | 339 | ||
299 | } | 340 | } |
300 | 341 | ||
301 | period.start = icaltime_null_time(); | 342 | period.start = icaltime_null_time(); |
302 | period.end = icaltime_null_time(); | 343 | period.end = icaltime_null_time(); |
303 | 344 | ||
304 | return period; | 345 | return period; |
305 | } | 346 | } |
306 | 347 | ||
307 | struct icalperiodtype icalspanlist_next_busy_time(icalspanlist* sl, | 348 | struct icalperiodtype icalspanlist_next_busy_time(icalspanlist* sl, |
308 | struct icaltimetype t); | 349 | struct icaltimetype t); |
309 | 350 | ||
351 | |||
352 | /** @brief Returns an hour-by-hour array of free/busy times over a | ||
353 | * given period. | ||
354 | * | ||
355 | * @param sl A valid icalspanlist | ||
356 | * @param delta_t The time slice to divide by, in seconds. Default 3600. | ||
357 | * | ||
358 | * @return A pointer to an array of integers containing the number of | ||
359 | * busy events in each delta_t time period. The final entry | ||
360 | * contains the value -1. | ||
361 | * | ||
362 | * This calculation is somewhat tricky. This is due to the fact that | ||
363 | * the time range contains the start time, but does not contain the | ||
364 | * end time. To perform a proper calculation we subtract one second | ||
365 | * off the end times to get a true containing time. | ||
366 | * | ||
367 | * Also note that if you supplying a spanlist that does not start or | ||
368 | * end on a time boundary divisible by delta_t you may get results | ||
369 | * that are not quite what you expect. | ||
370 | */ | ||
371 | |||
372 | int* icalspanlist_as_freebusy_matrix(icalspanlist* sl, int delta_t) { | ||
373 | pvl_elem itr; | ||
374 | int spanduration_secs; | ||
375 | int *matrix; | ||
376 | int matrix_slots; | ||
377 | time_t sl_start, sl_end; | ||
378 | |||
379 | icalerror_check_arg_rz( (sl!=0), "spanlist"); | ||
380 | |||
381 | if (!delta_t) | ||
382 | delta_t = 3600; | ||
383 | |||
384 | /** calculate the start and end time as time_t **/ | ||
385 | sl_start = icaltime_as_timet_with_zone(sl->start, icaltimezone_get_utc_timezone()); | ||
386 | sl_end = icaltime_as_timet_with_zone(sl->end, icaltimezone_get_utc_timezone()); | ||
387 | |||
388 | |||
389 | /** insure that the time period falls on a time boundary divisable | ||
390 | by delta_t */ | ||
391 | |||
392 | sl_start /= delta_t; | ||
393 | sl_start *= delta_t; | ||
394 | |||
395 | sl_end /= delta_t; | ||
396 | sl_end *= delta_t; | ||
397 | |||
398 | |||
399 | /** find the duration of this spanlist **/ | ||
400 | spanduration_secs = sl_end - sl_start; | ||
401 | |||
402 | |||
403 | /** malloc our matrix, add one extra slot for a final -1 **/ | ||
404 | matrix_slots = spanduration_secs/delta_t + 1; | ||
405 | |||
406 | matrix = (int*) malloc(sizeof(int) * matrix_slots); | ||
407 | if (matrix == NULL) { | ||
408 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
409 | return NULL; | ||
410 | } | ||
411 | memset(matrix, 0, sizeof(int) * matrix_slots); | ||
412 | matrix[matrix_slots-1] = -1; | ||
413 | |||
414 | /* loop through each span and mark the slots in the array */ | ||
415 | |||
416 | for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) { | ||
417 | struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); | ||
418 | |||
419 | if (s->is_busy == 1) { | ||
420 | int offset_start = s->start/delta_t - sl_start/delta_t; | ||
421 | int offset_end = (s->end - 1) /delta_t - sl_start/delta_t + 1; | ||
422 | int i; | ||
423 | |||
424 | if (offset_end >= matrix_slots) | ||
425 | offset_end = matrix_slots - 1; | ||
426 | |||
427 | i = offset_start; | ||
428 | for (i=offset_start; i < offset_end; i++) { | ||
429 | matrix[i]++; | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | return matrix; | ||
434 | } | ||
435 | |||
436 | |||
437 | /** @brief Return a VFREEBUSY component for the corresponding spanlist | ||
438 | * | ||
439 | * @param sl A valid icalspanlist, from icalspanlist_new() | ||
440 | * @param organizer The organizer specified as MAILTO:user@domain | ||
441 | * @param attendee The attendee specified as MAILTO:user@domain | ||
442 | * | ||
443 | * @return A valid icalcomponent or NULL. | ||
444 | * | ||
445 | * This function returns a VFREEBUSY component for the given spanlist. | ||
446 | * The start time is mapped to DTSTART, the end time to DTEND. | ||
447 | * Each busy span is represented as a separate FREEBUSY entry. | ||
448 | * An attendee parameter is required, and organizer parameter is | ||
449 | * optional. | ||
450 | */ | ||
451 | |||
452 | icalcomponent *icalspanlist_as_vfreebusy(icalspanlist* sl, | ||
453 | const char* organizer, | ||
454 | const char* attendee) { | ||
455 | icalcomponent *comp; | ||
456 | icalproperty *p; | ||
457 | struct icaltimetype atime = icaltime_from_timet( time(0),0); | ||
458 | pvl_elem itr; | ||
459 | icaltimezone *utc_zone; | ||
460 | icalparameter *param; | ||
461 | |||
462 | if (!attendee) { | ||
463 | icalerror_set_errno(ICAL_USAGE_ERROR); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | utc_zone = icaltimezone_get_utc_timezone (); | ||
468 | |||
469 | comp = icalcomponent_new_vfreebusy(); | ||
470 | |||
471 | icalcomponent_add_property(comp, icalproperty_new_dtstart(sl->start)); | ||
472 | icalcomponent_add_property(comp, icalproperty_new_dtend(sl->end)); | ||
473 | icalcomponent_add_property(comp, icalproperty_new_dtstamp(atime)); | ||
474 | |||
475 | if (organizer) { | ||
476 | icalcomponent_add_property(comp, icalproperty_new_organizer(organizer)); | ||
477 | } | ||
478 | icalcomponent_add_property(comp, icalproperty_new_attendee(attendee)); | ||
479 | |||
480 | /* now add the freebusy sections.. */ | ||
481 | |||
482 | for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) { | ||
483 | struct icalperiodtype period; | ||
484 | struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); | ||
485 | |||
486 | if (s->is_busy == 1) { | ||
487 | |||
488 | period.start = icaltime_from_timet_with_zone (s->start, 0, utc_zone); | ||
489 | period.end = icaltime_from_timet_with_zone (s->end, 0, utc_zone); | ||
490 | period.duration = icaldurationtype_null_duration(); | ||
491 | |||
492 | |||
493 | p = icalproperty_new_freebusy(period); | ||
494 | param = icalparameter_new_fbtype(ICAL_FBTYPE_BUSY); | ||
495 | icalproperty_add_parameter(p, param); | ||
496 | |||
497 | icalcomponent_add_property(comp, p); | ||
498 | } | ||
499 | |||
500 | } | ||
501 | |||
502 | return comp; | ||
503 | } | ||
504 | |||
505 | |||
506 | /** @brief Return a spanlist corresponding to the VFREEBUSY portion of | ||
507 | * an icalcomponent. | ||
508 | * | ||
509 | * @param c A valid icalcomponent. | ||
510 | * | ||
511 | * @return A valid icalspanlist or NULL if no VFREEBUSY section. | ||
512 | * | ||
513 | */ | ||
514 | |||
515 | |||
516 | icalspanlist *icalspanlist_from_vfreebusy(icalcomponent* comp) | ||
517 | { | ||
518 | icalcomponent *inner; | ||
519 | icalproperty *prop; | ||
520 | icalspanlist *sl; | ||
521 | |||
522 | icalerror_check_arg_rz((comp != NULL), "comp"); | ||
523 | |||
524 | inner = icalcomponent_get_inner(comp); | ||
525 | if (!inner) return NULL; | ||
526 | |||
527 | if ( ( sl = (icalspanlist*) malloc(sizeof(icalspanlist))) == 0) { | ||
528 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
529 | return 0; | ||
530 | } | ||
531 | sl->spans = pvl_newlist(); | ||
532 | |||
533 | /* cycle through each FREEBUSY property, adding to the spanlist */ | ||
534 | for (prop = icalcomponent_get_first_property(inner, ICAL_FREEBUSY_PROPERTY); | ||
535 | prop != NULL; | ||
536 | prop = icalcomponent_get_next_property(inner, ICAL_FREEBUSY_PROPERTY)) { | ||
537 | icaltime_span *s = (icaltime_span *) malloc(sizeof(icaltime_span)); | ||
538 | icalparameter *param; | ||
539 | struct icalperiodtype period; | ||
540 | icalparameter_fbtype fbtype; | ||
541 | |||
542 | if (s == 0) { | ||
543 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | param = icalproperty_get_first_parameter(prop, ICAL_FBTYPE_PARAMETER); | ||
548 | fbtype = (param) ? icalparameter_get_fbtype(param) : ICAL_FBTYPE_BUSY; | ||
549 | |||
550 | switch (fbtype) { | ||
551 | case ICAL_FBTYPE_FREE: | ||
552 | case ICAL_FBTYPE_NONE: | ||
553 | case ICAL_FBTYPE_X: | ||
554 | s->is_busy = 1; | ||
555 | default: | ||
556 | s->is_busy = 0; | ||
557 | } | ||
558 | |||
559 | period = icalproperty_get_freebusy(prop); | ||
560 | s->start = icaltime_as_timet_with_zone(period.start, icaltimezone_get_utc_timezone()); | ||
561 | s->end = icaltime_as_timet_with_zone(period.end, icaltimezone_get_utc_timezone()); | ||
562 | ; | ||
563 | pvl_insert_ordered(sl->spans, compare_span, (void*)s); | ||
564 | } | ||
565 | /** @todo calculate start/end limits.. fill in holes? **/ | ||
566 | return sl; | ||
567 | } | ||