]> code.citadel.org Git - citadel.git/blob - webcit/calendar.c
* save/delete/cancel
[citadel.git] / webcit / calendar.c
1 /*
2  * $Id$
3  *
4  * Functions which handle calendar objects and their processing/display.
5  *
6  */
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <sys/socket.h>
17 #include <limits.h>
18 #include <netinet/in.h>
19 #include <netdb.h>
20 #include <string.h>
21 #include <pwd.h>
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include "webcit.h"
27 #include "webserver.h"
28
29 #ifdef HAVE_ICAL_H
30 #include <ical.h>
31 #endif
32
33
34 #ifndef HAVE_ICAL_H
35
36 /*
37  * Handler stubs for builds with no calendar library available
38  */
39 void cal_process_attachment(char *part_source) {
40
41         wprintf("<I>This message contains calendaring/scheduling information,"
42                 " but support for calendars is not available on this "
43                 "particular system.  Please ask your system administrator to "
44                 "install a new version of the Citadel web service with "
45                 "calendaring enabled.</I><BR>\n"
46         );
47
48 }
49
50 void display_calendar(long msgnum) {
51         wprintf("<i>Cannot display calendar item</i><br>\n");
52 }
53
54 void display_task(long msgnum) {
55         wprintf("<i>Cannot display item from task list</i><br>\n");
56 }
57
58 #else /* HAVE_ICAL_H */
59
60
61 /******   End of handler stubs.  Everything below this line is real.   ******/
62
63
64 /*
65  * Process a single calendar component.
66  * It won't be a compound component at this point because those have
67  * already been broken down by cal_process_object().
68  */
69 void cal_process_subcomponent(icalcomponent *cal) {
70         wprintf("cal_process_subcomponent() called<BR>\n");
71         wprintf("cal_process_subcomponent() exiting<BR>\n");
72 }
73
74
75
76
77
78 /*
79  * Process a calendar object
80  * ...at this point it's already been deserialized by cal_process_attachment()
81  */
82 void cal_process_object(icalcomponent *cal) {
83         icalcomponent *c;
84         int num_subcomponents = 0;
85
86         wprintf("cal_process_object() called<BR>\n");
87
88         /* Iterate through all subcomponents */
89         wprintf("Iterating through all sub-components<BR>\n");
90         for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
91             (c != 0);
92             c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) {
93                 cal_process_subcomponent(c);
94                 ++num_subcomponents;
95         }
96
97         /* Iterate through all subcomponents */
98         wprintf("Iterating through VEVENTs<BR>\n");
99         for (c = icalcomponent_get_first_component(cal, ICAL_VEVENT_COMPONENT);
100             (c != 0);
101             c = icalcomponent_get_next_component(cal, ICAL_VEVENT_COMPONENT)) {
102                 cal_process_subcomponent(c);
103                 --num_subcomponents;
104         }
105
106         /* Iterate through all subcomponents */
107         wprintf("Iterating through VTODOs<BR>\n");
108         for (c = icalcomponent_get_first_component(cal, ICAL_VTODO_COMPONENT);
109             (c != 0);
110             c = icalcomponent_get_next_component(cal, ICAL_VTODO_COMPONENT)) {
111                 cal_process_subcomponent(c);
112                 --num_subcomponents;
113         }
114
115         /* Iterate through all subcomponents */
116         wprintf("Iterating through VJOURNALs<BR>\n");
117         for (c = icalcomponent_get_first_component(cal, ICAL_VJOURNAL_COMPONENT);
118             (c != 0);
119             c = icalcomponent_get_next_component(cal, ICAL_VJOURNAL_COMPONENT)) {
120                 cal_process_subcomponent(c);
121                 --num_subcomponents;
122         }
123
124         /* Iterate through all subcomponents */
125         wprintf("Iterating through VCALENDARs<BR>\n");
126         for (c = icalcomponent_get_first_component(cal, ICAL_VCALENDAR_COMPONENT);
127             (c != 0);
128             c = icalcomponent_get_next_component(cal, ICAL_VCALENDAR_COMPONENT)) {
129                 cal_process_subcomponent(c);
130                 --num_subcomponents;
131         }
132
133         /* Iterate through all subcomponents */
134         wprintf("Iterating through VFREEBUSYs<BR>\n");
135         for (c = icalcomponent_get_first_component(cal, ICAL_VFREEBUSY_COMPONENT);
136             (c != 0);
137             c = icalcomponent_get_next_component(cal, ICAL_VFREEBUSY_COMPONENT)) {
138                 cal_process_subcomponent(c);
139                 --num_subcomponents;
140         }
141
142         /* Iterate through all subcomponents */
143         wprintf("Iterating through VALARMs<BR>\n");
144         for (c = icalcomponent_get_first_component(cal, ICAL_VALARM_COMPONENT);
145             (c != 0);
146             c = icalcomponent_get_next_component(cal, ICAL_VALARM_COMPONENT)) {
147                 cal_process_subcomponent(c);
148                 --num_subcomponents;
149         }
150
151         /* Iterate through all subcomponents */
152         wprintf("Iterating through VTIMEZONEs<BR>\n");
153         for (c = icalcomponent_get_first_component(cal, ICAL_VTIMEZONE_COMPONENT);
154             (c != 0);
155             c = icalcomponent_get_next_component(cal, ICAL_VTIMEZONE_COMPONENT)) {
156                 cal_process_subcomponent(c);
157                 --num_subcomponents;
158         }
159
160         /* Iterate through all subcomponents */
161         wprintf("Iterating through VSCHEDULEs<BR>\n");
162         for (c = icalcomponent_get_first_component(cal, ICAL_VSCHEDULE_COMPONENT);
163             (c != 0);
164             c = icalcomponent_get_next_component(cal, ICAL_VSCHEDULE_COMPONENT)) {
165                 cal_process_subcomponent(c);
166                 --num_subcomponents;
167         }
168
169         /* Iterate through all subcomponents */
170         wprintf("Iterating through VQUERYs<BR>\n");
171         for (c = icalcomponent_get_first_component(cal, ICAL_VQUERY_COMPONENT);
172             (c != 0);
173             c = icalcomponent_get_next_component(cal, ICAL_VQUERY_COMPONENT)) {
174                 cal_process_subcomponent(c);
175                 --num_subcomponents;
176         }
177
178         /* Iterate through all subcomponents */
179         wprintf("Iterating through VCARs<BR>\n");
180         for (c = icalcomponent_get_first_component(cal, ICAL_VCAR_COMPONENT);
181             (c != 0);
182             c = icalcomponent_get_next_component(cal, ICAL_VCAR_COMPONENT)) {
183                 cal_process_subcomponent(c);
184                 --num_subcomponents;
185         }
186
187         /* Iterate through all subcomponents */
188         wprintf("Iterating through VCOMMANDs<BR>\n");
189         for (c = icalcomponent_get_first_component(cal, ICAL_VCOMMAND_COMPONENT);
190             (c != 0);
191             c = icalcomponent_get_next_component(cal, ICAL_VCOMMAND_COMPONENT)) {
192                 cal_process_subcomponent(c);
193                 --num_subcomponents;
194         }
195
196         if (num_subcomponents != 0) {
197                 wprintf("Warning: %d subcomponents unhandled<BR>\n",
198                         num_subcomponents);
199         }
200
201         wprintf("cal_process_object() exiting<BR>\n");
202 }
203
204
205 /*
206  * Deserialize a calendar object in a message so it can be processed.
207  * (This is the main entry point for these things)
208  */
209 void cal_process_attachment(char *part_source) {
210         icalcomponent *cal;
211
212         wprintf("Processing calendar attachment<BR>\n");
213         cal = icalcomponent_new_from_string(part_source);
214
215         if (cal == NULL) {
216                 wprintf("Error parsing calendar object: %s<BR>\n",
217                         icalerror_strerror(icalerrno));
218                 return;
219         }
220
221         cal_process_object(cal);
222
223         /* Free the memory we obtained from libical's constructor */
224         icalcomponent_free(cal);
225 }
226
227 /*****************************************************************************/
228
229
230
231
232
233 /*
234  * Display handlers for message reading
235  */
236 void display_individual_cal(icalcomponent *cal, long msgnum) {
237         wprintf("display_individual_cal() called<BR>\n");
238 }
239
240
241
242 /*
243  * Display a task in the task list
244  */
245 void display_individual_task(icalcomponent *vtodo, long msgnum) {
246         icalproperty *p;
247
248         p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY);
249         wprintf("<LI><A HREF=\"/display_edit_task?msgnum=%ld\">", msgnum);
250         if (p != NULL) escputs((char *)icalproperty_get_comment(p));
251         wprintf("</A>\n");
252         icalproperty_free(p);
253 }
254
255
256 /*
257  * Display a task by itself (for editing)
258  */
259 void display_edit_individual_task(icalcomponent *vtodo, long msgnum) {
260         icalproperty *p;
261
262         output_headers(3);
263         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=007700><TR><TD>"
264                 "<FONT SIZE=+1 COLOR=\"FFFFFF\""
265                 "<B>Edit task</B>"
266                 "</FONT></TD></TR></TABLE><BR>\n"
267         );
268
269         wprintf("<FORM METHOD=\"POST\" ACTION=\"/save_task\">\n");
270         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgnum\" VALUE=\"%ld\">\n",
271                 msgnum);
272
273         wprintf("Summary: "
274                 "<INPUT TYPE=\"text\" NAME=\"summary\" "
275                 "MAXLENGTH=\"64\" SIZE=\"64\" VALUE=\"");
276         p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY);
277         if (p != NULL) escputs((char *)icalproperty_get_comment(p));
278         icalproperty_free(p);
279         wprintf("\"><BR>\n");
280
281         wprintf("Start date: FIXME <BR>\n");
282
283         wprintf("Due date: FIXME <BR>\n");
284
285         wprintf("<CENTER><TEXTAREA NAME=\"msgtext\" wrap=soft "
286                 "ROWS=10 COLS=80 WIDTH=80>\n"
287         );
288         p = icalcomponent_get_first_property(vtodo, ICAL_DESCRIPTION_PROPERTY);
289         if (p != NULL) escputs((char *)icalproperty_get_comment(p));
290         icalproperty_free(p);
291         wprintf("</TEXTAREA><BR>\n");
292
293         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Save\">"
294                 "&nbsp;&nbsp;"
295                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Delete\">\n"
296                 "&nbsp;&nbsp;"
297                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\">\n"
298                 "</CENTER>\n"
299         );
300
301         wprintf("</FORM>\n");
302
303         wDumpContent(1);
304 }
305
306 /*
307  * Save an edited task
308  */
309 void edit_individual_task(icalcomponent *vtodo, long msgnum) {
310         char buf[SIZ];
311
312         if (!strcasecmp(bstr("sc"), "Save")) {
313
314                 /* FIXME
315                         1. Replace property values with ones from the form
316                         2. Serialize the task
317                         3. Make a message out of it
318                         4. Delete the existing message (msgnum)
319                         5. Save the new message
320                 */
321
322         }
323
324         if ( (!strcasecmp(bstr("sc"), "Save"))
325            || (!strcasecmp(bstr("sc"), "Delete")) ) {
326                 serv_printf("DELE %ld", atol(bstr("msgnum")));
327                 serv_gets(buf);
328         }
329
330         /* Go back to the task list */
331         readloop("readfwd");
332 }
333
334
335
336 /*
337  * Code common to all display handlers.  Given a message number and a MIME
338  * type, we load the message and hunt for that MIME type.  If found, we load
339  * the relevant part, deserialize it into a libical component, filter it for
340  * the requested object type, and feed it to the specified handler.
341  */
342 void display_using_handler(long msgnum,
343                         char *mimetype,
344                         icalcomponent_kind which_kind,
345                         void (*callback)(icalcomponent *, long)
346         ) {
347         char buf[SIZ];
348         char mime_partnum[SIZ];
349         char mime_filename[SIZ];
350         char mime_content_type[SIZ];
351         char mime_disposition[SIZ];
352         int mime_length;
353         char relevant_partnum[SIZ];
354         char *relevant_source = NULL;
355         icalcomponent *cal, *c;
356
357         sprintf(buf, "MSG0 %ld|1", msgnum);     /* ask for headers only */
358         serv_puts(buf);
359         serv_gets(buf);
360         if (buf[0] != '1') return;
361
362         while (serv_gets(buf), strcmp(buf, "000")) {
363                 if (!strncasecmp(buf, "part=", 5)) {
364                         extract(mime_filename, &buf[5], 1);
365                         extract(mime_partnum, &buf[5], 2);
366                         extract(mime_disposition, &buf[5], 3);
367                         extract(mime_content_type, &buf[5], 4);
368                         mime_length = extract_int(&buf[5], 5);
369
370                         if (!strcasecmp(mime_content_type, "text/calendar")) {
371                                 strcpy(relevant_partnum, mime_partnum);
372                         }
373
374                 }
375         }
376
377         if (strlen(relevant_partnum) > 0) {
378                 relevant_source = load_mimepart(msgnum, relevant_partnum);
379                 if (relevant_source != NULL) {
380
381                         /* Display the task */
382                         cal = icalcomponent_new_from_string(relevant_source);
383                         if (cal != NULL) {
384                                 for (c = icalcomponent_get_first_component(cal,
385                                     which_kind);
386                                     (c != 0);
387                                     c = icalcomponent_get_next_component(cal,
388                                     which_kind)) {
389                                         callback(c, msgnum);
390                                 }
391                                 icalcomponent_free(cal);
392                         }
393                         free(relevant_source);
394                 }
395         }
396
397 }
398
399 void display_calendar(long msgnum) {
400         display_using_handler(msgnum, "text/calendar",
401                                 ICAL_ANY_COMPONENT,
402                                 display_individual_cal);
403 }
404
405 void display_task(long msgnum) {
406         display_using_handler(msgnum, "text/calendar",
407                                 ICAL_VTODO_COMPONENT,
408                                 display_individual_task);
409 }
410
411 void display_edit_task(void) {
412         long msgnum = 0L;
413
414         msgnum = atol(bstr("msgnum"));
415         display_using_handler(msgnum, "text/calendar",
416                                 ICAL_VTODO_COMPONENT,
417                                 display_edit_individual_task);
418 }
419
420 void save_task(void) {
421         long msgnum = 0L;
422
423         msgnum = atol(bstr("msgnum"));
424         display_using_handler(msgnum, "text/calendar",
425                                 ICAL_VTODO_COMPONENT,
426                                 edit_individual_task);
427 }
428
429 #endif /* HAVE_ICAL_H */