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