* All OS-level includes are now included from webcit.h instead of from
[citadel.git] / webcit / calendar_view.c
1 /*
2  * $Id$
3  *
4  * Handles the HTML display of calendar items.
5  */
6
7 #include "webcit.h"
8 #include "webserver.h"
9
10 #ifndef WEBCIT_WITH_CALENDAR_SERVICE
11
12 void do_calendar_view(void) {   /* stub for non-libical builds */
13         wprintf("<CENTER><I>Calendar view not available</I></CENTER><br />\n");
14 }
15
16 void do_tasks_view(void) {      /* stub for non-libical builds */
17         wprintf("<CENTER><I>Tasks view not available</I></CENTER><br />\n");
18 }
19
20 #else   /* WEBCIT_WITH_CALENDAR_SERVICE */
21
22 /****************************************************************************/
23
24
25 void calendar_month_view_display_events(time_t thetime) {
26         int i;
27         time_t event_tt;
28         struct tm event_tm;
29         struct tm today_tm;
30         icalproperty *p;
31         struct icaltimetype t;
32         int month, day, year;
33         int all_day_event = 0;
34
35         if (WC->num_cal == 0) {
36                 wprintf("<br /><br /><br />\n");
37                 return;
38         }
39
40         localtime_r(&thetime, &today_tm);
41         month = today_tm.tm_mon + 1;
42         day = today_tm.tm_mday;
43         year = today_tm.tm_year + 1900;
44
45         for (i=0; i<(WC->num_cal); ++i) {
46                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
47                                                 ICAL_DTSTART_PROPERTY);
48                 if (p != NULL) {
49                         t = icalproperty_get_dtstart(p);
50                         event_tt = icaltime_as_timet(t);
51
52                         if (t.is_date) all_day_event = 1;
53                         else all_day_event = 0;
54
55                         if (all_day_event) {
56                                 gmtime_r(&event_tt, &event_tm);
57                         }
58                         else {
59                                 localtime_r(&event_tt, &event_tm);
60                         }
61
62                         if ((event_tm.tm_year == today_tm.tm_year)
63                            && (event_tm.tm_mon == today_tm.tm_mon)
64                            && (event_tm.tm_mday == today_tm.tm_mday)) {
65
66                                 p = icalcomponent_get_first_property(
67                                                         WC->disp_cal[i].cal,
68                                                         ICAL_SUMMARY_PROPERTY);
69                                 if (p != NULL) {
70
71                                         if (all_day_event) {
72                                                 wprintf("<TABLE border=0 cellpadding=2><TR>"
73                                                         "<TD BGCOLOR=\"#CCCCDD\">"
74                                                 );
75                                         }
76
77                                         wprintf("<FONT SIZE=-1>"
78                                                 "<A HREF=\"/display_edit_event?msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\">",
79                                                 WC->disp_cal[i].cal_msgnum,
80                                                 bstr("calview"),
81                                                 bstr("year"),
82                                                 bstr("month"),
83                                                 bstr("day")
84                                         );
85                                         escputs((char *)
86                                                 icalproperty_get_comment(p));
87                                         wprintf("</A></FONT><br />\n");
88
89                                         if (all_day_event) {
90                                                 wprintf("</TD></TR></TABLE>");
91                                         }
92
93                                 }
94
95                         }
96
97
98                 }
99         }
100 }
101
102
103
104 void calendar_month_view(int year, int month, int day) {
105         struct tm starting_tm;
106         struct tm tm;
107         time_t thetime;
108         int i;
109         time_t previous_month;
110         time_t next_month;
111
112         /* Determine what day to start.
113          * First, back up to the 1st of the month...
114          */
115         memset(&starting_tm, 0, sizeof(struct tm));
116         starting_tm.tm_year = year - 1900;
117         starting_tm.tm_mon = month - 1;
118         starting_tm.tm_mday = day;
119         thetime = mktime(&starting_tm);
120
121         memcpy(&tm, &starting_tm, sizeof(struct tm));
122         while (tm.tm_mday != 1) {
123                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
124                 localtime_r(&thetime, &tm);
125         }
126
127         /* Determine previous and next months ... for links */
128         previous_month = thetime - (time_t)864000L;     /* back 10 days */
129         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
130
131         /* Now back up until we're on a Sunday */
132         localtime_r(&thetime, &tm);
133         while (tm.tm_wday != 0) {
134                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
135                 localtime_r(&thetime, &tm);
136         }
137
138         /* Outer table (to get the background color) */
139         wprintf("<div id=\"fix_scrollbar_bug\">"
140                 "<TABLE width=100%% border=0 cellpadding=0 cellspacing=0 "
141                 "bgcolor=#204B78><TR><TD>\n");
142
143         wprintf("<TABLE width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
144
145         wprintf("<TD ALIGN=CENTER>");
146
147         localtime_r(&previous_month, &tm);
148         wprintf("<A HREF=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
149                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
150         wprintf("<IMG ALIGN=MIDDLE SRC=\"/static/prevdate_32x.gif\" BORDER=0></A>\n");
151
152         wprintf("&nbsp;&nbsp;"
153                 "<FONT SIZE=+1 COLOR=\"#FFFFFF\">"
154                 "%s %d"
155                 "</FONT>"
156                 "&nbsp;&nbsp;", months[month-1], year);
157
158         localtime_r(&next_month, &tm);
159         wprintf("<A HREF=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
160                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
161         wprintf("<IMG ALIGN=MIDDLE SRC=\"/static/nextdate_32x.gif\" BORDER=0></A>\n");
162
163         wprintf("</TD></TR></TABLE>\n");
164
165         /* Inner table (the real one) */
166         wprintf("<TABLE width=100%% border=0 cellpadding=1 cellspacing=1 "
167                 "bgcolor=#204B78><TR>");
168         for (i=0; i<7; ++i) {
169                 wprintf("<TD ALIGN=CENTER WIDTH=14%%>"
170                         "<FONT COLOR=\"#FFFFFF\">%s</FONT></TH>", days[i]);
171         }
172         wprintf("</TR>\n");
173
174         /* Now do 35 days */
175         for (i = 0; i < 35; ++i) {
176                 localtime_r(&thetime, &tm);
177
178                 /* Before displaying Sunday, start a new row */
179                 if ((i % 7) == 0) {
180                         wprintf("<TR>");
181                 }
182
183                 wprintf("<TD BGCOLOR=\"#%s\" WIDTH=14%% HEIGHT=60 align=left VALIGN=TOP><B>",
184                         ((tm.tm_mon != month-1) ? "DDDDDD" :
185                         ((tm.tm_wday==0 || tm.tm_wday==6) ? "EEEECC" :
186                         "FFFFFF"))
187                 );
188                 if ((i==0) || (tm.tm_mday == 1)) {
189                         wprintf("%s ", months[tm.tm_mon]);
190                 }
191                 wprintf("<A HREF=\"readfwd?calview=day&year=%d&month=%d&day=%d\">"
192                         "%d</A></B><br />",
193                         tm.tm_year + 1900,
194                         tm.tm_mon + 1,
195                         tm.tm_mday,
196                         tm.tm_mday);
197
198                 /* put the data here, stupid */
199                 calendar_month_view_display_events(thetime);
200
201                 wprintf("</TD>");
202
203                 /* After displaying Saturday, end the row */
204                 if ((i % 7) == 6) {
205                         wprintf("</TR>\n");
206                 }
207
208                 thetime += (time_t)86400;               /* ahead 24 hours */
209         }
210
211         wprintf("</TABLE>"                      /* end of inner table */
212                 "</TD></TR></TABLE>"            /* end of outer table */
213                 "</div>\n");
214 }
215
216
217 void calendar_week_view(int year, int month, int day) {
218         wprintf("<CENTER><I>week view FIXME</I></CENTER><br />\n");
219 }
220
221
222 /*
223  * Display events for a particular hour of a particular day.
224  * (Specify hour < 0 to show "all day" events)
225  */
226 void calendar_day_view_display_events(int year, int month,
227                                         int day, int hour) {
228         int i;
229         icalproperty *p;
230         struct icaltimetype t;
231         time_t event_tt;
232         struct tm *event_tm;
233         int all_day_event = 0;
234
235         if (WC->num_cal == 0) {
236                 // FIXME wprintf("<br /><br /><br />\n");
237                 return;
238         }
239
240         for (i=0; i<(WC->num_cal); ++i) {
241                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
242                                                 ICAL_DTSTART_PROPERTY);
243                 if (p != NULL) {
244                         t = icalproperty_get_dtstart(p);
245                         event_tt = icaltime_as_timet(t);
246                         if (t.is_date) all_day_event = 1;
247
248                         if (all_day_event) {
249                                 event_tm = gmtime(&event_tt);
250                         }
251                         else {
252                                 event_tm = localtime(&event_tt);
253                         }
254
255                         if ((event_tm->tm_year == (year-1900))
256                            && (event_tm->tm_mon == (month-1))
257                            && (event_tm->tm_mday == day)
258                            && ( ((event_tm->tm_hour == hour)&&(!t.is_date)) || ((hour<0)&&(t.is_date)) )
259                            ) {
260
261
262                                 p = icalcomponent_get_first_property(
263                                                         WC->disp_cal[i].cal,
264                                                         ICAL_SUMMARY_PROPERTY);
265                                 if (p != NULL) {
266
267                                         if (all_day_event) {
268                                                 wprintf("<TABLE border=1 cellpadding=2><TR>"
269                                                         "<TD BGCOLOR=\"#CCCCCC\">"
270                                                 );
271                                         }
272
273                                         wprintf("<FONT SIZE=-1>"
274                                                 "<A HREF=\"/display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d\">",
275                                                 WC->disp_cal[i].cal_msgnum,
276                                                 year, month, day
277                                         );
278                                         escputs((char *)
279                                                 icalproperty_get_comment(p));
280                                         wprintf("</A></FONT><br />\n");
281
282                                         if (all_day_event) {
283                                                 wprintf("</TD></TR></TABLE>");
284                                         }
285                                 }
286
287                         }
288
289
290                 }
291         }
292 }
293
294
295
296 void calendar_day_view(int year, int month, int day) {
297         int hour;
298         struct icaltimetype today, yesterday, tomorrow;
299         char calhourformat[16];
300
301         get_preference("calhourformat", calhourformat, sizeof calhourformat);
302
303         /* Figure out the dates for "yesterday" and "tomorrow" links */
304
305         memset(&today, 0, sizeof(struct icaltimetype));
306         today.year = year;
307         today.month = month;
308         today.day = day;
309         today.is_date = 1;
310
311         memcpy(&yesterday, &today, sizeof(struct icaltimetype));
312         --yesterday.day;
313         yesterday = icaltime_normalize(yesterday);
314
315         memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
316         ++tomorrow.day;
317         tomorrow = icaltime_normalize(tomorrow);
318
319
320         /* Outer table (to get the background color) */
321         wprintf("<div id=\"fix_scrollbar_bug\">"
322                 "<TABLE width=100%% border=0 cellpadding=0 cellspacing=0 "
323                 "bgcolor=#204B78><TR><TD>\n");
324
325         /* Inner table (the real one) */
326         wprintf("<TABLE width=100%% border=0 cellpadding=1 cellspacing=1 "
327                 "bgcolor=#204B78><TR>\n");
328
329         /* Innermost table (contains hours etc.) */
330         wprintf("<TD WIDTH=80%%>"
331                 "<TABLE width=100%% border=0 cellpadding=1 cellspacing=1 "
332                 "bgcolor=#204B78>\n");
333
334         /* Display events before 8:00 (hour=-1 is all-day events) */
335         wprintf("<TR>"
336                 "<TD BGCOLOR=\"#CCCCDD\" VALIGN=MIDDLE WIDTH=10%%></TD>"
337                 "<TD BGCOLOR=\"#FFFFFF\" VALIGN=TOP>");
338         for (hour = (-1); hour <= 7; ++hour) {
339                 calendar_day_view_display_events(year, month, day, hour);
340         }
341         wprintf("</TD></TR>\n");
342
343         /* Now the middle of the day... */      
344         for (hour = 8; hour <= 17; ++hour) {    /* could do HEIGHT=xx */
345                 wprintf("<TR HEIGHT=30><TD BGCOLOR=\"#CCCCDD\" ALIGN=MIDDLE "
346                         "VALIGN=MIDDLE WIDTH=10%%>");
347                 wprintf("<A HREF=\"/display_edit_event?msgnum=0"
348                         "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
349                         year, month, day, hour
350                 );
351
352                 if (!strcasecmp(calhourformat, "24")) {
353                         wprintf("%2d:00</A> ", hour);
354                 }
355                 else {
356                         wprintf("%d:00%s</A> ",
357                                 (hour <= 12 ? hour : hour-12),
358                                 (hour < 12 ? "am" : "pm")
359                         );
360                 }
361
362                 wprintf("</TD><TD BGCOLOR=\"#FFFFFF\" VALIGN=TOP>");
363
364                 /* put the data here, stupid */
365                 calendar_day_view_display_events(year, month, day, hour);
366
367                 wprintf("</TD></TR>\n");
368         }
369
370         /* Display events after 5:00... */
371         wprintf("<TR>"
372                 "<TD BGCOLOR=\"#CCCCDD\" VALIGN=MIDDLE WIDTH=10%%></TD>"
373                 "<TD BGCOLOR=\"#FFFFFF\" VALIGN=TOP>");
374         for (hour = 18; hour <= 23; ++hour) {
375                 calendar_day_view_display_events(year, month, day, hour);
376         }
377         wprintf("</TD></TR>\n");
378
379
380         wprintf("</TABLE>"                      /* end of innermost table */
381                 "</TD>"
382         );
383
384         wprintf("<TD WIDTH=20%% VALIGN=top>");  /* begin stuff-on-the-right */
385
386
387         /* Begin todays-date-with-left-and-right-arrows */
388         wprintf("<TABLE BORDER=0 WIDTH=100%% "
389                 "CELLSPACING=0 CELLPADDING=0 BGCOLOR=\"#FFFFFF\">\n");
390         wprintf("<TR>");
391
392         /* Left arrow */        
393         wprintf("<TD ALIGN=CENTER>");
394         wprintf("<A HREF=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
395                 yesterday.year, yesterday.month, yesterday.day);
396         wprintf("<IMG ALIGN=MIDDLE SRC=\"/static/prevdate_32x.gif\" BORDER=0></A>");
397         wprintf("</TD>");
398
399         /* Today's date */
400         wprintf("<TD ALIGN=CENTER>");
401         wprintf("<FONT SIZE=+2>%s</FONT><br />"
402                 "<FONT SIZE=+3>%d</FONT><br />"
403                 "<FONT SIZE=+2>%d</FONT><br />",
404                 months[month-1], day, year);
405         wprintf("</TD>");
406
407         /* Right arrow */
408         wprintf("<TD ALIGN=CENTER>");
409         wprintf("<A HREF=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
410                 tomorrow.year, tomorrow.month, tomorrow.day);
411         wprintf("<IMG ALIGN=MIDDLE SRC=\"/static/nextdate_32x.gif\""
412                 " BORDER=0></A>\n");
413         wprintf("</TD>");
414
415         wprintf("</TR></TABLE>\n");
416         /* End todays-date-with-left-and-right-arrows */
417
418         /* In the future we might want to put a month-o-matic here */
419
420         wprintf("</FONT></CENTER>\n");
421
422         wprintf("</TD>");                       /* end stuff-on-the-right */
423
424
425
426         wprintf("</TR></TABLE>"                 /* end of inner table */
427                 "</TD></TR></TABLE></div>"      /* end of outer table */
428         );
429
430
431
432 }
433
434 /*
435  * Display today's events.
436  */
437 void calendar_summary_view(void) {
438         int i;
439         icalproperty *p;
440         struct icaltimetype t;
441         time_t event_tt;
442         struct tm event_tm;
443         struct tm today_tm;
444         time_t now;
445         int all_day_event = 0;
446         char timestring[SIZ];
447
448         if (WC->num_cal == 0) {
449                 return;
450         }
451
452         now = time(NULL);
453         localtime_r(&now, &today_tm);
454
455         for (i=0; i<(WC->num_cal); ++i) {
456                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
457                                                 ICAL_DTSTART_PROPERTY);
458                 if (p != NULL) {
459                         t = icalproperty_get_dtstart(p);
460                         event_tt = icaltime_as_timet(t);
461                         if (t.is_date) all_day_event = 1;
462                         fmt_time(timestring, event_tt);
463
464                         if (all_day_event) {
465                                 gmtime_r(&event_tt, &event_tm);
466                         }
467                         else {
468                                 localtime_r(&event_tt, &event_tm);
469                         }
470
471                         if ( (event_tm.tm_year == today_tm.tm_year)
472                            && (event_tm.tm_mon == today_tm.tm_mon)
473                            && (event_tm.tm_mday == today_tm.tm_mday)
474                            ) {
475
476
477                                 p = icalcomponent_get_first_property(
478                                                         WC->disp_cal[i].cal,
479                                                         ICAL_SUMMARY_PROPERTY);
480                                 if (p != NULL) {
481                                         escputs((char *)
482                                                 icalproperty_get_comment(p));
483                                         wprintf(" (%s)<br />\n", timestring);
484                                 }
485                         }
486                 }
487         }
488         free_calendar_buffer();
489 }
490
491
492
493 void free_calendar_buffer(void) {
494         int i;
495         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
496                 icalcomponent_free(WC->disp_cal[i].cal);
497         }
498         WC->num_cal = 0;
499         free(WC->disp_cal);
500         WC->disp_cal = NULL;
501 }
502
503
504
505
506 void do_calendar_view(void) {
507         time_t now;
508         struct tm tm;
509         int year, month, day;
510         char calview[SIZ];
511
512         /* In case no date was specified, go with today */
513         now = time(NULL);
514         localtime_r(&now, &tm);
515         year = tm.tm_year + 1900;
516         month = tm.tm_mon + 1;
517         day = tm.tm_mday;
518
519         /* Now see if a date was specified */
520         if (strlen(bstr("year")) > 0) year = atoi(bstr("year"));
521         if (strlen(bstr("month")) > 0) month = atoi(bstr("month"));
522         if (strlen(bstr("day")) > 0) day = atoi(bstr("day"));
523
524         /* How would you like that cooked? */
525         if (strlen(bstr("calview")) > 0) {
526                 strcpy(calview, bstr("calview"));
527         }
528         else {
529                 strcpy(calview, "month");
530         }
531
532         /* Display the selected view */
533         if (!strcasecmp(calview, "day")) {
534                 calendar_day_view(year, month, day);
535         }
536         else if (!strcasecmp(calview, "week")) {
537                 calendar_week_view(year, month, day);
538         }
539         else {
540                 calendar_month_view(year, month, day);
541         }
542
543         /* Free the calendar stuff */
544         free_calendar_buffer();
545
546 }
547
548
549 /*
550  * Helper function for do_tasks_view().  Returns the date/time due.
551  */
552 time_t get_task_due_date(icalcomponent *vtodo) {
553         icalproperty *p;
554
555         if (vtodo == NULL) {
556                 return(0L);
557         }
558
559         /* If we're looking at a fully encapsulated VCALENDAR
560          * rather than a VTODO component, recurse into the data
561          * structure until we get a VTODO.
562          */
563         if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
564                 return get_task_due_date(
565                         icalcomponent_get_first_component(
566                                 vtodo, ICAL_VTODO_COMPONENT
567                         )
568                 );
569         }
570
571         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
572         if (p != NULL) {
573                 return(icaltime_as_timet(icalproperty_get_due(p)));
574         }
575         else {
576                 return(0L);
577         }
578 }
579
580
581 /*
582  * Compare the due dates of two tasks (this is for sorting)
583  */
584 int task_due_cmp(const void *task1, const void *task2) {
585         time_t t1;
586         time_t t2;
587
588         t1 =  get_task_due_date(((struct disp_cal *)task1)->cal);
589         t2 =  get_task_due_date(((struct disp_cal *)task2)->cal);
590
591         if (t1 < t2) return(-1);
592         if (t1 > t2) return(1);
593         return(0);
594 }
595
596
597
598
599
600 void do_tasks_view(void) {
601         int i;
602         time_t due;
603         int bg = 0;
604         char buf[SIZ];
605         icalproperty *p;
606
607         wprintf("<div id=\"fix_scrollbar_bug\">"
608                 "<table border=0 cellspacing=0 width=100%% bgcolor=\"#FFFFFF\">\n<tr>\n"
609                 "<TH>Name of task</TH>\n"
610                 "<TH>Date due</TH></TR>\n"
611         );
612
613         /* Sort them if necessary */
614         if (WC->num_cal > 1) {
615                 qsort(WC->disp_cal,
616                         WC->num_cal,
617                         sizeof(struct disp_cal),
618                         task_due_cmp
619                 );
620         }
621
622         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
623
624                 bg = 1 - bg;
625                 wprintf("<TR BGCOLOR=\"#%s\"><TD>",
626                         (bg ? "DDDDDD" : "FFFFFF")
627                 );
628
629                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
630                                                         ICAL_SUMMARY_PROPERTY);
631                 wprintf("<A HREF=\"/display_edit_task?msgnum=%ld&taskrm=",
632                         WC->disp_cal[i].cal_msgnum );
633                 urlescputs(WC->wc_roomname);
634                 wprintf("\">");
635                 wprintf("<IMG ALIGN=MIDDLE "
636                         "SRC=\"/static/taskmanag_16x.gif\" BORDER=0>&nbsp;");
637                 if (p != NULL) {
638                         escputs((char *)icalproperty_get_comment(p));
639                 }
640                 wprintf("</A>\n");
641                 wprintf("</TD>\n");
642
643                 due = get_task_due_date(WC->disp_cal[i].cal);
644                 fmt_date(buf, due, 0);
645                 wprintf("<TD><FONT");
646                 if (due < time(NULL)) {
647                         wprintf(" COLOR=\"#FF0000\"");
648                 }
649                 wprintf(">%s</FONT></TD></TR>\n", buf);
650         }
651
652         wprintf("</table></div>\n");
653
654         /* Free the list */
655         free_calendar_buffer();
656
657 }
658
659 #endif  /* WEBCIT_WITH_CALENDAR_SERVICE */