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