display webcit calendar day view events with minutes
[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  * \param dstart daystart 
631  */
632 void calendar_day_view_display_events(int year, int month,
633                                         int day, int hour,
634                                         int inner, int dstart) {
635         int i;
636         icalproperty *p;
637         icalproperty *pe = NULL;
638         struct icaltimetype t;
639         struct icaltimetype te;
640         time_t event_tt;
641         time_t event_tte;
642         struct tm event_te;
643         struct tm event_tm;
644         int all_day_event = 0;
645
646         if (WC->num_cal == 0) {
647                 // \todo FIXME wprintf("<br /><br /><br />\n");
648                 return;
649         }
650
651         for (i=0; i<(WC->num_cal); ++i) {
652                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
653                                                 ICAL_DTSTART_PROPERTY);
654                 pe = icalcomponent_get_first_property(WC->disp_cal[i].cal,
655                                                       ICAL_DTEND_PROPERTY);
656                 if (p != NULL) {
657                         t = icalproperty_get_dtstart(p);
658                         event_tt = icaltime_as_timet(t);
659                         if (t.is_date) {
660                                 all_day_event = 1;
661                         }
662                         else {
663                                 all_day_event = 0;
664                         }
665
666                         if (all_day_event) {
667                                 gmtime_r(&event_tt, &event_tm);
668                                 gmtime_r(&event_tt, &event_te);
669                         }
670                         else {
671                                 localtime_r(&event_tt, &event_tm);
672                                 if (pe != NULL)
673                                 {
674                                         te = icalproperty_get_dtend(pe);
675                                         event_tte = icaltime_as_timet(te);
676                                         localtime_r(&event_tte, &event_te);
677                                 }
678                                 else 
679                                         localtime_r(&event_tt, &event_te);
680                         }
681
682                         if (((event_tm.tm_year <= (year-1900))
683                              && (event_tm.tm_mon <= (month-1))
684                              && (event_tm.tm_mday <= day)
685                              && (event_te.tm_year >= (year-1900))
686                              && (event_te.tm_mon >= (month-1))
687                              && (event_te.tm_mday >= day))
688                             && (
689                                  // are we in the start hour?
690                                     ((event_tm.tm_mday == day)
691                                      && (event_tm.tm_hour == hour) 
692                                      && (!t.is_date)) 
693                                  // are we an all day event?
694                                     || ((hour<0)&&(t.is_date))
695                                  // does it span multible days and we're not at the start day?
696                                     || ((hour<0)
697                                         && (event_tm.tm_mday < day) 
698                                         && (event_te.tm_mday >= day))
699                                     ))
700                         {
701                                 p = icalcomponent_get_first_property(
702                                                         WC->disp_cal[i].cal,
703                                                         ICAL_SUMMARY_PROPERTY);
704                                 if (p != NULL) {
705
706                                         if (all_day_event) {
707                                         wprintf("<dd><a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
708                                                 WC->disp_cal[i].cal_msgnum,
709                                                 year, month, day, hour
710                                         );
711                                         escputs((char *)
712                                                 icalproperty_get_comment(p));
713                                         wprintf("</a></dd>\n");
714                                         }
715                                         else {
716                                                 if (inner) {
717                                                         wprintf("<dd  class=\"event\" "
718                                                                 "style=\"position: absolute; "
719                                                                 "top:%dpx; left:100px; "
720                                                                 "height:%dpx; \" >",
721                                                                 (1 + (event_tm.tm_min / 2) + (event_te.tm_hour - hour) + (hour * 30) - (dstart * 30)),
722                                                                 (((event_te.tm_min - event_tm.tm_min) / 2) +(event_te.tm_hour - hour) * 30)
723                                                         );
724                                                 }
725                                                 else {
726                                                         wprintf("<dd>");
727                                                 }
728                                                 wprintf("<a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
729                                                         WC->disp_cal[i].cal_msgnum,
730                                                         year, month, day, hour
731                                                 );
732                                                 escputs((char *)
733                                                         icalproperty_get_comment(p));
734                                                 wprintf("</a></dd>\n");
735                                           
736                                         }
737                                 }
738                         }
739
740                 }
741         }
742 }
743
744
745
746 /**
747  * \brief view one day
748  * \param year the year
749  * \param month the month 
750  * \param day the day we want to display
751  */
752 void calendar_day_view(int year, int month, int day) {
753         int hour;
754         struct icaltimetype today, yesterday, tomorrow;
755         int daystart = 8;
756         int dayend = 17;
757         char daystart_str[16], dayend_str[16];
758         struct tm d_tm;
759         char d_str[128];
760         int time_format;
761         
762         time_format = get_time_format_cached ();
763         get_preference("daystart", daystart_str, sizeof daystart_str);
764         if (!IsEmptyStr(daystart_str)) daystart = atoi(daystart_str);
765         get_preference("dayend", dayend_str, sizeof dayend_str);
766         if (!IsEmptyStr(dayend_str)) dayend = atoi(dayend_str);
767         
768
769         /** Figure out the dates for "yesterday" and "tomorrow" links */
770
771         memset(&today, 0, sizeof(struct icaltimetype));
772         today.year = year;
773         today.month = month;
774         today.day = day;
775         today.is_date = 1;
776
777         memcpy(&yesterday, &today, sizeof(struct icaltimetype));
778         --yesterday.day;
779         yesterday = icaltime_normalize(yesterday);
780
781         memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
782         ++tomorrow.day;
783         tomorrow = icaltime_normalize(tomorrow);
784
785         wprintf("<div class=\"fix_scrollbar_bug\">");
786
787         /** Inner table (the real one) */
788         wprintf("<table class=\"calendar\"><tr> \n");
789
790         /** Innermost cell (contains hours etc.) */
791         wprintf("<td class=\"middle_of_the_day\">");
792         wprintf("<dl style=\" "
793                 "       padding:0 ;"
794                 "       margin: 0;"
795                 "       position: absolute ;"
796                 "       top: 0;"
797                 "        left: 0;"
798                 "        width: 500px;"
799                 "        clip: rect(0px 500px %dpx 0px);"
800                 "        clip: rect(0px, 500px, %dpx, 0px);"
801                 "\">",
802         (dayend - daystart) * 30,
803         (dayend - daystart) * 30
804         ); 
805         /** Now the middle of the day... */     
806         for (hour = 0; hour <= dayend; ++hour) {        /* could do HEIGHT=xx */
807                 if (hour >= daystart) {
808                         wprintf("<dt><a href=\"display_edit_event?msgnum=0"
809                                 "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
810                                 year, month, day, hour
811                         );
812
813                         if (time_format == WC_TIMEFORMAT_24) {
814                                 wprintf("%2d:00</a> ", hour);
815                         }
816                         else {
817                                 wprintf("%d:00%s</a> ",
818                                         (hour <= 12 ? hour : hour-12),
819                                         (hour < 12 ? "am" : "pm")
820                                 );
821                         }
822
823                 wprintf("</dt>");
824                 }
825
826                 /* put the data here, stupid */
827                 calendar_day_view_display_events(year, month, day, hour, 1 , daystart);
828
829         }
830
831         wprintf("</dl>");
832         wprintf("</td>");                       /* end of innermost table */
833
834         /** Extra events on the middle */
835         wprintf("<td class=\"extra_events\">");
836
837         wprintf("<dl>");
838
839         /** Display all-day events) */
840         wprintf("<dt>All day events</dt>");
841                 calendar_day_view_display_events(year, month, day, -1, 0 , daystart);
842
843         /** Display events before daystart */
844         wprintf("<dt>Before day start</dt>");
845         for (hour = 0; hour <= (daystart-1); ++hour) {
846                 calendar_day_view_display_events(year, month, day, hour, 0, daystart );
847         }
848
849         /** Display events after dayend... */
850         wprintf("<dt>After</dt>");
851         for (hour = (dayend+1); hour <= 23; ++hour) {
852                 calendar_day_view_display_events(year, month, day, hour, 0, daystart );
853         }
854
855         wprintf("</dl>");
856
857         wprintf("</td>");       /** end extra on the middle */
858
859         wprintf("<td width=20%% valign=top>");  /** begin stuff-on-the-right */
860
861         /** Begin todays-date-with-left-and-right-arrows */
862         wprintf("<table border=0 width=100%% "
863                 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
864         wprintf("<tr>");
865
866         /** Left arrow */       
867         wprintf("<td align=center>");
868         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
869                 yesterday.year, yesterday.month, yesterday.day);
870         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
871         wprintf("</td>");
872
873         /** Today's date */
874         memset(&d_tm, 0, sizeof d_tm);
875         d_tm.tm_year = year - 1900;
876         d_tm.tm_mon = month - 1;
877         d_tm.tm_mday = day;
878         wc_strftime(d_str, sizeof d_str,
879                 "<td align=center>"
880                 "<font size=+2>%B</font><br />"
881                 "<font size=+3>%d</font><br />"
882                 "<font size=+2>%Y</font><br />"
883                 "</td>",
884                 &d_tm
885         );
886         wprintf("%s", d_str);
887
888         /** Right arrow */
889         wprintf("<td align=center>");
890         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
891                 tomorrow.year, tomorrow.month, tomorrow.day);
892         wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
893                 " border=0></a>\n");
894         wprintf("</td>");
895
896         wprintf("</tr></table>\n");
897         /** End todays-date-with-left-and-right-arrows */
898
899         /** \todo In the future we might want to put a month-o-matic here */
900
901         wprintf("</font></center>\n");
902
903         wprintf("</td></tr>");                  /** end stuff-on-the-right */
904
905         wprintf("</table>"                      /** end of inner table */
906                 "</div>");
907
908 }
909 /**
910  * \brief Display today's events.
911  */
912 void calendar_summary_view(void) {
913         int i;
914         icalproperty *p;
915         struct icaltimetype t;
916         time_t event_tt;
917         struct tm event_tm;
918         struct tm today_tm;
919         time_t now;
920         int all_day_event = 0;
921         char timestring[SIZ];
922
923         if (WC->num_cal == 0) {
924                 return;
925         }
926
927         now = time(NULL);
928         localtime_r(&now, &today_tm);
929
930         for (i=0; i<(WC->num_cal); ++i) {
931                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
932                                                 ICAL_DTSTART_PROPERTY);
933                 if (p != NULL) {
934                         t = icalproperty_get_dtstart(p);
935                         event_tt = icaltime_as_timet(t);
936                         if (t.is_date) {
937                                 all_day_event = 1;
938                         }
939                         else {
940                                 all_day_event = 0;
941                         }
942                         fmt_time(timestring, event_tt);
943
944                         if (all_day_event) {
945                                 gmtime_r(&event_tt, &event_tm);
946                         }
947                         else {
948                                 localtime_r(&event_tt, &event_tm);
949                         }
950
951                         if ( (event_tm.tm_year == today_tm.tm_year)
952                            && (event_tm.tm_mon == today_tm.tm_mon)
953                            && (event_tm.tm_mday == today_tm.tm_mday)
954                            ) {
955
956
957                                 p = icalcomponent_get_first_property(
958                                                         WC->disp_cal[i].cal,
959                                                         ICAL_SUMMARY_PROPERTY);
960                                 if (p != NULL) {
961                                         escputs((char *)
962                                                 icalproperty_get_comment(p));
963                                         wprintf(" (%s)<br />\n", timestring);
964                                 }
965                         }
966                 }
967         }
968         free_calendar_buffer();
969 }
970
971
972 /**
973  * \brief clean up ical memory
974  * \todo this could get troubel with future ical versions
975  */
976 void free_calendar_buffer(void) {
977         int i;
978         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
979                 icalcomponent_free(WC->disp_cal[i].cal);
980         }
981         WC->num_cal = 0;
982         free(WC->disp_cal);
983         WC->disp_cal = NULL;
984 }
985
986
987
988 /**
989  * \brief do the whole calendar page
990  * view any part of the calender. decide which way, etc.
991  */
992 void do_calendar_view(void) {
993         time_t now;
994         struct tm tm;
995         int year, month, day;
996         char calview[SIZ];
997
998         /** In case no date was specified, go with today */
999         now = time(NULL);
1000         localtime_r(&now, &tm);
1001         year = tm.tm_year + 1900;
1002         month = tm.tm_mon + 1;
1003         day = tm.tm_mday;
1004
1005         /** Now see if a date was specified */
1006         if (!IsEmptyStr(bstr("year"))) year = atoi(bstr("year"));
1007         if (!IsEmptyStr(bstr("month"))) month = atoi(bstr("month"));
1008         if (!IsEmptyStr(bstr("day"))) day = atoi(bstr("day"));
1009
1010         /** How would you like that cooked? */
1011         if (!IsEmptyStr(bstr("calview"))) {
1012                 strcpy(calview, bstr("calview"));
1013         }
1014         else {
1015                 strcpy(calview, "month");
1016         }
1017
1018         /** Display the selected view */
1019         if (!strcasecmp(calview, "day")) {
1020                 calendar_day_view(year, month, day);
1021         }
1022         else if (!strcasecmp(calview, "week")) {
1023                 calendar_week_view(year, month, day);
1024         }
1025         else {
1026                 if (WC->wc_view == VIEW_CALBRIEF) {
1027                         calendar_brief_month_view(year, month, day);
1028                 }
1029                 else {
1030                         calendar_month_view(year, month, day);
1031                 }
1032         }
1033
1034         /** Free the calendar stuff */
1035         free_calendar_buffer();
1036
1037 }
1038
1039
1040 /**
1041  * \brief get task due date
1042  * Helper function for do_tasks_view().  
1043  * \param vtodo a task to get the due date
1044  * \return the date/time due.
1045  */
1046 time_t get_task_due_date(icalcomponent *vtodo) {
1047         icalproperty *p;
1048
1049         if (vtodo == NULL) {
1050                 return(0L);
1051         }
1052
1053         /**
1054          * If we're looking at a fully encapsulated VCALENDAR
1055          * rather than a VTODO component, recurse into the data
1056          * structure until we get a VTODO.
1057          */
1058         if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
1059                 return get_task_due_date(
1060                         icalcomponent_get_first_component(
1061                                 vtodo, ICAL_VTODO_COMPONENT
1062                         )
1063                 );
1064         }
1065
1066         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
1067         if (p != NULL) {
1068                 return(icaltime_as_timet(icalproperty_get_due(p)));
1069         }
1070         else {
1071                 return(0L);
1072         }
1073 }
1074
1075
1076 /**
1077  * \brief Compare the due dates of two tasks (this is for sorting)
1078  * \param task1 first task to compare
1079  * \param task2 second task to compare
1080  */
1081 int task_due_cmp(const void *task1, const void *task2) {
1082         time_t t1;
1083         time_t t2;
1084
1085         t1 =  get_task_due_date(((struct disp_cal *)task1)->cal);
1086         t2 =  get_task_due_date(((struct disp_cal *)task2)->cal);
1087
1088         if (t1 < t2) return(-1);
1089         if (t1 > t2) return(1);
1090         return(0);
1091 }
1092
1093
1094
1095
1096 /**
1097  * \brief do the whole task view stuff
1098  */
1099 void do_tasks_view(void) {
1100         int i;
1101         time_t due;
1102         int bg = 0;
1103         char buf[SIZ];
1104         icalproperty *p;
1105
1106         wprintf("<div class=\"fix_scrollbar_bug\">"
1107                 "<table class=\"calendar_view_background\">\n<tr>\n"
1108                 "<th>");
1109         wprintf(_("Name of task"));
1110         wprintf("</th><th>");
1111         wprintf(_("Date due"));
1112         wprintf("</th></tr>\n"
1113         );
1114
1115         /** Sort them if necessary */
1116         if (WC->num_cal > 1) {
1117                 qsort(WC->disp_cal,
1118                         WC->num_cal,
1119                         sizeof(struct disp_cal),
1120                         task_due_cmp
1121                 );
1122         }
1123
1124         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
1125
1126                 bg = 1 - bg;
1127                 wprintf("<tr bgcolor=\"#%s\"><td>",
1128                         (bg ? "DDDDDD" : "FFFFFF")
1129                 );
1130
1131                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
1132                                                         ICAL_SUMMARY_PROPERTY);
1133                 wprintf("<a href=\"display_edit_task?msgnum=%ld&taskrm=",
1134                         WC->disp_cal[i].cal_msgnum );
1135                 urlescputs(WC->wc_roomname);
1136                 wprintf("\">");
1137                 wprintf("<img align=middle "
1138                         "src=\"static/taskmanag_16x.gif\" border=0>&nbsp;");
1139                 if (p != NULL) {
1140                         escputs((char *)icalproperty_get_comment(p));
1141                 }
1142                 wprintf("</a>\n");
1143                 wprintf("</td>\n");
1144
1145                 due = get_task_due_date(WC->disp_cal[i].cal);
1146                 fmt_date(buf, due, 0);
1147                 wprintf("<td><font");
1148                 if (due < time(NULL)) {
1149                         wprintf(" color=\"#FF0000\"");
1150                 }
1151                 wprintf(">%s</font></td></tr>\n", buf);
1152         }
1153
1154         wprintf("</table></div>\n");
1155
1156         /** Free the list */
1157         free_calendar_buffer();
1158
1159 }
1160
1161 #else   /* WEBCIT_WITH_CALENDAR_SERVICE */
1162
1163 /**\brief stub for non-libical builds */
1164 void do_calendar_view(void) {
1165         wprintf("<center><i>");
1166         wprintf(_("The calendar view is not available."));
1167         wprintf("</i></center><br />\n");
1168 }
1169
1170 /**\brief stub for non-libical builds */
1171 void do_tasks_view(void) {      
1172         wprintf("<center><I>");
1173         wprintf(_("The tasks view is not available."));
1174         wprintf("</i></center><br />\n");
1175 }
1176
1177
1178 #endif  /* WEBCIT_WITH_CALENDAR_SERVICE */
1179
1180 /** @} */