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