4 * Handles the HTML display of calendar items.
10 /* These define how high the hour rows are in the day view */
12 #define EXTRATIMELINE (TIMELINE / 2)
14 void embeddable_mini_calendar(int year
, int month
)
16 struct tm starting_tm
;
20 time_t previous_month
;
22 time_t colheader_time
;
23 struct tm colheader_tm
;
24 char colheader_label
[32];
29 snprintf(div_id
, sizeof div_id
, "mini_calendar_%d", rand() );
31 /* Determine what day to start. If an impossible value is found, start on Sunday.
33 get_pref_long("weekstart", &weekstart
, 17);
34 if (weekstart
> 6) weekstart
= 0;
37 * Now back up to the 1st of the month...
39 memset(&starting_tm
, 0, sizeof(struct tm
));
41 starting_tm
.tm_year
= year
- 1900;
42 starting_tm
.tm_mon
= month
- 1;
43 starting_tm
.tm_mday
= 1;
44 thetime
= mktime(&starting_tm
);
46 memcpy(&tm
, &starting_tm
, sizeof(struct tm
));
47 while (tm
.tm_mday
!= 1) {
48 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
49 localtime_r(&thetime
, &tm
);
52 /* Determine previous and next months ... for links */
53 previous_month
= thetime
- (time_t)864000L; /* back 10 days */
54 next_month
= thetime
+ (time_t)(31L * 86400L); /* ahead 31 days */
56 /* Now back up until we're on the user's preferred start day */
57 localtime_r(&thetime
, &tm
);
58 while (tm
.tm_wday
!= weekstart
) {
59 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
60 localtime_r(&thetime
, &tm
);
63 wprintf("<div class=\"mini_calendar\" id=\"%s\">\n", div_id
);
65 /* Previous month link */
66 localtime_r(&previous_month
, &tm
);
67 wprintf("<a href=\"javascript:minical_change_month(%d,%d);\">«</a>",
68 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
70 wc_strftime(colheader_label
, sizeof colheader_label
, "%B", &starting_tm
);
71 wprintf(" "
72 "<span class=\"mini_calendar_month_label\">"
75 " ", colheader_label
, year
);
78 localtime_r(&next_month
, &tm
);
79 wprintf("<a href=\"javascript:minical_change_month(%d,%d);\">»</a>",
80 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
82 wprintf("<table border=0 cellpadding=1 cellspacing=1 class=\"mini_calendar_days\">"
84 colheader_time
= thetime
;
86 colheader_time
= thetime
+ (i
* 86400) ;
87 localtime_r(&colheader_time
, &colheader_tm
);
88 wc_strftime(colheader_label
, sizeof colheader_label
, "%A", &colheader_tm
);
89 wprintf("<th>%c</th>", colheader_label
[0]);
95 /* Now do 35 or 42 days */
96 for (i
= 0; i
< 42; ++i
) {
97 localtime_r(&thetime
, &tm
);
101 /* Before displaying Sunday, start a new row */
106 if (tm
.tm_mon
== month
-1) {
107 snprintf(url
, sizeof url
, "readfwd?calview=day&year=%d&month=%d&day=%d",
108 tm
.tm_year
+1900, tm
.tm_mon
+1, tm
.tm_mday
);
109 wprintf("<td><a href=\"%s\">%d</a></td>", url
, tm
.tm_mday
);
112 wprintf("<td> </td>");
115 /* After displaying one week, end the row */
122 thetime
+= (time_t)86400; /* ahead 24 hours */
125 wprintf("</table>" /* end of inner table */
128 StrBufAppendPrintf(WC
->trailing_javascript
,
129 " function minical_change_month(year, month) { \n"
130 " p = 'year=' + year + '&month=' + month \n"
131 " + '&r=' + CtdlRandomString(); \n"
132 " new Ajax.Updater('%s', 'mini_calendar', \n"
133 " { method: 'get', parameters: p, evalScripts: true } ); \n"
142 * ajax embedder for the above mini calendar
144 void ajax_mini_calendar(void)
146 embeddable_mini_calendar( ibstr("year"), ibstr("month"));
151 * Display one day of a whole month view of a calendar
153 void calendar_month_view_display_events(int year
, int month
, int day
)
160 icalproperty
*p
= NULL
;
161 icalproperty
*q
= NULL
;
162 struct icaltimetype t
;
163 struct icaltimetype end_t
;
164 struct icaltimetype today_start_t
;
165 struct icaltimetype today_end_t
;
166 struct tm starting_tm
;
168 int all_day_event
= 0;
174 if (GetCount(WCC
->disp_cal_items
) == 0) {
175 wprintf("<br /><br /><br />\n");
180 * Create an imaginary event which spans the 24 hours of today. Any events which
181 * overlap with this one take place at least partially in this day. We have to
182 * convert it from a struct tm in order to make it UTC.
184 memset(&starting_tm
, 0, sizeof(struct tm
));
185 starting_tm
.tm_year
= year
- 1900;
186 starting_tm
.tm_mon
= month
- 1;
187 starting_tm
.tm_mday
= day
;
188 starting_tm
.tm_hour
= 0;
189 starting_tm
.tm_min
= 0;
190 today_start_t
= icaltime_from_timet_with_zone(mktime(&starting_tm
), 0, icaltimezone_get_utc_timezone());
191 today_start_t
.is_utc
= 1;
193 memset(&ending_tm
, 0, sizeof(struct tm
));
194 ending_tm
.tm_year
= year
- 1900;
195 ending_tm
.tm_mon
= month
- 1;
196 ending_tm
.tm_mday
= day
;
197 ending_tm
.tm_hour
= 23;
198 ending_tm
.tm_min
= 59;
199 today_end_t
= icaltime_from_timet_with_zone(mktime(&ending_tm
), 0, icaltimezone_get_utc_timezone());
200 today_end_t
.is_utc
= 1;
203 * Now loop through our list of events to see which ones occur today.
205 Pos
= GetNewHashPos(WCC
->disp_cal_items
, 0);
206 while (GetNextHashPos(WCC
->disp_cal_items
, Pos
, &hklen
, &HashKey
, &vCal
)) {
207 Cal
= (disp_cal
*)vCal
;
209 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTSTART_PROPERTY
);
211 t
= icalproperty_get_dtstart(q
);
214 memset(&t
, 0, sizeof t
);
216 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTEND_PROPERTY
);
218 end_t
= icalproperty_get_dtend(q
);
221 memset(&end_t
, 0, sizeof end_t
);
223 if (t
.is_date
) all_day_event
= 1;
227 show_event
= ((t
.year
== year
) && (t
.month
== month
) && (t
.day
== day
));
231 show_event
= ical_ctdl_is_overlap(t
, end_t
, today_start_t
, today_end_t
);
235 * If we determined that this event occurs today, then display it.
238 p
= icalcomponent_get_first_property(Cal
->cal
, ICAL_SUMMARY_PROPERTY
);
242 wprintf("<table border=0 cellpadding=2><TR>"
243 "<td bgcolor=\"#CCCCDD\">"
247 wprintf("<font size=\"-1\">"
248 "<a class=\"event%s\" href=\"display_edit_event?"
249 "msgnum=%ld?calview=month?year=%d?month=%d?day=%d\""
251 (Cal
->unread
)?"_unread":"_read",
256 wprintf("<i>%s: %s</i><br />", _("From"), Cal
->from
);
257 wprintf("<i>%s</i> ", _("Summary:"));
258 escputs((char *)icalproperty_get_comment(p
));
261 q
= icalcomponent_get_first_property(
263 ICAL_LOCATION_PROPERTY
);
265 wprintf("<i>%s</i> ", _("Location:"));
266 escputs((char *)icalproperty_get_comment(q
));
271 * Only show start/end times if we're actually looking at the VEVENT
272 * component. Otherwise it shows bogus dates for e.g. timezones
274 if (icalcomponent_isa(Cal
->cal
) == ICAL_VEVENT_COMPONENT
) {
276 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTSTART_PROPERTY
);
278 t
= icalproperty_get_dtstart(q
);
283 memset(&d_tm
, 0, sizeof d_tm
);
284 d_tm
.tm_year
= t
.year
- 1900;
285 d_tm
.tm_mon
= t
.month
- 1;
286 d_tm
.tm_mday
= t
.day
;
287 wc_strftime(d_str
, sizeof d_str
, "%x", &d_tm
);
288 wprintf("<i>%s</i> %s<br>",
292 tt
= icaltime_as_timet(t
);
293 webcit_fmt_date(buf
, tt
, 1);
294 wprintf("<i>%s</i> %s<br>",
295 _("Starting date/time:"), buf
);
298 * Embed the 'show end date/time' loop inside here so it
299 * only executes if this is NOT an all day event.
301 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTEND_PROPERTY
);
303 t
= icalproperty_get_dtend(q
);
304 tt
= icaltime_as_timet(t
);
305 webcit_fmt_date(buf
, tt
, 1);
306 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf
);
314 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DESCRIPTION_PROPERTY
);
316 wprintf("<i>%s</i> ", _("Notes:"));
317 escputs((char *)icalproperty_get_comment(q
));
323 icalproperty_get_comment(p
));
324 wprintf("</a></font><br />\n");
327 wprintf("</td></tr></table>");
341 * Display one day of a whole month view of a calendar
343 void calendar_month_view_brief_events(time_t thetime
, const char *daycolor
) {
357 struct icaltimetype t
;
359 int month
, day
, year
;
360 int all_day_event
= 0;
364 time_format
= get_time_format_cached ();
366 if (time_format
== WC_TIMEFORMAT_24
) timeformat
="%k:%M";
367 else timeformat
="%I:%M %p";
369 localtime_r(&thetime
, &today_tm
);
370 month
= today_tm
.tm_mon
+ 1;
371 day
= today_tm
.tm_mday
;
372 year
= today_tm
.tm_year
+ 1900;
374 Pos
= GetNewHashPos(WCC
->disp_cal_items
, 0);
375 while (GetNextHashPos(WCC
->disp_cal_items
, Pos
, &hklen
, &HashKey
, &vCal
)) {
376 Cal
= (disp_cal
*)vCal
;
377 p
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTSTART_PROPERTY
);
379 t
= icalproperty_get_dtstart(p
);
380 event_tt
= icaltime_as_timet(t
);
382 if (t
.is_date
) all_day_event
= 1;
383 else all_day_event
= 0;
386 gmtime_r(&event_tts
, &event_tms
);
389 localtime_r(&event_tts
, &event_tms
);
391 /* \todo epoch &! daymask */
392 if ((event_tms
.tm_year
== today_tm
.tm_year
)
393 && (event_tms
.tm_mon
== today_tm
.tm_mon
)
394 && (event_tms
.tm_mday
== today_tm
.tm_mday
)) {
400 p
= icalcomponent_get_first_property(
402 ICAL_SUMMARY_PROPERTY
);
403 e
= icalcomponent_get_first_property(
405 ICAL_DTEND_PROPERTY
);
406 if ((p
!= NULL
) && (e
!= NULL
)) {
409 t
= icalproperty_get_dtend(e
);
410 event_tte
= icaltime_as_timet(t
);
411 localtime_r(&event_tte
, &event_tme
);
412 difftime
=(event_tte
-event_tts
)/60;
413 hours
=(int)(difftime
/ 60);
414 minutes
=difftime
% 60;
415 wprintf("<tr><td bgcolor='%s'>%i:%2i</td><td bgcolor='%s'>"
417 "<a class=\"event%s\" href=\"display_edit_event?msgnum=%ld?calview=calbrief?year=%s?month=%s?day=%s\">",
420 (Cal
->unread
)?"_unread":"_read",
429 icalproperty_get_comment(p
));
430 /* \todo: allso ammitime format */
431 wc_strftime(&sbuf
[0], sizeof(sbuf
), timeformat
, &event_tms
);
432 wc_strftime(&ebuf
[0], sizeof(sbuf
), timeformat
, &event_tme
);
434 wprintf("</a></font></td>"
435 "<td bgcolor='%s'>%s</td><td bgcolor='%s'>%s</td></tr>",
452 * view one month. pretty view
454 void calendar_month_view(int year
, int month
, int day
) {
455 struct tm starting_tm
;
459 time_t previous_month
;
461 time_t colheader_time
;
462 struct tm colheader_tm
;
463 char colheader_label
[32];
467 * Determine what day to start. If an impossible value is found, start on Sunday.
469 get_pref_long("weekstart", &weekstart
, 17);
470 if (weekstart
> 6) weekstart
= 0;
473 * Now back up to the 1st of the month...
475 memset(&starting_tm
, 0, sizeof(struct tm
));
477 starting_tm
.tm_year
= year
- 1900;
478 starting_tm
.tm_mon
= month
- 1;
479 starting_tm
.tm_mday
= day
;
480 thetime
= mktime(&starting_tm
);
482 memcpy(&tm
, &starting_tm
, sizeof(struct tm
));
483 while (tm
.tm_mday
!= 1) {
484 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
485 localtime_r(&thetime
, &tm
);
488 /* Determine previous and next months ... for links */
489 previous_month
= thetime
- (time_t)864000L; /* back 10 days */
490 next_month
= thetime
+ (time_t)(31L * 86400L); /* ahead 31 days */
492 /* Now back up until we're on the user's preferred start day */
493 localtime_r(&thetime
, &tm
);
494 while (tm
.tm_wday
!= weekstart
) {
495 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
496 localtime_r(&thetime
, &tm
);
499 /* Outer table (to get the background color) */
500 wprintf("<div class=\"fix_scrollbar_bug\">"
501 "<table class=\"calendar\"> \n <tr><td>");
503 wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
505 wprintf("<td align=center>");
507 localtime_r(&previous_month
, &tm
);
508 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
509 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
510 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
512 wc_strftime(colheader_label
, sizeof colheader_label
, "%B", &starting_tm
);
513 wprintf(" "
514 "<font size=+1 color=\"#FFFFFF\">"
517 " ", colheader_label
, year
);
519 localtime_r(&next_month
, &tm
);
520 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
521 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
522 wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
524 wprintf("</td></tr></table>\n");
526 /* Inner table (the real one) */
527 wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
528 "bgcolor=#204B78 id=\"inner_month\"><tr>");
529 colheader_time
= thetime
;
530 for (i
=0; i
<7; ++i
) {
531 colheader_time
= thetime
+ (i
* 86400) ;
532 localtime_r(&colheader_time
, &colheader_tm
);
533 wc_strftime(colheader_label
, sizeof colheader_label
, "%A", &colheader_tm
);
534 wprintf("<th align=center width=14%%>"
535 "<font color=\"#FFFFFF\">%s</font></th>", colheader_label
);
541 /* Now do 35 or 42 days */
542 localtime_r(&thetime
, &tm
);
543 for (i
= 0; i
<42; ++i
) {
545 /* Before displaying the first day of the week, start a new row */
550 wprintf("<td class=\"cal%s\"><div class=\"day\">",
551 ((tm
.tm_mon
!= month
-1) ? "out" :
552 ((tm
.tm_wday
==0 || tm
.tm_wday
==6) ? "weekend" :
555 if ((i
==0) || (tm
.tm_mday
== 1)) {
556 wc_strftime(colheader_label
, sizeof colheader_label
, "%B", &tm
);
557 wprintf("%s ", colheader_label
);
559 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">"
566 /* put the data here, stupid */
567 calendar_month_view_display_events(
575 /* After displaying the last day of the week, end the row */
580 thetime
+= (time_t)86400; /* ahead 24 hours */
581 localtime_r(&thetime
, &tm
);
583 if ( ((i
% 7) == 6) && (tm
.tm_mon
!= month
-1) && (tm
.tm_mday
< 15) ) {
584 i
= 100; /* break out of the loop */
588 wprintf("</table>" /* end of inner table */
589 "</td></tr></table>" /* end of outer table */
593 * Initialize the bubble tooltips.
595 * Yes, this is as stupid as it looks. Instead of just making the call
596 * to btt_enableTooltips() straight away, we have to create a timer event
597 * and let it initialize as an event after 1 millisecond. This is to
598 * work around a bug in Internet Explorer that causes it to crash if we
599 * manipulate the innerHTML of various DOM nodes while the page is still
600 * being rendered. See http://www.shaftek.org/blog/archives/000212.html
601 * for more information.
603 StrBufAppendPrintf(WC
->trailing_javascript
,
604 " setTimeout(\"btt_enableTooltips('inner_month')\", 1); \n"
609 * view one month. brief view
611 void calendar_brief_month_view(int year
, int month
, int day
) {
612 struct tm starting_tm
;
616 time_t previous_month
;
618 char month_label
[32];
620 /* Determine what day to start.
621 * First, back up to the 1st of the month...
623 memset(&starting_tm
, 0, sizeof(struct tm
));
624 starting_tm
.tm_year
= year
- 1900;
625 starting_tm
.tm_mon
= month
- 1;
626 starting_tm
.tm_mday
= day
;
627 thetime
= mktime(&starting_tm
);
629 memcpy(&tm
, &starting_tm
, sizeof(struct tm
));
630 while (tm
.tm_mday
!= 1) {
631 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
632 localtime_r(&thetime
, &tm
);
635 /* Determine previous and next months ... for links */
636 previous_month
= thetime
- (time_t)864000L; /* back 10 days */
637 next_month
= thetime
+ (time_t)(31L * 86400L); /* ahead 31 days */
639 /* Now back up until we're on a Sunday */
640 localtime_r(&thetime
, &tm
);
641 while (tm
.tm_wday
!= 0) {
642 thetime
= thetime
- (time_t)86400; /* go back 24 hours */
643 localtime_r(&thetime
, &tm
);
646 /* Outer table (to get the background color) */
647 wprintf("<div class=\"fix_scrollbar_bug\">"
648 "<table width=100%% border=0 cellpadding=0 cellspacing=0 "
649 "bgcolor=#204B78><TR><TD>\n");
651 wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
653 wprintf("<td align=center>");
655 localtime_r(&previous_month
, &tm
);
656 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
657 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
658 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
660 wc_strftime(month_label
, sizeof month_label
, "%B", &tm
);
661 wprintf(" "
662 "<font size=+1 color=\"#FFFFFF\">"
665 " ", month_label
, year
);
667 localtime_r(&next_month
, &tm
);
668 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
669 (int)(tm
.tm_year
)+1900, tm
.tm_mon
+ 1);
670 wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
672 wprintf("</td></tr></table>\n");
674 /* Inner table (the real one) */
675 wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
676 "bgcolor=#EEEECC><TR>");
678 wprintf("<tr><td colspan=\"100%%\">\n");
681 for (i
= 0; i
< 35; ++i
) {
682 char weeknumber
[255];
683 char weekday_name
[32];
685 localtime_r(&thetime
, &tm
);
688 /* Before displaying Sunday, start a new CELL */
690 wc_strftime(&weeknumber
[0], sizeof(weeknumber
), "%U", &tm
);
691 wprintf("<table border='0' bgcolor=\"#EEEECC\" width='100%%'> <tr><th colspan='4'>%s %s</th></tr>"
692 " <tr><td>%s</td><td width=70%%>%s</td><td>%s</td><td>%s</td></tr>\n",
702 daycolor
=((tm
.tm_mon
!= month
-1) ? "DDDDDD" :
703 ((tm
.tm_wday
==0 || tm
.tm_wday
==6) ? "EEEECC" :
707 wc_strftime(weekday_name
, sizeof weekday_name
, "%A", &tm
);
708 wprintf("<tr><td bgcolor='%s' colspan='1' align='left'> %s,%i."
709 "</td><td bgcolor='%s' colspan='3'><hr></td></tr>\n",
711 weekday_name
,tm
.tm_mday
,
714 /* put the data of one day here, stupid */
715 calendar_month_view_brief_events(thetime
, daycolor
);
718 /* After displaying Saturday, end the row */
720 wprintf("</td></tr></table>\n");
723 thetime
+= (time_t)86400; /* ahead 24 hours */
726 wprintf("</table>" /* end of inner table */
727 "</td></tr></table>" /* end of outer table */
732 * Calendar week view -- not implemented yet, this is a stub function
734 void calendar_week_view(int year
, int month
, int day
) {
735 wprintf("<center><i>week view FIXME</i></center><br />\n");
741 * Display events for a particular hour of a particular day.
742 * (Specify hour < 0 to show "all day" events)
744 * dstart and dend indicate which hours our "daytime" begins and end
746 void calendar_day_view_display_events(time_t thetime
,
758 icalproperty
*p
= NULL
;
759 icalproperty
*q
= NULL
;
765 int all_day_event
= 0;
766 int ongoing_event
= 0;
769 struct icaltimetype t
;
770 struct icaltimetype end_t
;
771 struct icaltimetype today_start_t
;
772 struct icaltimetype today_end_t
;
773 struct tm starting_tm
;
786 if (GetCount(WCC
->disp_cal_items
) == 0) {
787 /* nothing to display */
791 /* Create an imaginary event which spans the current day. Any events which
792 * overlap with this one take place at least partially in this day.
794 memset(&starting_tm
, 0, sizeof(struct tm
));
795 starting_tm
.tm_year
= year
- 1900;
796 starting_tm
.tm_mon
= month
- 1;
797 starting_tm
.tm_mday
= day
;
798 starting_tm
.tm_hour
= 0;
799 starting_tm
.tm_min
= 0;
800 today_start_t
= icaltime_from_timet_with_zone(mktime(&starting_tm
), 0, icaltimezone_get_utc_timezone());
801 today_start_t
.is_utc
= 1;
803 memset(&ending_tm
, 0, sizeof(struct tm
));
804 ending_tm
.tm_year
= year
- 1900;
805 ending_tm
.tm_mon
= month
- 1;
806 ending_tm
.tm_mday
= day
;
807 ending_tm
.tm_hour
= 23;
808 ending_tm
.tm_min
= 59;
809 today_end_t
= icaltime_from_timet_with_zone(mktime(&ending_tm
), 0, icaltimezone_get_utc_timezone());
810 today_end_t
.is_utc
= 1;
812 /* Now loop through our list of events to see which ones occur today.
814 Pos
= GetNewHashPos(WCC
->disp_cal_items
, 0);
815 while (GetNextHashPos(WCC
->disp_cal_items
, Pos
, &hklen
, &HashKey
, &vCal
)) {
816 Cal
= (disp_cal
*)vCal
;
821 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTSTART_PROPERTY
);
823 t
= icalproperty_get_dtstart(q
);
824 event_tt
= icaltime_as_timet(t
);
825 localtime_r(&event_tt
, &event_te
);
828 memset(&t
, 0, sizeof t
);
830 q
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTEND_PROPERTY
);
832 end_t
= icalproperty_get_dtend(q
);
833 event_tte
= icaltime_as_timet(end_t
);
834 localtime_r(&event_tte
, &event_tm
);
837 memset(&end_t
, 0, sizeof end_t
);
839 if (t
.is_date
) all_day_event
= 1;
843 show_event
= ((t
.year
== year
) && (t
.month
== month
) && (t
.day
== day
) && (notime_events
));
847 show_event
= ical_ctdl_is_overlap(t
, end_t
, today_start_t
, today_end_t
);
850 /* If we determined that this event occurs today, then display it.
852 p
= icalcomponent_get_first_property(Cal
->cal
,ICAL_SUMMARY_PROPERTY
);
854 if ((show_event
) && (p
!= NULL
)) {
856 if ((event_te
.tm_mday
!= day
) || (event_tm
.tm_mday
!= day
)) ongoing_event
= 1;
858 if (all_day_event
&& notime_events
)
860 wprintf("<li class=\"event_framed%s\"> "
861 "<a href=\"display_edit_event?"
862 "msgnum=%ld?calview=day?year=%d?month=%d?day=%d\" "
863 " class=\"event_title\" "
865 (Cal
->unread
)?"_unread":"_read",
866 Cal
->cal_msgnum
, year
, month
, day
);
867 wprintf("<i>%s</i><br />", _("All day event"));
868 wprintf("<i>%s: %s</i><br />", _("From"), Cal
->from
);
869 wprintf("<i>%s</i> ", _("Summary:"));
870 escputs((char *) icalproperty_get_comment(p
));
872 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_LOCATION_PROPERTY
);
874 wprintf("<i>%s</i> ", _("Location:"));
875 escputs((char *)icalproperty_get_comment(q
));
878 memset(&d_tm
, 0, sizeof d_tm
);
879 d_tm
.tm_year
= t
.year
- 1900;
880 d_tm
.tm_mon
= t
.month
- 1;
881 d_tm
.tm_mday
= t
.day
;
882 wc_strftime(d_str
, sizeof d_str
, "%x", &d_tm
);
883 wprintf("<i>%s</i> %s<br>",_("Date:"), d_str
);
884 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_DESCRIPTION_PROPERTY
);
886 wprintf("<i>%s</i> ", _("Notes:"));
887 escputs((char *)icalproperty_get_comment(q
));
891 escputs((char *) icalproperty_get_comment(p
));
892 wprintf("</a> <span>(");
893 wprintf(_("All day event"));
894 wprintf(")</span></li>\n");
896 else if (ongoing_event
&& notime_events
)
898 wprintf("<li class=\"event_framed%s\"> "
899 "<a href=\"display_edit_event?"
900 "msgnum=%ld&calview=day?year=%d?month=%d?day=%d\" "
901 " class=\"event_title\" "
903 (Cal
->unread
)?"_unread":"_read",
904 Cal
->cal_msgnum
, year
, month
, day
);
905 wprintf("<i>%s</i><br />", _("Ongoing event"));
906 wprintf("<i>%s: %s</i><br />", _("From"), Cal
->from
);
907 wprintf("<i>%s</i> ", _("Summary:"));
908 escputs((char *) icalproperty_get_comment(p
));
910 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_LOCATION_PROPERTY
);
912 wprintf("<i>%s</i> ", _("Location:"));
913 escputs((char *)icalproperty_get_comment(q
));
916 webcit_fmt_date(buf
, event_tt
, 1);
917 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf
);
918 webcit_fmt_date(buf
, event_tte
, 1);
919 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf
);
920 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_DESCRIPTION_PROPERTY
);
922 wprintf("<i>%s</i> ", _("Notes:"));
923 escputs((char *)icalproperty_get_comment(q
));
927 escputs((char *) icalproperty_get_comment(p
));
928 wprintf("</a> <span>(");
929 wprintf(_("Ongoing event"));
930 wprintf(")</span></li>\n");
932 else if (!all_day_event
&& !notime_events
)
936 if (event_te
.tm_mday
!= day
) event_te
.tm_hour
= 0;
937 if (event_tm
.tm_mday
!= day
) event_tm
.tm_hour
= 24;
939 /* Calculate the location of the top of the box */
940 if (event_te
.tm_hour
< dstart
) {
941 startmin
= diffmin
= event_te
.tm_min
/ 6;
942 top
= (event_te
.tm_hour
* EXTRATIMELINE
) + startmin
;
944 else if ((event_te
.tm_hour
>= dstart
) && (event_te
.tm_hour
<= dend
)) {
945 startmin
= diffmin
= (event_te
.tm_min
/ 2);
946 top
= (dstart
* EXTRATIMELINE
) + ((event_te
.tm_hour
- dstart
) * TIMELINE
) + startmin
;
948 else if (event_te
.tm_hour
>dend
) {
949 startmin
= diffmin
= event_te
.tm_min
/ 6;
950 top
= (dstart
* EXTRATIMELINE
) + ((dend
- dstart
- 1) * TIMELINE
) + ((event_tm
.tm_hour
- dend
+ 1) * EXTRATIMELINE
) + startmin
;
953 /* should never get here */
956 /* Calculate the location of the bottom of the box */
957 if (event_tm
.tm_hour
< dstart
) {
958 endmin
= diffmin
= event_tm
.tm_min
/ 6;
959 bottom
= (event_tm
.tm_hour
* EXTRATIMELINE
) + endmin
;
961 else if ((event_tm
.tm_hour
>= dstart
) && (event_tm
.tm_hour
<= dend
)) {
962 endmin
= diffmin
= (event_tm
.tm_min
/ 2);
963 bottom
= (dstart
* EXTRATIMELINE
) + ((event_tm
.tm_hour
- dstart
) * TIMELINE
) + endmin
;
965 else if (event_tm
.tm_hour
>dend
) {
966 endmin
= diffmin
= event_tm
.tm_min
/ 6;
967 bottom
= (dstart
* EXTRATIMELINE
) + ((dend
- dstart
+ 1) * TIMELINE
) + ((event_tm
.tm_hour
- dend
- 1) * EXTRATIMELINE
) + endmin
;
970 /* should never get here */
973 wprintf("<dd class=\"event_framed%s\" "
974 "style=\"position: absolute; "
975 "top:%dpx; left:%dpx; "
977 (Cal
->unread
)?"_unread":"_read",
978 top
, (gap
* 40), (bottom
-top
)
980 wprintf("<a href=\"display_edit_event?"
981 "msgnum=%ld?calview=day?year=%d?month=%d?day=%d?hour=%d\" "
982 "class=\"event_title\" "
984 Cal
->cal_msgnum
, year
, month
, day
, t
.hour
);
985 wprintf("<i>%s: %s</i><br />", _("From"), Cal
->from
);
986 wprintf("<i>%s</i> ", _("Summary:"));
987 escputs((char *) icalproperty_get_comment(p
));
989 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_LOCATION_PROPERTY
);
991 wprintf("<i>%s</i> ", _("Location:"));
992 escputs((char *)icalproperty_get_comment(q
));
995 webcit_fmt_date(buf
, event_tt
, 1);
996 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf
);
997 webcit_fmt_date(buf
, event_tte
, 1);
998 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf
);
999 q
= icalcomponent_get_first_property(Cal
->cal
,ICAL_DESCRIPTION_PROPERTY
);
1001 wprintf("<i>%s</i> ", _("Notes:"));
1002 escputs((char *)icalproperty_get_comment(q
));
1007 escputs((char *) icalproperty_get_comment(p
));
1008 wprintf("</a></dd>\n");
1012 DeleteHashPos(&Pos
);
1018 void calendar_day_view(int year
, int month
, int day
) {
1020 struct icaltimetype today
, yesterday
, tomorrow
;
1027 int timeline
= TIMELINE
;
1028 int extratimeline
= EXTRATIMELINE
;
1033 time_format
= get_time_format_cached ();
1034 get_pref_long("daystart", &daystart
, 8);
1035 get_pref_long("dayend", &dayend
, 17);
1037 /* when loading daystart/dayend, replace missing, corrupt, or impossible values with defaults */
1038 if ((daystart
< 0) || (dayend
< 2) || (daystart
>= 23) || (dayend
> 23) || (dayend
<= daystart
)) {
1044 memset(&d_tm
, 0, sizeof d_tm
);
1045 d_tm
.tm_year
= year
- 1900;
1046 d_tm
.tm_mon
= month
- 1;
1048 today_t
= mktime(&d_tm
);
1050 /* Figure out the dates for "yesterday" and "tomorrow" links */
1052 memset(&today
, 0, sizeof(struct icaltimetype
));
1054 today
.month
= month
;
1058 memcpy(&yesterday
, &today
, sizeof(struct icaltimetype
));
1060 yesterday
= icaltime_normalize(yesterday
);
1062 memcpy(&tomorrow
, &today
, sizeof(struct icaltimetype
));
1064 tomorrow
= icaltime_normalize(tomorrow
);
1066 wprintf("<div class=\"fix_scrollbar_bug\">");
1068 /* Inner table (the real one) */
1069 wprintf("<table class=\"calendar\" id=\"inner_day\"><tr> \n");
1071 /* Innermost cell (contains hours etc.) */
1072 wprintf("<td class=\"events_of_the_day\" >");
1073 wprintf("<dl class=\"events\" >");
1075 /* Now the middle of the day... */
1077 extrahourlabel
= extratimeline
- 2;
1078 hourlabel
= extrahourlabel
* 150 / 100;
1079 if (hourlabel
> (timeline
- 2)) hourlabel
= timeline
- 2;
1081 for (hour
= 0; hour
< daystart
; ++hour
) { /* could do HEIGHT=xx */
1082 wprintf("<dt class=\"extrahour\" "
1084 "position: absolute; "
1085 "top: %dpx; left: 0px; "
1089 "<a href=\"display_edit_event?msgnum=0"
1090 "?calview=day?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1091 (hour
* extratimeline
),
1094 year
, month
, day
, hour
1097 if (time_format
== WC_TIMEFORMAT_24
) {
1098 wprintf("%2d:00</a> ", hour
);
1101 wprintf("%d:00%s</a> ",
1102 ((hour
== 0) ? 12 : (hour
<= 12 ? hour
: hour
-12)),
1103 (hour
< 12 ? "am" : "pm")
1110 gap
= daystart
* extratimeline
;
1112 for (hour
= daystart
; hour
<= dayend
; ++hour
) { /* could do HEIGHT=xx */
1113 wprintf("<dt class=\"hour\" "
1115 "position: absolute; "
1116 "top: %ldpx; left: 0px; "
1120 "<a href=\"display_edit_event?msgnum=0?calview=day"
1121 "?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1122 gap
+ ((hour
- daystart
) * timeline
),
1125 year
, month
, day
, hour
1128 if (time_format
== WC_TIMEFORMAT_24
) {
1129 wprintf("%2d:00</a> ", hour
);
1132 wprintf("%d:00%s</a> ",
1133 (hour
<= 12 ? hour
: hour
-12),
1134 (hour
< 12 ? "am" : "pm")
1141 gap
= gap
+ ((dayend
- daystart
+ 1) * timeline
);
1143 for (hour
= (dayend
+ 1); hour
< 24; ++hour
) { /* could do HEIGHT=xx */
1144 wprintf("<dt class=\"extrahour\" "
1146 "position: absolute; "
1147 "top: %ldpx; left: 0px; "
1151 "<a href=\"display_edit_event?msgnum=0?calview=day"
1152 "?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1153 gap
+ ((hour
- dayend
- 1) * extratimeline
),
1156 year
, month
, day
, hour
1159 if (time_format
== WC_TIMEFORMAT_24
) {
1160 wprintf("%2d:00</a> ", hour
);
1163 wprintf("%d:00%s</a> ",
1164 (hour
<= 12 ? hour
: hour
-12),
1165 (hour
< 12 ? "am" : "pm")
1172 /* Display events with start and end times on this day */
1173 calendar_day_view_display_events(today_t
, year
, month
, day
, 0, daystart
, dayend
);
1176 wprintf("</td>"); /* end of innermost table */
1178 /* Display extra events (start/end times not present or not today) in the middle column */
1179 wprintf("<td class=\"extra_events\">");
1183 /* Display all-day events */
1184 calendar_day_view_display_events(today_t
, year
, month
, day
, 1, daystart
, dayend
);
1188 wprintf("</td>"); /* end extra on the middle */
1190 wprintf("<td width=20%% align=center valign=top>"); /* begin stuff-on-the-right */
1192 /* Begin todays-date-with-left-and-right-arrows */
1193 wprintf("<table border=0 width=100%% "
1194 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
1198 wprintf("<td align=center>");
1199 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">",
1200 yesterday
.year
, yesterday
.month
, yesterday
.day
);
1201 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
1204 wc_strftime(d_str
, sizeof d_str
,
1206 "<font size=+2>%B</font><br />"
1207 "<font size=+3>%d</font><br />"
1208 "<font size=+2>%Y</font><br />"
1212 wprintf("%s", d_str
);
1215 wprintf("<td align=center>");
1216 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">",
1217 tomorrow
.year
, tomorrow
.month
, tomorrow
.day
);
1218 wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
1219 " border=0></a>\n");
1222 wprintf("</tr></table>\n");
1223 /* End todays-date-with-left-and-right-arrows */
1225 /* Embed a mini month calendar in this space */
1226 wprintf("<br />\n");
1227 embeddable_mini_calendar(year
, month
);
1229 wprintf("</font></center>\n");
1231 wprintf("</td></tr>"); /* end stuff-on-the-right */
1233 wprintf("</table>" /* end of inner table */
1236 StrBufAppendPrintf(WC
->trailing_javascript
,
1237 " setTimeout(\"btt_enableTooltips('inner_day')\", 1); \n"
1243 * Display today's events. Returns the number of items displayed.
1245 int calendar_summary_view(void) {
1247 const char *HashKey
;
1252 struct icaltimetype t
;
1257 int all_day_event
= 0;
1258 char timestring
[SIZ
];
1259 wcsession
*WCC
= WC
;
1260 int num_displayed
= 0;
1262 if (GetCount(WC
->disp_cal_items
) == 0) {
1267 localtime_r(&now
, &today_tm
);
1269 Pos
= GetNewHashPos(WCC
->disp_cal_items
, 0);
1270 while (GetNextHashPos(WCC
->disp_cal_items
, Pos
, &hklen
, &HashKey
, &vCal
)) {
1271 Cal
= (disp_cal
*)vCal
;
1272 p
= icalcomponent_get_first_property(Cal
->cal
, ICAL_DTSTART_PROPERTY
);
1274 t
= icalproperty_get_dtstart(p
);
1275 event_tt
= icaltime_as_timet(t
);
1282 fmt_time(timestring
, event_tt
);
1284 if (all_day_event
) {
1285 gmtime_r(&event_tt
, &event_tm
);
1288 localtime_r(&event_tt
, &event_tm
);
1291 if ( (event_tm
.tm_year
== today_tm
.tm_year
)
1292 && (event_tm
.tm_mon
== today_tm
.tm_mon
)
1293 && (event_tm
.tm_mday
== today_tm
.tm_mday
)
1296 p
= icalcomponent_get_first_property(Cal
->cal
, ICAL_SUMMARY_PROPERTY
);
1300 if (WCC
->wc_view
== VIEW_TASKS
) {
1301 wprintf("<a href=\"display_edit_task"
1303 "?return_to_summary=1"
1307 escputs(ChrPtr(WCC
->wc_roomname
));
1311 wprintf("<a href=\"display_edit_event"
1319 today_tm
.tm_year
+ 1900,
1320 today_tm
.tm_mon
+ 1,
1323 escputs(ChrPtr(WCC
->wc_roomname
));
1326 escputs((char *) icalproperty_get_comment(p
));
1327 if (!all_day_event
) {
1328 wprintf(" (%s)", timestring
);
1330 wprintf("</a><br />\n");
1336 DeleteHashPos(&Pos
);
1337 DeleteHash(&WC
->disp_cal_items
);
1338 return(num_displayed
);
1342 * Parse the URL variables in order to determine the scope and display of a calendar view
1344 void parse_calendar_view_request(struct calview
*c
) {
1350 /* In case no date was specified, go with today */
1352 localtime_r(&now
, &tm
);
1353 c
->year
= tm
.tm_year
+ 1900;
1354 c
->month
= tm
.tm_mon
+ 1;
1355 c
->day
= tm
.tm_mday
;
1357 /* Now see if a date was specified */
1358 if (havebstr("year")) c
->year
= ibstr("year");
1359 if (havebstr("month")) c
->month
= ibstr("month");
1360 if (havebstr("day")) c
->day
= ibstr("day");
1362 /* How would you like that cooked? */
1363 if (havebstr("calview")) {
1364 strcpy(calview
, bstr("calview"));
1367 strcpy(calview
, "month");
1370 /* Display the selected view */
1371 if (!strcasecmp(calview
, "day")) {
1372 c
->view
= calview_day
;
1374 else if (!strcasecmp(calview
, "week")) {
1375 c
->view
= calview_week
;
1377 else if (!strcasecmp(calview
, "summary")) { /* shouldn't ever happen, but just in case */
1378 c
->view
= calview_day
;
1381 if (WC
->wc_view
== VIEW_CALBRIEF
) {
1382 c
->view
= calview_brief
;
1385 c
->view
= calview_month
;
1389 /* Now try and set the lower and upper bounds so that we don't
1390 * burn too many cpu cycles parsing data way in the past or future
1393 tm
.tm_year
= c
->year
- 1900;
1394 tm
.tm_mon
= c
->month
- 1;
1395 tm
.tm_mday
= c
->day
;
1398 if (c
->view
== calview_month
) span
= 3888000;
1399 if (c
->view
== calview_brief
) span
= 3888000;
1400 if (c
->view
== calview_week
) span
= 604800;
1401 if (c
->view
== calview_day
) span
= 86400;
1402 if (c
->view
== calview_summary
) span
= 86400;
1404 c
->lower_bound
= now
- span
;
1405 c
->upper_bound
= now
+ span
;
1411 * Render a calendar view from data previously loaded into memory
1413 void render_calendar_view(struct calview
*c
)
1415 if (c
->view
== calview_day
) {
1416 calendar_day_view(c
->year
, c
->month
, c
->day
);
1418 else if (c
->view
== calview_week
) {
1419 calendar_week_view(c
->year
, c
->month
, c
->day
);
1422 if (WC
->wc_view
== VIEW_CALBRIEF
) {
1423 calendar_brief_month_view(c
->year
, c
->month
, c
->day
);
1426 calendar_month_view(c
->year
, c
->month
, c
->day
);
1430 /* Free the in-memory list of calendar items */
1431 DeleteHash(&WC
->disp_cal_items
);
1436 * Helper function for do_tasks_view(). Returns the due date/time of a vtodo.
1438 time_t get_task_due_date(icalcomponent
*vtodo
) {
1441 if (vtodo
== NULL
) {
1446 * If we're looking at a fully encapsulated VCALENDAR
1447 * rather than a VTODO component, recurse into the data
1448 * structure until we get a VTODO.
1450 if (icalcomponent_isa(vtodo
) == ICAL_VCALENDAR_COMPONENT
) {
1451 return get_task_due_date(
1452 icalcomponent_get_first_component(
1453 vtodo
, ICAL_VTODO_COMPONENT
1458 p
= icalcomponent_get_first_property(vtodo
, ICAL_DUE_PROPERTY
);
1460 return(icaltime_as_timet(icalproperty_get_due(p
)));
1469 * Compare the due dates of two tasks (this is for sorting)
1471 int task_due_cmp(const void *vtask1
, const void *vtask2
) {
1472 disp_cal
* Task1
= (disp_cal
*)GetSearchPayload(vtask1
);
1473 disp_cal
* Task2
= (disp_cal
*)GetSearchPayload(vtask2
);
1478 t1
= get_task_due_date(Task1
->cal
);
1479 t2
= get_task_due_date(Task2
->cal
);
1480 if (t1
< t2
) return(-1);
1481 if (t1
> t2
) return(1);
1486 * qsort filter to move completed tasks to bottom of task list
1488 int task_completed_cmp(const void *vtask1
, const void *vtask2
) {
1489 disp_cal
* Task1
= (disp_cal
*)GetSearchPayload(vtask1
);
1490 /* disp_cal * Task2 = (disp_cal *)GetSearchPayload(vtask2); */
1492 icalproperty_status t1
= icalcomponent_get_status((Task1
)->cal
);
1493 /* icalproperty_status t2 = icalcomponent_get_status(((struct disp_cal *)task2)->cal); */
1495 if (t1
== ICAL_STATUS_COMPLETED
)
1503 * do the whole task view stuff
1505 void do_tasks_view(void) {
1507 const char *HashKey
;
1515 wcsession
*WCC
= WC
;
1517 wprintf("<div class=\"fix_scrollbar_bug\">"
1518 "<table class=\"calendar_view_background\"><tbody id=\"taskview\">\n<tr>\n"
1520 wprintf(_("Completed?"));
1521 wprintf("</th><th>");
1522 wprintf(_("Name of task"));
1523 wprintf("</th><th>");
1524 wprintf(_("Date due"));
1525 wprintf("</th><th>");
1526 wprintf(_("Category"));
1527 wprintf(" (<select id=\"selectcategory\"><option value=\"showall\">%s</option></select>)</th></tr>\n",
1530 nItems
= GetCount(WC
->disp_cal_items
);
1532 /* Sort them if necessary
1534 SortByPayload(WC->disp_cal_items, task_due_cmp);
1536 * this shouldn't be neccessary, since we sort by the start time.
1539 /* And then again, by completed */
1541 SortByPayload(WC
->disp_cal_items
,
1542 task_completed_cmp
);
1545 Pos
= GetNewHashPos(WCC
->disp_cal_items
, 0);
1546 while (GetNextHashPos(WCC
->disp_cal_items
, Pos
, &hklen
, &HashKey
, &vCal
)) {
1547 icalproperty_status todoStatus
;
1549 Cal
= (disp_cal
*)vCal
;
1550 wprintf("<tr><td>");
1551 todoStatus
= icalcomponent_get_status(Cal
->cal
);
1552 wprintf("<input type=\"checkbox\" name=\"completed\" value=\"completed\" ");
1553 if (todoStatus
== ICAL_STATUS_COMPLETED
) {
1554 wprintf("checked=\"checked\" ");
1556 wprintf("disabled=\"disabled\">\n</td><td>");
1557 p
= icalcomponent_get_first_property(Cal
->cal
,
1558 ICAL_SUMMARY_PROPERTY
);
1559 wprintf("<a href=\"display_edit_task?msgnum=%ld?taskrm=", Cal
->cal_msgnum
);
1560 urlescputs(ChrPtr(WC
->wc_roomname
));
1562 /* wprintf("<img align=middle "
1563 "src=\"static/taskmanag_16x.gif\" border=0> "); */
1565 escputs((char *)icalproperty_get_comment(p
));
1570 due
= get_task_due_date(Cal
->cal
);
1571 wprintf("<td><span");
1573 webcit_fmt_date(buf
, due
, 0);
1579 wprintf("</span></td>");
1581 p
= icalcomponent_get_first_property(Cal
->cal
,
1582 ICAL_CATEGORIES_PROPERTY
);
1584 escputs((char *)icalproperty_get_categories(p
));
1590 wprintf("</tbody></table></div>\n");
1593 DeleteHash(&WC
->disp_cal_items
);
1594 DeleteHashPos(&Pos
);