]> code.citadel.org Git - citadel.git/blob - webcit/calendar.c
* ugly icon (won't be ugly with background)
[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 <time.h>
27 #include "webcit.h"
28 #include "webserver.h"
29
30 #ifndef HAVE_ICAL_H
31
32 /*
33  * Handler stubs for builds with no calendar library available
34  */
35 void cal_process_attachment(char *part_source) {
36
37         wprintf("<I>This message contains calendaring/scheduling information,"
38                 " but support for calendars is not available on this "
39                 "particular system.  Please ask your system administrator to "
40                 "install a new version of the Citadel web service with "
41                 "calendaring enabled.</I><BR>\n"
42         );
43
44 }
45
46 void display_calendar(long msgnum) {
47         wprintf("<i>"
48                 "Cannot display calendar item.  You are seeing this error "
49                 "because your WebCit service has not been installed with "
50                 "calendar support.  Please contact your system administrator."
51                 "</i><br>\n");
52 }
53
54 void display_task(long msgnum) {
55         wprintf("<i>"
56                 "Cannot display to-do item.  You are seeing this error "
57                 "because your WebCit service has not been installed with "
58                 "calendar support.  Please contact your system administrator."
59                 "</i><br>\n");
60 }
61
62 #else /* HAVE_ICAL_H */
63
64
65 /******   End of handler stubs.  Everything below this line is real.   ******/
66
67
68
69
70 /*
71  * Process a calendar object
72  * ...at this point it's already been deserialized by cal_process_attachment()
73  */
74 void cal_process_object(icalcomponent *cal) {
75         icalcomponent *c;
76
77         /* Iterate through all subcomponents */
78         wprintf("Iterating through all sub-components<BR>\n");
79         for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
80             (c != 0);
81             c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) {
82                 /* Recursively process subcomponent */
83                 cal_process_object(c);
84         }
85
86 }
87
88
89 /*
90  * Deserialize a calendar object in a message so it can be processed.
91  * (This is the main entry point for these things)
92  */
93 void cal_process_attachment(char *part_source) {
94         icalcomponent *cal;
95
96         wprintf("Processing calendar attachment<BR>\n");
97         cal = icalcomponent_new_from_string(part_source);
98
99         if (cal == NULL) {
100                 wprintf("Error parsing calendar object: %s<BR>\n",
101                         icalerror_strerror(icalerrno));
102                 return;
103         }
104
105         cal_process_object(cal);
106
107         /* Free the memory we obtained from libical's constructor */
108         icalcomponent_free(cal);
109 }
110
111 /*****************************************************************************/
112
113
114
115 /*
116  * Display handlers for message reading
117  */
118
119
120
121 /*
122  * If we're reading calendar items, just store them for now.  We have to
123  * sort and re-output them later when we draw the calendar.
124  */
125 void display_individual_cal(icalcomponent *cal, long msgnum) {
126
127         WC->num_cal += 1;
128
129         WC->disp_cal = realloc(WC->disp_cal,
130                         (sizeof(icalcomponent *) * WC->num_cal) );
131         WC->disp_cal[WC->num_cal - 1] = icalcomponent_new_clone(cal);
132
133         WC->cal_msgnum = realloc(WC->cal_msgnum,
134                         (sizeof(long) * WC->num_cal) );
135         WC->cal_msgnum[WC->num_cal - 1] = msgnum;
136 }
137
138
139
140 /*
141  * Display a task in the task list
142  */
143 void display_individual_task(icalcomponent *vtodo, long msgnum) {
144         icalproperty *p;
145
146         p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY);
147         wprintf("<LI><A HREF=\"/display_edit_task?msgnum=%ld\">", msgnum);
148         if (p != NULL) {
149                 escputs((char *)icalproperty_get_comment(p));
150         }
151         wprintf("</A>\n");
152 }
153
154
155 /*
156  * Display a task by itself (for editing)
157  */
158 void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum) {
159         icalcomponent *vtodo;
160         icalproperty *p;
161         struct icaltimetype t;
162         time_t now;
163         int created_new_vtodo = 0;
164
165         now = time(NULL);
166
167         if (supplied_vtodo != NULL) {
168                 vtodo = supplied_vtodo;
169         }
170         else {
171                 vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
172                 created_new_vtodo = 1;
173         }
174
175         output_headers(3);
176         wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=007700><TR><TD>"
177                 "<FONT SIZE=+1 COLOR=\"FFFFFF\""
178                 "<B>Edit task</B>"
179                 "</FONT></TD></TR></TABLE><BR>\n"
180         );
181
182         wprintf("<FORM METHOD=\"POST\" ACTION=\"/save_task\">\n");
183         wprintf("<INPUT TYPE=\"hidden\" NAME=\"msgnum\" VALUE=\"%ld\">\n",
184                 msgnum);
185
186         wprintf("Summary: "
187                 "<INPUT TYPE=\"text\" NAME=\"summary\" "
188                 "MAXLENGTH=\"64\" SIZE=\"64\" VALUE=\"");
189         p = icalcomponent_get_first_property(vtodo, ICAL_SUMMARY_PROPERTY);
190         if (p != NULL) {
191                 escputs((char *)icalproperty_get_comment(p));
192         }
193         wprintf("\"><BR>\n");
194
195         wprintf("Start date: ");
196         p = icalcomponent_get_first_property(vtodo, ICAL_DTSTART_PROPERTY);
197         if (p != NULL) {
198                 t = icalproperty_get_dtstart(p);
199         }
200         else {
201                 t = icaltime_from_timet(now, 0);
202         }
203         display_icaltimetype_as_webform(&t, "dtstart");
204         wprintf("<BR>\n");
205
206         wprintf("Due date: ");
207         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
208         if (p != NULL) {
209                 t = icalproperty_get_due(p);
210         }
211         else {
212                 t = icaltime_from_timet(now, 0);
213         }
214         display_icaltimetype_as_webform(&t, "due");
215         wprintf("<BR>\n");
216
217         wprintf("<CENTER><TEXTAREA NAME=\"description\" wrap=soft "
218                 "ROWS=10 COLS=80 WIDTH=80>\n"
219         );
220         p = icalcomponent_get_first_property(vtodo, ICAL_DESCRIPTION_PROPERTY);
221         if (p != NULL) {
222                 escputs((char *)icalproperty_get_comment(p));
223         }
224         wprintf("</TEXTAREA><BR>\n");
225
226         wprintf("<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Save\">"
227                 "&nbsp;&nbsp;"
228                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Delete\">\n"
229                 "&nbsp;&nbsp;"
230                 "<INPUT TYPE=\"submit\" NAME=\"sc\" VALUE=\"Cancel\">\n"
231                 "</CENTER>\n"
232         );
233
234         wprintf("</FORM>\n");
235
236         wDumpContent(1);
237
238         if (created_new_vtodo) {
239                 icalcomponent_free(vtodo);
240         }
241 }
242
243 /*
244  * Save an edited task
245  */
246 void save_individual_task(icalcomponent *supplied_vtodo, long msgnum) {
247         char buf[SIZ];
248         int delete_existing = 0;
249         icalproperty *prop;
250         icalcomponent *vtodo;
251         int created_new_vtodo = 0;
252
253         if (supplied_vtodo != NULL) {
254                 vtodo = supplied_vtodo;
255         }
256         else {
257                 vtodo = icalcomponent_new(ICAL_VTODO_COMPONENT);
258                 created_new_vtodo = 1;
259         }
260
261         if (!strcasecmp(bstr("sc"), "Save")) {
262
263                 /* Replace values in the component with ones from the form */
264
265                 while (prop = icalcomponent_get_first_property(vtodo,
266                       ICAL_SUMMARY_PROPERTY), prop != NULL) {
267                         icalcomponent_remove_property(vtodo, prop);
268                 }
269                 icalcomponent_add_property(vtodo,
270                         icalproperty_new_summary(bstr("summary")));
271                 
272                 while (prop = icalcomponent_get_first_property(vtodo,
273                       ICAL_DESCRIPTION_PROPERTY), prop != NULL) {
274                         icalcomponent_remove_property(vtodo, prop);
275                 }
276                 icalcomponent_add_property(vtodo,
277                         icalproperty_new_description(bstr("description")));
278         
279                 while (prop = icalcomponent_get_first_property(vtodo,
280                       ICAL_DTSTART_PROPERTY), prop != NULL) {
281                         icalcomponent_remove_property(vtodo, prop);
282                 }
283                 icalcomponent_add_property(vtodo,
284                         icalproperty_new_dtstart(
285                                 icaltime_from_webform("dtstart")
286                         )
287                 );
288         
289                 while (prop = icalcomponent_get_first_property(vtodo,
290                       ICAL_DUE_PROPERTY), prop != NULL) {
291                         icalcomponent_remove_property(vtodo, prop);
292                 }
293                 icalcomponent_add_property(vtodo,
294                         icalproperty_new_due(
295                                 icaltime_from_webform("due")
296                         )
297                 );
298         
299                 /* Serialize it and save it to the message base */
300                 serv_puts("ENT0 1|||4");
301                 serv_gets(buf);
302                 if (buf[0] == '4') {
303                         serv_puts("Content-type: text/calendar");
304                         serv_puts("");
305                         serv_puts(icalcomponent_as_ical_string(vtodo));
306                         serv_puts("000");
307                         delete_existing = 1;
308                 }
309         }
310
311         /*
312          * If the user clicked 'Delete' then delete it, period.
313          */
314         if (!strcasecmp(bstr("sc"), "Delete")) {
315                 delete_existing = 1;
316         }
317
318         if ( (delete_existing) && (msgnum > 0L) ) {
319                 serv_printf("DELE %ld", atol(bstr("msgnum")));
320                 serv_gets(buf);
321         }
322
323         if (created_new_vtodo) {
324                 icalcomponent_free(vtodo);
325         }
326
327         /* Go back to the task list */
328         readloop("readfwd");
329 }
330
331
332
333 /*
334  * Code common to all display handlers.  Given a message number and a MIME
335  * type, we load the message and hunt for that MIME type.  If found, we load
336  * the relevant part, deserialize it into a libical component, filter it for
337  * the requested object type, and feed it to the specified handler.
338  */
339 void display_using_handler(long msgnum,
340                         char *mimetype,
341                         icalcomponent_kind which_kind,
342                         void (*callback)(icalcomponent *, long)
343         ) {
344         char buf[SIZ];
345         char mime_partnum[SIZ];
346         char mime_filename[SIZ];
347         char mime_content_type[SIZ];
348         char mime_disposition[SIZ];
349         int mime_length;
350         char relevant_partnum[SIZ];
351         char *relevant_source = NULL;
352         icalcomponent *cal, *c;
353
354         sprintf(buf, "MSG0 %ld|1", msgnum);     /* ask for headers only */
355         serv_puts(buf);
356         serv_gets(buf);
357         if (buf[0] != '1') return;
358
359         while (serv_gets(buf), strcmp(buf, "000")) {
360                 if (!strncasecmp(buf, "part=", 5)) {
361                         extract(mime_filename, &buf[5], 1);
362                         extract(mime_partnum, &buf[5], 2);
363                         extract(mime_disposition, &buf[5], 3);
364                         extract(mime_content_type, &buf[5], 4);
365                         mime_length = extract_int(&buf[5], 5);
366
367                         if (!strcasecmp(mime_content_type, "text/calendar")) {
368                                 strcpy(relevant_partnum, mime_partnum);
369                         }
370
371                 }
372         }
373
374         if (strlen(relevant_partnum) > 0) {
375                 relevant_source = load_mimepart(msgnum, relevant_partnum);
376                 if (relevant_source != NULL) {
377
378                         cal = icalcomponent_new_from_string(relevant_source);
379                         if (cal != NULL) {
380
381                                 /* Simple components of desired type */
382                                 if (icalcomponent_isa(cal) == which_kind) {
383                                         callback(cal, msgnum);
384                                 }
385
386                                 /* Subcomponents of desired type */
387                                 for (c = icalcomponent_get_first_component(cal,
388                                     which_kind);
389                                     (c != 0);
390                                     c = icalcomponent_get_next_component(cal,
391                                     which_kind)) {
392                                         callback(c, msgnum);
393                                 }
394                                 icalcomponent_free(cal);
395                         }
396                         free(relevant_source);
397                 }
398         }
399
400 }
401
402 void display_calendar(long msgnum) {
403         display_using_handler(msgnum, "text/calendar",
404                                 ICAL_VEVENT_COMPONENT,
405                                 display_individual_cal);
406 }
407
408 void display_task(long msgnum) {
409         display_using_handler(msgnum, "text/calendar",
410                                 ICAL_VTODO_COMPONENT,
411                                 display_individual_task);
412 }
413
414 void display_edit_task(void) {
415         long msgnum = 0L;
416
417         msgnum = atol(bstr("msgnum"));
418         if (msgnum > 0L) {
419                 /* existing task */
420                 display_using_handler(msgnum, "text/calendar",
421                                 ICAL_VTODO_COMPONENT,
422                                 display_edit_individual_task);
423         }
424         else {
425                 /* new task */
426                 display_edit_individual_task(NULL, 0L);
427         }
428 }
429
430 void save_task(void) {
431         long msgnum = 0L;
432
433         msgnum = atol(bstr("msgnum"));
434         if (msgnum > 0L) {
435                 display_using_handler(msgnum, "text/calendar",
436                                 ICAL_VTODO_COMPONENT,
437                                 save_individual_task);
438         }
439         else {
440                 save_individual_task(NULL, 0L);
441         }
442 }
443
444 void display_edit_event(void) {
445         long msgnum = 0L;
446
447         msgnum = atol(bstr("msgnum"));
448         if (msgnum > 0L) {
449                 /* existing event */
450                 display_using_handler(msgnum, "text/calendar",
451                                 ICAL_VEVENT_COMPONENT,
452                                 display_edit_individual_event);
453         }
454         else {
455                 /* new event */
456                 display_edit_individual_event(NULL, 0L);
457         }
458 }
459
460 void save_event(void) {
461         long msgnum = 0L;
462
463         msgnum = atol(bstr("msgnum"));
464
465         if (msgnum > 0L) {
466                 display_using_handler(msgnum, "text/calendar",
467                                 ICAL_VEVENT_COMPONENT,
468                                 save_individual_event);
469         }
470         else {
471                 save_individual_event(NULL, 0L);
472         }
473 }
474
475 #endif /* HAVE_ICAL_H */