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