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