implemented Bubble Tooltips on calendar day view
[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 void embeddable_mini_calendar(int year, int month, char *urlformat)
18 {
19         struct tm starting_tm;
20         struct tm tm;
21         time_t thetime;
22         int i, len;
23         time_t previous_month;
24         time_t next_month;
25         time_t colheader_time;
26         struct tm colheader_tm;
27         char colheader_label[32];
28         int weekstart = 0;
29         char weekstart_buf[16];
30         char url[256];
31         char div_id[256];
32         char escaped_urlformat[256];
33
34         snprintf(div_id, sizeof div_id, "mini_calendar_%d", rand() );
35
36         /* Determine what day to start.
37          */
38         get_preference("weekstart", weekstart_buf, sizeof weekstart_buf);
39         weekstart = atoi(weekstart_buf);
40
41         /*
42          * Now back up to the 1st of the month...
43          */
44         memset(&starting_tm, 0, sizeof(struct tm));
45
46         starting_tm.tm_year = year - 1900;
47         starting_tm.tm_mon = month - 1;
48         starting_tm.tm_mday = 1;
49         thetime = mktime(&starting_tm);
50
51         memcpy(&tm, &starting_tm, sizeof(struct tm));
52         while (tm.tm_mday != 1) {
53                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
54                 localtime_r(&thetime, &tm);
55         }
56
57         /** Determine previous and next months ... for links */
58         previous_month = thetime - (time_t)864000L;     /* back 10 days */
59         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
60
61         /** Now back up until we're on the user's preferred start day */
62         localtime_r(&thetime, &tm);
63         while (tm.tm_wday != weekstart) {
64                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
65                 localtime_r(&thetime, &tm);
66         }
67
68         wprintf("<div class=\"mini_calendar\" id=\"%s\">\n", div_id);
69
70         /* Previous month link */
71         localtime_r(&previous_month, &tm);
72         wprintf("<a href=\"javascript:minical_change_month(%d,%d);\">&laquo;</a>", 
73                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
74
75         wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
76         wprintf("&nbsp;&nbsp;"
77                 "<span class=\"mini_calendar_month_label\">"
78                 "%s %d"
79                 "</span>"
80                 "&nbsp;&nbsp;", colheader_label, year);
81
82         /* Next month link */
83         localtime_r(&next_month, &tm);
84         wprintf("<a href=\"javascript:minical_change_month(%d,%d);\">&raquo;</a>",
85                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
86
87         wprintf("<table border=0 cellpadding=1 cellspacing=1 class=\"mini_calendar_days\">"
88                 "<tr>");
89         colheader_time = thetime;
90         for (i=0; i<7; ++i) {
91                 colheader_time = thetime + (i * 86400) ;
92                 localtime_r(&colheader_time, &colheader_tm);
93                 wc_strftime(colheader_label, sizeof colheader_label, "%A", &colheader_tm);
94                 wprintf("<th>%c</th>", colheader_label[0]);
95
96         }
97         wprintf("</tr>\n");
98
99
100         /** Now do 35 or 42 days */
101         for (i = 0; i < 42; ++i) {
102                 localtime_r(&thetime, &tm);
103
104                 if (i < 35) {
105
106                         /** Before displaying Sunday, start a new row */
107                         if ((i % 7) == 0) {
108                                 wprintf("<tr>");
109                         }
110
111                         if (tm.tm_mon == month-1) {
112                                 snprintf(url, sizeof url, urlformat,
113                                         tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
114                                 wprintf("<td><a href=\"%s\">%d</a></td>", url, tm.tm_mday);
115                         }
116                         else {
117                                 wprintf("<td> </td>");
118                         }
119
120                         /** After displaying one week, end the row */
121                         if ((i % 7) == 6) {
122                                 wprintf("</tr>\n");
123                         }
124
125                 }
126
127                 thetime += (time_t)86400;               /** ahead 24 hours */
128         }
129
130         wprintf("</table>"                      /** end of inner table */
131                 "</div>\n");
132
133         /* javascript for previous and next month */
134         len = strlen(urlformat);
135         for (i=0; i<len; ++i) {
136                 sprintf(&escaped_urlformat[i*2], "%02X", urlformat[i]);
137         }
138
139         wprintf("<script type=\"text/javascript\">                                                      "
140                 "       function minical_change_month(year, month) {                                    "
141                 "               p = 'year=' + year + '&month=' + month                                  "
142                 "                       + '&urlformat=%s&r=' + CtdlRandomString();                      "
143                 "               new Ajax.Updater('%s', 'mini_calendar',                                 "
144                 "                       { method: 'get', parameters: p, evalScripts: true } );          "
145                 "       }                                                                               "
146                 "</script>\n"
147                 ,
148                 escaped_urlformat, div_id
149         );
150
151 }
152
153 /* ajax embedder for the above mini calendar */
154 void ajax_mini_calendar(void) {
155         char urlformat[256];
156         int i, len;
157         char *escaped_urlformat;
158
159         escaped_urlformat = bstr("urlformat");
160         len = strlen(escaped_urlformat) * 2 ;
161         for (i=0; i<len; ++i) {
162                 urlformat[i] = xtoi(&escaped_urlformat[i*2], 2);
163                 urlformat[i+1] = 0;
164         }
165
166         embeddable_mini_calendar( atoi(bstr("year")), atoi(bstr("month")), urlformat );
167 }
168
169
170 /**
171  * \brief Display one day of a whole month view of a calendar
172  * \param thetime the month we want to see 
173  */
174 void calendar_month_view_display_events(int year, int month, int day)
175 {
176         int i;
177         icalproperty *p = NULL;
178         icalproperty *q = NULL;
179         struct icaltimetype t;
180         struct icaltimetype end_t;
181         struct icaltimetype today_start_t;
182         struct icaltimetype today_end_t;
183         struct tm starting_tm;
184         struct tm ending_tm;
185         int all_day_event = 0;
186         int show_event = 0;
187         char buf[256];
188         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
189         struct disp_cal *Cal;
190         time_t tt;
191
192         if (WCC->num_cal == 0) {
193                 wprintf("<br /><br /><br />\n");
194                 return;
195         }
196
197         /* Create an imaginary event which spans the 24 hours of today.  Any events which
198          * overlap with this one take place at least partially in this day.  We have to
199          * convert it from a struct tm in order to make it UTC.
200          */
201         memset(&starting_tm, 0, sizeof(struct tm));
202         starting_tm.tm_year = year - 1900;
203         starting_tm.tm_mon = month - 1;
204         starting_tm.tm_mday = day;
205         starting_tm.tm_hour = 0;
206         starting_tm.tm_min = 0;
207         today_start_t = icaltime_from_timet_with_zone(mktime(&starting_tm), 0, icaltimezone_get_utc_timezone());
208         today_start_t.is_utc = 1;
209
210         memset(&ending_tm, 0, sizeof(struct tm));
211         ending_tm.tm_year = year - 1900;
212         ending_tm.tm_mon = month - 1;
213         ending_tm.tm_mday = day;
214         ending_tm.tm_hour = 23;
215         ending_tm.tm_min = 59;
216         today_end_t = icaltime_from_timet_with_zone(mktime(&ending_tm), 0, icaltimezone_get_utc_timezone());
217         today_end_t.is_utc = 1;
218
219         /* Now loop through our list of events to see which ones occur today.
220          */
221         for (i=0; i<(WCC->num_cal); ++i) {
222                 Cal = &WCC->disp_cal[i];
223                 all_day_event = 0;
224                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
225                 if (q != NULL) {
226                         t = icalproperty_get_dtstart(q);
227                 }
228                 else {
229                         memset(&t, 0, sizeof t);
230                 }
231                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
232                 if (q != NULL) {
233                         end_t = icalproperty_get_dtend(q);
234                 }
235                 else {
236                         memset(&end_t, 0, sizeof end_t);
237                 }
238                 if (t.is_date) all_day_event = 1;
239
240                 if (all_day_event)
241                 {
242                         show_event = ((t.year == year) && (t.month == month) && (t.day == day));
243                 }
244                 else
245                 {
246                         show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
247                 }
248
249                 /* If we determined that this event occurs today, then display it.
250                  */
251                 if (show_event) {
252                         p = icalcomponent_get_first_property(Cal->cal, ICAL_SUMMARY_PROPERTY);
253                         if (p != NULL) {
254
255                                 if (all_day_event) {
256                                         wprintf("<table border=0 cellpadding=2><TR>"
257                                                 "<td bgcolor=\"#CCCCDD\">"
258                                                 );
259                                 }
260
261                                 wprintf("<font size=-1>"
262                                         "<a href=\"display_edit_event?"
263                                         "msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\""
264                                         " btt_tooltext=\"",
265                                         WC->disp_cal[i].cal_msgnum,
266                                         bstr("calview"),
267                                         bstr("year"),
268                                         bstr("month"),
269                                         bstr("day")
270                                         );
271
272                                 wprintf("<i>%s</i> ", _("Summary:"));
273                                 escputs((char *)icalproperty_get_comment(p));
274                                 wprintf("<br />");
275                                 
276                                 q = icalcomponent_get_first_property(
277                                         WC->disp_cal[i].cal,
278                                         ICAL_LOCATION_PROPERTY);
279                                 if (q) {
280                                         wprintf("<i>%s</i> ", _("Location:"));
281                                         escputs((char *)icalproperty_get_comment(q));
282                                         wprintf("<br />");
283                                         }
284                                 
285                                 /**
286                                  * Only show start/end times if we're actually looking at the VEVENT
287                                  * component.  Otherwise it shows bogus dates for e.g. timezones
288                                  */
289                                 if (icalcomponent_isa(Cal->cal) == ICAL_VEVENT_COMPONENT) {
290                                         
291                                         q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
292                                         if (q != NULL) {
293                                                 t = icalproperty_get_dtstart(q);
294                                                 
295                                                 if (t.is_date) {
296                                                         struct tm d_tm;
297                                                         char d_str[32];
298                                                         memset(&d_tm, 0, sizeof d_tm);
299                                                         d_tm.tm_year = t.year - 1900;
300                                                         d_tm.tm_mon = t.month - 1;
301                                                         d_tm.tm_mday = t.day;
302                                                         wc_strftime(d_str, sizeof d_str, "%x", &d_tm);
303                                                         wprintf("<i>%s</i> %s<br>",
304                                                                 _("Date:"), d_str);
305                                                 }
306                                                 else {
307                                                         tt = icaltime_as_timet(t);
308                                                         fmt_date(buf, tt, 1);
309                                                         wprintf("<i>%s</i> %s<br>",
310                                                                 _("Starting date/time:"), buf);
311                                                         
312                                                         /* Embed the 'show end date/time' loop inside here so it
313                                                          * only executes if this is NOT an all day event.
314                                                          */
315                                                         q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
316                                                         if (q != NULL) {
317                                                                 t = icalproperty_get_dtend(q);
318                                                                 tt = icaltime_as_timet(t);
319                                                                 fmt_date(buf, tt, 1);
320                                                                 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
321                                                         }
322                                                         
323                                                 }
324                                         }
325                                         
326                                 }
327                                 
328                                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DESCRIPTION_PROPERTY);
329                                 if (q) {
330                                         wprintf("<i>%s</i> ", _("Notes:"));
331                                         escputs((char *)icalproperty_get_comment(q));
332                                         wprintf("<br />");
333                                 }
334                                 
335                                 wprintf("\">");
336                                 escputs((char *)
337                                         icalproperty_get_comment(p));
338                                 wprintf("</a></font><br />\n");
339                                 
340                                 if (all_day_event) {
341                                         wprintf("</td></tr></table>");
342                                 }
343                                 
344                         }
345                         
346                 }
347                 
348                 
349         }
350 }
351
352
353 /**
354  * \brief Display one day of a whole month view of a calendar
355  * \param thetime the month we want to see 
356  */
357 void calendar_month_view_brief_events(time_t thetime, const char *daycolor) {
358         int i;
359         time_t event_tt;
360         time_t event_tts;
361         time_t event_tte;
362         struct tm event_tms;
363         struct tm event_tme;
364         struct tm today_tm;
365         icalproperty *p;
366         icalproperty *e;
367         struct icaltimetype t;
368         int month, day, year;
369         int all_day_event = 0;
370         char *timeformat;
371         int time_format;
372         
373         time_format = get_time_format_cached ();
374
375         if (time_format == WC_TIMEFORMAT_24) timeformat="%k:%M";
376         else timeformat="%I:%M %p";
377
378         localtime_r(&thetime, &today_tm);
379         month = today_tm.tm_mon + 1;
380         day = today_tm.tm_mday;
381         year = today_tm.tm_year + 1900;
382
383         for (i=0; i<(WC->num_cal); ++i) {
384                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
385                                                 ICAL_DTSTART_PROPERTY);
386                 if (p != NULL) {
387                         t = icalproperty_get_dtstart(p);
388                         event_tt = icaltime_as_timet(t);
389                         event_tts=event_tt;
390                         if (t.is_date) all_day_event = 1;
391                         else all_day_event = 0;
392
393                         if (all_day_event) {
394                                 gmtime_r(&event_tts, &event_tms);
395                         }
396                         else {
397                                 localtime_r(&event_tts, &event_tms);
398                         }
399                         /** \todo epoch &! daymask */
400                         if ((event_tms.tm_year == today_tm.tm_year)
401                            && (event_tms.tm_mon == today_tm.tm_mon)
402                            && (event_tms.tm_mday == today_tm.tm_mday)) {
403                                 
404                                 
405                                 char sbuf[255];
406                                 char ebuf[255];
407
408                                 p = icalcomponent_get_first_property(
409                                                         WC->disp_cal[i].cal,
410                                                         ICAL_SUMMARY_PROPERTY);
411                                 e = icalcomponent_get_first_property(
412                                                         WC->disp_cal[i].cal, 
413                                                         ICAL_DTEND_PROPERTY);
414                                 if ((p != NULL) && (e != NULL)) {
415                                         time_t difftime;
416                                         int hours, minutes;
417                                         t = icalproperty_get_dtend(e);
418                                         event_tte = icaltime_as_timet(t);
419                                         localtime_r(&event_tte, &event_tme);
420                                         difftime=(event_tte-event_tts)/60;
421                                         hours=(int)(difftime / 60);
422                                         minutes=difftime % 60;
423                                         wprintf("<tr><td bgcolor='%s'>%i:%2i</td><td bgcolor='%s'>"
424                                                         "<font size=-1>"
425                                                         "<a href=\"display_edit_event?msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\">",
426                                                         daycolor,
427                                                         hours, minutes,
428                                                         daycolor,
429                                                         WC->disp_cal[i].cal_msgnum,
430                                                         bstr("calview"),
431                                                         bstr("year"),
432                                                         bstr("month"),
433                                                         bstr("day")
434                                                         );
435
436                                         escputs((char *)
437                                                         icalproperty_get_comment(p));
438                                         /** \todo: allso ammitime format */
439                                         wc_strftime(&sbuf[0], sizeof(sbuf), timeformat, &event_tms);
440                                         wc_strftime(&ebuf[0], sizeof(sbuf), timeformat, &event_tme);
441
442                                         wprintf("</a></font></td>"
443                                                         "<td bgcolor='%s'>%s</td><td bgcolor='%s'>%s</td></tr>",
444                                                         daycolor,
445                                                         sbuf,
446                                                         daycolor,
447                                                         ebuf);
448                                         
449                                 }
450                                 
451                         }
452                         
453                         
454                 }
455         }
456 }
457
458
459 /**
460  * \brief view one month. pretty view
461  * \param year the year
462  * \param month the month
463  * \param day the actual day we want to see
464  */
465 void calendar_month_view(int year, int month, int day) {
466         struct tm starting_tm;
467         struct tm tm;
468         time_t thetime;
469         int i;
470         time_t previous_month;
471         time_t next_month;
472         time_t colheader_time;
473         struct tm colheader_tm;
474         char colheader_label[32];
475         int chg_month = 0;
476         int weekstart = 0;
477         char weekstart_buf[16];
478
479         /* Determine what day to start.
480          */
481         get_preference("weekstart", weekstart_buf, sizeof weekstart_buf);
482         weekstart = atoi(weekstart_buf);
483
484         /*
485          * Now back up to the 1st of the month...
486          */
487         memset(&starting_tm, 0, sizeof(struct tm));
488
489         starting_tm.tm_year = year - 1900;
490         starting_tm.tm_mon = month - 1;
491         starting_tm.tm_mday = day;
492         thetime = mktime(&starting_tm);
493
494         memcpy(&tm, &starting_tm, sizeof(struct tm));
495         while (tm.tm_mday != 1) {
496                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
497                 localtime_r(&thetime, &tm);
498         }
499
500         /** Determine previous and next months ... for links */
501         previous_month = thetime - (time_t)864000L;     /* back 10 days */
502         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
503
504         /** Now back up until we're on the user's preferred start day */
505         localtime_r(&thetime, &tm);
506         while (tm.tm_wday != weekstart) {
507                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
508                 localtime_r(&thetime, &tm);
509         }
510
511         /** Outer table (to get the background color) */
512         wprintf("<div class=\"fix_scrollbar_bug\">"
513                 "<table class=\"calendar\"> \n <tr><td>"); 
514
515         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
516
517         wprintf("<td align=center>");
518
519         localtime_r(&previous_month, &tm);
520         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
521                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
522         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
523
524         wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
525         wprintf("&nbsp;&nbsp;"
526                 "<font size=+1 color=\"#FFFFFF\">"
527                 "%s %d"
528                 "</font>"
529                 "&nbsp;&nbsp;", colheader_label, year);
530
531         localtime_r(&next_month, &tm);
532         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
533                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
534         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
535
536         wprintf("</td></tr></table>\n");
537
538         /** Inner table (the real one) */
539         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
540                 "bgcolor=#204B78 id=\"inner_month\"><tr>");
541         colheader_time = thetime;
542         for (i=0; i<7; ++i) {
543                 colheader_time = thetime + (i * 86400) ;
544                 localtime_r(&colheader_time, &colheader_tm);
545                 wc_strftime(colheader_label, sizeof colheader_label, "%A", &colheader_tm);
546                 wprintf("<td align=center width=14%%>"
547                         "<font color=\"#FFFFFF\">%s</font></th>", colheader_label);
548
549         }
550         wprintf("</tr>\n");
551
552
553         /** Now do 35 or 42 days */
554         for (i = 0; i < 42; ++i) {
555                 localtime_r(&thetime, &tm);
556
557                 if ((i < 35) || (chg_month == 0)) {
558
559                         if ((i > 27) && ((tm.tm_mday == 1) || (tm.tm_mday == 31))) {
560                                 chg_month = 1;
561                         }
562                         if (i > 35) {
563                                 chg_month = 0;
564                         }
565
566                         /** Before displaying Sunday, start a new row */
567                         if ((i % 7) == 0) {
568                                 wprintf("<tr>");
569                         }
570
571                         wprintf("<td class=\"cal%s\"><div class=\"day\">",
572                                 ((tm.tm_mon != month-1) ? "out" :
573                                 ((tm.tm_wday==0 || tm.tm_wday==6) ? "weekend" :
574                                 "day"))
575                         );
576                         if ((i==0) || (tm.tm_mday == 1)) {
577                                 wc_strftime(colheader_label, sizeof colheader_label, "%B", &tm);
578                                 wprintf("%s ", colheader_label);
579                         }
580                         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">"
581                                 "%d</a></div>",
582                                 tm.tm_year + 1900,
583                                 tm.tm_mon + 1,
584                                 tm.tm_mday,
585                                 tm.tm_mday);
586
587                         /** put the data here, stupid */
588                         calendar_month_view_display_events(
589                                 tm.tm_year + 1900,
590                                 tm.tm_mon + 1,
591                                 tm.tm_mday
592                         );
593
594                         wprintf("</td>");
595
596                         /** After displaying Saturday, end the row */
597                         if ((i % 7) == 6) {
598                                 wprintf("</tr>\n");
599                         }
600
601                 }
602
603                 thetime += (time_t)86400;               /** ahead 24 hours */
604         }
605
606         wprintf("</table>"                      /** end of inner table */
607                 "</td></tr></table>"            /** end of outer table */
608                 "</div>\n");
609
610         /**
611          * Initialize the bubble tooltips.
612          *
613          * Yes, this is as stupid as it looks.  Instead of just making the call
614          * to btt_enableTooltips() straight away, we have to create a timer event
615          * and let it initialize as an event after 1 millisecond.  This is to
616          * work around a bug in Internet Explorer that causes it to crash if we
617          * manipulate the innerHTML of various DOM nodes while the page is still
618          * being rendered.  See http://www.shaftek.org/blog/archives/000212.html
619          * for more information.
620          */ 
621         wprintf("<script type=\"text/javascript\">"
622                 " setTimeout(\"btt_enableTooltips('inner_month')\", 1); "
623                 "</script>\n"
624         );
625 }
626
627 /**
628  * \brief view one month. brief view
629  * \param year the year
630  * \param month the month
631  * \param day the actual day we want to see
632  */
633 void calendar_brief_month_view(int year, int month, int day) {
634         struct tm starting_tm;
635         struct tm tm;
636         time_t thetime;
637         int i;
638         time_t previous_month;
639         time_t next_month;
640         char month_label[32];
641
642         /** Determine what day to start.
643          * First, back up to the 1st of the month...
644          */
645         memset(&starting_tm, 0, sizeof(struct tm));
646         starting_tm.tm_year = year - 1900;
647         starting_tm.tm_mon = month - 1;
648         starting_tm.tm_mday = day;
649         thetime = mktime(&starting_tm);
650
651         memcpy(&tm, &starting_tm, sizeof(struct tm));
652         while (tm.tm_mday != 1) {
653                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
654                 localtime_r(&thetime, &tm);
655         }
656
657         /** Determine previous and next months ... for links */
658         previous_month = thetime - (time_t)864000L;     /* back 10 days */
659         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
660
661         /** Now back up until we're on a Sunday */
662         localtime_r(&thetime, &tm);
663         while (tm.tm_wday != 0) {
664                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
665                 localtime_r(&thetime, &tm);
666         }
667
668         /** Outer table (to get the background color) */
669         wprintf("<div class=\"fix_scrollbar_bug\">"
670                 "<table width=100%% border=0 cellpadding=0 cellspacing=0 "
671                 "bgcolor=#204B78><TR><TD>\n");
672
673         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
674
675         wprintf("<td align=center>");
676
677         localtime_r(&previous_month, &tm);
678         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
679                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
680         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
681
682         wc_strftime(month_label, sizeof month_label, "%B", &tm);
683         wprintf("&nbsp;&nbsp;"
684                 "<font size=+1 color=\"#FFFFFF\">"
685                 "%s %d"
686                 "</font>"
687                 "&nbsp;&nbsp;", month_label, year);
688
689         localtime_r(&next_month, &tm);
690         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
691                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
692         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
693
694         wprintf("</td></tr></table>\n");
695
696         /** Inner table (the real one) */
697         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
698                 "bgcolor=#EEEECC><TR>");
699         wprintf("</tr>\n");
700         wprintf("<tr><td colspan=\"100%\">\n");
701
702         /** Now do 35 days */
703         for (i = 0; i < 35; ++i) {
704                 char weeknumber[255];
705                 char weekday_name[32];
706                 char *daycolor;
707                 localtime_r(&thetime, &tm);
708
709
710                 /** Before displaying Sunday, start a new CELL */
711                 if ((i % 7) == 0) {
712                         wc_strftime(&weeknumber[0], sizeof(weeknumber), "%U", &tm);
713                         wprintf("<table border='0' bgcolor=\"#EEEECC\" width='100%'> <tr><th colspan='4'>%s %s</th></tr>"
714                                         "   <tr><td>%s</td><td width=70%%>%s</td><td>%s</td><td>%s</td></tr>\n",
715                                         _("Week"), 
716                                         weeknumber,
717                                         _("Hours"),
718                                         _("Subject"),
719                                         _("Start"),
720                                         _("End")
721                                         );
722                 }
723                 
724                 daycolor=((tm.tm_mon != month-1) ? "DDDDDD" :
725                                   ((tm.tm_wday==0 || tm.tm_wday==6) ? "EEEECC" :
726                                    "FFFFFF"));
727                 
728                 /** Day Header */
729                 wc_strftime(weekday_name, sizeof weekday_name, "%A", &tm);
730                 wprintf("<tr><td bgcolor='%s' colspan='1' align='left'> %s,%i."
731                                 "</td><td bgcolor='%s' colspan='3'><hr></td></tr>\n",
732                                 daycolor,
733                                 weekday_name,tm.tm_mday,
734                                 daycolor);
735
736                 /** put the data of one day  here, stupid */
737                 calendar_month_view_brief_events(thetime, daycolor);
738
739
740                 /** After displaying Saturday, end the row */
741                 if ((i % 7) == 6) {
742                         wprintf("</td></tr></table>\n");
743                 }
744
745                 thetime += (time_t)86400;               /** ahead 24 hours */
746         }
747
748         wprintf("</table>"                      /** end of inner table */
749                 "</td></tr></table>"            /** end of outer table */
750                 "</div>\n");
751 }
752
753 /** 
754  * \brief view one week
755  * this should view just one week, but it's not here yet.
756  * \todo ny implemented
757  * \param year the year
758  * \param month the month
759  * \param day the day which we want to see the week around
760  */
761 void calendar_week_view(int year, int month, int day) {
762         wprintf("<center><i>week view FIXME</i></center><br />\n");
763 }
764
765
766 /**
767  * \brief display one day
768  * Display events for a particular hour of a particular day.
769  * (Specify hour < 0 to show "all day" events)
770  * \param year the year
771  * \param month the month
772  * \param day the day
773  * \param hour the hour we want to start displaying
774  * \param dstart daystart 
775  * \param dend dayend 
776  */
777 void calendar_day_view_display_events(time_t thetime, int year, int month,
778                                         int day, int hour,
779                                         int dstart, int dend) {
780         int i;
781         icalproperty *p = NULL;
782         icalproperty *q = NULL;
783         time_t event_start;
784         time_t event_end;
785         time_t event_tt;
786         time_t event_tte;
787         struct tm event_te;
788         struct tm event_tm;
789         int show_event = 0;
790         int all_day_event = 0;
791         int ongoing_event = 0;
792         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
793         struct disp_cal *Cal;
794         struct icaltimetype t;
795         struct icaltimetype end_t;
796         struct icaltimetype today_start_t;
797         struct icaltimetype today_end_t;
798         struct tm starting_tm;
799         struct tm ending_tm;
800         int top = 0;
801         int height = 0;
802         int gap = 1;
803         int startmin = 0;
804         int diffmin = 0;
805         int endmin = 0;
806
807         char buf[256];
808         struct tm d_tm;
809         char d_str[32];
810
811         if (WCC->num_cal == 0) {
812                 // \todo FIXME wprintf("<br /><br /><br />\n");
813                 return;
814         }
815
816         event_start = thetime + 60 * 60 * hour;
817         event_end = thetime + 60 * 60 * (hour + 1);
818
819
820         /* Create an imaginary event which spans the current hour.  Any events which
821          * overlap with this one take place at least partially in this day.
822          */
823         memset(&starting_tm, 0, sizeof(struct tm));
824         starting_tm.tm_year = year - 1900;
825         starting_tm.tm_mon = month - 1;
826         starting_tm.tm_mday = day;
827         starting_tm.tm_hour = hour;
828         starting_tm.tm_min = 0;
829         today_start_t = icaltime_from_timet_with_zone(mktime(&starting_tm), 0, icaltimezone_get_utc_timezone());
830         today_start_t.is_utc = 1;
831
832         memset(&ending_tm, 0, sizeof(struct tm));
833         ending_tm.tm_year = year - 1900;
834         ending_tm.tm_mon = month - 1;
835         ending_tm.tm_mday = day;
836         ending_tm.tm_hour = hour;
837         ending_tm.tm_min = 59;
838         today_end_t = icaltime_from_timet_with_zone(mktime(&ending_tm), 0, icaltimezone_get_utc_timezone());
839         today_end_t.is_utc = 1;
840
841         /* Now loop through our list of events to see which ones occur today.
842          */
843         for (i=0; i<(WCC->num_cal); ++i) {
844                 Cal = &WCC->disp_cal[i];
845
846                 all_day_event = 0;
847                 ongoing_event=0;
848
849                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
850                 if (q != NULL) {
851                         t = icalproperty_get_dtstart(q);
852                         event_tt = icaltime_as_timet(t);
853                         localtime_r(&event_tt, &event_te);
854                 }
855                 else {
856                         memset(&t, 0, sizeof t);
857                 }
858                 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
859                 if (q != NULL) {
860                         end_t = icalproperty_get_dtend(q);
861                         event_tte = icaltime_as_timet(end_t);
862                         localtime_r(&event_tte, &event_tm);
863                 }
864                 else {
865                         memset(&end_t, 0, sizeof end_t);
866                 }
867                 if (t.is_date) all_day_event = 1;
868
869                 if (all_day_event)
870                 {
871                         show_event = ((t.year == year) && (t.month == month) && (t.day == day) && (hour == -1));
872                 }
873                 else
874                 {
875                         show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
876                 }
877
878  
879                 /* If we determined that this event occurs today, then display it.
880                  */
881                 p = icalcomponent_get_first_property(Cal->cal,ICAL_SUMMARY_PROPERTY);
882
883                 if ((show_event) && (p != NULL)) {
884
885                         if ((event_te.tm_mday != today_start_t.day) && (event_tm.tm_mday != today_start_t.day)) ongoing_event = 1; 
886
887                         if (all_day_event) 
888                         {
889                               wprintf("<li class=\"event\"> "
890                                 "<a href=\"display_edit_event?"
891                                 "msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\" "
892                                 " class=\"event_title\" "
893                                 " btt_tooltext=\"",
894                                         Cal->cal_msgnum, year, month, day, hour);
895                                 wprintf("<i>%s</i><br />", _("All day event"));
896                                 wprintf("<i>%s</i> ",    _("Summary:"));
897                                 escputs((char *) icalproperty_get_comment(p));
898                                 wprintf("<br />");
899                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
900                                 if (q) {
901                                         wprintf("<i>%s</i> ", _("Location:"));
902                                         escputs((char *)icalproperty_get_comment(q));
903                                         wprintf("<br />");
904                                         }
905                                 memset(&d_tm, 0, sizeof d_tm);
906                                 d_tm.tm_year = t.year - 1900;
907                                 d_tm.tm_mon = t.month - 1;
908                                 d_tm.tm_mday = t.day;
909                                 wc_strftime(d_str, sizeof d_str, "%x", &d_tm);
910                                 wprintf("<i>%s</i> %s<br>",_("Date:"), d_str);
911                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
912                                 if (q) {
913                                         wprintf("<i>%s</i> ", _("Notes:"));
914                                         escputs((char *)icalproperty_get_comment(q));
915                                         wprintf("<br />");
916                                 }
917                                 wprintf("\">");
918                                 escputs((char *) icalproperty_get_comment(p));
919                                 wprintf("</a> <span>(");
920                                 wprintf(_("All day event"));
921                                 wprintf(")</span></li>\n");
922                         }
923                         else if (ongoing_event && (hour == -1)) 
924                         {
925                                 wprintf("<li class=\"event\"> "
926                                 "<a href=\"display_edit_event?"
927                                 "msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\" "
928                                 " class=\"event_title\" " 
929                                 "btt_tooltext=\"",
930                                 Cal->cal_msgnum, year, month, day, hour);
931                                 wprintf("<i>%s</i><br />", _("Ongoing event"));
932                                 wprintf("<i>%s</i> ",    _("Summary:"));
933                                 escputs((char *) icalproperty_get_comment(p));
934                                 wprintf("<br />");
935                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
936                                 if (q) {
937                                         wprintf("<i>%s</i> ", _("Location:"));
938                                         escputs((char *)icalproperty_get_comment(q));
939                                         wprintf("<br />");
940                                         }
941                                 fmt_date(buf, event_tt, 1);
942                                 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf);
943                                 fmt_date(buf, event_tte, 1);
944                                 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
945                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
946                                 if (q) {
947                                         wprintf("<i>%s</i> ", _("Notes:"));
948                                         escputs((char *)icalproperty_get_comment(q));
949                                         wprintf("<br />");
950                                 }
951                                 wprintf("\">");
952                                 escputs((char *) icalproperty_get_comment(p));
953                                 wprintf("</a> <span>(");
954                                 wprintf(_("Ongoing event"));
955                                 wprintf(")</span></li>\n");
956                         }
957                         else 
958                         {
959                                 gap++;
960                                 if ((hour == event_te.tm_hour) && ! ongoing_event ) {
961
962                                         if (event_te.tm_mday != today_start_t.day)      event_te.tm_hour = 0;
963                                         if (event_tm.tm_mday != today_start_t.day) event_tm.tm_hour = 24;
964
965                                         if ((event_te.tm_hour < dstart) && (event_tm.tm_hour <= dstart)) {
966                                                 startmin = diffmin = event_te.tm_min / 6;
967                                                 endmin = ((event_tm.tm_hour == hour) ? (event_tm.tm_min / 2) : (event_tm.tm_min / 6)) ;
968                                                 top = (event_te.tm_hour * 10) + startmin -1;
969                                                 height= ((event_tm.tm_hour - event_te.tm_hour) * 10) + endmin - diffmin ;
970                                         }
971                                         if ((event_te.tm_hour < dstart) && (event_tm.tm_hour >= dstart)) {
972                                                 startmin = diffmin = event_te.tm_min / 6;
973                                                 endmin = event_tm.tm_min / 2;
974                                                 top = (event_te.tm_hour * 10) + startmin - 1;
975                                                 height = ((dstart - event_te.tm_hour) * 10) + ((event_tm.tm_hour - dstart) * 30) + endmin - (diffmin * 3);
976                                         }
977                                         if ((event_te.tm_hour <= dstart) && (event_tm.tm_hour > dend)) {
978                                                 startmin = diffmin = ((event_te.tm_hour == hour) ? (event_te.tm_min / 2) : (event_te.tm_min / 6)) ;
979                                                 endmin = event_tm.tm_min / 6; 
980                                                 top = (event_te.tm_hour * 10)  + startmin - 1;
981                                                 height = ((dstart - event_te.tm_hour) * 10) + ((dend - dstart + 1) * 30) + ((event_tm.tm_hour - dend - 1) * 10) + endmin - diffmin;
982                                         }
983                                         if ((event_te.tm_hour >= dstart) && (event_tm.tm_hour <= dend)) {
984                                                 startmin = diffmin = (event_te.tm_min / 2);
985                                                 endmin = event_tm.tm_min / 2;
986                                                 top = (dstart * 10) + ((event_te.tm_hour - dstart) * 30) + startmin - 1;
987                                                 height = ((event_tm.tm_hour - event_te.tm_hour) * 30) + endmin - diffmin;
988                                         }
989                                         if ((event_te.tm_hour >= dstart) && (event_te.tm_hour <= dend) && (event_tm.tm_hour > dend)) {
990                                                 startmin = diffmin = (event_te.tm_min / 2);
991                                                 endmin = event_tm.tm_min / 6;
992                                                 top = (dstart * 10) + ((event_te.tm_hour - dstart) * 30)  + diffmin - 1;
993                                                 height = (((dend - event_te.tm_hour + 1) * 30) + ((event_tm.tm_hour - dend - 1) * 10)) + endmin - diffmin;
994                                         }
995                                         if ((event_te.tm_hour > dend) && (event_tm.tm_hour > dend)) {
996                                                 startmin = diffmin = event_te.tm_min / 6;
997                                                 endmin = event_tm.tm_min / 6;
998                                                 top = (dstart * 10) + ((dend - dstart) * 30) + ((event_tm.tm_hour - event_te.tm_hour) * 10) + startmin - 1;
999                                                 height = ((event_tm.tm_hour - event_te.tm_hour) * 10) + endmin - diffmin;
1000                                         }
1001                                 wprintf("<dd  class=\"event\" "
1002                                         "style=\"position: absolute; "
1003                                         "top:%dpx; left:%dpx; "
1004                                         "height:%dpx; \" >",
1005                                         top, (gap * 40), height
1006                                         );
1007                                 wprintf("<a href=\"display_edit_event?"
1008                                         "msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d&case=%d\" "
1009                                         "class=\"event_title\" "
1010                                         "btt_tooltext=\"",
1011                                         Cal->cal_msgnum, year, month, day, t.hour, hour);
1012                                 wprintf("<i>%s</i> ",    _("Summary:"));
1013                                 escputs((char *) icalproperty_get_comment(p));
1014                                 wprintf("<br />");
1015                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
1016                                 if (q) {
1017                                         wprintf("<i>%s</i> ", _("Location:"));
1018                                         escputs((char *)icalproperty_get_comment(q));
1019                                         wprintf("<br />");
1020                                         }
1021                                 fmt_date(buf, event_tt, 1);
1022                                 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf);
1023                                 fmt_date(buf, event_tte, 1);
1024                                 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
1025                                 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
1026                                 if (q) {
1027                                         wprintf("<i>%s</i> ", _("Notes:"));
1028                                         escputs((char *)icalproperty_get_comment(q));
1029                                         wprintf("<br />");
1030                                 }
1031                                 wprintf("\">");
1032
1033                                 escputs((char *) icalproperty_get_comment(p));
1034                                 wprintf("</a></dd>\n");
1035                                 }
1036                                 
1037                         }
1038                 }
1039         }
1040 }
1041
1042 /**
1043  * \brief view one day
1044  * \param year the year
1045  * \param month the month 
1046  * \param day the day we want to display
1047  */
1048 void calendar_day_view(int year, int month, int day) {
1049         int hour;
1050         struct icaltimetype today, yesterday, tomorrow;
1051         int daystart = 8;
1052         int dayend = 17;
1053         char daystart_str[16], dayend_str[16];
1054         struct tm d_tm;
1055         char d_str[128];
1056         int time_format;
1057         time_t today_t;
1058         int timeline = 30;
1059         int extratimeline = 0;
1060         int gap = 0;
1061
1062         time_format = get_time_format_cached ();
1063         get_preference("daystart", daystart_str, sizeof daystart_str);
1064         if (!IsEmptyStr(daystart_str)) daystart = atoi(daystart_str);
1065         get_preference("dayend", dayend_str, sizeof dayend_str);
1066         if (!IsEmptyStr(dayend_str)) dayend = atoi(dayend_str);
1067         
1068         /** Today's date */
1069         memset(&d_tm, 0, sizeof d_tm);
1070         d_tm.tm_year = year - 1900;
1071         d_tm.tm_mon = month - 1;
1072         d_tm.tm_mday = day;
1073         today_t = mktime(&d_tm); 
1074
1075         /** Figure out the dates for "yesterday" and "tomorrow" links */
1076
1077         memset(&today, 0, sizeof(struct icaltimetype));
1078         today.year = year;
1079         today.month = month;
1080         today.day = day;
1081         today.is_date = 1;
1082
1083         memcpy(&yesterday, &today, sizeof(struct icaltimetype));
1084         --yesterday.day;
1085         yesterday = icaltime_normalize(yesterday);
1086
1087         memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
1088         ++tomorrow.day;
1089         tomorrow = icaltime_normalize(tomorrow);
1090
1091         wprintf("<div class=\"fix_scrollbar_bug\">");
1092
1093         /** Inner table (the real one) */
1094         wprintf("<table class=\"calendar\" id=\"inner_day\"><tr> \n");
1095
1096         /** Innermost cell (contains hours etc.) */
1097         wprintf("<td class=\"events_of_the_day\" >");
1098         wprintf("<dl class=\"events\" >");
1099
1100         /** Now the middle of the day... */
1101
1102         extratimeline = timeline / 3;   
1103
1104         for (hour = 0; hour < daystart; ++hour) {       /* could do HEIGHT=xx */
1105                 wprintf("<dt class=\"extrahour\"        "
1106                         "style=\"               "
1107                         "position: absolute;    "
1108                         "top: %dpx; left: 0px;  "
1109                         "height: %dpx;          "       
1110                         "\" >                   "
1111                         "<a href=\"display_edit_event?msgnum=0"
1112                         "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
1113                         (hour * extratimeline ), extratimeline, 
1114                         year, month, day, hour
1115                 );
1116
1117                 if (time_format == WC_TIMEFORMAT_24) {
1118                         wprintf("%2d:00</a> ", hour);
1119                 }
1120                 else {
1121                         wprintf("%d:00%s</a> ",
1122                                 (hour <= 12 ? hour : hour-12),
1123                                 (hour < 12 ? "am" : "pm")
1124                         );
1125                 }
1126
1127                 wprintf("</dt>");
1128         
1129                 /* put the data here, stupid */
1130                 calendar_day_view_display_events(today_t, year, month, day, hour, daystart, dayend);
1131
1132         }
1133
1134         gap = daystart * extratimeline;
1135
1136         for (hour = daystart; hour <= dayend; ++hour) {       /* could do HEIGHT=xx */
1137                 wprintf("<dt class=\"hour\"     "
1138                         "style=\"               "
1139                         "position: absolute;    "
1140                         "top: %dpx; left: 0px;  "
1141                         "height: %dpx;          "
1142                         "\" >                   "
1143                         "<a href=\"display_edit_event?msgnum=0"
1144                         "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
1145                         gap + ((hour - daystart) * timeline ), timeline,
1146                         year, month, day, hour
1147                 );
1148
1149                 if (time_format == WC_TIMEFORMAT_24) {
1150                         wprintf("%2d:00</a> ", hour);
1151                 }
1152                 else {
1153                         wprintf("%d:00%s</a> ",
1154                                 (hour <= 12 ? hour : hour-12),
1155                                 (hour < 12 ? "am" : "pm")
1156                         );
1157                 }
1158
1159                 wprintf("</dt>");
1160
1161                 /* put the data here, stupid */
1162                 calendar_day_view_display_events(today_t, year, month, day, hour, daystart, dayend);
1163
1164         }
1165
1166         gap = gap + ((dayend - daystart + 1) * timeline);
1167
1168         for (hour = (dayend + 1); hour < 24; ++hour) {       /* could do HEIGHT=xx */
1169                 wprintf("<dt class=\"extrahour\"     "
1170                         "style=\"               "
1171                         "position: absolute;    "
1172                         "top: %dpx; left: 0px;  "
1173                         "height: %dpx;          "
1174                         "\" >                   "
1175                         "<a href=\"display_edit_event?msgnum=0"
1176                         "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
1177                         gap + ((hour - dayend - 1) * extratimeline ), extratimeline,
1178                         year, month, day, hour
1179                 );
1180
1181                 if (time_format == WC_TIMEFORMAT_24) {
1182                         wprintf("%2d:00</a> ", hour);
1183                 }
1184                 else {
1185                         wprintf("%d:00%s</a> ",
1186                                 (hour <= 12 ? hour : hour-12),
1187                                 (hour < 12 ? "am" : "pm")
1188                         );
1189                 }
1190
1191                 wprintf("</dt>");
1192
1193                 /* put the data here, stupid */
1194                 calendar_day_view_display_events(today_t, year, month, day, hour, daystart, dayend);
1195
1196         }
1197
1198         wprintf("</dl>");
1199         wprintf("</td>");                       /* end of innermost table */
1200
1201         /** Extra events on the middle */
1202         wprintf("<td class=\"extra_events\">");
1203
1204         wprintf("<ul>");
1205
1206         /** Display all-day events) */
1207                 calendar_day_view_display_events(today_t, year, month, day, -1, daystart, dayend);
1208
1209         wprintf("</ul>");
1210
1211         wprintf("</td>");       /** end extra on the middle */
1212
1213         wprintf("<td width=20%% align=center valign=top>");     /** begin stuff-on-the-right */
1214
1215         /** Begin todays-date-with-left-and-right-arrows */
1216         wprintf("<table border=0 width=100%% "
1217                 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
1218         wprintf("<tr>");
1219
1220         /** Left arrow */       
1221         wprintf("<td align=center>");
1222         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
1223                 yesterday.year, yesterday.month, yesterday.day);
1224         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
1225         wprintf("</td>");
1226
1227         wc_strftime(d_str, sizeof d_str,
1228                 "<td align=center>"
1229                 "<font size=+2>%B</font><br />"
1230                 "<font size=+3>%d</font><br />"
1231                 "<font size=+2>%Y</font><br />"
1232                 "</td>",
1233                 &d_tm
1234         );
1235         wprintf("%s", d_str);
1236
1237         /** Right arrow */
1238         wprintf("<td align=center>");
1239         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
1240                 tomorrow.year, tomorrow.month, tomorrow.day);
1241         wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
1242                 " border=0></a>\n");
1243         wprintf("</td>");
1244
1245         wprintf("</tr></table>\n");
1246         /** End todays-date-with-left-and-right-arrows */
1247
1248         /** Embed a mini month calendar in this space */
1249         wprintf("<br />\n");
1250         embeddable_mini_calendar(year, month, "readfwd?calview=day&year=%d&month=%d&day=%d");
1251
1252         wprintf("</font></center>\n");
1253
1254         wprintf("</td></tr>");                  /** end stuff-on-the-right */
1255
1256         wprintf("</table>"                      /** end of inner table */
1257                 "</div>");
1258
1259         wprintf("<script type=\"text/javascript\">"
1260                 " setTimeout(\"btt_enableTooltips('inner_day')\", 1); "
1261                 "</script>\n"
1262         );
1263 }
1264
1265
1266 /**
1267  * \brief Display today's events.
1268  */
1269 void calendar_summary_view(void) {
1270         int i;
1271         icalproperty *p;
1272         struct icaltimetype t;
1273         time_t event_tt;
1274         struct tm event_tm;
1275         struct tm today_tm;
1276         time_t now;
1277         int all_day_event = 0;
1278         char timestring[SIZ];
1279
1280         if (WC->num_cal == 0) {
1281                 return;
1282         }
1283
1284         now = time(NULL);
1285         localtime_r(&now, &today_tm);
1286
1287         for (i=0; i<(WC->num_cal); ++i) {
1288                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
1289                                                 ICAL_DTSTART_PROPERTY);
1290                 if (p != NULL) {
1291                         t = icalproperty_get_dtstart(p);
1292                         event_tt = icaltime_as_timet(t);
1293                         if (t.is_date) {
1294                                 all_day_event = 1;
1295                         }
1296                         else {
1297                                 all_day_event = 0;
1298                         }
1299                         fmt_time(timestring, event_tt);
1300
1301                         if (all_day_event) {
1302                                 gmtime_r(&event_tt, &event_tm);
1303                         }
1304                         else {
1305                                 localtime_r(&event_tt, &event_tm);
1306                         }
1307
1308                         if ( (event_tm.tm_year == today_tm.tm_year)
1309                            && (event_tm.tm_mon == today_tm.tm_mon)
1310                            && (event_tm.tm_mday == today_tm.tm_mday)
1311                            ) {
1312
1313
1314                                 p = icalcomponent_get_first_property(
1315                                                         WC->disp_cal[i].cal,
1316                                                         ICAL_SUMMARY_PROPERTY);
1317                                 if (p != NULL) {
1318                                         escputs((char *)
1319                                                 icalproperty_get_comment(p));
1320                                         wprintf(" (%s)<br />\n", timestring);
1321                                 }
1322                         }
1323                 }
1324         }
1325         free_calendar_buffer();
1326 }
1327
1328
1329 /**
1330  * \brief clean up ical memory
1331  * \todo this could get troubel with future ical versions
1332  */
1333 void free_calendar_buffer(void) {
1334         int i;
1335         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
1336                 icalcomponent_free(WC->disp_cal[i].cal);
1337         }
1338         WC->num_cal = 0;
1339         free(WC->disp_cal);
1340         WC->disp_cal = NULL;
1341 }
1342
1343
1344
1345 /**
1346  * \brief do the whole calendar page
1347  * view any part of the calender. decide which way, etc.
1348  */
1349 void do_calendar_view(void) {
1350         time_t now;
1351         struct tm tm;
1352         int year, month, day;
1353         char calview[SIZ];
1354
1355         /** In case no date was specified, go with today */
1356         now = time(NULL);
1357         localtime_r(&now, &tm);
1358         year = tm.tm_year + 1900;
1359         month = tm.tm_mon + 1;
1360         day = tm.tm_mday;
1361
1362         /** Now see if a date was specified */
1363         if (!IsEmptyStr(bstr("year"))) year = atoi(bstr("year"));
1364         if (!IsEmptyStr(bstr("month"))) month = atoi(bstr("month"));
1365         if (!IsEmptyStr(bstr("day"))) day = atoi(bstr("day"));
1366
1367         /** How would you like that cooked? */
1368         if (!IsEmptyStr(bstr("calview"))) {
1369                 strcpy(calview, bstr("calview"));
1370         }
1371         else {
1372                 strcpy(calview, "month");
1373         }
1374
1375         /** Display the selected view */
1376         if (!strcasecmp(calview, "day")) {
1377                 calendar_day_view(year, month, day);
1378         }
1379         else if (!strcasecmp(calview, "week")) {
1380                 calendar_week_view(year, month, day);
1381         }
1382         else {
1383                 if (WC->wc_view == VIEW_CALBRIEF) {
1384                         calendar_brief_month_view(year, month, day);
1385                 }
1386                 else {
1387                         calendar_month_view(year, month, day);
1388                 }
1389         }
1390
1391         /** Free the calendar stuff */
1392         free_calendar_buffer();
1393
1394 }
1395
1396
1397 /**
1398  * \brief get task due date
1399  * Helper function for do_tasks_view().  
1400  * \param vtodo a task to get the due date
1401  * \return the date/time due.
1402  */
1403 time_t get_task_due_date(icalcomponent *vtodo) {
1404         icalproperty *p;
1405
1406         if (vtodo == NULL) {
1407                 return(0L);
1408         }
1409
1410         /**
1411          * If we're looking at a fully encapsulated VCALENDAR
1412          * rather than a VTODO component, recurse into the data
1413          * structure until we get a VTODO.
1414          */
1415         if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
1416                 return get_task_due_date(
1417                         icalcomponent_get_first_component(
1418                                 vtodo, ICAL_VTODO_COMPONENT
1419                         )
1420                 );
1421         }
1422
1423         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
1424         if (p != NULL) {
1425                 return(icaltime_as_timet(icalproperty_get_due(p)));
1426         }
1427         else {
1428                 return(0L);
1429         }
1430 }
1431
1432
1433 /**
1434  * \brief Compare the due dates of two tasks (this is for sorting)
1435  * \param task1 first task to compare
1436  * \param task2 second task to compare
1437  */
1438 int task_due_cmp(const void *task1, const void *task2) {
1439         time_t t1;
1440         time_t t2;
1441
1442         t1 =  get_task_due_date(((struct disp_cal *)task1)->cal);
1443         t2 =  get_task_due_date(((struct disp_cal *)task2)->cal);
1444
1445         if (t1 < t2) return(-1);
1446         if (t1 > t2) return(1);
1447         return(0);
1448 }
1449
1450
1451
1452
1453 /**
1454  * \brief do the whole task view stuff
1455  */
1456 void do_tasks_view(void) {
1457         int i;
1458         time_t due;
1459         int bg = 0;
1460         char buf[SIZ];
1461         icalproperty *p;
1462
1463         wprintf("<div class=\"fix_scrollbar_bug\">"
1464                 "<table class=\"calendar_view_background\">\n<tr>\n"
1465                 "<th>");
1466         wprintf(_("Name of task"));
1467         wprintf("</th><th>");
1468         wprintf(_("Date due"));
1469         wprintf("</th></tr>\n"
1470         );
1471
1472         /** Sort them if necessary */
1473         if (WC->num_cal > 1) {
1474                 qsort(WC->disp_cal,
1475                         WC->num_cal,
1476                         sizeof(struct disp_cal),
1477                         task_due_cmp
1478                 );
1479         }
1480
1481         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
1482
1483                 bg = 1 - bg;
1484                 wprintf("<tr bgcolor=\"#%s\"><td>",
1485                         (bg ? "DDDDDD" : "FFFFFF")
1486                 );
1487
1488                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
1489                                                         ICAL_SUMMARY_PROPERTY);
1490                 wprintf("<a href=\"display_edit_task?msgnum=%ld&taskrm=",
1491                         WC->disp_cal[i].cal_msgnum );
1492                 urlescputs(WC->wc_roomname);
1493                 wprintf("\">");
1494                 wprintf("<img align=middle "
1495                         "src=\"static/taskmanag_16x.gif\" border=0>&nbsp;");
1496                 if (p != NULL) {
1497                         escputs((char *)icalproperty_get_comment(p));
1498                 }
1499                 wprintf("</a>\n");
1500                 wprintf("</td>\n");
1501
1502                 due = get_task_due_date(WC->disp_cal[i].cal);
1503                 fmt_date(buf, due, 0);
1504                 wprintf("<td><font");
1505                 if (due < time(NULL)) {
1506                         wprintf(" color=\"#FF0000\"");
1507                 }
1508                 wprintf(">%s</font></td></tr>\n", buf);
1509         }
1510
1511         wprintf("</table></div>\n");
1512
1513         /** Free the list */
1514         free_calendar_buffer();
1515
1516 }
1517
1518 #else   /* WEBCIT_WITH_CALENDAR_SERVICE */
1519
1520 /**\brief stub for non-libical builds */
1521 void do_calendar_view(void) {
1522         wprintf("<center><i>");
1523         wprintf(_("The calendar view is not available."));
1524         wprintf("</i></center><br />\n");
1525 }
1526
1527 /**\brief stub for non-libical builds */
1528 void do_tasks_view(void) {      
1529         wprintf("<center><I>");
1530         wprintf(_("The tasks view is not available."));
1531         wprintf("</i></center><br />\n");
1532 }
1533
1534 /**\brief stub for non-libical builds */
1535 void ajax_mini_calendar(void) {
1536 }
1537
1538 #endif  /* WEBCIT_WITH_CALENDAR_SERVICE */
1539
1540 /** @} */