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