Rewrote the multi day event code using only the
[citadel.git] / webcit / calendar_view.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup CalHtmlHandles Handles the HTML display of calendar items.
6  * \ingroup Calendaring
7  */
8 /*@{*/
9 #include "webcit.h"
10 #include "webserver.h"
11
12 #ifdef WEBCIT_WITH_CALENDAR_SERVICE
13
14 /****************************************************************************/
15
16 /**
17  * \brief Display one day of a whole month view of a calendar
18  * \param thetime the month we want to see 
19  */
20 void calendar_month_view_display_events(int year, int month, int day)
21 {
22         int i;
23         icalproperty *p = NULL;
24         icalproperty *q = NULL;
25         struct icaltimetype t;
26         struct icaltimetype end_t;
27         struct icaltimetype today_start_t;
28         struct icaltimetype today_end_t;
29         int all_day_event = 0;
30         int show_event = 0;
31         char buf[256];
32         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
33         struct disp_cal *Cal;
34         time_t tt;
35
36         if (WCC->num_cal == 0) {
37                 wprintf("<br /><br /><br />\n");
38                 return;
39         }
40
41         /* Create an imaginary event which spans the 24 hours of today.  Any events which
42          * overlap with this one take place at least partially in this day.
43          */
44         memset(&today_start_t, 0, sizeof today_start_t);
45         today_start_t.year = year;
46         today_start_t.month = month;
47         today_start_t.day = day;
48         today_start_t.hour = 0;
49         today_start_t.minute = 0;
50         memset(&today_end_t, 0, sizeof today_end_t);
51         today_end_t.year = year;
52         today_end_t.month = month;
53         today_end_t.day = day;
54         today_end_t.hour = 23;
55         today_end_t.minute = 59;
56
57         /* Now loop through our list of events to see which ones occur today.
58          */
59         for (i=0; i<(WCC->num_cal); ++i) {
60                 Cal = &WCC->disp_cal[i];
61                 all_day_event = 0;
62                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
63                 if (q != NULL) {
64                         t = icalproperty_get_dtstart(q);
65                 }
66                 else {
67                         memset(&t, 0, sizeof t);
68                 }
69                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
70                 if (q != NULL) {
71                         end_t = icalproperty_get_dtend(q);
72                 }
73                 else {
74                         memset(&end_t, 0, sizeof end_t);
75                 }
76                 if (t.is_date) all_day_event = 1;
77
78                 if (all_day_event)
79                 {
80                         show_event = ((t.year == year) && (t.month == month) && (t.day == day));
81                 }
82                 else
83                 {
84                         show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
85                 }
86
87                 /* If we determined that this event occurs today, then display it.
88                  */
89                 if (show_event) {
90                         p = icalcomponent_get_first_property(Cal->cal, ICAL_SUMMARY_PROPERTY);
91                         if (p != NULL) {
92
93                                 if (all_day_event) {
94                                         wprintf("<table border=0 cellpadding=2><TR>"
95                                                 "<td bgcolor=\"#CCCCDD\">"
96                                                 );
97                                 }
98
99                                 wprintf("<font size=-1>"
100                                         "<a href=\"display_edit_event?"
101                                         "msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\""
102                                         " btt_tooltext=\"",
103                                         WC->disp_cal[i].cal_msgnum,
104                                         bstr("calview"),
105                                         bstr("year"),
106                                         bstr("month"),
107                                         bstr("day")
108                                         );
109
110                                 wprintf("<i>%s</i> ", _("Summary:"));
111                                 escputs((char *)icalproperty_get_comment(p));
112                                 wprintf("<br />");
113                                 
114                                 q = icalcomponent_get_first_property(
115                                         WC->disp_cal[i].cal,
116                                         ICAL_LOCATION_PROPERTY);
117                                 if (q) {
118                                         wprintf("<i>%s</i> ", _("Location:"));
119                                         escputs((char *)icalproperty_get_comment(q));
120                                         wprintf("<br />");
121                                         }
122                                 
123                                 /**
124                                  * Only show start/end times if we're actually looking at the VEVENT
125                                  * component.  Otherwise it shows bogus dates for e.g. timezones
126                                  */
127                                 if (icalcomponent_isa(Cal->cal) == ICAL_VEVENT_COMPONENT) {
128                                         
129                                         q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
130                                         if (q != NULL) {
131                                                 t = icalproperty_get_dtstart(q);
132                                                 
133                                                 if (t.is_date) {
134                                                         struct tm d_tm;
135                                                         char d_str[32];
136                                                         memset(&d_tm, 0, sizeof d_tm);
137                                                         d_tm.tm_year = t.year - 1900;
138                                                         d_tm.tm_mon = t.month - 1;
139                                                         d_tm.tm_mday = t.day;
140                                                         wc_strftime(d_str, sizeof d_str, "%x", &d_tm);
141                                                         wprintf("<i>%s</i> %s<br>",
142                                                                 _("Date:"), d_str);
143                                                 }
144                                                 else {
145                                                         tt = icaltime_as_timet(t);
146                                                         fmt_date(buf, tt, 1);
147                                                         wprintf("<i>%s</i> %s<br>",
148                                                                 _("Starting date/time:"), buf);
149                                                         
150                                                         /* Embed the 'show end date/time' loop inside here so it
151                                                          * only executes if this is NOT an all day event.
152                                                          */
153                                                         q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
154                                                         if (q != NULL) {
155                                                                 t = icalproperty_get_dtend(q);
156                                                                 tt = icaltime_as_timet(t);
157                                                                 fmt_date(buf, tt, 1);
158                                                                 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
159                                                         }
160                                                         
161                                                 }
162                                         }
163                                         
164                                 }
165                                 
166                                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DESCRIPTION_PROPERTY);
167                                 if (q) {
168                                         wprintf("<i>%s</i> ", _("Notes:"));
169                                         escputs((char *)icalproperty_get_comment(q));
170                                         wprintf("<br />");
171                                 }
172                                 
173                                 wprintf("\">");
174                                 escputs((char *)
175                                         icalproperty_get_comment(p));
176                                 wprintf("</a></font><br />\n");
177                                 
178                                 if (all_day_event) {
179                                         wprintf("</td></tr></table>");
180                                 }
181                                 
182                         }
183                         
184                 }
185                 
186                 
187         }
188 }
189
190
191 /**
192  * \brief Display one day of a whole month view of a calendar
193  * \param thetime the month we want to see 
194  */
195 void calendar_month_view_brief_events(time_t thetime, const char *daycolor) {
196         int i;
197         time_t event_tt;
198         time_t event_tts;
199         time_t event_tte;
200         struct tm event_tms;
201         struct tm event_tme;
202         struct tm today_tm;
203         icalproperty *p;
204         icalproperty *e;
205         struct icaltimetype t;
206         int month, day, year;
207         int all_day_event = 0;
208         char *timeformat;
209         int time_format;
210         
211         time_format = get_time_format_cached ();
212
213         if (time_format == WC_TIMEFORMAT_24) timeformat="%k:%M";
214         else timeformat="%I:%M %p";
215
216         localtime_r(&thetime, &today_tm);
217         month = today_tm.tm_mon + 1;
218         day = today_tm.tm_mday;
219         year = today_tm.tm_year + 1900;
220
221         for (i=0; i<(WC->num_cal); ++i) {
222                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
223                                                 ICAL_DTSTART_PROPERTY);
224                 if (p != NULL) {
225                         t = icalproperty_get_dtstart(p);
226                         event_tt = icaltime_as_timet(t);
227                         event_tts=event_tt;
228                         if (t.is_date) all_day_event = 1;
229                         else all_day_event = 0;
230
231                         if (all_day_event) {
232                                 gmtime_r(&event_tts, &event_tms);
233                         }
234                         else {
235                                 localtime_r(&event_tts, &event_tms);
236                         }
237                         /** \todo epoch &! daymask */
238                         if ((event_tms.tm_year == today_tm.tm_year)
239                            && (event_tms.tm_mon == today_tm.tm_mon)
240                            && (event_tms.tm_mday == today_tm.tm_mday)) {
241                                 
242                                 
243                                 char sbuf[255];
244                                 char ebuf[255];
245
246                                 p = icalcomponent_get_first_property(
247                                                         WC->disp_cal[i].cal,
248                                                         ICAL_SUMMARY_PROPERTY);
249                                 e = icalcomponent_get_first_property(
250                                                         WC->disp_cal[i].cal, 
251                                                         ICAL_DTEND_PROPERTY);
252                                 if ((p != NULL) && (e != NULL)) {
253                                         time_t difftime;
254                                         int hours, minutes;
255                                         t = icalproperty_get_dtend(e);
256                                         event_tte = icaltime_as_timet(t);
257                                         localtime_r(&event_tte, &event_tme);
258                                         difftime=(event_tte-event_tts)/60;
259                                         hours=(int)(difftime / 60);
260                                         minutes=difftime % 60;
261                                         wprintf("<tr><td bgcolor='%s'>%i:%2i</td><td bgcolor='%s'>"
262                                                         "<font size=-1>"
263                                                         "<a href=\"display_edit_event?msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\">",
264                                                         daycolor,
265                                                         hours, minutes,
266                                                         daycolor,
267                                                         WC->disp_cal[i].cal_msgnum,
268                                                         bstr("calview"),
269                                                         bstr("year"),
270                                                         bstr("month"),
271                                                         bstr("day")
272                                                         );
273
274                                         escputs((char *)
275                                                         icalproperty_get_comment(p));
276                                         /** \todo: allso ammitime format */
277                                         wc_strftime(&sbuf[0], sizeof(sbuf), timeformat, &event_tms);
278                                         wc_strftime(&ebuf[0], sizeof(sbuf), timeformat, &event_tme);
279
280                                         wprintf("</a></font></td>"
281                                                         "<td bgcolor='%s'>%s</td><td bgcolor='%s'>%s</td></tr>",
282                                                         daycolor,
283                                                         sbuf,
284                                                         daycolor,
285                                                         ebuf);
286                                         
287                                 }
288                                 
289                         }
290                         
291                         
292                 }
293         }
294 }
295
296
297 /**
298  * \brief view one month. pretty view
299  * \param year the year
300  * \param month the month
301  * \param day the actual day we want to see
302  */
303 void calendar_month_view(int year, int month, int day) {
304         struct tm starting_tm;
305         struct tm tm;
306         time_t thetime;
307         int i;
308         time_t previous_month;
309         time_t next_month;
310         time_t colheader_time;
311         struct tm colheader_tm;
312         char colheader_label[32];
313         int chg_month = 0;
314         int weekstart = 0;
315         char weekstart_buf[16];
316
317         /* Determine what day to start.
318          */
319         get_preference("weekstart", weekstart_buf, sizeof weekstart_buf);
320         weekstart = atoi(weekstart_buf);
321
322         /*
323          * Now back up to the 1st of the month...
324          */
325         memset(&starting_tm, 0, sizeof(struct tm));
326
327         starting_tm.tm_year = year - 1900;
328         starting_tm.tm_mon = month - 1;
329         starting_tm.tm_mday = day;
330         thetime = mktime(&starting_tm);
331
332         memcpy(&tm, &starting_tm, sizeof(struct tm));
333         while (tm.tm_mday != 1) {
334                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
335                 localtime_r(&thetime, &tm);
336         }
337
338         /** Determine previous and next months ... for links */
339         previous_month = thetime - (time_t)864000L;     /* back 10 days */
340         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
341
342         /** Now back up until we're on the user's preferred start day */
343         localtime_r(&thetime, &tm);
344         while (tm.tm_wday != weekstart) {
345                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
346                 localtime_r(&thetime, &tm);
347         }
348
349         /** Outer table (to get the background color) */
350         wprintf("<div class=\"fix_scrollbar_bug\">"
351                 "<table class=\"calendar\"> \n <tr><td>"); 
352
353         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
354
355         wprintf("<td align=center>");
356
357         localtime_r(&previous_month, &tm);
358         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
359                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
360         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
361
362         wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
363         wprintf("&nbsp;&nbsp;"
364                 "<font size=+1 color=\"#FFFFFF\">"
365                 "%s %d"
366                 "</font>"
367                 "&nbsp;&nbsp;", colheader_label, year);
368
369         localtime_r(&next_month, &tm);
370         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
371                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
372         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
373
374         wprintf("</td></tr></table>\n");
375
376         /** Inner table (the real one) */
377         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
378                 "bgcolor=#204B78 id=\"inner_month\"><tr>");
379         colheader_time = thetime;
380         for (i=0; i<7; ++i) {
381                 colheader_time = thetime + (i * 86400) ;
382                 localtime_r(&colheader_time, &colheader_tm);
383                 wc_strftime(colheader_label, sizeof colheader_label, "%A", &colheader_tm);
384                 wprintf("<td align=center width=14%%>"
385                         "<font color=\"#FFFFFF\">%s</font></th>", colheader_label);
386
387         }
388         wprintf("</tr>\n");
389
390
391         /** Now do 35 or 42 days */
392         for (i = 0; i < 42; ++i) {
393                 localtime_r(&thetime, &tm);
394
395                 if ((i < 35) || (chg_month == 0)) {
396
397                         if ((i > 27) && ((tm.tm_mday == 1) || (tm.tm_mday == 31))) {
398                                 chg_month = 1;
399                         }
400                         if (i > 35) {
401                                 chg_month = 0;
402                         }
403
404                         /** Before displaying Sunday, start a new row */
405                         if ((i % 7) == 0) {
406                                 wprintf("<tr>");
407                         }
408
409                         wprintf("<td class=\"cal%s\"><div class=\"day\">",
410                                 ((tm.tm_mon != month-1) ? "out" :
411                                 ((tm.tm_wday==0 || tm.tm_wday==6) ? "weekend" :
412                                 "day"))
413                         );
414                         if ((i==0) || (tm.tm_mday == 1)) {
415                                 wc_strftime(colheader_label, sizeof colheader_label, "%B", &tm);
416                                 wprintf("%s ", colheader_label);
417                         }
418                         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">"
419                                 "%d</a></div>",
420                                 tm.tm_year + 1900,
421                                 tm.tm_mon + 1,
422                                 tm.tm_mday,
423                                 tm.tm_mday);
424
425                         /** put the data here, stupid */
426                         calendar_month_view_display_events(
427                                 tm.tm_year + 1900,
428                                 tm.tm_mon + 1,
429                                 tm.tm_mday
430                         );
431
432                         wprintf("</td>");
433
434                         /** After displaying Saturday, end the row */
435                         if ((i % 7) == 6) {
436                                 wprintf("</tr>\n");
437                         }
438
439                 }
440
441                 thetime += (time_t)86400;               /** ahead 24 hours */
442         }
443
444         wprintf("</table>"                      /** end of inner table */
445                 "</td></tr></table>"            /** end of outer table */
446                 "</div>\n");
447
448         /**
449          * Initialize the bubble tooltips.
450          *
451          * Yes, this is as stupid as it looks.  Instead of just making the call
452          * to btt_enableTooltips() straight away, we have to create a timer event
453          * and let it initialize as an event after 1 millisecond.  This is to
454          * work around a bug in Internet Explorer that causes it to crash if we
455          * manipulate the innerHTML of various DOM nodes while the page is still
456          * being rendered.  See http://www.shaftek.org/blog/archives/000212.html
457          * for more information.
458          */ 
459         wprintf("<script type=\"text/javascript\">"
460                 " setTimeout(\"btt_enableTooltips('inner_month')\", 1); "
461                 "</script>\n"
462         );
463 }
464
465 /**
466  * \brief view one month. brief view
467  * \param year the year
468  * \param month the month
469  * \param day the actual day we want to see
470  */
471 void calendar_brief_month_view(int year, int month, int day) {
472         struct tm starting_tm;
473         struct tm tm;
474         time_t thetime;
475         int i;
476         time_t previous_month;
477         time_t next_month;
478         char month_label[32];
479
480         /** Determine what day to start.
481          * First, back up to the 1st of the month...
482          */
483         memset(&starting_tm, 0, sizeof(struct tm));
484         starting_tm.tm_year = year - 1900;
485         starting_tm.tm_mon = month - 1;
486         starting_tm.tm_mday = day;
487         thetime = mktime(&starting_tm);
488
489         memcpy(&tm, &starting_tm, sizeof(struct tm));
490         while (tm.tm_mday != 1) {
491                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
492                 localtime_r(&thetime, &tm);
493         }
494
495         /** Determine previous and next months ... for links */
496         previous_month = thetime - (time_t)864000L;     /* back 10 days */
497         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
498
499         /** Now back up until we're on a Sunday */
500         localtime_r(&thetime, &tm);
501         while (tm.tm_wday != 0) {
502                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
503                 localtime_r(&thetime, &tm);
504         }
505
506         /** Outer table (to get the background color) */
507         wprintf("<div class=\"fix_scrollbar_bug\">"
508                 "<table width=100%% border=0 cellpadding=0 cellspacing=0 "
509                 "bgcolor=#204B78><TR><TD>\n");
510
511         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
512
513         wprintf("<td align=center>");
514
515         localtime_r(&previous_month, &tm);
516         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
517                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
518         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
519
520         wc_strftime(month_label, sizeof month_label, "%B", &tm);
521         wprintf("&nbsp;&nbsp;"
522                 "<font size=+1 color=\"#FFFFFF\">"
523                 "%s %d"
524                 "</font>"
525                 "&nbsp;&nbsp;", month_label, year);
526
527         localtime_r(&next_month, &tm);
528         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
529                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
530         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
531
532         wprintf("</td></tr></table>\n");
533
534         /** Inner table (the real one) */
535         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
536                 "bgcolor=#EEEECC><TR>");
537         wprintf("</tr>\n");
538         wprintf("<tr><td colspan=\"100%\">\n");
539
540         /** Now do 35 days */
541         for (i = 0; i < 35; ++i) {
542                 char weeknumber[255];
543                 char weekday_name[32];
544                 char *daycolor;
545                 localtime_r(&thetime, &tm);
546
547
548                 /** Before displaying Sunday, start a new CELL */
549                 if ((i % 7) == 0) {
550                         wc_strftime(&weeknumber[0], sizeof(weeknumber), "%U", &tm);
551                         wprintf("<table border='0' bgcolor=\"#EEEECC\" width='100%'> <tr><th colspan='4'>%s %s</th></tr>"
552                                         "   <tr><td>%s</td><td width=70%%>%s</td><td>%s</td><td>%s</td></tr>\n",
553                                         _("Week"), 
554                                         weeknumber,
555                                         _("Hours"),
556                                         _("Subject"),
557                                         _("Start"),
558                                         _("End")
559                                         );
560                 }
561                 
562                 daycolor=((tm.tm_mon != month-1) ? "DDDDDD" :
563                                   ((tm.tm_wday==0 || tm.tm_wday==6) ? "EEEECC" :
564                                    "FFFFFF"));
565                 
566                 /** Day Header */
567                 wc_strftime(weekday_name, sizeof weekday_name, "%A", &tm);
568                 wprintf("<tr><td bgcolor='%s' colspan='1' align='left'> %s,%i."
569                                 "</td><td bgcolor='%s' colspan='3'><hr></td></tr>\n",
570                                 daycolor,
571                                 weekday_name,tm.tm_mday,
572                                 daycolor);
573
574                 /** put the data of one day  here, stupid */
575                 calendar_month_view_brief_events(thetime, daycolor);
576
577
578                 /** After displaying Saturday, end the row */
579                 if ((i % 7) == 6) {
580                         wprintf("</td></tr></table>\n");
581                 }
582
583                 thetime += (time_t)86400;               /** ahead 24 hours */
584         }
585
586         wprintf("</table>"                      /** end of inner table */
587                 "</td></tr></table>"            /** end of outer table */
588                 "</div>\n");
589 }
590
591 /** 
592  * \brief view one week
593  * this should view just one week, but it's not here yet.
594  * \todo ny implemented
595  * \param year the year
596  * \param month the month
597  * \param day the day which we want to see the week around
598  */
599 void calendar_week_view(int year, int month, int day) {
600         wprintf("<center><i>week view FIXME</i></center><br />\n");
601 }
602
603
604 /**
605  * \brief display one day
606  * Display events for a particular hour of a particular day.
607  * (Specify hour < 0 to show "all day" events)
608  * \param year the year
609  * \param month the month
610  * \param day the day
611  * \param hour the hour we want to start displaying
612  * \param dstart daystart 
613  * \param dend dayend 
614  */
615 void calendar_day_view_display_events(time_t thetime, int year, int month,
616                                         int day, int hour,
617                                         int dstart, int dend) {
618         int i;
619         icalproperty *p = NULL;
620         icalproperty *q = NULL;
621         time_t event_start;
622         time_t event_end;
623         struct tm event_te;
624         struct tm event_tm;
625         int show_event = 0;
626         int all_day_event = 0;
627         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
628         struct disp_cal *Cal;
629         struct icaltimetype t;
630         struct icaltimetype end_t;
631         struct icaltimetype today_start_t;
632         struct icaltimetype today_end_t;
633
634
635         if (WCC->num_cal == 0) {
636                 // \todo FIXME wprintf("<br /><br /><br />\n");
637                 return;
638         }
639
640         event_start = thetime + 60 * 60 * hour;
641         event_end = thetime + 60 * 60 * (hour + 1);
642
643
644         /* Create an imaginary event which spans the 24 hours of today.  Any events which
645          * overlap with this one take place at least partially in this day.
646          */
647         memset(&today_start_t, 0, sizeof today_start_t);
648         today_start_t.year = year;
649         today_start_t.month = month;
650         today_start_t.day = day;
651         today_start_t.hour = 0;
652         today_start_t.minute = 0;
653         memset(&today_end_t, 0, sizeof today_end_t);
654         today_end_t.year = year;
655         today_end_t.month = month;
656         today_end_t.day = day;
657         today_end_t.hour = 23;
658         today_end_t.minute = 59;
659
660
661         /* Now loop through our list of events to see which ones occur today.
662          */
663         for (i=0; i<(WCC->num_cal); ++i) {
664                 Cal = &WCC->disp_cal[i];
665
666                 all_day_event = 0;
667                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
668                 if (q != NULL) {
669                         t = icalproperty_get_dtstart(q);
670                 }
671                 else {
672                         memset(&t, 0, sizeof t);
673                 }
674                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
675                 if (q != NULL) {
676                         end_t = icalproperty_get_dtend(q);
677                 }
678                 else {
679                         memset(&end_t, 0, sizeof end_t);
680                 }
681                 if (t.is_date) all_day_event = 1;
682
683                 if (all_day_event)
684                 {
685                         show_event = ((t.year == year) && (t.month == month) && (t.day == day));
686                 }
687                 else
688                 {
689                         show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
690                 }
691
692                 /* If we determined that this event occurs today, then display it.
693                  */
694                 p = icalcomponent_get_first_property(Cal->cal,ICAL_SUMMARY_PROPERTY);
695                 if ((show_event) && (p != NULL)) {
696                         if (all_day_event)
697                         {
698                                 wprintf("<dd><a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
699                                         Cal->cal_msgnum, year, month, day, hour);
700                                 escputs((char *) icalproperty_get_comment(p));
701                                 wprintf("</a></dd>\n");
702                         }
703                         else 
704                         {
705                                 wprintf("<dd  class=\"event\" "
706                                         "style=\"position: absolute; "
707                                         "top:%dpx; left:100px; "
708                                         "height:%dpx; \" >",
709                                         (100 + (event_tm.tm_min / 2) + (event_te.tm_hour - hour) + (hour * 30) - (dstart * 30)),
710                                         (((event_te.tm_min - event_tm.tm_min) / 2) +(event_te.tm_hour - hour) * 30)
711                                 );
712                                 wprintf("<a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
713                                         Cal->cal_msgnum, year, month, day, hour);
714                                 escputs((char *) icalproperty_get_comment(p));
715                                 wprintf("</a></dd>\n");
716                         }
717                 }
718         }
719 }
720
721 /**
722  * \brief view one day
723  * \param year the year
724  * \param month the month 
725  * \param day the day we want to display
726  */
727 void calendar_day_view(int year, int month, int day) {
728         int hour;
729         struct icaltimetype today, yesterday, tomorrow;
730         int daystart = 8;
731         int dayend = 17;
732         char daystart_str[16], dayend_str[16];
733         struct tm d_tm;
734         char d_str[128];
735         int time_format;
736         time_t today_t;
737
738         time_format = get_time_format_cached ();
739         get_preference("daystart", daystart_str, sizeof daystart_str);
740         if (!IsEmptyStr(daystart_str)) daystart = atoi(daystart_str);
741         get_preference("dayend", dayend_str, sizeof dayend_str);
742         if (!IsEmptyStr(dayend_str)) dayend = atoi(dayend_str);
743         
744         /** Today's date */
745         memset(&d_tm, 0, sizeof d_tm);
746         d_tm.tm_year = year - 1900;
747         d_tm.tm_mon = month - 1;
748         d_tm.tm_mday = day;
749         today_t = mktime(&d_tm); 
750
751         /** Figure out the dates for "yesterday" and "tomorrow" links */
752
753         memset(&today, 0, sizeof(struct icaltimetype));
754         today.year = year;
755         today.month = month;
756         today.day = day;
757         today.is_date = 1;
758
759         memcpy(&yesterday, &today, sizeof(struct icaltimetype));
760         --yesterday.day;
761         yesterday = icaltime_normalize(yesterday);
762
763         memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
764         ++tomorrow.day;
765         tomorrow = icaltime_normalize(tomorrow);
766
767         wprintf("<div class=\"fix_scrollbar_bug\">");
768
769         /** Inner table (the real one) */
770         wprintf("<table class=\"calendar\" id=\"inner_day\"><tr> \n");
771
772         /** Innermost cell (contains hours etc.) */
773         wprintf("<td class=\"events_of_the_day\" >");
774         wprintf("<dl class=\"events\" >");
775         /** Now the middle of the day... */     
776         for (hour = 0; hour < 24; ++hour) {     /* could do HEIGHT=xx */
777                 wprintf("<dt class=\"hour%s\"><a href=\"display_edit_event?msgnum=0"
778                         "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
779                         (hour < daystart ? "before" : (hour > dayend ? "after" : "")),
780                         year, month, day, hour
781                 );
782
783                 if (time_format == WC_TIMEFORMAT_24) {
784                         wprintf("%2d:00</a> ", hour);
785                 }
786                 else {
787                         wprintf("%d:00%s</a> ",
788                                 (hour <= 12 ? hour : hour-12),
789                                 (hour < 12 ? "am" : "pm")
790                         );
791                 }
792
793                 wprintf("</dt>");
794         
795
796                 /* put the data here, stupid */
797                 calendar_day_view_display_events(today_t, year, month, day, hour, daystart, dayend);
798
799         }
800
801         wprintf("</dl>");
802         wprintf("</td>");                       /* end of innermost table */
803
804         /** Extra events on the middle */
805         wprintf("<td class=\"extra_events\">");
806
807         wprintf("<dl>");
808
809         /** Display all-day events) */
810         wprintf("<dt>All day events</dt>");
811                 calendar_day_view_display_events(today_t, year, month, day, -1, daystart, dayend);
812
813         wprintf("</dl>");
814
815         wprintf("</td>");       /** end extra on the middle */
816
817         wprintf("<td width=20%% valign=top>");  /** begin stuff-on-the-right */
818
819         /** Begin todays-date-with-left-and-right-arrows */
820         wprintf("<table border=0 width=100%% "
821                 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
822         wprintf("<tr>");
823
824         /** Left arrow */       
825         wprintf("<td align=center>");
826         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
827                 yesterday.year, yesterday.month, yesterday.day);
828         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
829         wprintf("</td>");
830
831         wc_strftime(d_str, sizeof d_str,
832                 "<td align=center>"
833                 "<font size=+2>%B</font><br />"
834                 "<font size=+3>%d</font><br />"
835                 "<font size=+2>%Y</font><br />"
836                 "</td>",
837                 &d_tm
838         );
839         wprintf("%s", d_str);
840
841         /** Right arrow */
842         wprintf("<td align=center>");
843         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
844                 tomorrow.year, tomorrow.month, tomorrow.day);
845         wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
846                 " border=0></a>\n");
847         wprintf("</td>");
848
849         wprintf("</tr></table>\n");
850         /** End todays-date-with-left-and-right-arrows */
851
852         /** \todo In the future we might want to put a month-o-matic here */
853
854         wprintf("</font></center>\n");
855
856         wprintf("</td></tr>");                  /** end stuff-on-the-right */
857
858         wprintf("</table>"                      /** end of inner table */
859                 "</div>");
860
861         wprintf("<script type=\"text/javascript\">"
862                 " setTimeout(\"btt_enableTooltips('inner_day')\", 1); "
863                 "</script>\n"
864         );
865 }
866
867
868 /**
869  * \brief Display today's events.
870  */
871 void calendar_summary_view(void) {
872         int i;
873         icalproperty *p;
874         struct icaltimetype t;
875         time_t event_tt;
876         struct tm event_tm;
877         struct tm today_tm;
878         time_t now;
879         int all_day_event = 0;
880         char timestring[SIZ];
881
882         if (WC->num_cal == 0) {
883                 return;
884         }
885
886         now = time(NULL);
887         localtime_r(&now, &today_tm);
888
889         for (i=0; i<(WC->num_cal); ++i) {
890                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
891                                                 ICAL_DTSTART_PROPERTY);
892                 if (p != NULL) {
893                         t = icalproperty_get_dtstart(p);
894                         event_tt = icaltime_as_timet(t);
895                         if (t.is_date) {
896                                 all_day_event = 1;
897                         }
898                         else {
899                                 all_day_event = 0;
900                         }
901                         fmt_time(timestring, event_tt);
902
903                         if (all_day_event) {
904                                 gmtime_r(&event_tt, &event_tm);
905                         }
906                         else {
907                                 localtime_r(&event_tt, &event_tm);
908                         }
909
910                         if ( (event_tm.tm_year == today_tm.tm_year)
911                            && (event_tm.tm_mon == today_tm.tm_mon)
912                            && (event_tm.tm_mday == today_tm.tm_mday)
913                            ) {
914
915
916                                 p = icalcomponent_get_first_property(
917                                                         WC->disp_cal[i].cal,
918                                                         ICAL_SUMMARY_PROPERTY);
919                                 if (p != NULL) {
920                                         escputs((char *)
921                                                 icalproperty_get_comment(p));
922                                         wprintf(" (%s)<br />\n", timestring);
923                                 }
924                         }
925                 }
926         }
927         free_calendar_buffer();
928 }
929
930
931 /**
932  * \brief clean up ical memory
933  * \todo this could get troubel with future ical versions
934  */
935 void free_calendar_buffer(void) {
936         int i;
937         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
938                 icalcomponent_free(WC->disp_cal[i].cal);
939         }
940         WC->num_cal = 0;
941         free(WC->disp_cal);
942         WC->disp_cal = NULL;
943 }
944
945
946
947 /**
948  * \brief do the whole calendar page
949  * view any part of the calender. decide which way, etc.
950  */
951 void do_calendar_view(void) {
952         time_t now;
953         struct tm tm;
954         int year, month, day;
955         char calview[SIZ];
956
957         /** In case no date was specified, go with today */
958         now = time(NULL);
959         localtime_r(&now, &tm);
960         year = tm.tm_year + 1900;
961         month = tm.tm_mon + 1;
962         day = tm.tm_mday;
963
964         /** Now see if a date was specified */
965         if (!IsEmptyStr(bstr("year"))) year = atoi(bstr("year"));
966         if (!IsEmptyStr(bstr("month"))) month = atoi(bstr("month"));
967         if (!IsEmptyStr(bstr("day"))) day = atoi(bstr("day"));
968
969         /** How would you like that cooked? */
970         if (!IsEmptyStr(bstr("calview"))) {
971                 strcpy(calview, bstr("calview"));
972         }
973         else {
974                 strcpy(calview, "month");
975         }
976
977         /** Display the selected view */
978         if (!strcasecmp(calview, "day")) {
979                 calendar_day_view(year, month, day);
980         }
981         else if (!strcasecmp(calview, "week")) {
982                 calendar_week_view(year, month, day);
983         }
984         else {
985                 if (WC->wc_view == VIEW_CALBRIEF) {
986                         calendar_brief_month_view(year, month, day);
987                 }
988                 else {
989                         calendar_month_view(year, month, day);
990                 }
991         }
992
993         /** Free the calendar stuff */
994         free_calendar_buffer();
995
996 }
997
998
999 /**
1000  * \brief get task due date
1001  * Helper function for do_tasks_view().  
1002  * \param vtodo a task to get the due date
1003  * \return the date/time due.
1004  */
1005 time_t get_task_due_date(icalcomponent *vtodo) {
1006         icalproperty *p;
1007
1008         if (vtodo == NULL) {
1009                 return(0L);
1010         }
1011
1012         /**
1013          * If we're looking at a fully encapsulated VCALENDAR
1014          * rather than a VTODO component, recurse into the data
1015          * structure until we get a VTODO.
1016          */
1017         if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
1018                 return get_task_due_date(
1019                         icalcomponent_get_first_component(
1020                                 vtodo, ICAL_VTODO_COMPONENT
1021                         )
1022                 );
1023         }
1024
1025         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
1026         if (p != NULL) {
1027                 return(icaltime_as_timet(icalproperty_get_due(p)));
1028         }
1029         else {
1030                 return(0L);
1031         }
1032 }
1033
1034
1035 /**
1036  * \brief Compare the due dates of two tasks (this is for sorting)
1037  * \param task1 first task to compare
1038  * \param task2 second task to compare
1039  */
1040 int task_due_cmp(const void *task1, const void *task2) {
1041         time_t t1;
1042         time_t t2;
1043
1044         t1 =  get_task_due_date(((struct disp_cal *)task1)->cal);
1045         t2 =  get_task_due_date(((struct disp_cal *)task2)->cal);
1046
1047         if (t1 < t2) return(-1);
1048         if (t1 > t2) return(1);
1049         return(0);
1050 }
1051
1052
1053
1054
1055 /**
1056  * \brief do the whole task view stuff
1057  */
1058 void do_tasks_view(void) {
1059         int i;
1060         time_t due;
1061         int bg = 0;
1062         char buf[SIZ];
1063         icalproperty *p;
1064
1065         wprintf("<div class=\"fix_scrollbar_bug\">"
1066                 "<table class=\"calendar_view_background\">\n<tr>\n"
1067                 "<th>");
1068         wprintf(_("Name of task"));
1069         wprintf("</th><th>");
1070         wprintf(_("Date due"));
1071         wprintf("</th></tr>\n"
1072         );
1073
1074         /** Sort them if necessary */
1075         if (WC->num_cal > 1) {
1076                 qsort(WC->disp_cal,
1077                         WC->num_cal,
1078                         sizeof(struct disp_cal),
1079                         task_due_cmp
1080                 );
1081         }
1082
1083         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
1084
1085                 bg = 1 - bg;
1086                 wprintf("<tr bgcolor=\"#%s\"><td>",
1087                         (bg ? "DDDDDD" : "FFFFFF")
1088                 );
1089
1090                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
1091                                                         ICAL_SUMMARY_PROPERTY);
1092                 wprintf("<a href=\"display_edit_task?msgnum=%ld&taskrm=",
1093                         WC->disp_cal[i].cal_msgnum );
1094                 urlescputs(WC->wc_roomname);
1095                 wprintf("\">");
1096                 wprintf("<img align=middle "
1097                         "src=\"static/taskmanag_16x.gif\" border=0>&nbsp;");
1098                 if (p != NULL) {
1099                         escputs((char *)icalproperty_get_comment(p));
1100                 }
1101                 wprintf("</a>\n");
1102                 wprintf("</td>\n");
1103
1104                 due = get_task_due_date(WC->disp_cal[i].cal);
1105                 fmt_date(buf, due, 0);
1106                 wprintf("<td><font");
1107                 if (due < time(NULL)) {
1108                         wprintf(" color=\"#FF0000\"");
1109                 }
1110                 wprintf(">%s</font></td></tr>\n", buf);
1111         }
1112
1113         wprintf("</table></div>\n");
1114
1115         /** Free the list */
1116         free_calendar_buffer();
1117
1118 }
1119
1120 #else   /* WEBCIT_WITH_CALENDAR_SERVICE */
1121
1122 /**\brief stub for non-libical builds */
1123 void do_calendar_view(void) {
1124         wprintf("<center><i>");
1125         wprintf(_("The calendar view is not available."));
1126         wprintf("</i></center><br />\n");
1127 }
1128
1129 /**\brief stub for non-libical builds */
1130 void do_tasks_view(void) {      
1131         wprintf("<center><I>");
1132         wprintf(_("The tasks view is not available."));
1133         wprintf("</i></center><br />\n");
1134 }
1135
1136
1137 #endif  /* WEBCIT_WITH_CALENDAR_SERVICE */
1138
1139 /** @} */