]> Pileus Git - lackey/blob - cals/ical.c
Fix some ical memory issues
[lackey] / cals / ical.c
1 /*
2  * Copyright (C) 2012 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <libical/ical.h>
21
22 #include "util.h"
23 #include "date.h"
24 #include "cal.h"
25
26 /* Local types */
27 typedef struct {
28         icalcomponent *comp;
29         struct icaltimetype start;
30         struct icaltimetype end;
31 } ical_inst;
32
33 /* Helper functions */
34 static int ical_compare(const void *_a, const void *_b)
35 {
36         const ical_inst *a = _a;
37         const ical_inst *b = _b;
38         int scomp = icaltime_compare(a->start, b->start);
39         int ecomp = icaltime_compare(a->end,   b->end);
40         return scomp != 0 ? scomp :
41                ecomp != 0 ? ecomp : 0 ;
42 }
43
44 static date_t to_date(struct icaltimetype time)
45 {
46         return (date_t){
47                 .year  = time.year,
48                 .month = time.month ? time.month-1 : 0,
49                 .day   = time.day   ? time.day  -1 : 0,
50                 .hour  = time.hour,
51                 .min   = time.minute,
52         };
53 }
54
55 static void add_recur(icalarray *array, icalcomponent *comp,
56                 icaltimetype start, icaltimetype end,
57                 icalcomponent_kind which)
58 {
59         icalcomponent_kind kind = icalcomponent_isa(comp);
60
61         if (kind == which) {
62                 /* Get recurrence data */
63                 struct icaltimetype cstart, cend; // Component times
64                 struct icaltimetype istart, iend; // Instance times
65                 struct icaldurationtype length;   // Duration
66
67                 icalproperty             *rrule;
68                 struct icalrecurrencetype recur;
69                 icalrecur_iterator       *iter;
70
71                 cstart = icalcomponent_get_dtstart(comp);
72                 cend   = icalcomponent_get_dtend(comp);
73                 length = icaltime_subtract(cend, cstart);
74
75                 rrule  = icalcomponent_get_first_property(comp, ICAL_RRULE_PROPERTY);
76                 recur  = icalproperty_get_rrule(rrule);
77                 iter   = icalrecur_iterator_new(recur, cstart);
78
79                 /* Add recurrences */
80                 if (icaltime_is_null_time(cstart) ||
81                     which == ICAL_VTODO_COMPONENT) {
82                         icalarray_append(array, &(ical_inst){
83                                 .comp  = comp,
84                                 .start = cstart,
85                                 .end   = cend,
86                         });
87                 } else while (1) {
88                         istart = iend = icalrecur_iterator_next(iter);
89                         if (icaltime_is_null_time(istart))
90                                 break;    // no more instances
91                         if (!icaltime_is_null_time(cend))
92                                 iend = icaltime_add(iend, length);
93
94                         if (icaltime_compare(iend, start) <= 0)
95                                 continue; // instance ends before start time
96                         if (icaltime_compare(istart, end) >= 0)
97                                 break;    // instance begins after stop time
98
99                         icalarray_append(array, &(ical_inst){
100                                 .comp  = comp,
101                                 .start = istart,
102                                 .end   = iend,
103                         });
104                 }
105
106                 icalrecur_iterator_free(iter);
107         }
108
109         /* Add children */
110         icalcomponent_kind find = ICAL_ANY_COMPONENT;
111         icalcomponent *child = icalcomponent_get_first_component(comp, find);
112         while (child) {
113                 add_recur(array, child, start, end, which);
114                 child = icalcomponent_get_next_component(comp, find);
115         }
116 }
117
118 /* Event functions */
119 static event_t *to_event(ical_inst *inst)
120 {
121         icalproperty *prop = icalcomponent_get_first_property(inst->comp, ICAL_CATEGORIES_PROPERTY);
122
123         event_t *event = new0(event_t);
124         event->name  = strcopy(icalcomponent_get_summary(inst->comp));
125         event->desc  = strcopy(icalcomponent_get_description(inst->comp));
126         event->loc   = strcopy(icalcomponent_get_location(inst->comp));
127         event->cat   = icalproperty_get_value_as_string_r(prop);
128         event->start = to_date(inst->start);
129         event->end   = to_date(inst->end);
130         return event;
131 }
132
133 static event_t *to_events(icalarray *array)
134 {
135         event_t  list = {};
136         event_t *tail = &list;
137         for (int i = 0; i < array->num_elements; i++) {
138                  ical_inst *inst = icalarray_element_at(array, i);
139                  tail->next = to_event(inst);
140                  tail = tail->next;
141         }
142         return list.next;
143 }
144
145 static void print_events(event_t *start)
146 {
147         for (event_t *cur = start; cur; cur = cur->next)
148                 printf("%04d-%02d-%02d %02d:%02d - %s\n",
149                         cur->start.year, cur->start.month, cur->start.day,
150                         cur->start.hour, cur->start.min,
151                         cur->name ?: cur->desc ?: "[no summary]");
152 }
153
154 /* Todo functions */
155 static todo_t *to_todo(ical_inst *inst)
156 {
157         icalproperty *cat  = icalcomponent_get_first_property(inst->comp, ICAL_CATEGORIES_PROPERTY);
158         icalproperty *perc = icalcomponent_get_first_property(inst->comp, ICAL_PERCENTCOMPLETE_PROPERTY);
159
160         todo_t *todo = new0(todo_t);
161         todo->name   = strcopy(icalcomponent_get_summary(inst->comp));
162         todo->desc   = strcopy(icalcomponent_get_description(inst->comp));
163         todo->cat    = strcopy(icalproperty_get_value_as_string(cat));
164         todo->status = icalcomponent_get_status(inst->comp) == ICAL_STATUS_COMPLETED ? 100 :
165                        perc ? icalproperty_get_percentcomplete(perc) : 0;
166         todo->start  = to_date(inst->start);
167         todo->due    = to_date(icalcomponent_get_due(inst->comp));
168         return todo;
169 }
170
171 static todo_t *to_todos(icalarray *array)
172 {
173         todo_t  list = {};
174         todo_t *tail = &list;
175         for (int i = 0; i < array->num_elements; i++) {
176                  ical_inst *inst = icalarray_element_at(array, i);
177                  tail->next = to_todo(inst);
178                  tail = tail->next;
179         }
180         return list.next;
181 }
182
183 static void print_todos(todo_t *start)
184 {
185         for (todo_t *cur = start; cur; cur = cur->next)
186                 printf("%04d-%02d-%02d %02d:%02d - %d%% - %s\n",
187                         cur->due.year, cur->due.month, cur->due.day,
188                         cur->due.hour, cur->due.min,   cur->status,
189                         cur->name ?: cur->desc ?: "[no summary]");
190 }
191
192 /* Event functions */
193 event_t *ical_events(cal_t *cal, year_t year, month_t month, day_t day, int days)
194 {
195         /* Load ical */
196         FILE *file = fopen("data/all.ics", "r");
197         if (!file)
198                 return NULL;
199         icalparser *parser = icalparser_new();
200         icalparser_set_gen_data(parser, file);
201         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
202         icalparser_free(parser);
203
204         /* Add events */
205         icalarray *array = icalarray_new(sizeof(ical_inst), 1);
206         icaltimetype start = {.year = 2000};
207         icaltimetype end   = {.year = 2020};
208         add_recur(array, ical, start, end, ICAL_VEVENT_COMPONENT);
209         icalarray_sort(array, ical_compare);
210         event_t *events = to_events(array);
211         icalarray_free(array);
212         icalcomponent_free(ical);
213
214         return events;
215 }
216
217 /* Todo functions */
218 todo_t *ical_todos(cal_t *cal, year_t year, month_t month, day_t day, int days)
219 {
220         /* Load ical */
221         FILE *file = fopen("data/all.ics", "r");
222         if (!file)
223                 return NULL;
224         icalparser *parser = icalparser_new();
225         icalparser_set_gen_data(parser, file);
226         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
227         icalparser_free(parser);
228
229         /* Add todos */
230         icalarray *array = icalarray_new(sizeof(ical_inst), 1);
231         icaltimetype start = {.year = 2000};
232         icaltimetype end   = {.year = 2020};
233         add_recur(array, ical, start, end, ICAL_VTODO_COMPONENT);
234         icalarray_sort(array, ical_compare);
235         todo_t *todos = to_todos(array);
236         icalarray_free(array);
237         icalcomponent_free(ical);
238
239         return todos;
240 }
241
242 /* Test functions */
243 void ical_printr(icalcomponent *comp, int depth)
244 {
245         /* Print component */
246         icalcomponent_kind kind = icalcomponent_isa(comp);
247         printf("%*s", depth, "");
248         printf("%s",  icalcomponent_kind_to_string(kind));
249         if (kind == ICAL_VEVENT_COMPONENT ||
250             kind == ICAL_VTODO_COMPONENT)
251                 printf(" - %s", icalcomponent_get_summary(comp) ?: "[no summary]");
252         printf("\n");
253
254         /* Print children */
255         icalcomponent_kind find = ICAL_ANY_COMPONENT;
256         icalcomponent *child = icalcomponent_get_first_component(comp, find);
257         while (child) {
258                 ical_printr(child, depth+2);
259                 child = icalcomponent_get_next_component(comp, find);
260         }
261 }
262
263 void ical_test(void)
264 {
265         /* Load ical */
266         FILE *file = fopen("data/all.ics", "r");
267         icalparser *parser = icalparser_new();
268         icalparser_set_gen_data(parser, file);
269         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
270
271         /* Misc */
272         icalarray *array;
273         icaltimetype start = {.year = 2000};
274         icaltimetype end   = {.year = 2020};
275
276         /* Find events */
277         array = icalarray_new(sizeof(ical_inst), 1);
278         add_recur(array, ical, start, end, ICAL_VEVENT_COMPONENT);
279         icalarray_sort(array, ical_compare);
280         event_t *events = to_events(array);
281         icalarray_free(array);
282
283         /* Find Todos */
284         array = icalarray_new(sizeof(ical_inst), 1);
285         add_recur(array, ical, start, end, ICAL_VTODO_COMPONENT);
286         icalarray_sort(array, ical_compare);
287         todo_t *todos = to_todos(array);
288         icalarray_free(array);
289
290         /* Print */
291         //ical_printr(ical, 0);
292         //print_events(events);
293         print_todos(todos);
294
295         (void)print_events;
296         (void)print_todos;
297         (void)events;
298         (void)todos;
299
300         /* Cleanup */
301         icalparser_free(parser);
302 }