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