]> Pileus Git - lackey/blob - cals/ical.c
Add alloc0 and new0 functions
[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
107         /* Add children */
108         icalcomponent_kind find = ICAL_ANY_COMPONENT;
109         icalcomponent *child = icalcomponent_get_first_component(comp, find);
110         while (child) {
111                 add_recur(array, child, start, end, which);
112                 child = icalcomponent_get_next_component(comp, find);
113         }
114 }
115
116 /* Event functions */
117 static event_t *to_event(ical_inst *inst)
118 {
119         icalproperty *prop = icalcomponent_get_first_property(inst->comp, ICAL_CATEGORIES_PROPERTY);
120
121         event_t *event = new0(event_t);
122         event->name  = icalcomponent_get_summary(inst->comp);
123         event->desc  = icalcomponent_get_description(inst->comp);
124         event->loc   = icalcomponent_get_location(inst->comp);
125         event->cat   = icalproperty_get_value_as_string_r(prop);
126         event->start = to_date(inst->start);
127         event->end   = to_date(inst->end);
128         return event;
129 }
130
131 static event_t *to_events(icalarray *array)
132 {
133         event_t  list = {};
134         event_t *tail = &list;
135         for (int i = 0; i < array->num_elements; i++) {
136                  ical_inst *inst = icalarray_element_at(array, i);
137                  tail->next = to_event(inst);
138                  tail = tail->next;
139         }
140         return list.next;
141 }
142
143 static void print_events(event_t *start)
144 {
145         for (event_t *cur = start; cur; cur = cur->next)
146                 printf("%04d-%02d-%02d %02d:%02d - %s\n",
147                         cur->start.year, cur->start.month, cur->start.day,
148                         cur->start.hour, cur->start.min,
149                         cur->name ?: cur->desc ?: "[no summary]");
150 }
151
152 /* Todo functions */
153 static todo_t *to_todo(ical_inst *inst)
154 {
155         icalproperty *cat  = icalcomponent_get_first_property(inst->comp, ICAL_CATEGORIES_PROPERTY);
156         icalproperty *perc = icalcomponent_get_first_property(inst->comp, ICAL_PERCENTCOMPLETE_PROPERTY);
157
158         todo_t *todo = new0(todo_t);
159         todo->name   = icalcomponent_get_summary(inst->comp);
160         todo->desc   = icalcomponent_get_description(inst->comp);
161         todo->cat    = icalproperty_get_value_as_string(cat);
162         todo->status = icalcomponent_get_status(inst->comp) == ICAL_STATUS_COMPLETED ? 100 :
163                        perc ? icalproperty_get_percentcomplete(perc) : 0;
164         todo->start  = to_date(inst->start);
165         todo->due    = to_date(icalcomponent_get_due(inst->comp));
166         return todo;
167 }
168
169 static todo_t *to_todos(icalarray *array)
170 {
171         todo_t  list = {};
172         todo_t *tail = &list;
173         for (int i = 0; i < array->num_elements; i++) {
174                  ical_inst *inst = icalarray_element_at(array, i);
175                  tail->next = to_todo(inst);
176                  tail = tail->next;
177         }
178         return list.next;
179 }
180
181 static void print_todos(todo_t *start)
182 {
183         for (todo_t *cur = start; cur; cur = cur->next)
184                 printf("%04d-%02d-%02d %02d:%02d - %d%% - %s\n",
185                         cur->due.year, cur->due.month, cur->due.day,
186                         cur->due.hour, cur->due.min,   cur->status,
187                         cur->name ?: cur->desc ?: "[no summary]");
188 }
189
190 /* Event functions */
191 event_t *ical_events(cal_t *cal, year_t year, month_t month, day_t day, int days)
192 {
193         /* Load ical */
194         FILE *file = fopen("data/all.ics", "r");
195         if (!file)
196                 return NULL;
197         icalparser *parser = icalparser_new();
198         icalparser_set_gen_data(parser, file);
199         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
200
201         /* Add events */
202         icalarray *array = icalarray_new(sizeof(ical_inst), 1);
203         icaltimetype start = {.year = 2000};
204         icaltimetype end   = {.year = 2020};
205         add_recur(array, ical, start, end, ICAL_VEVENT_COMPONENT);
206         icalarray_sort(array, ical_compare);
207         return to_events(array);
208
209         /* Todo, memory management */
210 }
211
212 /* Todo functions */
213 todo_t *ical_todos(cal_t *cal, year_t year, month_t month, day_t day, int days)
214 {
215         /* Load ical */
216         FILE *file = fopen("data/all.ics", "r");
217         if (!file)
218                 return NULL;
219         icalparser *parser = icalparser_new();
220         icalparser_set_gen_data(parser, file);
221         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
222
223         /* Add todos */
224         icalarray *array = icalarray_new(sizeof(ical_inst), 1);
225         icaltimetype start = {.year = 2000};
226         icaltimetype end   = {.year = 2020};
227         add_recur(array, ical, start, end, ICAL_VTODO_COMPONENT);
228         icalarray_sort(array, ical_compare);
229         return to_todos(array);
230
231         /* Todo, memory management */
232 }
233
234 /* Test functions */
235 void ical_printr(icalcomponent *comp, int depth)
236 {
237         /* Print component */
238         icalcomponent_kind kind = icalcomponent_isa(comp);
239         printf("%*s", depth, "");
240         printf("%s",  icalcomponent_kind_to_string(kind));
241         if (kind == ICAL_VEVENT_COMPONENT ||
242             kind == ICAL_VTODO_COMPONENT)
243                 printf(" - %s", icalcomponent_get_summary(comp) ?: "[no summary]");
244         printf("\n");
245
246         /* Print children */
247         icalcomponent_kind find = ICAL_ANY_COMPONENT;
248         icalcomponent *child = icalcomponent_get_first_component(comp, find);
249         while (child) {
250                 ical_printr(child, depth+2);
251                 child = icalcomponent_get_next_component(comp, find);
252         }
253 }
254
255 void ical_test(void)
256 {
257         /* Load ical */
258         FILE *file = fopen("data/all.ics", "r");
259         icalparser *parser = icalparser_new();
260         icalparser_set_gen_data(parser, file);
261         icalcomponent *ical = icalparser_parse(parser, (void*)fgets);
262
263         /* Misc */
264         icalarray *array;
265         icaltimetype start = {.year = 2000};
266         icaltimetype end   = {.year = 2020};
267
268         /* Find events */
269         array = icalarray_new(sizeof(ical_inst), 1);
270         add_recur(array, ical, start, end, ICAL_VEVENT_COMPONENT);
271         icalarray_sort(array, ical_compare);
272         event_t *events = to_events(array);
273
274         /* Find Todos */
275         array = icalarray_new(sizeof(ical_inst), 1);
276         add_recur(array, ical, start, end, ICAL_VTODO_COMPONENT);
277         icalarray_sort(array, ical_compare);
278         todo_t *todos = to_todos(array);
279
280         /* Print */
281         //ical_printr(ical, 0);
282         //print_events(events);
283         print_todos(todos);
284
285         (void)print_events;
286         (void)print_todos;
287         (void)events;
288         (void)todos;
289
290         /* Cleanup */
291         icalparser_free(parser);
292 }