* for some reason copying an event from our calendar seems to be the better way to...
[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  * \brief Display one day of a whole month view of a calendar
18  * \param thetime the month we want to see 
19  */
20 void calendar_month_view_display_events(time_t thetime) {
21         int i;
22         struct tm today_tm;
23         icalproperty *p = NULL;
24         icalproperty *q = NULL;
25         struct icaltimetype t;
26         int month, day, year;
27         int all_day_event = 0;
28         int multi_day_event = 0;
29         int fill_day_event = 0;
30         int show_event = 0;
31         time_t tt;
32         char buf[256];
33         struct wcsession *WCC;
34         struct disp_cal *Cal;
35
36         WCC = WC;
37
38         if (WCC->num_cal == 0) {
39                 wprintf("<br /><br /><br />\n");
40                 return;
41         }
42
43         localtime_r(&thetime, &today_tm);
44         month = today_tm.tm_mon + 1;
45         day = today_tm.tm_mday;
46         year = today_tm.tm_year + 1900;
47
48         for (i=0; i<(WCC->num_cal); ++i) {
49                 fill_day_event = 0;
50                 multi_day_event = 0;
51
52                 Cal = &WCC->disp_cal[i];
53                 all_day_event =  Cal->start_hour == -1;
54                 show_event = thetime == Cal->start_day;
55                 if (Cal->multi_day_event) {
56
57                         // are we in the range of the event?
58                         show_event = (Cal->start_day <= thetime) && 
59                                 (Cal->end_day >= thetime);
60
61                         // are we not start or end day?
62                         fill_day_event = (Cal->start_day < thetime) && 
63                                 (Cal->end_day > thetime);
64                 }
65
66                 if (show_event) {
67                         p = icalcomponent_get_first_property(
68                                 Cal->cal,
69                                 ICAL_SUMMARY_PROPERTY);
70                         if (p != NULL) {
71
72                                 if (all_day_event) {
73                                         wprintf("<table border=0 cellpadding=2><TR>"
74                                                 "<td bgcolor=\"#CCCCDD\">"
75                                                 );
76                                 }
77
78                                 wprintf("<font size=-1>"
79                                         "<a href=\"display_edit_event?"
80                                         "msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\""
81                                         " btt_tooltext=\"",
82                                         WC->disp_cal[i].cal_msgnum,
83                                         bstr("calview"),
84                                         bstr("year"),
85                                         bstr("month"),
86                                         bstr("day")
87                                         );
88
89                                 wprintf("<i>%s</i> ", _("Summary:"));
90                                 escputs((char *)icalproperty_get_comment(p));
91                                 wprintf("<br />");
92                                 
93                                 q = icalcomponent_get_first_property(
94                                         WC->disp_cal[i].cal,
95                                         ICAL_LOCATION_PROPERTY);
96                                 if (q) {
97                                         wprintf("<i>%s</i> ", _("Location:"));
98                                         escputs((char *)icalproperty_get_comment(q));
99                                         wprintf("<br />");
100                                         }
101                                 
102                                 /**
103                                  * Only show start/end times if we're actually looking at the VEVENT
104                                  * component.  Otherwise it shows bogus dates for e.g. timezones
105                                  */
106                                 if (icalcomponent_isa(Cal->cal) == ICAL_VEVENT_COMPONENT) {
107                                         
108                                         q = icalcomponent_get_first_property(Cal->cal,
109                                                                              ICAL_DTSTART_PROPERTY);
110                                         if (q != NULL) {
111                                                 t = icalproperty_get_dtstart(q);
112                                                 
113                                                 if (t.is_date) {
114                                                         struct tm d_tm;
115                                                         char d_str[32];
116                                                         memset(&d_tm, 0, sizeof d_tm);
117                                                         d_tm.tm_year = t.year - 1900;
118                                                         d_tm.tm_mon = t.month - 1;
119                                                         d_tm.tm_mday = t.day;
120                                                         wc_strftime(d_str, sizeof d_str, "%x", &d_tm);
121                                                         wprintf("<i>%s</i> %s<br>",
122                                                                 _("Date:"), d_str);
123                                                 }
124                                                 else {
125                                                         tt = icaltime_as_timet(t);
126                                                         fmt_date(buf, tt, 1);
127                                                         wprintf("<i>%s</i> %s<br>",
128                                                                 _("Starting date/time:"), buf);
129                                                         
130                                                         /* Embed the 'show end date/time' loop inside here so it
131                                                          * only executes if this is NOT an all day event.
132                                                          */
133                                                         q = icalcomponent_get_first_property(Cal->cal,
134                                                                                              ICAL_DTEND_PROPERTY);
135                                                         if (q != NULL) {
136                                                                 t = icalproperty_get_dtend(q);
137                                                                 tt = icaltime_as_timet(t);
138                                                                 fmt_date(buf, tt, 1);
139                                                                 wprintf("<i>%s</i> %s<br>",
140                                                                         _("Ending date/time:"), buf);
141                                                         }
142                                                         
143                                                 }
144                                         }
145                                         
146                                 }
147                                 
148                                 q = icalcomponent_get_first_property(
149                                         Cal->cal,
150                                         ICAL_DESCRIPTION_PROPERTY);
151                                 if (q) {
152                                         wprintf("<i>%s</i> ", _("Notes:"));
153                                         escputs((char *)icalproperty_get_comment(q));
154                                         wprintf("<br />");
155                                 }
156                                 
157                                 wprintf("\">");
158                                 escputs((char *)
159                                         icalproperty_get_comment(p));
160                                 wprintf("</a></font><br />\n");
161                                 
162                                 if (all_day_event) {
163                                         wprintf("</td></tr></table>");
164                                 }
165                                 
166                         }
167                         
168                 }
169                 
170                 
171         }
172 }
173
174
175 /**
176  * \brief Display one day of a whole month view of a calendar
177  * \param thetime the month we want to see 
178  */
179 void calendar_month_view_brief_events(time_t thetime, const char *daycolor) {
180         int i;
181         time_t event_tt;
182         time_t event_tts;
183         time_t event_tte;
184         struct tm event_tms;
185         struct tm event_tme;
186         struct tm today_tm;
187         icalproperty *p;
188         icalproperty *e;
189         struct icaltimetype t;
190         int month, day, year;
191         int all_day_event = 0;
192         char *timeformat;
193         int time_format;
194         
195         time_format = get_time_format_cached ();
196
197         if (time_format == WC_TIMEFORMAT_24) timeformat="%k:%M";
198         else timeformat="%I:%M %p";
199
200         localtime_r(&thetime, &today_tm);
201         month = today_tm.tm_mon + 1;
202         day = today_tm.tm_mday;
203         year = today_tm.tm_year + 1900;
204
205         for (i=0; i<(WC->num_cal); ++i) {
206                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
207                                                 ICAL_DTSTART_PROPERTY);
208                 if (p != NULL) {
209                         t = icalproperty_get_dtstart(p);
210                         event_tt = icaltime_as_timet(t);
211                         event_tts=event_tt;
212                         if (t.is_date) all_day_event = 1;
213                         else all_day_event = 0;
214
215                         if (all_day_event) {
216                                 gmtime_r(&event_tts, &event_tms);
217                         }
218                         else {
219                                 localtime_r(&event_tts, &event_tms);
220                         }
221                         /** \todo epoch &! daymask */
222                         if ((event_tms.tm_year == today_tm.tm_year)
223                            && (event_tms.tm_mon == today_tm.tm_mon)
224                            && (event_tms.tm_mday == today_tm.tm_mday)) {
225                                 
226                                 
227                                 char sbuf[255];
228                                 char ebuf[255];
229
230                                 p = icalcomponent_get_first_property(
231                                                         WC->disp_cal[i].cal,
232                                                         ICAL_SUMMARY_PROPERTY);
233                                 e = icalcomponent_get_first_property(
234                                                         WC->disp_cal[i].cal, 
235                                                         ICAL_DTEND_PROPERTY);
236                                 if ((p != NULL) && (e != NULL)) {
237                                         time_t difftime;
238                                         int hours, minutes;
239                                         t = icalproperty_get_dtend(e);
240                                         event_tte = icaltime_as_timet(t);
241                                         localtime_r(&event_tte, &event_tme);
242                                         difftime=(event_tte-event_tts)/60;
243                                         hours=(int)(difftime / 60);
244                                         minutes=difftime % 60;
245                                         wprintf("<tr><td bgcolor='%s'>%i:%2i</td><td bgcolor='%s'>"
246                                                         "<font size=-1>"
247                                                         "<a href=\"display_edit_event?msgnum=%ld&calview=%s&year=%s&month=%s&day=%s\">",
248                                                         daycolor,
249                                                         hours, minutes,
250                                                         daycolor,
251                                                         WC->disp_cal[i].cal_msgnum,
252                                                         bstr("calview"),
253                                                         bstr("year"),
254                                                         bstr("month"),
255                                                         bstr("day")
256                                                         );
257
258                                         escputs((char *)
259                                                         icalproperty_get_comment(p));
260                                         /** \todo: allso ammitime format */
261                                         wc_strftime(&sbuf[0], sizeof(sbuf), timeformat, &event_tms);
262                                         wc_strftime(&ebuf[0], sizeof(sbuf), timeformat, &event_tme);
263
264                                         wprintf("</a></font></td>"
265                                                         "<td bgcolor='%s'>%s</td><td bgcolor='%s'>%s</td></tr>",
266                                                         daycolor,
267                                                         sbuf,
268                                                         daycolor,
269                                                         ebuf);
270                                         
271                                 }
272                                 
273                         }
274                         
275                         
276                 }
277         }
278 }
279
280
281 /**
282  * \brief view one month. pretty view
283  * \param year the year
284  * \param month the month
285  * \param day the actual day we want to see
286  */
287 void calendar_month_view(int year, int month, int day) {
288         struct tm starting_tm;
289         struct tm tm;
290         time_t thetime;
291         int i;
292         time_t previous_month;
293         time_t next_month;
294         time_t colheader_time;
295         struct tm colheader_tm;
296         char colheader_label[32];
297         int chg_month = 0;
298
299         /** Determine what day to start.
300          * First, back up to the 1st of the month...
301          */
302         memset(&starting_tm, 0, sizeof(struct tm));
303         if (WC->num_cal > 0) 
304                 localtime_r(&WC->disp_cal[0].start_day, &starting_tm);
305
306         starting_tm.tm_year = year - 1900;
307         starting_tm.tm_mon = month - 1;
308         starting_tm.tm_mday = day;
309         thetime = mktime(&starting_tm);
310
311         memcpy(&tm, &starting_tm, sizeof(struct tm));
312         while (tm.tm_mday != 1) {
313                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
314                 localtime_r(&thetime, &tm);
315         }
316
317         /** Determine previous and next months ... for links */
318         previous_month = thetime - (time_t)864000L;     /* back 10 days */
319         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
320
321         /** Now back up until we're on a Sunday */
322         localtime_r(&thetime, &tm);
323         while (tm.tm_wday != 0) {
324                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
325                 localtime_r(&thetime, &tm);
326         }
327
328         /** Outer table (to get the background color) */
329         wprintf("<div class=\"fix_scrollbar_bug\">"
330                 "<table class=\"calendar\"> \n <tr><td>"); 
331
332         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
333
334         wprintf("<td align=center>");
335
336         localtime_r(&previous_month, &tm);
337         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
338                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
339         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
340
341         wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
342         wprintf("&nbsp;&nbsp;"
343                 "<font size=+1 color=\"#FFFFFF\">"
344                 "%s %d"
345                 "</font>"
346                 "&nbsp;&nbsp;", colheader_label, year);
347
348         localtime_r(&next_month, &tm);
349         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
350                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
351         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
352
353         wprintf("</td></tr></table>\n");
354
355         /** Inner table (the real one) */
356         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
357                 "bgcolor=#204B78 id=\"inner_month\"><tr>");
358         colheader_time = thetime;
359         for (i=0; i<7; ++i) {
360                 colheader_time = thetime + (i * 86400) ;
361                 localtime_r(&colheader_time, &colheader_tm);
362                 wc_strftime(colheader_label, sizeof colheader_label, "%A", &colheader_tm);
363                 wprintf("<td align=center width=14%%>"
364                         "<font color=\"#FFFFFF\">%s</font></th>", colheader_label);
365
366         }
367         wprintf("</tr>\n");
368
369
370         /** Now do 35 or 42 days */
371         for (i = 0; i < 42; ++i) {
372                 localtime_r(&thetime, &tm);
373
374                 if ((i < 35) || (chg_month == 0)) {
375
376                         if ((i > 27) && ((tm.tm_mday == 1) || (tm.tm_mday == 31))) {
377                                 chg_month = 1;
378                         }
379                         if (i > 35) {
380                                 chg_month = 0;
381                         }
382
383                         /** Before displaying Sunday, start a new row */
384                         if ((i % 7) == 0) {
385                                 wprintf("<tr>");
386                         }
387
388                         wprintf("<td class=\"cal%s\"><div class=\"day\">",
389                                 ((tm.tm_mon != month-1) ? "out" :
390                                 ((tm.tm_wday==0 || tm.tm_wday==6) ? "weekend" :
391                                 "day"))
392                         );
393                         if ((i==0) || (tm.tm_mday == 1)) {
394                                 wc_strftime(colheader_label, sizeof colheader_label, "%B", &tm);
395                                 wprintf("%s ", colheader_label);
396                         }
397                         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">"
398                                 "%d</a></div>",
399                                 tm.tm_year + 1900,
400                                 tm.tm_mon + 1,
401                                 tm.tm_mday,
402                                 tm.tm_mday);
403
404                         /** put the data here, stupid */
405                         calendar_month_view_display_events(thetime);
406
407                         wprintf("</td>");
408
409                         /** After displaying Saturday, end the row */
410                         if ((i % 7) == 6) {
411                                 wprintf("</tr>\n");
412                         }
413
414                 }
415
416                 thetime += (time_t)86400;               /** ahead 24 hours */
417         }
418
419         wprintf("</table>"                      /** end of inner table */
420                 "</td></tr></table>"            /** end of outer table */
421                 "</div>\n");
422
423         /**
424          * Initialize the bubble tooltips.
425          *
426          * Yes, this is as stupid as it looks.  Instead of just making the call
427          * to btt_enableTooltips() straight away, we have to create a timer event
428          * and let it initialize as an event after 1 millisecond.  This is to
429          * work around a bug in Internet Explorer that causes it to crash if we
430          * manipulate the innerHTML of various DOM nodes while the page is still
431          * being rendered.  See http://www.shaftek.org/blog/archives/000212.html
432          * for more information.
433          */ 
434         wprintf("<script type=\"text/javascript\">"
435                 " setTimeout(\"btt_enableTooltips('inner_month')\", 1); "
436                 "</script>\n"
437         );
438 }
439
440 /**
441  * \brief view one month. brief view
442  * \param year the year
443  * \param month the month
444  * \param day the actual day we want to see
445  */
446 void calendar_brief_month_view(int year, int month, int day) {
447         struct tm starting_tm;
448         struct tm tm;
449         time_t thetime;
450         int i;
451         time_t previous_month;
452         time_t next_month;
453         char month_label[32];
454
455         /** Determine what day to start.
456          * First, back up to the 1st of the month...
457          */
458         memset(&starting_tm, 0, sizeof(struct tm));
459         starting_tm.tm_year = year - 1900;
460         starting_tm.tm_mon = month - 1;
461         starting_tm.tm_mday = day;
462         thetime = mktime(&starting_tm);
463
464         memcpy(&tm, &starting_tm, sizeof(struct tm));
465         while (tm.tm_mday != 1) {
466                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
467                 localtime_r(&thetime, &tm);
468         }
469
470         /** Determine previous and next months ... for links */
471         previous_month = thetime - (time_t)864000L;     /* back 10 days */
472         next_month = thetime + (time_t)(31L * 86400L);  /* ahead 31 days */
473
474         /** Now back up until we're on a Sunday */
475         localtime_r(&thetime, &tm);
476         while (tm.tm_wday != 0) {
477                 thetime = thetime - (time_t)86400;      /* go back 24 hours */
478                 localtime_r(&thetime, &tm);
479         }
480
481         /** Outer table (to get the background color) */
482         wprintf("<div class=\"fix_scrollbar_bug\">"
483                 "<table width=100%% border=0 cellpadding=0 cellspacing=0 "
484                 "bgcolor=#204B78><TR><TD>\n");
485
486         wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
487
488         wprintf("<td align=center>");
489
490         localtime_r(&previous_month, &tm);
491         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
492                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
493         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
494
495         wc_strftime(month_label, sizeof month_label, "%B", &tm);
496         wprintf("&nbsp;&nbsp;"
497                 "<font size=+1 color=\"#FFFFFF\">"
498                 "%s %d"
499                 "</font>"
500                 "&nbsp;&nbsp;", month_label, year);
501
502         localtime_r(&next_month, &tm);
503         wprintf("<a href=\"readfwd?calview=month&year=%d&month=%d&day=1\">",
504                 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
505         wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
506
507         wprintf("</td></tr></table>\n");
508
509         /** Inner table (the real one) */
510         wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
511                 "bgcolor=#EEEECC><TR>");
512         wprintf("</tr>\n");
513         wprintf("<tr><td colspan=\"100%\">\n");
514
515         /** Now do 35 days */
516         for (i = 0; i < 35; ++i) {
517                 char weeknumber[255];
518                 char weekday_name[32];
519                 char *daycolor;
520                 localtime_r(&thetime, &tm);
521
522
523                 /** Before displaying Sunday, start a new CELL */
524                 if ((i % 7) == 0) {
525                         wc_strftime(&weeknumber[0], sizeof(weeknumber), "%U", &tm);
526                         wprintf("<table border='0' bgcolor=\"#EEEECC\" width='100%'> <tr><th colspan='4'>%s %s</th></tr>"
527                                         "   <tr><td>%s</td><td width=70%%>%s</td><td>%s</td><td>%s</td></tr>\n",
528                                         _("Week"), 
529                                         weeknumber,
530                                         _("Hours"),
531                                         _("Subject"),
532                                         _("Start"),
533                                         _("End")
534                                         );
535                 }
536                 
537                 daycolor=((tm.tm_mon != month-1) ? "DDDDDD" :
538                                   ((tm.tm_wday==0 || tm.tm_wday==6) ? "EEEECC" :
539                                    "FFFFFF"));
540                 
541                 /** Day Header */
542                 wc_strftime(weekday_name, sizeof weekday_name, "%A", &tm);
543                 wprintf("<tr><td bgcolor='%s' colspan='1' align='left'> %s,%i."
544                                 "</td><td bgcolor='%s' colspan='3'><hr></td></tr>\n",
545                                 daycolor,
546                                 weekday_name,tm.tm_mday,
547                                 daycolor);
548
549                 /** put the data of one day  here, stupid */
550                 calendar_month_view_brief_events(thetime, daycolor);
551
552
553                 /** After displaying Saturday, end the row */
554                 if ((i % 7) == 6) {
555                         wprintf("</td></tr></table>\n");
556                 }
557
558                 thetime += (time_t)86400;               /** ahead 24 hours */
559         }
560
561         wprintf("</table>"                      /** end of inner table */
562                 "</td></tr></table>"            /** end of outer table */
563                 "</div>\n");
564 }
565
566 /** 
567  * \brief view one week
568  * this should view just one week, but it's not here yet.
569  * \todo ny implemented
570  * \param year the year
571  * \param month the month
572  * \param day the day which we want to see the week around
573  */
574 void calendar_week_view(int year, int month, int day) {
575         wprintf("<center><i>week view FIXME</i></center><br />\n");
576 }
577
578
579 /**
580  * \brief display one day
581  * Display events for a particular hour of a particular day.
582  * (Specify hour < 0 to show "all day" events)
583  * \param year the year
584  * \param month the month
585  * \param day the day
586  * \param hour the hour we want to start displaying
587  * \param inner a flag to display between daystart and dayend
588  * (Specify inner to 1 to show inner events)
589  * (Specify inner to 0 to show "all day events and events after dayend)
590  * \param dstart daystart 
591  */
592 void calendar_day_view_display_events(time_t thetime, int year, int month,
593                                         int day, int hour,
594                                         int inner, int dstart) {
595         int i;
596         icalproperty *p;
597         time_t event_start;
598         time_t event_end;
599         icalproperty *l;
600         icalproperty *n;
601         struct tm event_te;
602         struct tm event_tm;
603         int show_event = 0;
604         int all_day_event = 0;
605         struct wcsession *WCC;
606         struct disp_cal *Cal;
607
608         WCC = WC;
609
610         if (WCC->num_cal == 0) {
611                 // \todo FIXME wprintf("<br /><br /><br />\n");
612                 return;
613         }
614
615         event_start = thetime + 60 * 60 * hour;
616         event_end = thetime + 60 * 60 * (hour + 1);
617
618         for (i=0; i<(WCC->num_cal); ++i) {
619                 Cal = &WCC->disp_cal[i];
620                 all_day_event =  Cal->start_hour == -1;
621
622                 show_event = 0;
623                 if (! all_day_event && inner)
624                 {
625                         show_event = (thetime == Cal->start_day) && 
626                                 (event_start <= Cal->start_hour) &&
627                                 ((Cal->end_hour != -1)? 
628                                    (Cal->end_hour < event_end) : 1);
629
630                 }
631                 else
632                 {
633                         show_event = !inner && (Cal->start_day == thetime);
634                 }
635
636                 p = icalcomponent_get_first_property(Cal->cal,ICAL_SUMMARY_PROPERTY);
637                 if ((show_event) && (p != NULL)) {
638                         if (all_day_event) {
639                                 wprintf("<dd><a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
640                                         Cal->cal_msgnum,year, month, day, hour);
641                                 escputs((char *) icalproperty_get_comment(p));
642                                 wprintf("</a></dd>\n");
643                         }
644                         else {
645                                 wprintf("<dd  class=\"event\" "
646                                         "style=\"position: absolute; "
647                                         "top:%dpx; left:100px; "
648                                         "height:%dpx; \" >",
649                                         (1 + (event_tm.tm_min / 2) + (event_te.tm_hour - hour) + (hour * 30) - (dstart * 30)),
650                                                                 (((event_te.tm_min - event_tm.tm_min) / 2) +(event_te.tm_hour - hour) * 30)
651                                         );
652                         }/*
653                         else {
654                                 wprintf("<dd>");
655                                 }* /
656                                                         );
657                                                 }
658                                                 else {
659                                                         wprintf("<dd>");
660                                                 }
661                                                 wprintf("<a href=\"display_edit_event?"
662                                                         "msgnum=%ld&calview=day&year=%d"
663                                                         "&month=%d&day=%d&hour=%d\""
664                                                         " btt_tooltext=\"",
665                                                         WC->disp_cal[i].cal_msgnum,
666                                                         year, month, day, hour
667                                                 );
668                                                 wprintf("<i>%s</i> ", _("Summary:"));
669                                                 escputs((char *)icalproperty_get_comment(p));
670                                                 wprintf("<br />");
671         
672                                                 l = icalcomponent_get_first_property(
673                                                                 WC->disp_cal[i].cal,
674                                                                 ICAL_LOCATION_PROPERTY);
675                                                 if (l) {
676                                                         wprintf("<i>%s</i> ", _("Location:"));
677                                                         escputs((char *)icalproperty_get_comment(l));
678                                                         wprintf("<br />");
679                                                 }       
680                                                 n = icalcomponent_get_first_property(
681                                                                 WC->disp_cal[i].cal,
682                                                                 ICAL_DESCRIPTION_PROPERTY);
683                                                 if (n) {
684                                                         wprintf("<i>%s</i> ", _("Notes:"));
685                                                         escputs((char *)icalproperty_get_comment(n));
686                                                         wprintf("<br />");
687                                                 }
688                                                 wprintf("\">");
689                                                 escputs((char *)
690                                                         icalproperty_get_comment(p));
691                                                 wprintf("</a></dd>\n");
692                                           
693                                         }
694                                 }
695                         }
696
697                 }
698
699                 /* TODO: whats that? thierry, when do we need to show this?
700                 wprintf("<a href=\"display_edit_event?msgnum=%ld&calview=day&year=%d&month=%d&day=%d&hour=%d\">",
701                         WC->disp_cal[i].cal_msgnum,
702                         year, month, day, hour
703                         );
704                 escputs((char *)
705                         icalproperty_get_comment(p));
706                 wprintf("</a></dd>\n");
707                 */
708                 }
709         }
710 }
711
712
713
714 /**
715  * \brief view one day
716  * \param year the year
717  * \param month the month 
718  * \param day the day we want to display
719  */
720 void calendar_day_view(int year, int month, int day) {
721         int hour;
722         struct icaltimetype today, yesterday, tomorrow;
723         int daystart = 8;
724         int dayend = 17;
725         char daystart_str[16], dayend_str[16];
726         struct tm d_tm;
727         char d_str[128];
728         int time_format;
729         time_t today_t;
730         
731         time_format = get_time_format_cached ();
732         get_preference("daystart", daystart_str, sizeof daystart_str);
733         if (!IsEmptyStr(daystart_str)) daystart = atoi(daystart_str);
734         get_preference("dayend", dayend_str, sizeof dayend_str);
735         if (!IsEmptyStr(dayend_str)) dayend = atoi(dayend_str);
736         
737         /** Today's date */
738         memset(&d_tm, 0, sizeof d_tm);
739         if (WC->num_cal > 0) 
740                 localtime_r(&WC->disp_cal[0].start_day, &d_tm);
741
742         d_tm.tm_year = year - 1900;
743         d_tm.tm_mon = month - 1;
744         d_tm.tm_mday = day;
745         today_t = mktime(&d_tm); 
746
747         /** Figure out the dates for "yesterday" and "tomorrow" links */
748
749         memset(&today, 0, sizeof(struct icaltimetype));
750         today.year = year;
751         today.month = month;
752         today.day = day;
753         today.is_date = 1;
754
755         memcpy(&yesterday, &today, sizeof(struct icaltimetype));
756         --yesterday.day;
757         yesterday = icaltime_normalize(yesterday);
758
759         memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
760         ++tomorrow.day;
761         tomorrow = icaltime_normalize(tomorrow);
762
763         wprintf("<div class=\"fix_scrollbar_bug\">");
764
765         /** Inner table (the real one) */
766         wprintf("<table class=\"calendar\" id=\"inner_day\"><tr> \n");
767
768         /** Innermost cell (contains hours etc.) */
769         wprintf("<td class=\"middle_of_the_day\" >");
770         wprintf("<dl    "
771                 "style=\"                       "
772                 "       padding:0 ;             "
773                 "       margin: 0;              "
774                 "       position: absolute ;    "
775                 "       top: 0;                 "
776                 "       left: 0;                "
777                 "       width: 500px;           "
778                 "       clip: rect(0px 500px %dpx 0px);"
779                 "       clip: rect(0px, 500px, %dpx, 0px);"
780                 "\">",
781         (dayend - daystart) * 30,
782         (dayend - daystart) * 30
783         ); 
784         /** Now the middle of the day... */     
785         for (hour = 0; hour <= dayend; ++hour) {        /* could do HEIGHT=xx */
786                 if (hour >= daystart) {
787                         wprintf("<dt><a href=\"display_edit_event?msgnum=0"
788                                 "&year=%d&month=%d&day=%d&hour=%d&minute=0\">",
789                                 year, month, day, hour
790                         );
791
792                         if (time_format == WC_TIMEFORMAT_24) {
793                                 wprintf("%2d:00</a> ", hour);
794                         }
795                         else {
796                                 wprintf("%d:00%s</a> ",
797                                         (hour <= 12 ? hour : hour-12),
798                                         (hour < 12 ? "am" : "pm")
799                                 );
800                         }
801
802                 wprintf("</dt>");
803                 }
804
805                 /* put the data here, stupid */
806                 calendar_day_view_display_events(today_t, year, month, day, hour, 1 , daystart);
807
808         }
809
810         wprintf("</dl>");
811         wprintf("</td>");                       /* end of innermost table */
812
813         /** Extra events on the middle */
814         wprintf("<td class=\"extra_events\">");
815
816         wprintf("<dl>");
817
818         /** Display all-day events) */
819         wprintf("<dt>All day events</dt>");
820                 calendar_day_view_display_events(today_t, year, month, day, -1, 0 , daystart);
821
822         /** Display events before daystart */
823         wprintf("<dt>Before day start</dt>");
824         for (hour = 0; hour <= (daystart-1); ++hour) {
825                 calendar_day_view_display_events(today_t, year, month, day, hour, 0, daystart );
826         }
827
828         /** Display events after dayend... */
829         wprintf("<dt>After</dt>");
830         for (hour = (dayend+1); hour <= 23; ++hour) {
831                 calendar_day_view_display_events(today_t, year, month, day, hour, 0, daystart );
832         }
833
834         wprintf("</dl>");
835
836         wprintf("</td>");       /** end extra on the middle */
837
838         wprintf("<td width=20%% valign=top>");  /** begin stuff-on-the-right */
839
840         /** Begin todays-date-with-left-and-right-arrows */
841         wprintf("<table border=0 width=100%% "
842                 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
843         wprintf("<tr>");
844
845         /** Left arrow */       
846         wprintf("<td align=center>");
847         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
848                 yesterday.year, yesterday.month, yesterday.day);
849         wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
850         wprintf("</td>");
851
852         wc_strftime(d_str, sizeof d_str,
853                 "<td align=center>"
854                 "<font size=+2>%B</font><br />"
855                 "<font size=+3>%d</font><br />"
856                 "<font size=+2>%Y</font><br />"
857                 "</td>",
858                 &d_tm
859         );
860         wprintf("%s", d_str);
861
862         /** Right arrow */
863         wprintf("<td align=center>");
864         wprintf("<a href=\"readfwd?calview=day&year=%d&month=%d&day=%d\">",
865                 tomorrow.year, tomorrow.month, tomorrow.day);
866         wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
867                 " border=0></a>\n");
868         wprintf("</td>");
869
870         wprintf("</tr></table>\n");
871         /** End todays-date-with-left-and-right-arrows */
872
873         /** \todo In the future we might want to put a month-o-matic here */
874
875         wprintf("</font></center>\n");
876
877         wprintf("</td></tr>");                  /** end stuff-on-the-right */
878
879         wprintf("</table>"                      /** end of inner table */
880                 "</div>");
881
882         wprintf("<script type=\"text/javascript\">"
883                 " setTimeout(\"btt_enableTooltips('inner_day')\", 1); "
884                 "</script>\n"
885         );
886
887
888 }
889 /**
890  * \brief Display today's events.
891  */
892 void calendar_summary_view(void) {
893         int i;
894         icalproperty *p;
895         struct icaltimetype t;
896         time_t event_tt;
897         struct tm event_tm;
898         struct tm today_tm;
899         time_t now;
900         int all_day_event = 0;
901         char timestring[SIZ];
902
903         if (WC->num_cal == 0) {
904                 return;
905         }
906
907         now = time(NULL);
908         localtime_r(&now, &today_tm);
909
910         for (i=0; i<(WC->num_cal); ++i) {
911                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
912                                                 ICAL_DTSTART_PROPERTY);
913                 if (p != NULL) {
914                         t = icalproperty_get_dtstart(p);
915                         event_tt = icaltime_as_timet(t);
916                         if (t.is_date) {
917                                 all_day_event = 1;
918                         }
919                         else {
920                                 all_day_event = 0;
921                         }
922                         fmt_time(timestring, event_tt);
923
924                         if (all_day_event) {
925                                 gmtime_r(&event_tt, &event_tm);
926                         }
927                         else {
928                                 localtime_r(&event_tt, &event_tm);
929                         }
930
931                         if ( (event_tm.tm_year == today_tm.tm_year)
932                            && (event_tm.tm_mon == today_tm.tm_mon)
933                            && (event_tm.tm_mday == today_tm.tm_mday)
934                            ) {
935
936
937                                 p = icalcomponent_get_first_property(
938                                                         WC->disp_cal[i].cal,
939                                                         ICAL_SUMMARY_PROPERTY);
940                                 if (p != NULL) {
941                                         escputs((char *)
942                                                 icalproperty_get_comment(p));
943                                         wprintf(" (%s)<br />\n", timestring);
944                                 }
945                         }
946                 }
947         }
948         free_calendar_buffer();
949 }
950
951
952 /**
953  * \brief clean up ical memory
954  * \todo this could get troubel with future ical versions
955  */
956 void free_calendar_buffer(void) {
957         int i;
958         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
959                 icalcomponent_free(WC->disp_cal[i].cal);
960         }
961         WC->num_cal = 0;
962         free(WC->disp_cal);
963         WC->disp_cal = NULL;
964 }
965
966
967
968 /**
969  * \brief do the whole calendar page
970  * view any part of the calender. decide which way, etc.
971  */
972 void do_calendar_view(void) {
973         time_t now;
974         struct tm tm;
975         int year, month, day;
976         char calview[SIZ];
977
978         /** In case no date was specified, go with today */
979         now = time(NULL);
980         localtime_r(&now, &tm);
981         year = tm.tm_year + 1900;
982         month = tm.tm_mon + 1;
983         day = tm.tm_mday;
984
985         /** Now see if a date was specified */
986         if (!IsEmptyStr(bstr("year"))) year = atoi(bstr("year"));
987         if (!IsEmptyStr(bstr("month"))) month = atoi(bstr("month"));
988         if (!IsEmptyStr(bstr("day"))) day = atoi(bstr("day"));
989
990         /** How would you like that cooked? */
991         if (!IsEmptyStr(bstr("calview"))) {
992                 strcpy(calview, bstr("calview"));
993         }
994         else {
995                 strcpy(calview, "month");
996         }
997
998         /** Display the selected view */
999         if (!strcasecmp(calview, "day")) {
1000                 calendar_day_view(year, month, day);
1001         }
1002         else if (!strcasecmp(calview, "week")) {
1003                 calendar_week_view(year, month, day);
1004         }
1005         else {
1006                 if (WC->wc_view == VIEW_CALBRIEF) {
1007                         calendar_brief_month_view(year, month, day);
1008                 }
1009                 else {
1010                         calendar_month_view(year, month, day);
1011                 }
1012         }
1013
1014         /** Free the calendar stuff */
1015         free_calendar_buffer();
1016
1017 }
1018
1019
1020 /**
1021  * \brief get task due date
1022  * Helper function for do_tasks_view().  
1023  * \param vtodo a task to get the due date
1024  * \return the date/time due.
1025  */
1026 time_t get_task_due_date(icalcomponent *vtodo) {
1027         icalproperty *p;
1028
1029         if (vtodo == NULL) {
1030                 return(0L);
1031         }
1032
1033         /**
1034          * If we're looking at a fully encapsulated VCALENDAR
1035          * rather than a VTODO component, recurse into the data
1036          * structure until we get a VTODO.
1037          */
1038         if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
1039                 return get_task_due_date(
1040                         icalcomponent_get_first_component(
1041                                 vtodo, ICAL_VTODO_COMPONENT
1042                         )
1043                 );
1044         }
1045
1046         p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
1047         if (p != NULL) {
1048                 return(icaltime_as_timet(icalproperty_get_due(p)));
1049         }
1050         else {
1051                 return(0L);
1052         }
1053 }
1054
1055
1056 /**
1057  * \brief Compare the due dates of two tasks (this is for sorting)
1058  * \param task1 first task to compare
1059  * \param task2 second task to compare
1060  */
1061 int task_due_cmp(const void *task1, const void *task2) {
1062         time_t t1;
1063         time_t t2;
1064
1065         t1 =  get_task_due_date(((struct disp_cal *)task1)->cal);
1066         t2 =  get_task_due_date(((struct disp_cal *)task2)->cal);
1067
1068         if (t1 < t2) return(-1);
1069         if (t1 > t2) return(1);
1070         return(0);
1071 }
1072
1073
1074
1075
1076 /**
1077  * \brief do the whole task view stuff
1078  */
1079 void do_tasks_view(void) {
1080         int i;
1081         time_t due;
1082         int bg = 0;
1083         char buf[SIZ];
1084         icalproperty *p;
1085
1086         wprintf("<div class=\"fix_scrollbar_bug\">"
1087                 "<table class=\"calendar_view_background\">\n<tr>\n"
1088                 "<th>");
1089         wprintf(_("Name of task"));
1090         wprintf("</th><th>");
1091         wprintf(_("Date due"));
1092         wprintf("</th></tr>\n"
1093         );
1094
1095         /** Sort them if necessary */
1096         if (WC->num_cal > 1) {
1097                 qsort(WC->disp_cal,
1098                         WC->num_cal,
1099                         sizeof(struct disp_cal),
1100                         task_due_cmp
1101                 );
1102         }
1103
1104         if (WC->num_cal) for (i=0; i<(WC->num_cal); ++i) {
1105
1106                 bg = 1 - bg;
1107                 wprintf("<tr bgcolor=\"#%s\"><td>",
1108                         (bg ? "DDDDDD" : "FFFFFF")
1109                 );
1110
1111                 p = icalcomponent_get_first_property(WC->disp_cal[i].cal,
1112                                                         ICAL_SUMMARY_PROPERTY);
1113                 wprintf("<a href=\"display_edit_task?msgnum=%ld&taskrm=",
1114                         WC->disp_cal[i].cal_msgnum );
1115                 urlescputs(WC->wc_roomname);
1116                 wprintf("\">");
1117                 wprintf("<img align=middle "
1118                         "src=\"static/taskmanag_16x.gif\" border=0>&nbsp;");
1119                 if (p != NULL) {
1120                         escputs((char *)icalproperty_get_comment(p));
1121                 }
1122                 wprintf("</a>\n");
1123                 wprintf("</td>\n");
1124
1125                 due = get_task_due_date(WC->disp_cal[i].cal);
1126                 fmt_date(buf, due, 0);
1127                 wprintf("<td><font");
1128                 if (due < time(NULL)) {
1129                         wprintf(" color=\"#FF0000\"");
1130                 }
1131                 wprintf(">%s</font></td></tr>\n", buf);
1132         }
1133
1134         wprintf("</table></div>\n");
1135
1136         /** Free the list */
1137         free_calendar_buffer();
1138
1139 }
1140
1141 #else   /* WEBCIT_WITH_CALENDAR_SERVICE */
1142
1143 /**\brief stub for non-libical builds */
1144 void do_calendar_view(void) {
1145         wprintf("<center><i>");
1146         wprintf(_("The calendar view is not available."));
1147         wprintf("</i></center><br />\n");
1148 }
1149
1150 /**\brief stub for non-libical builds */
1151 void do_tasks_view(void) {      
1152         wprintf("<center><I>");
1153         wprintf(_("The tasks view is not available."));
1154         wprintf("</i></center><br />\n");
1155 }
1156
1157
1158 #endif  /* WEBCIT_WITH_CALENDAR_SERVICE */
1159
1160 /** @} */