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